现在的国产手机基本都是不能保证的 随随便便一杀就没了 复活不了;我的华为P9就不行,其他的我觉得也够呛,但是使用公司自己得MTK5.0平台, 那真是特吗和病毒没什么区别。。。
我这是在腾讯课堂里学习来得;动脑学院,挺好得一个学习android看视频得地方;
1: java方式守护
AndroidMainfast.xml 中定义process = “:remote”字段;
手机厂商可以修改xml解析的方式,导致进程不能成功开启;普及率低
轮询;
2: ndk方式守护
双进程保活;
宿主进程 / 守护进程
客户端 / 服务端
客户端: socket()---> connect() ---> write() <---> read() ----> close()
服务端: socket() --->bind() ---->listen() ---->accept()----->阻塞状态,直到客户端连接上----> read() <----> write() ----> read()这里会收到客户端close()时的消息------>close();
linux socket
等待连接;与java不同这里是分开的;
读取消息;分开的;
socket跨进程 基于文件 读写;
额外一个比较有趣的打电话:
am start -a android .intent.action.CALL -d tel:10086
首先先来个service,记得注册;
/**
* 所守护的service
*/
public class ProcessService extends Service {
private static final String TAG = ProcessService.class.getSimpleName();
private int i;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// return super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
@Override
public void onCreate() {
super.onCreate();
// 这里是JNI;
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.e(TAG, "service is opening ... " + i);
i++;
// 这里只是在手机的一个目录下一直写东西;;;就不贴了;
FileUtils.JsonWrite(Environment.getExternalStorageDirectory() + "//textDoubleProtect.txt", i + "\n");
}
}, 0, 1000 * 3);
}
@Override
public void onDestroy() {
// 这里直接杀掉是不走这里的;
Log.e(TAG, "service onDestroy");
super.onDestroy();
}
}
watcher类;
/**
* Created by bysd-2 on 2018/6/13.
*/
public class Watcher {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
public native void createWatcher(String userId); // jni
public native void connectMonitor();
}
jni的代码;
这里是头文件;
//
// Created by bysd-2 on 2018/6/13.
//
#ifndef DOUBLEPROCESSPROTECT_NATIVE_LIB_H
#define DOUBLEPROCESSPROTECT_NATIVE_LIB_H
#endif //DOUBLEPROCESSPROTECT_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/un.h>
#include <errno.h>
#include <stdlib.h>
#include <linux/signal.h>
#include <android/log.h>
#define LOG_TAG "tuch"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
// 方法在c里面;
void child_do_work();
int child_create_channel();
void child_listen_msg();
//
#include <jni.h>
#include <string>
#include <unistd.h>
// child_create_channel()
#include "native-lib.h"
const char *PATH = "****************************这里自己定义路径 如 /data/data/com.example.demo/...";
int m_child;
const char *userId;
/**
* 创建socket;
*/
void child_do_work() {
// 守护进程为服务端;
// open socket
if (child_create_channel()) {
child_listen_msg();
}
}
/**
* 创建服务端socket
*/
void child_listen_msg() {
fd_set rfds;
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);
// LOGE("读取消息前 %d ", r);
if (r > 0) { // 选择了客户端
// 缓冲区
char pkg[256] = {0};
// 保证所读到的信息是指定apk的客户端;
if (FD_ISSET(m_child, &rfds)) {
int result = read(m_child, pkg, sizeof(pkg));
LOGE("userId %s ",userId);
// 开启服务;
execlp("am", "am", "startservice", "--user", userId,
"包名/service的全类名",
(char *) NULL);
break;
}
}
}
}
/**
* 服务端读取信息;
* 客户端;
*/
int child_create_channel() {
// socket 第一步;
int listenfd = socket(AF_LOCAL, SOCK_STREAM, 0);
//
unlink(PATH);
// bind
struct sockaddr_un addr;
// 清空内存,全部置0;
memset(&addr, 0, sizeof(sockaddr_un));
addr.sun_family = AF_LOCAL;
//
int connfd = 0;
// 复制赋值;
strcpy(addr.sun_path, PATH);
//
int a = bind(listenfd, (const sockaddr *) &addr, sizeof(sockaddr_un));
if (a < 0) {
// 绑定错误;
LOGE("绑定错误!!!");
return 0;
}
listen(listenfd, 5);// 监听最大客服端数目: 5
// 保证 宿主进程连接成功;
while (1) {
// 返回值为客户端的地址; 阻塞式函数;
connfd = accept(listenfd, NULL, NULL); // 执行完 errno会有值;
if (connfd < 0) { // 连接失败;
if (errno == EINTR) { // errno为linux内置成员变量;accept执行完会赋值;
continue;
} else {
LOGE("读取错误!!!");
return 0;
}
}
m_child = connfd;
break;
}
return 1;
}
extern "C"
JNIEXPORT void JNICALL
Java_com_htnova_doubleprocessprotect_Watcher_connectMonitor(JNIEnv *env, jobject instance) {
int socked;
// 内存区域
struct sockaddr_un addr;
while (1) {
LOGE("客户端 父进程开始连接");
socked = socket(AF_LOCAL, SOCK_STREAM, 0); // 要与服务端的配置一样;
if (socked < 0) {
LOGE("客户端连接失败");
return;
}
// 清空内存,全部置0;
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;
}
}
extern "C"
JNIEXPORT
void JNICALL
Java_com_htnova_doubleprocessprotect_Watcher_createWatcher(JNIEnv *env, jobject instance,
jstring userId_) {
userId = env->GetStringUTFChars(userId_, 0);
// TODO 创建socket;
// linux 开启双进程
pid_t pid = fork();
if (pid < 0) {
// 失败;
}
else if (pid == 0) {
// 子进程; 守护进程
child_do_work();
} else if (pid > 0) {
// 父进程;
}
env->ReleaseStringUTFChars(userId_, userId);
}
到这里就可以了,c里面的东西可能比较难懂,但主要看service里面的东西 基本能知道大概;不懂得话copy一下 跑起来就知道怎么回事了;记录一下 虽然现在限制的很多 基本白费劲 但是也学习了一种方式; 好了 下班!