C語言實現android中內存和CPUUsage的控制(同樣適用於任何linux設備)

Name: Background tool
Descroption: manage android memory and CPU usage.
Preparation: 
1. download BGMonitor and BGManager and push them into /system/bin.
2. chmod 777.
Usage:
1. Malloc some memory.
1.1 Format: BGManager -m [size(Mb)]
1.2 Example: BGManager -m 100
1.3 Explain: system will malloc 100Mb
2. remain some memory.
2.1 Format: BGManager -r [size(Mb)]
2.2 Example: BGManager -r 200
2.3 Explain: memory will remain 200Mb
3. spawn process.
3.1 Format: BGManager -c [number]
3.2 Example: BGManager -c 20
3.3 Explain: system will spawn 20 new processes
4. stop all processes and free all memory.
4.1 Format: BGManager -m/-r/-c -1
Note:
1. BGMonitor must be pushed into /system/bin though we would never run it.
2. If system hang after running BGmanager, please execute "rm /data/.my_fifo*" and try again.
Open issue:
1. system hang when exiting BGMonitor service when only 1 process spawned.
Steps: a. execute "BGManager -c 1".
             b. execute "BGManager -c -1".
Result: system hang.

2. system will remain at least 7-10M memory though executing "BGManager -r 0". And the reason of this issue is the android low memory mechanism. 


BG_server.c源碼

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

//#define FIFO_CHANNEL "./.my_fifo"  
//#define FIFO_CHANNEL_2 "./.my_fifo_2"  
#define FIFO_CHANNEL "/data/.my_fifo"
#define FIFO_CHANNEL_2 "/data/.my_fifo_2"
#define MBUNIT 1000000
#define KBUNIT 1000
#define STATE_TRANSITION_IS(curr_s, next_s) ((curr_state == curr_s) && (next_state == next_s))

enum {
	STATE_INIT,
	STATE_NORMAL,
};

void* mem_region_start;
long long occupiedMem = 0;

char* getStateName(int s) {
	switch(s) {
	case STATE_INIT:
		return "STATE_INIT";
	case STATE_NORMAL:
		return "STATE_NORMAL";
	default:
		return NULL;
	}
}

void delete_char(char *source, char c)
{
	int i, j, len;
	
	len = strlen(source);
	for(i=0; i<len; i++)
	{
		if(source[i] == c)
	    {
			for(j=i;j<(len-1);j++)
				source[j]=source[j+1];
			len--;
			source[len] = '\0';
	    }
	}
}

void delete_everyChar(char *source, char *deleteChar)
{
	int i, len;
	
	len = strlen(deleteChar);
	for (i=0; i<len; i++)
	{
		delete_char(source, deleteChar[i]);
	}

}

long long getCurrFreeMem() {
	FILE *stream;
	char buf[1024];
	long size;
		
	memset(buf, '\0', sizeof(buf));
	stream = popen("cat /proc/meminfo | grep MemFree", "r");
	fread(buf, sizeof(char), sizeof(buf), stream);
	pclose(stream);
	fprintf("%s", stderr, buf);
		 
	delete_everyChar(buf, "MemFree:	kB ");
	size = atoll(buf);
	return size;
}

void state_machine(long long size) {

	int curr_state, next_state;

	(mem_region_start == NULL)? (curr_state = STATE_INIT): (curr_state = STATE_NORMAL);

	switch(curr_state) {
	case STATE_INIT:
		if(size > 0) {
			next_state = STATE_NORMAL;
		}
		else {  //size==0
			next_state = STATE_INIT;
		}
		break;
	case STATE_NORMAL:
		if(size == 0) {
			next_state = STATE_INIT;
		}
		else {   //(size > 0)
			next_state = STATE_NORMAL;
		}
		break;
	}

	//fprintf(stderr,"%s -> %s\n", getStateName(curr_state), getStateName(next_state));

	if(STATE_TRANSITION_IS(STATE_INIT, STATE_INIT)) {
		//do nothing
	}
	else if(STATE_TRANSITION_IS(STATE_NORMAL, STATE_INIT)) {
		free(mem_region_start);
		mem_region_start = NULL;
		occupiedMem = 0;
		//fprintf(stderr,"free memory\n");
	}
	else if(STATE_TRANSITION_IS(STATE_INIT, STATE_NORMAL)) {
		mem_region_start = NULL;
		mem_region_start = malloc(size);
		memset(mem_region_start, 0xff, size);
		occupiedMem = size;
		//fprintf(stderr,"init %x len:%d\n", mem_region_start, size);
	}
	else if(STATE_TRANSITION_IS(STATE_NORMAL, STATE_NORMAL)) {
		free(mem_region_start);
		mem_region_start = NULL;
		mem_region_start = malloc(size);
		memset(mem_region_start, 0xff, size);
		occupiedMem = size;
		//fprintf(stderr,"resize to %x len:%d\n", mem_region_start, size);
	}

}

long FIFO_read() {
	int ret;
	int fd;
	char buf[128];
	
	memset(buf, 0, sizeof buf);
	
	if((fd=open(FIFO_CHANNEL,O_RDONLY)) < 0) {
		perror("Cannot open the FIFO");
		return -1;
	}

	if(ret=read(fd, buf, sizeof buf) < 0)
	{
		perror("Cannot read content from FIFO");
		close(fd);
		return -1;
	}
	
	//printf("%s %s\n", __FUNCTION__, buf);
	close(fd);
	return atol(buf);
}

int FIFO_read_2() {
	int ret;
	int fd;
	char buf[4];
	
	memset(buf, 0, sizeof buf);
	
	if((fd=open(FIFO_CHANNEL_2,O_RDONLY)) < 0) {
		perror("Cannot open the FIFO");
		return -1;
	}

	if(ret=read(fd, buf, sizeof buf) < 0)
	{
		perror("Cannot read content from FIFO");
		close(fd);
		return -1;
	}
	
	//printf("%s %s\n", __FUNCTION__, buf);
	close(fd);
	return atoi(buf);
}

int main() {
	fprintf(stderr, "To stop server: just start a client and send -1\n");
	unlink(FIFO_CHANNEL);
	unlink(FIFO_CHANNEL_2);

	if(mkfifo(FIFO_CHANNEL,0777) < 0) {
		perror("Cannot create FIFO channel");
		return -1;
	}
	if(mkfifo(FIFO_CHANNEL_2,0777) < 0) {
		perror("Cannot create FIFO channel_2");
		return -1;
	}

	while(1) {
		long size = 0;
		int type = 0;
		
		size = FIFO_read();
		type = FIFO_read_2();

		if (size == -1) {
			fprintf(stderr, "BGMonitor service stop\n");
			free(mem_region_start);
			break;
		}
		else if(size < -1) {
			fprintf(stderr, "Cannot input negetive value\n");
		}
		else
		{
			if(type == 1 || type == 2)
			{
				if(size >= 0) {		
					fprintf(stderr, "--------------------------------------\n");
					fprintf(stderr, "Before malloc:\n	");
					long currFreeMem = getCurrFreeMem();
					//fprintf(stderr, "malloc %d\n", size);
					if (type == 1) {
						if (size >= 8000 || (size * KBUNIT) >= (currFreeMem + occupiedMem/KBUNIT)) {
							fprintf(stderr, "Cannot malloc, not enough memory\n");
						}
						else {
							state_machine(size * MBUNIT);							
						}
					}
					else {
						if (size < 8000) {
							int checkSize = currFreeMem + occupiedMem/KBUNIT - size * KBUNIT;
							if (checkSize < 0) {
								fprintf(stderr, "Cannot malloc, not enough memory\n");
							}
							else {
								size = currFreeMem * KBUNIT + occupiedMem - size * MBUNIT;
								state_machine(size);							
							}
						}
						else {
							fprintf(stderr, "Cannot malloc, not enough memory\n");
						}
								
					}
					fprintf(stderr, "After malloc: \n");
					fprintf(stderr, "	MemOccupied:  	%lld kB\n	", occupiedMem/KBUNIT);
					getCurrFreeMem();
					fprintf(stderr, "\nPress ENTER to quit and send -1 to stop server and other process.\n");
				}
				else {
					fprintf(stderr, "Cannot input negetive value\n");
				}
			}
			else if(type == 3)
			{
				int pid, i;
					
				for(i=1;i<=size;i++)
				{
					pid = fork();
					if (pid < 0)
					{
						fprintf(stderr, "error while forking.\n");
						exit(-1);
					}
					else if (pid == 0)
					{
						int a;
						fprintf(stderr, "One process generated.\n");
						if(access("/data/.flag", 0) != 0) {
							system("touch /data/.flag");
						}
						while(1)
						{
							if(access("/data/.flag", 0) != 0) {
								break;
							}
							else {
								a = sqrt(2);
							}
						}
						exit(0);
					}
					else
					{
						;
					}
				}
			}
			else
			{
				perror("Unknown command type");
				exit(-1);
			}
		}
		
	}
 
	unlink(FIFO_CHANNEL);
	unlink(FIFO_CHANNEL_2);
	return 0;
}

BG_client.c源碼

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

//#define FIFO_CHANNEL "./.my_fifo"  
//#define FIFO_CHANNEL_2 "./.my_fifo_2"  
#define FIFO_CHANNEL "/data/.my_fifo"
#define FIFO_CHANNEL_2 "/data/.my_fifo_2"

int type = 0;

int create_server() {
	int i = system("/system/bin/BGMonitor");
	if (i != 0) {
		perror("Cannot find BG server binary!");
		return -1;
	}
	return 0;
}

int send_to_server(long size) {
	int ret = 0;
	int fd;
	char buf[128];
	char buf_2[4];
	
	memset(buf, 0, sizeof buf);
	memset(buf_2, 0, sizeof buf_2);

	if((fd=open(FIFO_CHANNEL,O_WRONLY))==-1) {
		perror("Cannot open the FIFO");
		return -1;
	}
	
	sprintf(buf, "%ld", size);

	if(ret=write(fd, buf, strlen(buf)) < 0)
	{
		perror("Cannot write to FIFO");
		close(fd);
	}
	
	if((fd=open(FIFO_CHANNEL_2,O_WRONLY))==-1) {
		perror("Cannot open the FIFO_2");
		return -1;
	}
		
	sprintf(buf_2, "%d", type);

	if(ret=write(fd, buf_2, strlen(buf_2)) < 0)
	{
		perror("Cannot write to FIFO_2");
		close(fd);
	}
	
	//printf("%s %s\n", __FUNCTION__, buf);
	close(fd);
	return 0;
}

int main(int argc, char *argv[]) {
	
	long size;
	
	if(argc != 3) {
		 fprintf(stderr,"USAGE:\n	./MemManager [type(-m, -r, -c)] [size(M)/num]\nINTRO:\n	-m: memory will malloc [size]Mb.\n	-r: memory will remain [size]Mb.\n	-c: system will spawn [num] process (cost 50\% CPU per process).\n");
		 return -1;
	}
		
	if (strcmp(argv[1], "-m") == 0) {
		type = 1;
	}
	else if (strcmp(argv[1], "-r") == 0) {
		type = 2;
	}
	else if (strcmp(argv[1], "-c") == 0) {
		type = 3;
	}
	else {
		 fprintf(stderr,"only support -m, -r and -c!\n");
		 exit(-1);
	}
	
	size = atol(argv[2]);
	if (size <= -1)
	{
		size = -1;
		system("rm /data/.flag");
	}

	
	
	if (access(FIFO_CHANNEL, 0) != 0) {
		int pid;
		pid = fork();
		if (pid < 0) {
			perror("Cannot create new child process\n");
			return -1;
		}
		else if (pid == 0) {
			create_server();
			exit(0);
		}
		else {
			sleep(1);
			send_to_server(size);		
		}
	}
	else {
		send_to_server(size);
	}
	
	return 0;
}

本程序適用於任何linux設備和服務器,只需要修改FIFO_CHANNEL和FIFO_CHANNEL_2的值即可。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章