NDK层双进程守护
系统关键服务杀得死吗?
不能!
那么系统服务是怎么来的:zygote
在Android系统中,所有的应用程序进程以及系统服务进程SystemServer都是由Zygote进程孕育(fork)出来的,因为Android系统是基于Linux内核的,而在Linux系统中,所有的进程都是init进程的子孙进程,也就是说,所有的进程都是直接或者间接地由init进程fork出来的。Zygote进程也不例外,它是在系统启动的过程,由init进程创建的,在系统启动脚本system/core/rootdir/init.rc文件中,我们可以看到启动Zygote进程
从上面介绍我们知道 android 所有的进程都是init进程的子孙进程
我们看看init进程,从图可以看到PID=1
从这个图我们看到zygote的PPID=1;也就是他 他的父进程就是init
我们看到Phone进程的PPID=1330; 由此我们可以看出android的 所有系统进程都是由zygote产出
fork
所有的进程都是直接或者间接地由init进程fork出来的
ok我们来fork
我们先创建一个Watcher
public class Watcher {
static {
System.loadLibrary("native-lib");
}
public native void createWatcher(String userId);
public native void connectMonitor();
}
我们要启动的服务
public class ProcessService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
public int index;
private static final String TAG = "ProcessService";
@Override
public void onCreate() {
super.onCreate();
Watcher watcher = new Watcher();
watcher.createWatcher(String.valueOf(Process.myUid()));
watcher.connectMonitor();
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
Log.i(TAG, "run: 你杀不死我 " + index);
index++;
}
}, 0, 5000);
}
}
native-lib.cpp
#include <jni.h>
#include <string>
#include <string.h>
#include "native_lib.h"
extern "C"
JNIEXPORT jstring
JNICALL
Java_com_ndk_1guard_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
const char *userId;
/**
* PATH=/dada/dada/包名/my.sock
*/
const char *PATH = "/data/data/com.ndk_guard/my.sock";
int m_child;
void child_do_work() {
//开启socket
if (child_create_channel()) {
child_listen_msg();
}
}
void child_listen_msg() {
fd_set rfds;
//时间 3秒
struct timeval timeout = {3, 0};
while (1) {
//清空内容
FD_ZERO(&rfds);
FD_SET(m_child, &rfds);
//选择范围 一般+1;
int r = select(m_child + 1, &rfds, NULL, NULL, &timeout);
if (r > 0) {
char pkg[256] = {0};
//保证所读到的信息是指定apk客户端的信息
if (FD_ISSET(m_child, &rfds)) {
//阻塞函数
int result = read(m_child, pkg, sizeof(pkg));
//一旦和apk断开 就执行下面代码
//开启服务
execl("am", "am", "startservice", "--user", userId,
"com.ndk_guard/com.ndk_guard.ProcessService", NULL);
break;
}
}
}
}
/**
* 开启socket 服务
* @return
*/
int child_create_channel() {
int listenfd = socket(AF_LOCAL, SOCK_STREAM, 0);
struct sockaddr_un addr;
unlink(PATH);
memset(&addr, 0, sizeof(sockaddr));
addr.sun_family = AF_LOCAL;
strcpy(addr.sun_path, PATH);
int connfd;
if (bind(listenfd, (const sockaddr *) &addr, sizeof(sockaddr_un)) < 0) {
LOGE("绑定错误");
return 0;
}
//最多同时连接5个
listen(listenfd, 5);
//while 保证宿主连接成功
while (1) {
//返回值 客户端的地址 //阻塞函数
if ((connfd = accept(listenfd, NULL, NULL)) < 0) {
if (errno == EINTR) {
LOGE("读取错误EINTR");
continue;
} else {
LOGE("读取错误");
return 0;
}
}
m_child = connfd;
LOGE("apk 父进程连接上 %s" , m_child);
break;
}
return 1;
}
extern "C"
JNIEXPORT void JNICALL
Java_com_ndk_1guard_Watcher_createWatcher(JNIEnv *env, jobject instance, jstring userId_) {
userId = env->GetStringUTFChars(userId_, 0);
//开双进程
pid_t pid = fork();
if (pid < 0) {
//fork失败
} else if (pid == 0) {
//子线程 守护进程
child_do_work();
} else if (pid > 0) {
//主线程
}
env->ReleaseStringUTFChars(userId_, userId);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_ndk_1guard_Watcher_connectMonitor(JNIEnv *env, jobject instance) {
int socked;
while (1) {
LOGE("客户端 开始进行连接了");
socked = socket(AF_LOCAL, SOCK_STREAM, 0);
if (socked < 0) {
LOGE("连接失败0");
return;
}
struct sockaddr_un addr;
memset(&addr, 0, sizeof(sockaddr));
addr.sun_family = AF_LOCAL;
strcpy(addr.sun_path, PATH);
if (connect(socked, (const sockaddr *) &addr, sizeof(sockaddr_un)) < 0) {
LOGE("连接失败");
close(socked);
sleep(1);
//在来下一次尝试连接
continue;
}
LOGE("连接成功");
break;
}
}
native_lib.h
#ifndef NDK_GUARD_NATIVE_LIB_H
#define NDK_GUARD_NATIVE_LIB_H
#endif //NDK_GUARD_NATIVE_LIB_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 <stdalign.h>
#include <linux/signal.h>
#include <unistd.h>
#include <sys/un.h>
#define LOG_TAG "tuch"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
void child_do_work();
void child_listen_msg();
int child_create_channel();
运行代码 启动服务
startService(new Intent(this,ProcessService.class));
我们启动的进程PPID=1330 也就是依赖于zygote PPID=4295 依赖我们fork出来的进程
可以看到我们连接成功了 并且服务已经启动成功,接下来我们直接下死app
根据上图我们可以看到当你的app杀死后,会重新启动服务