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的值即可。