最近学习了一个关于Android Native进程保活的工程,在此进行一下总结。
工程github如下:https://github.com/Coolerfall/Android-AppDaemon
其总体的保活工作流程如图所示:
其工作流程如下:
首先,用户调用Daemon的静态方法run,传入上下文、Service组件类名、以及检查等待的时间间隔:
1 | /** |
工程通过android.os.Build.CPU_ABI获取设备的CPU架构,选择对应的二进制文件,通过AssetManager访问文件后,复制到指定位置,使用chmod指令改变文件权限为0755:
1 | Runtime.getRuntime().exec("chmod " + mode + " " + abspath).waitFor(); |
asset文件目录如下:
通过shell执行二进制文件,传入包名、类名与时间间隔:
1 | String cmd = context.getDir(BIN_DIR_NAME, Context.MODE_PRIVATE) |
在二进制文件中,首先检查了传入的参数是否正确:
1 | if (argc < 7) |
保证传入参数个数正确,包名类名不为空后,开始创建守护进程:
1 | if ((pid = fork()) < 0) |
创建守护进程的流程如下:(此处的方法感觉有点欠缺,具体的可以去查看博客:http://blog.chinaunix.net/uid-25365622-id-3055635.html)
- 调用fork函数,创建子进程
- 使进程在后台运行,关闭父进程
- 调用setsid函数,脱离控制终端,登录会话和进程组(创建新会话)
- 调用chdir函数,改变当前工作目录至根目录
- 调用close函数,关闭从父进程继承的文件描述符,一般而言由于没有了输入终端,因此可以关闭标准输入、输出、错误文件(即0、1和2三个文件)
当工程成功创建守护进程后,开始调用signal函数处理信号:
1 | // 标识select等待循环是否运行的flag |
接着,守护进程处理以前开启的守护进程:
1 | int pid_list[100]; |
最后,利用循环轮询的方式来唤醒服务组件:
1 | while(sig_running) |
唤醒组件的代码如下:
1 | /* start daemon service */ |
在上述代码中,守护进程fork了一个子进程,然后在子进程中通过am的startservice命令,加上我们传入的包名与类名来启动对应的服务组件,启动完成后退出子进程。
因此,为了让服务可被外部调用,该工程要求我们设置Service组件的exported属性:
1 | <service |
总的来说,个人认为该工程还有以下待改进的地方:
- 该工程使用的是轮询的方法来定期给Service发送intent,资源消耗较大
- Android 5.0以上的系统在清理进程时,会把c进程一同清理掉
- 其守护方式是单向的,如果c进程挂掉了,将无法守护Service组件
- 根据源码,其每次开启守护进程时都会清除旧的守护进程,无法同时守护两个Service组件