安卓zygote启动相关

Zygote

zygote启动脚本

init.zygote.rc文件是 Zygote 进程的启动配置文件。安卓通过init.rc文件来引入(import)相应的 init.zygote.rc文件的。这是一个动态选择的过程,获取 ro.zygote的属性值,根据属性值拼接文件名。

init.rcinit.zygote.rc都位于system/core/rootdir目录下:

bash 复制代码
/system/core/rootdir⟫ ls init.zygote*
init.zygote32.rc  init.zygote64_32.rc  init.zygote64.rc

可以看到在system/core/rootdir文件夹下有多个init.zygote.rc文件,那具体是哪个呢?可以看init.rc,在里面搜索zygote字样,可以发现在init.rc中用import导入的是${ro.zygote}.rc,这是一个动态拼接的,根据ro.zygote这个属性:

rc 复制代码
init.rc

import /system/etc/init/hw/init.${ro.zygote}.rc

然后在命令行中输入adb shell getprop ro.zygote,就可以确定是哪个init.zygote.rc,根据命令输出,这里执行的是init.zygote64_32.rc这个rc文件:

makefile 复制代码
C:\Users\cmy>adb shell getprop ro.zygote
zygote64_32

zygote启动脚本内容

perl 复制代码
# init.zygote64_32.rc

import /system/etc/init/hw/init.zygote64.rc

service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote_secondary stream 660 root system
    socket usap_pool_secondary stream 660 root system
    onrestart restart zygote
    task_profiles ProcessCapacityHigh MaxPerformance

init.zygote64_32.rc第一行就引入了init.zygote64.rc,所以实际执行链是:

csharp 复制代码
先执行 init.zygote64.rc
再执行 init.zygote64_32.rc 剩余内容

也就是:

csharp 复制代码
init.zygote64.rc      (定义主zygote)
        ↓
init.zygote64_32.rc   (补 secondary zygote)

最终生效的是两个文件共同组成的结果

perl 复制代码
#  init.zygote64.rc

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    socket usap_pool_primary stream 660 root system
    onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
    onrestart write /sys/power/state on
    # NOTE: If the wakelock name here is changed, then also
    # update it in SystemSuspend.cpp
    onrestart write /sys/power/wake_lock zygote_kwl
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart --only-if-running media.tuner
    onrestart restart netd
    onrestart restart wificond
    task_profiles ProcessCapacityHigh MaxPerformance
    critical window=${zygote.critical_window.minute:-off} target=zygote-fatal

关键在init.zygote64.rc第一句: 大概得知Zygote进程名称为zygote,执行程序为app_process64,class name为main。 app_process一般可以通过framework目录下grep app_process。这里要搜索app_process而不是app_process64,因为你搜app_process64搜不到内容,搜app_process才可以。根据网上的资料说搜不到 app_process64,因为 它不是一个单独源码模块名,而是由同一个二进制通过安装阶段生成的符号链接/别名 。在init.zygote32.rc中,默认就是service zygote /system/bin/app_process。马哥视频教的就是init.zygote32.rc,我自己太菜了,不行我也分析这个。

framework目录下执行grep "app_process" ./ -rn 结果如下:

bash 复制代码
./base/cmds/app_process/Android.bp:19:    name: "app_process"

代码路径:frameworks/base/cmds/app_process/


app_process文件夹中,主入口位于app_main.cpp

shell 复制代码
frameworks/base/cmds/app_process$ ls
Android.bp  app_main.cpp  cmds  MODULE_LICENSE_APACHE2  NOTICE  version-script.txt

app_process中app_main.cpp源码分析

cpp 复制代码
/* frameworks/base/cmds/app_process/app_main.cpp */
    
#if defined(__LP64__)
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist64";
static const char ZYGOTE_NICE_NAME[] = "zygote64";
#else
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist32";
static const char ZYGOTE_NICE_NAME[] = "zygote";
#endif

int main(int argc, char* const argv[])
{
    ...

    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    // Process command line arguments
    // ignore argv[0]
    argc--;
    argv++;

    ...

    // Parse runtime arguments.  Stop at first unrecognized option.
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;

    ++i;  // Skip unused "parent dir" argument.
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true; //变量zygote设置
            niceName = ZYGOTE_NICE_NAME; // ZYGOTE_NICE_NAME为zygote或者zygote64
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName = (arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            className = arg;
            break;
        } else {
            --i;
            break;
        }
    }

    Vector<String8> args;
    if (!className.empty()) {
        ...
    } else {
        ...
    }

    if (!niceName.empty()) {
        // 设置进程名
        runtime.setArgv0(niceName.c_str(), true /* setProcName */);
    }

    if (zygote) {
        //之前分析的zygote为true,走这里
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (!className.empty()) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    }
}

zygote进程调用runtime.start("com.android.internal.os.ZygoteInit", args, zygote),因为AppRuntime runtime继承AndroidRuntime,所以需要分析AndroidRuntimestart方法。

AndroidRuntimestart方法

cpp 复制代码
/* frameworks/base/core/jni/AndroidRuntime.cpp */
    
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    ...

    /* start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    //启动java需要的jvm环境,java虚拟机环境
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
        return;
    }
    onVmCreated(env);

    /*
     * Register android functions.
     */
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }

    ...

    /*
     * Start VM.  This thread becomes the main thread of the VM, and will
     * not return until the VM exits.
     */
    // toSlashClassName将com.android.internal.os.ZygoteInit变成com/android/internal/os/ZygoteInit
    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ...
    } else {
        //找className的main方法
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ...
        } else {
            // c++调用java的main方法
            //关键调用对应的"com.android.internal.os.ZygoteInit"类main方法
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
...
}

上面可以看出app_main主要做的工作就是准备虚拟机环境,让进程运行到了java层的ZygoteInit的main方法。

ZygoteInit的main方法

cpp 复制代码
/* frameworks/base/core/java/com/android/internal/os/ZygoteInit.java */

public static void main(String[] argv) {
    	// ZygoteServer对象
        ZygoteServer zygoteServer = null;

        ...

        Runnable caller;
        try {
            ...

            boolean startSystemServer = false;
            String zygoteSocketName = "zygote";
            String abiList = null;
            boolean enableLazyPreload = false;
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true;
                } 
            ...

            
            if (!enableLazyPreload) {
                bootTimingsTraceLog.traceBegin("ZygotePreload");
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                        SystemClock.uptimeMillis());
                preload(bootTimingsTraceLog); // 加载资源
                ...
            }

            ...
		   //创建SocketServer端
            zygoteServer = new ZygoteServer(isPrimaryZygote);

            if (startSystemServer) {
                // 核心就是forkSystemServer方法
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);

                // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
                // child (system_server) process.
                if (r != null) {
                    r.run();
                    return;
                }
            }

            Log.i(TAG, "Accepting command socket connections");

            // The select loop returns early in the child process after a fork and
            // loops forever in the zygote.
            // 进入永久循环等待请求来创建新的进程
            caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with fatal exception", ex);
            throw ex;
        } finally {
            if (zygoteServer != null) {
                zygoteServer.closeServerSocket();
            }
        }

        // We're in the child process and have exited the select loop. Proceed to execute the
        // command.
        if (caller != null) {
            caller.run();
        }
    }
    
    
static void preload(TimingsTraceLog bootTimingsTraceLog) {
        ...
        preloadClasses();
        ...
}
    
/**
 * The path of a file that contains classes to preload.
 */
// 预加载class路径
private static final String PRELOADED_CLASSES = "/system/etc/preloaded-classes";
    
private static void preloadClasses() {
        final VMRuntime runtime = VMRuntime.getRuntime();

        InputStream is;
        try {
// 读取/system/etc/preloaded-classes,其中preloaded-classes可以在framework中用find命令搜索
                is = new FileInputStream(PRELOADED_CLASSES);
        } catch (FileNotFoundException e) {
            Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
            return;
        }
    	... 
}

ZygoteInit.java的main方法中核心就是forkSystemServer方法。根据一路搜索,最终可以定位到frameworks/base/core/jni/com_android_internal_os_Zygote.cppzygote::ForkCommon方法。

简单调用

ZygoteInit.java的main调用forkSystemServer ↓ ZygoteInit.java的forkSystemServer调用Zygote.forkSystemServer ↓ frameworks/base/core/java/com/android/internal/os/Zygote.java的forkSystemServer调用nativeForkSystemServer。 private static native int nativeForkSystemServer 其中nativeForkSystemServer是native方法,调用cpp。

这里搜索nativeForkSystemServer有两种方法: 一种是直接在framework下搜索**grep "_nativeForkSystemServer(" ./ -rn** ,最好是加下划线,因为cpp中对应的native方法一般都会有下划线。 第二种是,Zygote.java里的native方法,一般对应在Zygote.cpp中,搜索文件可以看到com_android_internal_os_Zygote.cpp,为什么说是这个cpp,看文件名com_android_internal_os_Zygote跟com/android/internal/os/Zygote.java一一对应。

↓ frameworks/base/core/jni/com_android_internal_os_Zygote.cpp的com_android_internal_os_Zygote_nativeForkSystemServer调用zygote::ForkCommon ↓ com_android_internal_os_Zygote.cpp的ForkCommon调用linux系统的fork()

cpp 复制代码
/* frameworks/base/core/jni/com_android_internal_os_Zygote.cpp */

pid_t zygote::ForkCommon(JNIEnv* env, bool is_system_server,
                         const std::vector<int>& fds_to_close,
                         const std::vector<int>& fds_to_ignore,
                         bool is_priority_fork,
                         bool purge) {
  ...

  pid_t pid = fork(); // 最终调用的这里fork()函数,这里是真正创建子进程的地方
    
  if (pid == 0) {
	...
  } else if (pid > 0) {
	...
  }
  return pid;
    
}    

新知识

一台电脑连接多台设备

当一台电脑通过usb连接两台设备时,进行adb操作会出现歧义:

makefile 复制代码
C:\Users\cmy>adb devices
List of devices attached
21639818        device
d6876cf4        device


C:\Users\cmy>adb shell
adb.exe: more than one device/emulator    在这里,adb不知道选哪一台设备

方法1

通过adb -s 设备序列号 你要进行的操作。其中s的含义是SERIAL序列号的缩写,用adb --help可以查看

makefile 复制代码
C:\Users\cmy>adb -s d6876cf4 shell
ZM10:/ $

adb -s d6876cf4 logcat
adb -s d6876cf4 install app.apk

如果你要用 && 进行连续操作,也只需要在第一个操作中加 -s

vbnet 复制代码
C:\Users\cmy>adb -s d6876cf4 root && adb remount && adb shell
adbd is already running as root
Verity is already disabled
Remounted /system as RW
Remounted /system_ext as RW
Remounted /vendor as RW
Remounted /vendor_dlkm as RW
Remounted /system_dlkm as RW
Remounted /odm as RW
Remounted /product as RW
Remounted /oem as RW
Remounted /vendor/dsp as RW
Remount succeeded
ZM10:/ #

方法2

在当前窗口中设置临时环境变量ANDROID_SERIAL,仅当前窗口有效 ,至于为什么是ANDROID_SERIAL,这个是写死的,可以用adb --help命令查看关于-s的说明。

在Windows的cmd中

bash 复制代码
设置
set ANDROID_SERIAL=d6876cf4

查看
echo %ANDROID_SERIAL%

在你设置完ANDROID_SERIAL,在当前窗口 执行任何adb操作都不需要加-s了,默认都是ANDROID_SERIAL指定的那个。但是要注意,仅对当前窗口起作用

vbnet 复制代码
C:\Users\cmy>set ANDROID_SERIAL=d6876cf4

C:\Users\cmy>echo %ANDROID_SERIAL%
d6876cf4

C:\Users\cmy>adb shell
ZM10:/ #

查看当前 Android 系统的所有环境变量

adb shell env

相关推荐
Mac的实验室3 小时前
2026年最新真实社交怎么注册?手把手教你如何成功注册Truth Social账号
android
毕设源码-郭学长3 小时前
【开题答辩全过程】以 基于Android的点餐APP的设计为例,包含答辩的问题和答案
android
polaris06303 小时前
学生成绩管理系统(MySQL)
android·数据库·mysql
__Yvan4 小时前
Kotlin 的 ?.let{} ?: run{} 真的等价于 if-else 吗?
android·开发语言·前端·kotlin
tangweiguo030519874 小时前
Android WorkManager 完整实战教程(含完整文件)
android·kotlin
loitawu4 小时前
Rockchip Android16 系统裁剪指南
android·android16·android裁剪·系统裁剪·rockchip app
小羊子说5 小时前
关于车机中的升级流程小结(SOC、MCU、4G升级流程)
android·adb·性能优化·车载系统
肖。35487870946 小时前
[技巧-11]AndroidManifest.xml完善小技巧。
android
小羊子说6 小时前
Android 车机开发中常用的adb 脚本(更新中)
android·linux·adb·性能优化·车载系统