Android Zygote启动构造流程及进程创建详解
一、前言
本文主要讲解内容
1、系统启动zygote、zygote的构造流程、主要做了什么
2、如何创建一个新的进程
3、systemserver的ams创建应用如何建立socket联系,以及如何收发消息
先简单提一下开机流程
init.rc -> zygote.rc -> app_main.cpp -> AndroidRuntime.cpp (启动虚拟机,注册jni,启动zygote) -> ZygoteInit.java -> SystemServer进程
其中init是我们系统启动的第一个进程,正是它通过linux的forck方法,创建我们系统的最重要的进程之一zygote.
zygote的启动过程以及作用:启动dalvik虚拟机,加载系统必须的一些资源,启动framework的systemserver进程。最后等待app请求创建应用进程
zygote在fork一个新的进程时会克隆出和之前zygote几乎一样的进程包含zygote的资源,新进程不需要进行初始化操作,只会修改一些必要参数
由于源码过多,本文的代码都会精简要点,最好结合源码阅读,源码基于androidR,各安卓版本代码可能有小区别但整体不会变化很大
二、启动流程
2.1、init.rc启动的地方
关于zygote的rc文件有几个地方:
./system/core/rootdir/init.zygote32_64.rc ./system/core/rootdir/init.zygote32.rc ./system/core/rootdir/init.zygote64_32.rc ./system/core/rootdir/init.zygote64.rc
他们的32和64分别对应两个启动的地方app_process32和app_process64
例如:zygote64_32.rc,那么它以app_process64为主,app_process32为辅,它两都会启动,也就是有两个zygote进程
./system/core/rootdir/init.zygote64.rc
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server 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 onrestart restart audioserver onrestart restart cameraserver onrestart restart media onrestart restart netd onrestart restart wificond writepid /dev/cpuset/foreground/tasks
上面就是开始启动zygote的地方,不管是启动32/64,都比较类似,执行手机里的/system/bin/app_process它对应的地方
2.2、app_main init主入口
app_main.cpp frameworks\base\cmds\app_process 11671 2022/2/23 241
app_main.cpp的main函数就成了入口,它主要做了如下几个事情:
//1、构建runtime AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); //2、解析运行参数 while (i < argc) { const char* arg = argv[i++]; if (strcmp(arg, "--zygote") == 0) { zygote = true; niceName = ZYGOTE_NICE_NAME; } 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; } } //3、runtime start zygoteinit 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."); }
这里的runtime只是一个调用,实现在
AndroidRuntime.cpp frameworks\base\core\jni
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) { //这句日志实际输出02-21 11:29:59.487 496 496 D AndroidRuntime: >>>>>> START com.android.internal.os.ZygoteInit uid 0 <<<<<< //达标className = com.android.internal.os.ZygoteInit ALOGD(">>>>>> START %s uid %d <<<<<<\n", className != NULL ? className : "(unknown)", getuid()); //打印关键日志boot_progress_start 表示开机过程上层开始 for (size_t i = 0; i < options.size(); ++i) { if (options[i] == startSystemServer) { primary_zygote = true; /* track our progress through the boot sequence */ const int LOG_BOOT_PROGRESS_START = 3000; LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC))); } } 1、启动虚拟机 /* start the virtual machine */ JniInvocation jni_invocation; jni_invocation.Init(NULL); JNIEnv* env; if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) { return; } onVmCreated(env); 2、注册JNI /* * Register android functions. */ if (startReg(env) < 0) { ALOGE("Unable to register all android natives\n"); return; } 3、调用ZygoteInit的main函数 //这就是上面备注的className = ZygoteIni char* slashClassName = toSlashClassName(className != NULL ? className : ""); jclass startClass = env->FindClass(slashClassName); if (startClass == NULL) { ALOGE("JavaVM unable to locate class '%s'\n", slashClassName); /* keep going */ } else { jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V");
2.3、ZygoteInit.java#main zygote入口
public static void main(String argv[]) { 1、加载进程的资源和类(这里可以多线程加载class文件优化开机速度) preload(bootTimingsTraceLog); 2、创建zygoteServer zygoteServer = new ZygoteServer(isPrimaryZygote); if (startSystemServer) { 3、把sokeckname传进去systemserver中,并开始运行systemserver Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer); if (r != null) { r.run(); return; } 4、最后开启loop等待消息 caller = zygoteServer.runSelectLoop(abiList); }
看一下forkSystemServer中关键的两个地方
private static Runnable forkSystemServer(String abiList, String socketName, ZygoteServer zygoteServer) { 1、zygote调用forkSystemServer这个native方法创建出系统进程 pid = Zygote.forkSystemServer( parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids, parsedArgs.mRuntimeFlags, null, parsedArgs.mPermittedCapabilities, parsedArgs.mEffectiveCapabilities); 2、给应用创建新的进程,走handleSystemServerProcess逻辑 /* For child process */ if (pid == 0) { if (hasSecondZygote(abiList)) { waitForSecondaryZygote(socketName); } zygoteServer.closeServerSocket(); return handleSystemServerProcess(parsedArgs); } }
这里下一步就开始启动我们熟悉的systemserver服务。关于Systemserver就不过多阐述了,它主要启动了我们整个android系统的各种service
三、zygote创建子进程流程
3.1、调用流程
创建一个应用流程这里就不详述了,都大同小异,这里直接跟踪到关键点,当我们跟踪启动流程跟踪到
ActivityStack.java frameworks\base\services\core\java\com\android\server\wm
ActivityStack#resumeTopActivityInnerLocked
mStackSupervisor.startSpecificActivity(next, true, false);
startSpecificActivity主要判断当前应用是否进程已经在运行,会跟踪改到ActivityTaskManager#startProcessAsync方法
final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::startProcess, mAmInternal, activity.processName, activity.info.applicationInfo, knownToBeDead, isTop, hostingType, activity.intent.getComponent());即来到ActivityManagerServie#startProcess
public void startProcess(String processName, ApplicationInfo info, boolean knownToBeDead, boolean isTop, String hostingType, ComponentName hostingName) { startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */, new HostingRecord(hostingType, hostingName, isTop), ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE, false /* allowWhileBooting */, false /* isolated */, true /* keepIfLarge */);
即来到ActivityManagerServie#startProcessLocked - ProcessList#startProcessLocked -
ProcessList.java frameworks\base\services\core\java\com\android\server\am
private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint, ProcessRecord app, int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags, int mountExternal, String seInfo, String requiredAbi, String instructionSet, String invokeWith, long startTime) { Process.ProcessStartResult startResult; if (hostingRecord.usesWebviewZygote()) { startResult = startWebView(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, null, app.info.packageName, app.mDisabledCompatChanges, new String[]{PROC_START_SEQ_IDENT + app.startSeq}); } else if (hostingRecord.usesAppZygote()) { final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app); // We can't isolate app data and storage data as parent zygote already did that. startResult = appZygote.getProcess().start(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, null, app.info.packageName, /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp, app.mDisabledCompatChanges, pkgDataInfoMap, whitelistedAppDataInfoMap, false, false, new String[]{PROC_START_SEQ_IDENT + app.startSeq}); } else { //modify for prefork blank process begin PreForkArgs preforkArgs = new PreForkArgs(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags, isTopApp, app.mDisabledCompatChanges, pkgDataInfoMap, whitelistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs, new String[] {PROC_START_SEQ_IDENT + app.startSeq}); startResult = mService.handlePreForkStartProcess(preforkArgs); if (startResult == null) { startResult = Process.start(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags, isTopApp, app.mDisabledCompatChanges, pkgDataInfoMap, whitelistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs, new String[]{PROC_START_SEQ_IDENT + app.startSeq}); } //modify for prefork blank process end } }
其中主要是appZygote.getProcess().start这一句,调用栈
ZygoteProcess中start - startViaZygote -
ygoteProces - zygoteSendArgsAndGetResult - attemptZygoteSendArgsAndGetResult
3.2、连接socket发送数据
1、sokeck建立的地方
startViaZygote - openZygoteSocketIfNeeded - attemptConnectionToPrimaryZygote @GuardedBy("mLock") private void attemptConnectionToPrimaryZygote() throws IOException { primaryZygoteState = ZygoteState.connect(mZygoteSocketAddress, mUsapPoolSocketAddress); //构建好消息这里发送 maybeSetApiBlacklistExemptions(primaryZygoteState, false); } static ZygoteState connect(@NonNull LocalSocketAddress zygoteSocketAddress, @Nullable LocalSocketAddress usapSocketAddress) { DataInputStream zygoteInputStream; BufferedWriter zygoteOutputWriter; final LocalSocket zygoteSessionSocket = new LocalSocket(); if (zygoteSocketAddress == null) { throw new IllegalArgumentException("zygoteSocketAddress can't be null"); } try { //关键点,这里连接上了zygote的socket zygoteSessionSocket.connect(zygoteSocketAddress); zygoteInputStream = new DataInputStream(zygoteSessionSocket.getInputStream()); zygoteOutputWriter = new BufferedWriter( new OutputStreamWriter(zygoteSessionSocket.getOutputStream()), Zygote.SOCKET_BUFFER_SIZE); }
2、通过zygoteState的BufferedWriter,用socket发消息给zygote
private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult( ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx { try { final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter; final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream; zygoteWriter.write(msgStr); zygoteWriter.flush(); // Always read the entire result from the input stream to avoid leaving // bytes in the stream for future process starts to accidentally stumble // upon. Process.ProcessStartResult result = new Process.ProcessStartResult(); result.pid = zygoteInputStream.readInt(); result.usingWrapper = zygoteInputStream.readBoolean(); if (result.pid < 0) { throw new ZygoteStartFailedEx("fork() failed"); }
上面这段代码,通过zygoteWriter把消息发给zygote,即发送流程
3.3、接收流程
接着上面的第二部分的ZygoteInit#main函数中,new了一个ZygoteServer
3.3.1 创建socket
ZygoteServer(boolean isPrimaryZygote) { mUsapPoolEventFD = Zygote.getUsapPoolEventFD(); if (isPrimaryZygote) { mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME); static LocalServerSocket createManagedSocketFromInitSocket(String socketName) { int fileDesc; // fullSocketName = “ANDROID_SOCKET_” + “zygote"; final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; try { String env = System.getenv(fullSocketName); fileDesc = Integer.parseInt(env); } catch (RuntimeException ex) { throw new RuntimeException("Socket unset or invalid: " + fullSocketName, ex); } try { FileDescriptor fd = new FileDescriptor(); fd.setInt$(fileDesc); return new LocalServerSocket(fd); } catch (IOException ex) { throw new RuntimeException( "Error building socket from file descriptor: " + fileDesc, ex); } }
3.3.2 sokeck创建后消息发送到了哪里
这里又接着上面的第二部分的ZygoteInit#main函数中第四步zygoteServer.runSelectLoop(abiList);
ZygoteServer创建了socket,runSelectLoop会执行
Runnable runSelectLoop(String abiList) { while(true) { try { ZygoteConnection connection = peers.get(pollIndex); // while循环到这句话会执行forck操作,进行新的进程的创建 final Runnable command = connection.processOneCommand(this); // TODO (chriswailes): Is this extra check necessary? if (mIsForkChild) { // We're in the child. We should always have a command to run at // this stage if processOneCommand hasn't called "exec". if (command == null) { throw new IllegalStateException("command == null"); } return command; } } }
3.4 创建子进程
ZygoteConnection#processOneCommand Runnable processOneCommand(ZygoteServer zygoteServer) { pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids, parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo, parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote, parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mIsTopApp, parsedArgs.mPkgDataInfoList, parsedArgs.mWhitelistedDataInfoList, parsedArgs.mBindMountAppDataDirs, parsedArgs.mBindMountAppStorageDirs); //穿件完后给ams回复 return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote); } //Zygote#forkAndSpecialize static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp, String[] pkgDataInfoList, String[] whitelistedDataInfoList, boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) { ZygoteHooks.preFork(); int pid = nativeForkAndSpecialize( uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote, instructionSet, appDataDir, isTopApp, pkgDataInfoList, whitelistedDataInfoList, bindMountAppDataDirs, bindMountAppStorageDirs);
子进程的初始化操作就不详述了大概说下调用栈
handleChildProc - ZygoteInit.zygoteInit - RuntimeInit.applicationInit - RuntimeInit.findStaticMain
四、写在最后
本文意在分析zygote的构建,以及如何通过socke构建新的进程。下面说两个比较常规的问题
为啥系统其它进程都用binder而这里采用socket呢?
首先binder是多线程的,zygote的fork函数是不允许多线程的,不然容易造成死锁(copy on write)
为啥运行app不新建一个进程而采用zygote fork?
因为应用是独立运行在dalvik中,他们的进程空间是分开的。如果每个应用都是新建进程,那么zygote加载的系统资源就会重复创建添加浪费系统资源。且zygote孵化也可节约创建的时间。
以上就是Android Zygote启动构造流程及进程创建详解的详细内容,更多关于Android Zygote启动的资料请关注脚本之家其它相关文章!
相关文章
Android提高之SurfaceView的基本用法实例分析
这篇文章主要介绍了Android提高之SurfaceView的基本用法,非常实用的功能,需要的朋友可以参考下2014-08-08Android编程之ListView和EditText发布帖子隐藏软键盘功能详解
这篇文章主要介绍了Android编程之ListView和EditText发布帖子隐藏软键盘功能,结合实例形式分析了Android控件调用、隐藏软键盘的原理与具体实现技巧,需要的朋友可以参考下2017-08-08解决Android Studio 3.0 butterknife:7.0.1配置的问题
下面小编就为大家分享一篇解决Android Studio 3.0 butterknife:7.0.1配置的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧2017-12-12
最新评论