0
点赞
收藏
分享

微信扫一扫

浅谈Zygote启动流程

yeamy 2023-05-14 阅读 104

前言

之前简单总结了下Android启动流程,这里从源码的角度再具体分析每一步都做了什么?

源码分析

这里从 init的入口函数main.cpp的main方法开始分析

  • init的入口函数main.cpp的main方法
// 路径:system/core/init/main.cpp
int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
    __asan_set_error_report_callback(AsanReportCallback);
#endif

    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")) {
            return SetupSelinux(argv);
        }

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

    return FirstStageMain(argc, argv);
}

这里我们主要看下SecondStageMain(argc, argv)

// 路径:system/core/init/init.cpp

int SecondStageMain(int argc, char** argv) {
	...
	//用来存放解析出的内容
   ActionManager& am = ActionManager::GetInstance();
   ServiceList& sm = ServiceList::GetInstance();
   //在这个方法中会对 /system/core/rootdir/init.rc 脚本文件文件进行解析
   LoadBootScripts(am, sm);
   //循环处理init.rc脚本中的command命令,处理完就进入等待
    while (true) {
         if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) 
         {
            //内部遍历执行每个action中携带的command对应的执行函数
			am.ExecuteOneCommand();
         }
    }
	...
}


  • init.rc
// 位置:system/core/rootdir/init.rc
 start servicemanager
 start zygote

可见,init进程会启动ServiceManager和Zygote进程

  • 我们在看下启动Zygote对应的参数配置
// 位置:system/core/rootdir/init.zygote32.rc
...
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
...
  • 而zygote进程的入口处理函数是app_main.cpp中的main()函数;
//位置:/frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[]) //这里入参是--zygote --start-system-server
{
	...
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;

    ++i;  
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true; 
            niceName = ZYGOTE_NICE_NAME; //赋值niceName为Zygote,之前实际是app_process
        } 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.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
    }
...
    if (!niceName.isEmpty()) {
        runtime.setArgv0(niceName.string(), true /* setProcName */);//最终,设置进程名为Zygote
    }

    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote); //启动进程
    } else if (className) {
        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.");
    }

之前代码都在Native层,之后都是在Java层

  • ZygoteInit
public static void main(String argv[]) {
//参数会传递过来,因此startSystemServer = true  enableLazyPreload =false
        ZygoteServer zygoteServer = null;
            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;
                } else if ("--enable-lazy-preload".equals(argv[i])) {
                    enableLazyPreload = true;
                } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                    zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }
			
			...
            if (!enableLazyPreload) {
            	//由于enableLazyPreload == false,所以这里代码执行
            	这里做预加载工作:
            	1.加载系统类 "/system/etc/preloaded-classes”,如android.accounts.*/android.animation.*/android.app.*
            	2.加载资源文件;
            	3.加载一些so;
            	4. ...
                preload(bootTimingsTraceLog);
            
            }


            zygoteServer = new ZygoteServer(isPrimaryZygote); //内部通过LocalServerSocket实现进程间通信

            if (startSystemServer) {
            	//fork SystemServer进程
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
                if (r != null) {
                    r.run();
                    return;
                }
            }

            caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            throw ex;
        } finally {
            if (zygoteServer != null) {
                zygoteServer.closeServerSocket();
            }
        }
        if (caller != null) {
            caller.run();
        }
    }

从上面代码中看出,Zygote进程主要做了以下几件事:
1. 预加载系统类、资源等工作;

  1. 创建ZygoteServer对象实现进程间通信,内部是通过ServerSocket实现的;那为什么不通过Binder实现呢??

对于这个问题可以查看:android中AMS通知Zygote去fork进程为什么使用socket而不使用binder?

简单小结下主要是以下几点原因:
a. 启动先后顺序问题,由于ServiceManager和Zygote是不同进程,无法保证时序,我们知道使用Binder需要先注册到ServiceManager;
b. 多线程问题,zygote如果使用binder,会导致子进程中binder线程的挂起和锁状态不可恢复;
c. 效率问题,binder虽说内存拷贝只有一次,但由于涉及到安全验证等等环节,效率实际比LocalSocket低;
d. 安全问题,LocalSocket同样支持权限验证,也是安全的;
e. .Binder拷贝问题;

  1. fork SystemServer进程;
  • SystemServer进程,主要是调用run方法
	...
   		startBootstrapServices(t); //启动AMS/PMS/PowerMangerService等等;
        startCoreServices(t); 
        startOtherServices(t)...

由此可见,AMS/PMS是由SystemServer进程启动,同时我们查看AMS、PMS代码他们并没有main函数,因此和SystemServer进程是同一进程

结语

如果以上文章对您有一点点帮助,希望您不要吝啬的点个赞加个关注,您每一次小小的举动都是我坚持写作的不懈动力!ღ( ´・ᴗ・` )

举报

相关推荐

0 条评论