android ndk守护服务,Android 使用NDK编写 基于C层的守护进程

做过android开发的人应该都知道GC会在资源不够用的时候会无情的回收掉我们写的进程,但是有时候我们需要我们的进程常驻后台。这该怎么办呢?

首先说下我试过的还有网上看到过的方法吧!

1.提高优先级

这个办法只是降低了应用被杀死的概率,但是如果真的被系统回收了,我们也只能对着系统呵呵哒!

扩展下,有人也写过双service守护进程,service1发现service2死了,他就复活service2。然后service2发现service1死了,他就复活service1。

这样写虽然在一部份情况下还是能坚持一会的。但是遇到一些清理软件,service1和service2都会瞬间死亡。守护功能当然也谈不上。

2.重写service.onStartCommand返回START_STICKY

@Override

public int onStartCommand(Intent intent, int flags, int startId) {

flags = START_STICKY;

return super.onStartCommand(intent, flags, startId);

}

如果在adb shell当中kill掉进程模拟应用被意外杀死的情况或者用360手机卫士进行清理操作(当然这里是没有ROOT的手机,据说360root后会在内存层面杀死程序,这个谁都挡不住的),如果服务的onStartCommand返回START_STICKY,在进程管理器中会发现被杀死的进程的确又会出现在任务管理器中。但是如果关闭进程的命令来自底层(比如系统命令adb shell am force-stop com.leon.test),这时候会发现即使onStartCommand返回了START_STICKY,应用还是没能重新启动起来!

3.让应用成为系统应用

实验发现即使成为系统应用(在烧rom的时候吧直接把APK扔到SYSTEM内),被杀死之后也不能自动重新启动。但是如果对一个系统应用设置了persistent="true",情况就不一样了。实验表明对一个设置了persistent属性的系统应用,即使kill掉会立刻重启。一个设置了persistent="true"的系统应用,在android中具有core service优先级,这种优先级的应用对系统的low memory killer是免疫的!

看了上面大家也有应该发现了一问题。只有越接近Android核心的应用才能保证在被意外杀死之后做到立刻复活。那么该怎么办呢?这里就来说一说双进程守护。网上也有人提到过双进程守护,这里给大家安利一个GitHub上面的守护进程(传送门:https://github.com/Coolerfall/AndroidAppDaemon)但是由于使用的方法并不符合我的需求,所以并没有使用。

双守护进程的原理请参考1的扩展,简而言之就是互相监视,一个死了另一个就复活他。

在写之前希望大家去了解两个命令

fork()和execlp

OK。那开始贴代码了(注意这个是C++代码,建工程的时候请使用cpp后缀)。

#ifndef _PROCESS_H

#define _PROCESS_H

#include #include #include #include #include #include #include #include #include #include #include #include #include #define LOG_TAG "Native"

#define LOGE(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)

static bool DEBUG = true;

/**

* 功能:对父子进程的一个抽象

* @author LeonWang

* @date 2015-12-28

*/

class ProcessBase {

public:

ProcessBase();

/**

* 父子进程要做的工作不相同,留出一个抽象接口由父子进程

* 自己去实现.

*/

virtual void do_work() = 0;

/**

* 进程可以根据需要创建子进程,如果不需要创建子进程,可以给

* 此接口一个空实现即可.

*/

virtual bool create_child() = 0;

/**

* 捕捉子进程死亡的信号,如果没有子进程此方法可以给一个空实现.

*/

virtual void catch_child_dead_signal() = 0;

/**

* 在子进程死亡之后做任意事情.

*/

virtual void on_child_end() = 0;

virtual ~ProcessBase();

};

/**

* 功能:父进程的实现

* @author LeonWang

* @date 2015-12-28

*/

class Parent: public ProcessBase {

public:

Parent(JNIEnv* env, jobject jobj);

virtual bool create_child();

virtual void do_work();

virtual void catch_child_dead_signal();

virtual void on_child_end();

virtual ~Parent();

bool create_channel();

/**

* 获取父进程的JNIEnv

*/

JNIEnv *get_jni_env() const;

/**

* 获取Java层的对象

*/

jobject get_jobj() const;

};

/**

* 子进程的实现

* @author LeonWang

* @date 2015-12-28

*/

class Child: public ProcessBase {

public:

Child();

virtual ~Child();

virtual void do_work();

virtual bool create_child();

virtual void catch_child_dead_signal();

virtual void on_child_end();

private:

/**

* 处理父进程死亡事件

*/

void handle_parent_die();

/**

* 重新启动父进程.

*/

void restart_parent();

/**

* 线程函数,用来检测父进程是否挂掉

*/

void* parent_monitor();

void start_parent_monitor();

/**

* 这个联合体的作用是帮助将类的成员函数做为线程函数使用

*/

union {

void* (*thread_rtn)(void*);

void* (Child::*member_rtn)();

} RTN_MAP;

};

extern ProcessBase *g_process;

extern const char* g_objname;

extern const char* g_type;

extern JNIEnv* g_env;

int get_version();

ProcessBase::ProcessBase() {

}

ProcessBase::~ProcessBase() {

}

Parent::Parent(JNIEnv *env, jobject jobj) {

if (DEBUG) {

LOGE("<>");

}

}

Parent::~Parent() {

if (DEBUG) {

LOGE("<>");

}

g_process = NULL;

}

void Parent::do_work() {

}

/**

* 子进程死亡会发出SIGCHLD信号,通过捕捉此信号父进程可以

* 知道子进程已经死亡,此函数即为SIGCHLD信号的处理函数.

*/

static void sig_handler(int signo) {

pid_t pid;

int status;

//调用wait等待子进程死亡时发出的SIGCHLD

//信号以给子进程收尸,防止它变成僵尸进程

pid = wait(&status);

if (DEBUG) {

LOGE("<>");

}

if (g_process != NULL) {

g_process->on_child_end();

}

}

void Parent::catch_child_dead_signal() {

if (DEBUG) {

LOGE("<>", getpid());

}

struct sigaction sa;

sigemptyset(&sa.sa_mask);

sa.sa_flags = 0;

sa.sa_handler = sig_handler;

sigaction(SIGCHLD, &sa, NULL);

}

void Parent::on_child_end() {

if (DEBUG) {

LOGE("<>");

}

create_child();

}

bool Parent::create_child() {

pid_t pid;

if ((pid = fork()) < 0) {

return false;

} else if (pid == 0) //子进程

{

if (DEBUG) {

LOGE("<>", getpid());

}

Child child;

ProcessBase& ref_child = child;

ref_child.do_work();

} else if (pid > 0) //父进程

{

if (DEBUG) {

LOGE("<>", getpid());

}

}

return true;

}

bool Child::create_child() {

//子进程不需要再去创建子进程,此函数留空

return false;

}

Child::Child() {

RTN_MAP.member_rtn = &Child::parent_monitor;

}

Child::~Child() {

}

void Child::catch_child_dead_signal() {

//子进程不需要捕捉SIGCHLD信号

return;

}

void Child::on_child_end() {

//子进程不需要处理

return;

}

void Child::handle_parent_die() {

//子进程成为了孤儿进程,等待被Init进程收养后在进行后续处理

while (getppid() != 1) {

usleep(500); //休眠0.5ms

}

//重启父进程服务

if (DEBUG) {

LOGE("<>");

}

restart_parent();

}

void Child::restart_parent() {

if (DEBUG) {

LOGE("<>");

}

/**

* TODO 重启父进程,通过am启动Java空间的任一组件(service或者activity等)即可让应用重新启动

*/

if (strcmp(g_type, "Activity") == 0) {

if (DEBUG) {

LOGE("<>");

}

execlp("am", "am", "start","-e","daemon","triger","--user", "0", "-n", g_objname, "-a",

"android.intent.action.VIEW", "-d", "", (char *) NULL);

} else if (strcmp(g_type, "Service") == 0) {

//在api17之后AM命令有些不同这里需要写兼容。获取版本号的方法已经写在了下面。

int g_version=get_version();

if (g_version >= 17 || g_version == 0) {

if (DEBUG) {

LOGE("<>");

}

int ret = execlp("am", "am", "startservice","-e","daemon","triger","--user", "0", "-n",g_objname, (char *) NULL);

} else {

if (DEBUG) {

LOGE("<>");

}

execlp("am", "am", "startservice","-e","daemon","triger","-n", g_objname, (char *) NULL);

}

}

}

void* Child::parent_monitor() {

handle_parent_die();

}

void Child::start_parent_monitor() {

pthread_t tid;

pthread_create(&tid, NULL, RTN_MAP.thread_rtn, this);

pthread_join(tid, NULL);

}

void Child::do_work() {

start_parent_monitor(); //启动监视线程

if (DEBUG) {

LOGE("<>");

}

}

char* jstringToString(JNIEnv* env, jstring jstr) {

char* rtn = NULL;

jclass clsstring = env->FindClass("java/lang/String");

jstring strencode = env->NewStringUTF("utf-8");

jmethodID mid = env->GetMethodID(clsstring, "getBytes","(Ljava/lang/String;)[B");

jbyteArray barr = (jbyteArray) env->CallObjectMethod(jstr, mid, strencode);

jsize array_lenth = env->GetArrayLength(barr);

jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);

if (array_lenth > 0) {

rtn = (char*) malloc(array_lenth + 1);

memcpy(rtn, ba, array_lenth);

rtn[array_lenth] = 0;

}

env->ReleaseByteArrayElements(barr, ba, 0);

return rtn;

}

int get_version()

{

char value[8] = "";

__system_property_get("ro.build.version.sdk", value);

return atoi(value);

}

#endif

守护进程的主程序就是这样了。

我封装好了一个可以直接使用的Jar包,有需要的可以自行下载。

地址:http://download.csdn.net/detail/kakathya/9385869

过fork分支一个子进程,子进程发现父进程死亡就重启服务或者activity。

后面有时间再写一个NDK的基础教程吧。

祝大家2016新年快乐。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值