6.1 framework 开机流程

2023年 8月 29日 73.7k 0

6.1 framework 开机流程

init 流程:

每一个进程的启动都是从main函数开始的,比如下面的 init 的 main 函数

// init 的main 函数,没有中途return的话,会进入 firststagemain
// argv 0 是函数名,argv 1 是第一个参数
int main(int argc, char** argv) {
  ...
		if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }

    if (argc > 1) {
        if (!strcmp(argv[1], "subcontext")) {
            android::base::InitLogging(argv, &android::base::KernelLogger);
            const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();

            return SubcontextMain(argc, argv, &function_map);
        }

        if (!strcmp(argv[1], "selinux_setup")) {
            android::mboot::mdb("SELinux Setup ...");
            return SetupSelinux(argv);
        }

        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);
        }
    }
  ...
		return FirstStageMain(argc, argv);
}

// firstStageMain 中进行一些 mout 文件挂载,因为 linux 一切皆文件嘛,肯定要先把文件准备好
int FirstStageMain(int argc, char** argv) {
		...
		CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));
    CHECKCALL(mkdir("/dev/pts", 0755));
    CHECKCALL(mkdir("/dev/socket", 0755));
    CHECKCALL(mkdir("/dev/dm-user", 0755));
    CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL));
    ...
		// 开始进入 init 的第二阶段,这里定义了 init 进程所在路径和参数
    const char* path = "/system/bin/init";
    const char* args[] = {path, "selinux_setup", nullptr};
    ...
    
    // 这里执行定义好的 path 和 args,
    // 从上面的 main 函数来看,init 进程被进入 setlinux_setup 阶段
    **execv(path, const_cast(args));**

    // execv() only returns if an error happened, in which case we
    // panic and never fall through this conditional.
    PLOG(FATAL)  /system/core/rootdir/init.rc
// init.rc 包含了 start zygote 的工作,
// 当然此阶段也会构建许多许多文件,这是 linux 系统的典型,linux 系统就是解析路径的

on zygote-start && property:ro.crypto.state=unencrypted
    wait_for_prop odsign.verification.done 1
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start statsd
    start netd
    **start zygote   // start zyogte** 
    start zygote_secondary

on zygote-start && property:ro.crypto.state=unsupported
    wait_for_prop odsign.verification.done 1
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start statsd
    start netd
    start zygote
    start zygote_secondary

on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file
    wait_for_prop odsign.verification.done 1
    # A/B update verifier that marks a successful boot.

// 它要去启动 zygote 的时候,就会去解析 init.zygote.rc
// init.zygote32.rc
// init.zygote64_32.rc
// init.zygote64.rc
// 里面有一行命令,比较有意思,标红的就是下面 zygote main 函数 argv 索要的参数
service **zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server**
    class main  // 解析的时候会找到这个 main 函数,找到 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
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart media.tuner
    onrestart restart netd
    onrestart restart wificond
    task_profiles ProcessCapacityHigh
    critical window=${zygote.critical_window.minute:-off} target=zygote-fatal

// zygote 的 main 函数在这里 --->  /frameworks/base/cmds/app_process/app_main.cpp
// 这里的 main 函数就会去手机上述的参数来进行解析
int main(int argc, char* const argv[]){
		...
    // 如果匹配到了 --zygote,就悄悄换个名字,这里还是蛮有意思的哈
		if (strcmp(arg, "--zygote") == 0) {
				zygote = true;
				niceName = ZYGOTE_NICE_NAME;
		}
    ...
		
		// 在这里将 start init 加入了 args 参数中,这个参数最后会传给 runtime
		if (startSystemServer) {
				args.add(String8("start-system-server"));
		}
    
    // 在这里 start 启动了 android runtime 这个东西,android 是一个 jni 层的东西
    if (zygote) {
				runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
		} else if (!className.isEmpty()) {
				runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
		} else {
		...
}

// 来看到 android runtime 这个东西  --> /frameworks/base/core/jni/AndroidRuntime.cpp
// 这里就开始 start 了,并且原生还插桩 boot_progress_start,说明framework层开始起来了

void AndroidRuntime::start(const char* className, const Vector& options, bool ...{
		...
		// system server 起来
		static const String8 startSystemServer("start-system-server");
		...
    // 插桩 boot_progress_start 
		addBootEvent("boot_progress_start");
		...
    // 创建虚拟机
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
		...

		// 注册 android 常用 jni
		if (startReg(env) FindClass(slashClassName); // 找到类 className
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
				// 这是一个比较重要的 main 函数,通过反射来启动
				// 基于类找到它的方法
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
				} else {
						// 调用 call 执行这个main函数
						// 所以上面的 runtime.start("com.android.internal.os.**ZygoteInit**", args, zygote)
						// 参数传下来,就是执行的 ZygoteInit 这个类的 main 函数
				    env->CallStaticVoidMethod(startClass, startMeth, strArray);

			...
}

// startVm,虚拟机这个东西蛮重要的,有一个团队来搞呢,所以很重要的一个函数
// 因为虚拟机堆内存的管理比较重要,
// 比如jvm stop the world,所有的调优都是基于这个函数来的
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool primary_zygote)
{
    JavaVMInitArgs initArgs;
    char propBuf[PROPERTY_VALUE_MAX];
    char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
    char heapstartsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
    char heapsizeOptsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
    char heapgrowthlimitOptsBuf[sizeof("-XX:HeapGrowthLimit=")-1 + PROPERTY_VALUE_MAX];
    char heapminfreeOptsBuf[sizeof("-XX:HeapMinFree=")-1 + PROPERTY_VALUE_MAX];
    char heapmaxfreeOptsBuf[sizeof("-XX:HeapMaxFree=")-1 +    ...}// 接下来还要谈谈这个 startReg,即注册 jni 函数/* * Register android native functions with the VM. *//*static*/ int AndroidRuntime::startReg(JNIEnv* env){		...		// 这个 gRegJNI 变量可以关注一下,    // 这里注册了java 调用 native的jni    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) FindClass(slashClassName); // 找到类 className
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
				// 这是一个比较重要的 main 函数,通过反射来启动
				// 基于类找到它的方法
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
				} else {
						// 调用 call 执行这个main函数
						**// 所以上面的 runtime.start("com.android.internal.os.ZygoteInit", args, zygote)
						// 参数传下来,就是执行的 ZygoteInit 这个类的 main 函数**
				    env->CallStaticVoidMethod(startClass, startMeth, strArray);
}

// 这个时候就来到了 java 层级
// ZygoteInit.java --> /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

android runtime 做了3件事情,start 虚拟机(虚拟机就是一个内存管理工具),注册 jni,反射了 zygoteInit 进入 zygote

// 这个时候就来到了 java 层级
// ZygoteInit.java --> /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String[] argv) {
        ZygoteServer zygoteServer = null;

        // Mark zygote start. This ensures that thread creation will throw
        // an error.
        ZygoteHooks.startZygoteNoThreadCreation();

        // Zygote goes into its own process group.
        try {
            Os.setpgid(0, 0);
        } catch (ErrnoException ex) {
            throw new RuntimeException("Failed to setpgid(0,0)", ex);
        }

        Runnable caller;
        try {
            // Store now for StatsLogging later.
            final long startTime = SystemClock.elapsedRealtime();
            final boolean isRuntimeRestarted = "1".equals(
                    SystemProperties.get("sys.boot_completed"));
			...
			if (!enableLazyPreload) {
			      bootTimingsTraceLog.traceBegin("ZygotePreload");
			      EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
			                SystemClock.uptimeMillis());
						// step1: 这里有个比较重要的 preload 函数过程,这个函数是比较耗时的,是可以优化的
			      preload(bootTimingsTraceLog);
			      EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
			                        SystemClock.uptimeMillis());
			       bootTimingsTraceLog.traceEnd(); // ZygotePreload
			            }
			...
			ZygoteHooks.stopZygoteNoThreadCreation();
			// step2 重要函数 创建 socket 服务器,等待别人通知fork进程
			zygoteServer = new ZygoteServer(isPrimaryZygote);

      if (startSystemServer) {
						// Zygote fork 出的第一个进程 system server
						// 所谓的 fork 就是复制出来一个进程
						// 谁来通知我来 fork 一个进程,ams 来通知,ams 通过一个 socket 通信!
            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.
						// 循环等待 fork 出其它的应用进程,比如 launcher,比如 app
						// runSelectLoop 这个函数保证 zygote while 死循环,没东西就 poll 休眠
            caller = zygoteServer.runSelectLoop(abiList);
							
						...
						// fork完进程,会返回进程pid
						pid = Zygote.forkSystemServer(
						// return 到 handle 这里去处理
						return handleSystemServerProcess(parsedArgs);
								
			...

					
}

// handleSystemServerProcess 方法会返回到 zygoteInit 去处理
private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {
		...
		return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
							parsedArgs.mDisabledCompatChanges,
							parsedArgs.mRemainingArgs, cl);
}

public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {
        if (RuntimeInit.DEBUG) {
            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
        }

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
        RuntimeInit.redirectLogStreams();

        RuntimeInit.commonInit(); // 初始化运行环境
        ZygoteInit.nativeZygoteInit(); // 启动binder,方法在 androidRuntime.cpp 中注册
				// 通过反射创建**程序入口函数**的 method 对象,并返回 runable 对象
        return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
                classLoader);
    }

// preload 这个函数也在 ZygoteInit.java 里面
static void preload(TimingsTraceLog bootTimingsTraceLog) {
        Log.d(TAG, "begin preload");
        bootTimingsTraceLog.traceBegin("BeginPreload");
        beginPreload();
        bootTimingsTraceLog.traceEnd(); // BeginPreload
        bootTimingsTraceLog.traceBegin("PreloadClasses");
        preloadClasses(); // 加载系统类,系统常用类,比如上层需要用的 TextView、ImageView等
													// 在这里加载了,app就可以直接拿来用了,这也是为什么 app 可以直接用的原因
        bootTimingsTraceLog.traceEnd(); // PreloadClasses
        bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders");
        cacheNonBootClasspathClassLoaders();
        bootTimingsTraceLog.traceEnd(); // CacheNonBootClasspathClassLoaders
        bootTimingsTraceLog.traceBegin("PreloadResources");
        preloadResources();  // 加载系统资源,R 文件等,以前经常在系统改的
        bootTimingsTraceLog.traceEnd(); // PreloadResources
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
        nativePreloadAppProcessHALs();
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadGraphicsDriver");
        maybePreloadGraphicsDriver();
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
        preloadSharedLibraries();  // 加载一些共享 so库,其实就三个:android、compiler_rt、jnigraphic
        preloadTextResources();  // 加载字体资源,app运行时,字体库拿来的,就是这里来的,
        // Ask the WebViewFactory to do any initialization that must run in the zygote process,
        // for memory sharing purposes.
        WebViewFactory.prepareWebViewInZygote(); // 加载 webview 相关资源
        endPreload();
        warmUpJcaProviders(); // 初始化 jca 安全相关的参数
        Log.d(TAG, "end preload");

        sPreloadComplete = true;
    }

// preloadClasses() 函数也在 ZygoteInit.java
private static void preloadClasses() {
				...
				} finally {
           IoUtils.closeQuietly(is);

            // Fill in dex caches with classes, fields, and methods brought in by preloading.
            Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadDexCaches");
            runtime.preloadDexCaches(); // 最后在这个地方加载的 preload classes
            Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
				...

// fork 进程了解一下
fork 的时候倒是几个设置线程优先级的,可以研究一下

相关文章

服务器端口转发,带你了解服务器端口转发
服务器开放端口,服务器开放端口的步骤
产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
如何使用 WinGet 下载 Microsoft Store 应用
百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

发布评论