NDK fork拉活-底层C守护进程拉起App进程

发布于:2025-07-22 ⋅ 阅读:(15) ⋅ 点赞:(0)

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

0

    ActivityManager         pid-1626                             I  startProcessLocked com.ayst.helloapptypejava.lang.Throwable	at 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)

    为啥我想玩这个保活的技术呢?因为我最近有时间研究反保活,反正随便玩一玩哈。

    0

    引言

    在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命令秒级重启

    二、完整实现步骤

    0

    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声明服务:

          <service     android: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()    }}

              应用宝也是这样干的哈

              0

              0

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


              网站公告

              今日签到

              点亮在社区的每一天
              去签到