Skip to content

Instantly share code, notes, and snippets.

@spiritedRunning
Last active March 30, 2021 08:54
Show Gist options
  • Save spiritedRunning/6a4178a2e939b9a0db7eddacefa8d67d to your computer and use it in GitHub Desktop.
Save spiritedRunning/6a4178a2e939b9a0db7eddacefa8d67d to your computer and use it in GitHub Desktop.
进程守护 使用信号量通知
#include <jni.h>
#include "ProcessWatcher.h"
extern ProcessBase *g_process;
JNIEXPORT jboolean JNICALL
Java_com_example_free_watcher_Watcher_createWatcher(JNIEnv *env, jobject instance, jstring objname_,
jstring type_) {
const char *objname = env->GetStringUTFChars(objname_, 0);
const char *type = env->GetStringUTFChars(type_, 0);
// TODO
g_process = new Parent(env, instance);
g_process->catch_child_dead_signal();
if (!g_process->create_child()) {
LOGE("<<create child error!>>");
return JNI_FALSE;
}
env->ReleaseStringUTFChars(objname_, objname);
env->ReleaseStringUTFChars(type_, type);
return JNI_TRUE;
}
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Watcher watcher = new Watcher();
watcher.createActivityMonitor("com.example.free.ndkdemocode/com.example.free.ndkdemocode.MainActivity");
}
}
#include "ProcessWatcher.h"
ProcessBase *g_process;
const char *g_objname;
const char *g_type;
JNIEnv *g_env;
int get_version();
static bool DEBUG = true;
ProcessBase::ProcessBase() {
}
ProcessBase::~ProcessBase() {
}
Parent::Parent(JNIEnv *env, jobject jobj) {
if (DEBUG) {
LOGE("<<new parent instance>>");
}
}
Parent::~Parent() {
if (DEBUG) {
LOGE("<<Parent::~Parent()>>");
}
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("<<sig_handler>>");
}
if (g_process != NULL) {
g_process->on_child_end();
}
}
void Parent::catch_child_dead_signal() {
if (DEBUG) {
LOGE("<<process %d install child dead signal detector!>>", 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("<<on_child_end:create a new child process>>");
}
create_child();
}
bool Parent::create_child() {
pid_t pid;
if ((pid = fork()) < 0) {
return false;
} else if (pid == 0) //子进程
{
if (DEBUG) {
LOGE("<<In child process,pid=%d>>", getpid());
}
Child child;
ProcessBase &ref_child = child;
ref_child.do_work();
} else if (pid > 0) //父进程
{
if (DEBUG) {
LOGE("<<In parent process,pid=%d>>", 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("<<parent died,restart now>>");
}
restart_parent();
}
void Child::restart_parent() {
if (DEBUG) {
LOGE("<<restart_parent enter>>");
}
/**
* TODO 重启父进程,通过am启动Java空间的任一组件(service或者activity等)即可让应用重新启动
*/
if (strcmp(g_type, "Activity") == 0) {
if (DEBUG) {
LOGE("<<restart_Activity>>");
}
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("<<restart_service more than 17>>");
}
int ret = execlp("am", "am", "startservice", "-e", "daemon", "triger", "--user", "0",
"-n", g_objname, (char *) NULL);
} else {
if (DEBUG) {
LOGE("<<restart_service enter bleow 17>>");
}
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("<<start_parent_monitor>>");
}
}
int get_version() {
char value[8] = "";
__system_property_get("ro.build.version.sdk", value);
return atoi(value);
}
#ifndef NDKDEMOCODE_DAEMON_H
#define NDKDEMOCODE_DAEMON_H
#include <jni.h>
#include <sys/select.h>
#include <unistd.h>
#include <sys/socket.h>
#include <pthread.h>
#include <signal.h>
#include <sys/wait.h>
#include <android/log.h>
#include <sys/types.h>
#include <sys/un.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/system_properties.h>
#define LOG_TAG "Native"
#define LOGE(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
/**
* 功能:对父子进程的一个抽象
*/
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();
};
/**
* 功能:父进程的实现
*/
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;
};
/**
* 子进程的实现
*/
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;
};
#endif //NDKDEMOCODE_DAEMON_H
public class Watcher {
static {
System.loadLibrary("ProcessWatcher");
}
public Watcher() {
}
public void createActivityMonitor(String g_objname) {
this.createWatcher(g_objname, "Activity");
}
public void createServiceMonitor(String g_objname) {
this.createWatcher(g_objname, "Service");
}
private native boolean createWatcher(String objname, String type);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment