守护进程拉起App进程的日志现象

ActivityManager pid-1626 I startProcessLocked com.ayst.helloapptypejava.lang.Throwableat com.android.server.am.ProcessList.startProcessLocked(ProcessList.java:1860)at com.android.server.am.ProcessList.startProcessLocked(ProcessList.java:2655)at com.android.server.am.ProcessList.startProcessLocked(ProcessList.java:2801)at com.android.server.am.ActivityManagerService.startProcessLocked(ActivityManagerService.java:3076)at com.android.server.am.ActivityManagerService$LocalService.startProcess(ActivityManagerService.java:19655)at com.android.server.wm.ActivityTaskManagerService$$ExternalSyntheticLambda20.accept(R8$$SyntheticClass:0)at com.android.internal.util.function.pooled.PooledLambdaImpl.doInvoke(PooledLambdaImpl.java:363)at com.android.internal.util.function.pooled.PooledLambdaImpl.invoke(PooledLambdaImpl.java:204)at com.android.internal.util.function.pooled.OmniFunction.run(OmniFunction.java:87)at android.os.Handler.handleCallback(Handler.java:959)at android.os.Handler.dispatchMessage(Handler.java:100)at android.os.Looper.loopOnce(Looper.java:232)at android.os.Looper.loop(Looper.java:317)at android.os.HandlerThread.run(HandlerThread.java:85)at com.android.server.ServiceThread.run(ServiceThread.java:46)
为啥我想玩这个保活的技术呢?因为我最近有时间研究反保活,反正随便玩一玩哈。

引言
在Android开发中,后台服务保活一直是难题。随着系统版本升级,单纯依靠Java层的Service越来越容易被系统回收。本文将介绍一种Native层+Service双进程守护的方案,通过JNI fork子进程监控主进程状态,实现高存活率的后台任务管理
一、方案核心原理
1.双进程守护机制
- Native层:通过JNI调用Linux的fork()创建子进程,定时检查主进程存活状态
- Java层:START_STICKYService提供基础保活能力,与Native进程形成双向守护
2.技术亮点
- 跨语言协作:Kotlin调用Native代码,实现Linux级进程管理
- 低功耗轮询:Native层使用sleep(interval)控制CPU占用
- 快速恢复:进程异常退出时,通过am startservice命令秒级重启
二、完整实现步骤

1. 配置Native层(C代码)
#include <jni.h>#include <unistd.h>#include <sys/types.h>#include <sys/wait.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <signal.h>#include <android/log.h>#define LOG_TAG "Daemon"#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)// 检查进程是否存活int is_process_alive(const char *package_name) {char cmd[128];sprintf(cmd, "ps | grep %s", package_name);FILE *fp = popen(cmd, "r");if (fp) {char buf[256];while (fgets(buf, sizeof(buf), fp)) {if (strstr(buf, package_name)) {pclose(fp);return 1;}}pclose(fp);}return 0;}// 拉起Java进程void launch_app(const char *package_name, const char *service_name) {char cmd[256];sprintf(cmd, "am start -n %s/%s", package_name, service_name);system(cmd);LOGD("Launching app: %s", cmd);}// 启动Service替代Activityvoid launch_service(const char *package_name, const char *service_name) {char cmd[256];sprintf(cmd, "am startservice -n %s/%s", package_name, service_name);system(cmd);LOGD("Launching service: %s", cmd);}// 守护进程主逻辑void run_daemon(const char *package_name, const char *service_name, int interval) {while (1) {if (!is_process_alive(package_name)) {LOGD("Process dead, relaunching service...");launch_service(package_name, service_name);}sleep(interval);}}// JNI接口JNIEXPORT void JNICALLJava_com_ayst_helloapptype_NativeDaemon_startDaemon( // 修正包路径JNIEnv *env,jobject thiz,jstring java_package_name,jstring java_service_name,jint interval) {const char *package_name = (*env)->GetStringUTFChars(env, java_package_name, 0);const char *service_name = (*env)->GetStringUTFChars(env, java_service_name, 0);pid_t pid = fork();if (pid < 0) {LOGD("Fork failed!");} else if (pid == 0) {// 子进程成为守护进程setsid(); // 创建新会话run_daemon(package_name, service_name, (int)interval);_exit(0);}// 父进程继续执行Java逻辑(*env)->ReleaseStringUTFChars(env, java_package_name, package_name);(*env)->ReleaseStringUTFChars(env, java_service_name, service_name);}
2. 声明JNI接口(Kotlin)
package com.ayst.helloapptypeimport android.util.Logobject NativeDaemon {init {System.loadLibrary("daemon-lib")}// Native 声明external fun startDaemon(packageName: String?, serviceName: String?, interval: Int)fun start(packageName: String?, serviceName: String?) {// 启动守护进程,每30秒检查一次startDaemon(packageName, serviceName, 30)Log.d("sufadi", "NativeDaemon start:" + serviceName)}}
注意:需在AndroidManifest.xml声明服务:
<serviceandroid:name=".FadiDaemonService"android:exported="true" /> <!-- 允许跨进程启动 -->
4. CMake配置
cmake_minimum_required(VERSION 3.4.1)add_library(daemon-lib # 库名SHARED # 动态库daemon.c # 源文件)target_link_libraries(daemon-lib log) # 链接Android日志库
5. 调用方式NativeDaemon.start(getPackageName(), FadiDaemonService::class.java.name)
package com.ayst.helloapptypeimport android.app.Activityimport android.os.Bundleimport android.util.Logclass MainActivity : Activity() {private val TAG = "sufadi"override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)Log.d(TAG, "Daemon start")NativeDaemon.start(getPackageName(), FadiDaemonService::class.java.name)}override fun onDestroy() {super.onDestroy()}}
应用宝也是这样干的哈


理论 Android Daemon 在处理后台任务、长期运行的服务时非常有用。但是我使用是系统开发角度,我的工作是反保活哈。所以对我来说拦截自启动的技术也是一样的,本质就是一个return的事情解除保活状态。



1565

被折叠的 条评论
为什么被折叠?



