• 思路
  • 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不被杀死相关推荐

  1. vue 不会热启动_使用PM2搭建在线vue.js开发环境(以守护进程方式热启动)

    项目以vue.js+layUI的作为前端开发技术栈,需要有一个在线的环境供项目成员实时查看效果,总不能每次都webpack打包发布后才能看到效果吧!刚开始就简单使用npm run dev命令热启动,但 ...

  2. 使用PM2搭建在线vue.js开发环境(以守护进程方式热启动)

    项目以vue.js+layUI的作为前端开发技术栈,需要有一个在线的环境供项目成员实时查看效果,总不能每次都webpack打包发布后才能看到效果吧!刚开始就简单使用npm run dev命令热启动,但 ...

  3. 使用nohup以守护进程方式启动程序

    要让程序以守护进程的方式工作,一种方法是按守护进程的规则去编程,这种方法需要在代码中进行特殊操作,比较麻烦:另一种方法是仍然用普通方法编程,然后用nohup命令启动程序: nohup <程序名& ...

  4. 【k8s】理解Docker容器的进程管理(PID1进程(容器内kill命令无法杀死)、进程信号处理、僵尸进程)

    文章目录 概述 1. 容器的PID namespace(名空间) 2. 如何指明容器PID1进程 3. 进程信号处理 4. 孤儿进程与僵尸进程管理 5. 进程监控 6. 总结 参考 概述 简介: Do ...

  5. 在阿里云上以Daemon进程方式运行SAP Cloud Connector portable版本的尝试

    url: https://help.sap.com/viewer/cca91383641e40ffbe03bdc78f00f681/Cloud/en-US/f069840fa34c4196a5858b ...

  6. twisted系列教程十六–twisted守护进程

    Introduction 到目前为止我们写的server 还运行在一个终端里面,通过print 语句向外输出内容.开发的时候这样做是很有好处的,但是当你部署一个产品的时候这样就不好了.一个生产环境中的 ...

  7. 禅道客户端服务端部署xxd守护进程运行

    配置禅道客户端 1.生成配置文件并下载喧喧服务端xxd 2 将下载文件上传到服务器 执行./xxd [root@localhost xxd]# ls cert config log nohup.out ...

  8. 守护进程的三种实现方式

    实现守护进程 (1)nohup (2)fork()按步骤创建 (3)deamon函数创建    Linux Daemon(守护进程)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务 ...

  9. Python 多进程笔记 — 启动进程的方式、守护进程、进程间通信、进程池、进程池之间通信、多进程生产消费模型

    1 面向过程启动多进程 Python 操作进程的类都定义在 multiprocessing 模块,该模块提供了一个 Process 类来代表一个进程对象,这个对象可以理解为是一个独立的进程,可以执行另 ...

最新文章

  1. python之模块csv之CSV文件的写入(按行写入)
  2. batchnorm2d参数 torch_Pytorch-nn.BatchNorm2d()
  3. 回文字符串啊~---太搞了 少年 DXH
  4. Ubuntu 安装 Sun JDK
  5. javascript学习系列(24):数组中的substring方法
  6. matlab字符和字符串,MATLAB字符和字符串
  7. TryCatchFinallyProcessHelper
  8. 数据库设计指南【转】
  9. Shiro的详细简介解释(快速搭建官网解释代码)
  10. VM安装windows10操作系统
  11. wechart image标签
  12. Jackson 生成xml格式文件
  13. contourlet matlab 源码,contourlet_toolbox matlab 238万源代码下载- www.pudn.com
  14. 操作系统指纹识别(基于kali)
  15. 知识图谱(Knowledge Graph)
  16. 指定条件查找计算机,Excel函数教程: 查找符合指定条件的数据-excel技巧-电脑技巧收藏家...
  17. java实现支付宝app支付
  18. 在服务系统部署MFC程序,出现DLL缺失情况的问题解决方式
  19. 2021年中国CRM市场规模及市场格局分析:市场规模达156亿元[图]
  20. SEO是做什么的,每天需要做什么

热门文章

  1. 名片识别,史上最简单的集成攻略来啦!附有SDK包
  2. DM数据库安装过程--基于NeoKylin操作系统详解
  3. python qq群文件_python 获取qq群成员列表数据
  4. 微信小程序多次跳转后不能点_微信突然更新,但我劝你这次别升级
  5. 地税系统WEB打印提示未注册
  6. 灵悟礼品网上专卖店——客户端的登录功能开发
  7. 测试职业规划之知识点总结
  8. return next(val for val in obj if safe_isfinite(val)) StopIteravtion报错解决方法
  9. 使用 软考免费真题app刷题库 手机小程序版
  10. java excel 批注_Java 添加、修改、读取、复制、删除Excel批注