版权声明:本文为博主原创文章,未经博主允许不得转载。
问题的提出
- 目前android的系统,我们的程序常常由于几种原因被停掉或杀掉而不能及时重启,这对于一个安全程序来说是有相当的隐患的。例如
- 当用户从程序管理里面停掉程序。
- 其他程序优化系统时杀掉程序。
- 程序崩溃。
- 在android系统里,其他程序还能禁掉我们程序各种广播接受器,导致我们程序不能根据广播来启动。
问题的解决
- 因此,这里我想了一个办法来解决这个问题。
- 我们在android程序运行时启动一个native程序,名字叫supervisor, 该程序具备以下几个功能
- 定时检测android程序是否还在运行,如果没在运行,则启动android程序的service。
- 同一时间只有一个supervisor进程,不会起多个supervisor进程。
- 能检测android程序是否被卸载,如果被卸载则结束supervisor进程。
- 我们使用NDK实现一个native程序,程序代码如下:
1 #include <errno.h>
2 #include <fcntl.h>
3 #include <limits.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <sys/types.h>
8 #include <sys/wait.h>
9 #include <unistd.h>
10
11 #define BUFFER_LENGTH 1024
12 #define FLAG_FILE "/data/local/tmp/tmp.lock"
13 #define SLEEP_INTERVEL 10 // every x seconds to check if process is running
14 int isProcessExist(char* busyboxPath, char *processName);
15 void runProcess(char* packageName, char* serviceName);
16
17 int main(int argc, char **argv)
18 {
19 if (argc < 4)
20 {
21 fprintf(stderr, "Usage:%s <packagename> <ServiceNameOrActivityName> <busyboxpath>\n", argv[0]);
22 return -1;
23 }
24 // check if self already running.
25 int ret = -1;
26 FILE * g_lockfile = NULL;
27
28 // 检查是否已经有一个supervisor进程在运行
29 g_lockfile = fopen(FLAG_FILE, "a+");
30 if (g_lockfile == NULL)
31 {
32 fprintf(stderr, "fopen() failed:%s!\n", strerror(errno));
33 return -1;
34 }
35
36 ret = flock(fileno(g_lockfile), LOCK_EX |LOCK_NB);
37 if (ret != 0)
38 {
39 fprintf(stderr, "flock() failed:%s!\n", strerror(errno));
40 printf("this program already running\n");
41 return -1;
42 }
43
44 // 循环检测android进程是否在运行
45 while(1)
46 {
47 // 判断程序是否已被卸载,如果已经被卸载,则退出supervisor
48 if (access(argv[3], 0) == -1)
49 {
50 printf("file not exist. file:%s\n", argv[3]);
51 exit(-1);
52 }
53 // 判断android进程是否在运行,如果不在运行,则运行之
54 if (!isProcessExist(argv[3], argv[1]))
55 {
56 runProcess(argv[1], argv[2]);
57 }
58
59 sleep(SLEEP_INTERVEL);
60 }
61
62 return 0;
63 }
64
65 // 使用busybox的pidof命令来检测目标进程是否在运行
66 int isProcessExist(char* busyboxPath, char *processName)
67 {
68 char buf[BUFFER_LENGTH];
69 char command[BUFFER_LENGTH];
70 FILE *fp;
71 int ret = 0;
72 sprintf(command, "%s pidof %s", busyboxPath, processName);
73
74 if ((fp = popen(command,"r")) == NULL)
75 {
76 printf("popen failed\n");
77 exit(1);
78 }
79
80 if ((fgets(buf,BUFFER_LENGTH,fp))!= NULL )
81 {
82 ret = 1;
83 printf("pid is:%s\n", buf);
84 }
85
86 pclose(fp);
87 return ret;
88 }
89 //使用am命令来启动android程序
90 void runProcess(char* packageName, char* serviceName)
91 {
92 FILE *fp;
93 char command[BUFFER_LENGTH];
94 sprintf(command, "am start -n %s/%s", packageName, serviceName);
95 //sprintf(command, "am startservice -n %s/%s", packageName, serviceName);
96 printf("run cmd: %s\n", command);
97 if ((fp = popen(command,"r")) == NULL)
98 {
99 printf("popen failed\n");
100 exit(1);
101 }
102
103 pclose(fp);
104 }
对应的android.mk文件如下
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := supervisor LOCAL_SRC_FILES := supervisor.c include $(BUILD_EXECUTABLE)
如何启动supervisor
首先,supervisor文件是放在assets里的,在android程序第一次启动时,需要把supervisor拷贝到/data/data/应用程序下的files目录里。同时修改其属性为755.当然,我们也还需要busybox文件,因为要用到它里面的pidof命令。同理拷贝到files目录里,修改属性为755.下面是拷贝代码,然后利用ProcessBuilder的方法来运行命令。