守护进程方式保证App不被杀死
- 思路
- linux进程中用到的方法
- 代码
- 1 linux进程部分
- 2 App部分
- 3 Androidmk部分
转载请注明链接
因为Android的内存管理机制,当系统内存紧张时,App如果运行在后台,容易被LowMemoryKiller杀死。为了保证App的Service能够在杀死后重启,下面介绍一种在进程杀死后能够重新拉起App的方式。
1. 思路:
简单来讲,就是开启linux守护进程,轮询App进程是否存活,如果发现进程已被杀死,通过am start将App的Service拉起。
由于此linux进程与App进程不在同一进程空间,LowMemoryKiller杀死App进程时会放过linux进程,这样就保证了linux进程作为守护进程在后台存活,监视App进程。
为了比较显著得观察到守护进程拉起App进程的过程,本例使用拉起Activity的方式演示。
2. linux进程中用到的方法:
int getopt_long(int argc, char * const argv[],const char *optstring,const struct option *longopts, int *longindex);
获取命令行参数,此处获取由Activity启动守护进程时传递进来的守护进程名、包名、Activity名、轮询间隔时间。
signal(SIGCHLD,SIG_IGN);
防止内核在子进程结束时产生僵尸进程。
int daemon(int nochdir,int noclose)
使进程成为守护进程,在后台运行。监视App进程是否存活。
int system(const char * cmdstring)
fork出shell子进程执行cmd,父进程等待shell执行完毕。用以执行am start命令,拉起App。
FILE *popen(const char *command, const char *type);
管道形式fork子进程执行command,从管道中读或写。用以读取ps命令返回的存活进程。
3. 代码:
代码实现的思路如下:
- 实现守护进程,并通过Android.mk,在源码编译或是ndk-build生成可执行程序appdaemon。
- 将守护进程程序重名为libappdaemon.so,并放在App工程ibs目录下。
- Run App安装,libappdaemon.so会拷贝在/data/data/com.example.immortalapp/lib目录下。
- 重命名libappdaemon.so为appdaemon,并chmod其执行权限。
- shell执行appdaemon,启动守护进程,并传递相关am start参数至守护进程。
- 守护进程轮询ps命令返回的存活进程,如有发现App死亡,便以am start命令启动App。
3.1 linux进程部分
#include <signal.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <android/log.h>int chk_process(const char *process_name) {FILE *stream;char *line = NULL;size_t len = 0;ssize_t read_len;//执行ps命令,获取当前进程liststream = popen("ps", "r");if (stream == NULL)return -1;int exists = 0;while (getline(&line, &len, stream) != -1) {int len = strlen(line);char *cmd = line + len;while (len > 0) {len--;if (*cmd == ' ') {cmd++;break;}cmd--;}//进程还在运行if (strncmp(cmd, process_name, strlen(process_name)) == 0) {exists = 1;break;}}pclose(stream);if (line != NULL)free(line);return exists;
}void amstart(const char *process_name, const char *package_name, const char *activity_name,int interval_sec) {char *start_command = NULL;// am start -n com.example.immortalapp/.MainActivityasprintf(&start_command, "/system/bin/am start -n %s/%s", package_name, activity_name);__android_log_print(ANDROID_LOG_DEBUG, "immortalapp", "am start_command: %s", start_command);while (1) {if (chk_process(process_name) == 0) {// system方式执行start commandsystem(start_command);// 注意释放freefree(start_command);}// sleep 时间间隔参数sleep(interval_sec);}
}int main(int argc, char *argv[]) {signal(SIGTERM, SIG_IGN);const char *process_name = NULL;const char *package_name = NULL;const char *activity_name = NULL;int interval_sec = 30;struct option options[] ={{"process_name", required_argument, 0, 'p'},{"package_name", required_argument, 0, 'a'},{"activity_name", required_argument, 0, 'c'},{"interval_sec", required_argument, 0, 'i'},{0, 0, 0, 0}};int c;for (;;) {c = getopt_long(argc, argv, "p:a:c:i:", options, NULL);if (c == -1) {break;}switch (c) {case 'p':process_name = optarg;break;case 'a':package_name = optarg;break;case 'c':activity_name = optarg;break;case 'i':interval_sec = atoi(optarg);break;default:exit(EXIT_FAILURE);}}if (process_name == NULL || package_name == NULL || activity_name == NULL)exit(EXIT_FAILURE);daemon(1, 1);amstart(process_name, package_name, activity_name, interval_sec);return 0;
}
3.2 App部分
package com.example.immortalapp;import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;public class MainActivity extends Activity {private static final String TAG = "immortalapp";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);String packageName = getPackageName();String path = "/data/data/" + packageName;String command = "dd if=" + path + "/lib/libappdaemon.so of=" + path + "/appdaemon";execCommand(command, packageName);command = "chmod 777 appdaemon";execCommand(command, packageName);// 通过daemon进程执行循环检查,监听到进程died,立即am start命令重新启动command = "./appdaemon -p " + packageName + " -a " + packageName + " -c " + ".MainActivity" + " -i " + "10";execCommand(command, packageName);}public boolean execCommand(String command, String packageName) {Process process = null;DataInputStream inputStream = null;DataOutputStream outputStream = null;try {// shell processprocess = Runtime.getRuntime().exec("sh");inputStream = new DataInputStream(process.getInputStream());outputStream = new DataOutputStream(process.getOutputStream());// change到app的data目录下outputStream.writeBytes("cd /data/data/" + packageName + "\n");outputStream.writeBytes(command + " \n");outputStream.writeBytes("exit\n");outputStream.flush();// 注意阻塞process.waitFor();byte[] buffer = new byte[inputStream.available()];inputStream.read(buffer);String result = new String(buffer);Log.i(TAG, "command execute result result:" + result);} catch (Exception e) {Log.i(TAG, "exception caught e:" + e);return false;} finally {try {inputStream.close();outputStream.close();} catch (IOException e) {e.printStackTrace();}}return true;}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}}
3.3 Android.mk部分
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)
LOCAL_MODULE := appdaemon
LOCAL_SRC_FILES := daemon.c
LOCAL_LDLIBS += -llog
include $(BUILD_EXECUTABLE)
测试在小米5,android5.0上可用。不保证所有手机可用。
守护进程方式保证App不被杀死相关推荐
- vue 不会热启动_使用PM2搭建在线vue.js开发环境(以守护进程方式热启动)
项目以vue.js+layUI的作为前端开发技术栈,需要有一个在线的环境供项目成员实时查看效果,总不能每次都webpack打包发布后才能看到效果吧!刚开始就简单使用npm run dev命令热启动,但 ...
- 使用PM2搭建在线vue.js开发环境(以守护进程方式热启动)
项目以vue.js+layUI的作为前端开发技术栈,需要有一个在线的环境供项目成员实时查看效果,总不能每次都webpack打包发布后才能看到效果吧!刚开始就简单使用npm run dev命令热启动,但 ...
- 使用nohup以守护进程方式启动程序
要让程序以守护进程的方式工作,一种方法是按守护进程的规则去编程,这种方法需要在代码中进行特殊操作,比较麻烦:另一种方法是仍然用普通方法编程,然后用nohup命令启动程序: nohup <程序名& ...
- 【k8s】理解Docker容器的进程管理(PID1进程(容器内kill命令无法杀死)、进程信号处理、僵尸进程)
文章目录 概述 1. 容器的PID namespace(名空间) 2. 如何指明容器PID1进程 3. 进程信号处理 4. 孤儿进程与僵尸进程管理 5. 进程监控 6. 总结 参考 概述 简介: Do ...
- 在阿里云上以Daemon进程方式运行SAP Cloud Connector portable版本的尝试
url: https://help.sap.com/viewer/cca91383641e40ffbe03bdc78f00f681/Cloud/en-US/f069840fa34c4196a5858b ...
- twisted系列教程十六–twisted守护进程
Introduction 到目前为止我们写的server 还运行在一个终端里面,通过print 语句向外输出内容.开发的时候这样做是很有好处的,但是当你部署一个产品的时候这样就不好了.一个生产环境中的 ...
- 禅道客户端服务端部署xxd守护进程运行
配置禅道客户端 1.生成配置文件并下载喧喧服务端xxd 2 将下载文件上传到服务器 执行./xxd [root@localhost xxd]# ls cert config log nohup.out ...
- 守护进程的三种实现方式
实现守护进程 (1)nohup (2)fork()按步骤创建 (3)deamon函数创建 Linux Daemon(守护进程)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务 ...
- Python 多进程笔记 — 启动进程的方式、守护进程、进程间通信、进程池、进程池之间通信、多进程生产消费模型
1 面向过程启动多进程 Python 操作进程的类都定义在 multiprocessing 模块,该模块提供了一个 Process 类来代表一个进程对象,这个对象可以理解为是一个独立的进程,可以执行另 ...
最新文章
- python之模块csv之CSV文件的写入(按行写入)
- batchnorm2d参数 torch_Pytorch-nn.BatchNorm2d()
- 回文字符串啊~---太搞了 少年 DXH
- Ubuntu 安装 Sun JDK
- javascript学习系列(24):数组中的substring方法
- matlab字符和字符串,MATLAB字符和字符串
- TryCatchFinallyProcessHelper
- 数据库设计指南【转】
- Shiro的详细简介解释(快速搭建官网解释代码)
- VM安装windows10操作系统
- wechart image标签
- Jackson 生成xml格式文件
- contourlet matlab 源码,contourlet_toolbox matlab 238万源代码下载- www.pudn.com
- 操作系统指纹识别(基于kali)
- 知识图谱(Knowledge Graph)
- 指定条件查找计算机,Excel函数教程: 查找符合指定条件的数据-excel技巧-电脑技巧收藏家...
- java实现支付宝app支付
- 在服务系统部署MFC程序,出现DLL缺失情况的问题解决方式
- 2021年中国CRM市场规模及市场格局分析:市场规模达156亿元[图]
- SEO是做什么的,每天需要做什么
热门文章
- 名片识别,史上最简单的集成攻略来啦!附有SDK包
- DM数据库安装过程--基于NeoKylin操作系统详解
- python qq群文件_python 获取qq群成员列表数据
- 微信小程序多次跳转后不能点_微信突然更新,但我劝你这次别升级
- 地税系统WEB打印提示未注册
- 灵悟礼品网上专卖店——客户端的登录功能开发
- 测试职业规划之知识点总结
- return next(val for val in obj if safe_isfinite(val)) StopIteravtion报错解决方法
- 使用 软考免费真题app刷题库 手机小程序版
- java excel 批注_Java 添加、修改、读取、复制、删除Excel批注