AndroID的zygote本质上是AndroID的虚拟机,是AndroID的SystemServer和几乎所有Java应用的卵化器,它们的父进程都是zygote。没有zygote就没有AndroID,AndroID的启动也离不开zygote。
zygote是很重要的一个服务进程,我们在本文档中分析以下zygote在AndroID中所扮演的角色、作用以及一些设计的特点。
AndroID版本:AndroidQ。
zygote是服务进程的别名,zygote实际上是app_process这个可执行程序所运行的:
service zygote /system/bin/app_process -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 write /sys/androID_power/request_state wake 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由rc文件定义init启动的服务,其来源就是app_process,这也是AndroID的虚拟机的可执行文件。从rc文件中也有一些细节:
1.zygote的进程优先级是最高的,priority被设成-20,主要是因为AndroID的启动非常依赖于SystemServer的启动,而SystemServer也是zygote fork出来的,因此需要将其的优先级设成最高的。
2.zygote的user是root权限,其group是root、readproc(读取/proc的节点)、reserved_disk(未知).
3.zygote在启动时创建了两个socket(zygote和usap_pool_primary),用于进程间的通信,后面会有说到。
4.zygote是AndroID非常重要的核心服务之一,当其因异常退出后init会将其重新启动,并将一些相关的节点和服务重新设置。
5.向内核通告其为前台进程任务。
zygote的启动实际上是分成了两部分:①SystemServer的启动;②ZygoteServer的启动。这两者前面是在同一个进程中执行的,当虚拟机创建完成后才正式分离。
zygote启动的前奏我们先来看以下前面的部分:
// frameworks/base/cmds/app_process/app_main.cppint main(int argc, char* const argv[]){ AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); 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; 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; } } Vector<String8> args; if (!classname.isEmpty()) { args.add(application ? String8("application") : String8("tool")); runtime.setClassnameAndArgs(classname, argc - i, argv + i); } else { // We're in zygote mode. maybeCreateDalvikCache(); if (startSystemServer) { args.add(String8("start-system-server")); } char prop[PROP_VALUE_MAX]; if (property_get(ABI_List_PROPERTY, prop, NulL) == 0) { LOG_ALWAYS_FATAL("app_process: Unable to determine ABI List from property %s.", ABI_List_PROPERTY); return 11; } String8 abiFlag("--abi-List="); abiFlag.append(prop); args.add(abiFlag); for (; i < argc; ++i) { args.add(String8(argv[i])); } } if (!nicename.isEmpty()) { runtime.setArgv0(nicename.string(), true /* setProcname */); } 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."); }}
app_process的main方法比较长,以上是精简后的代码,再根据rc中定义zygote服务的参数,可以获知,局部变量zygote为true,startSystemServer为true,classname为空串。因此这里会先创建Java虚拟机cache,然后执行Java代码ZygoteInit的main方法。
@UnsupportedAppUsagepublic static voID main(String argv[]) { ZygoteServer zygoteServer = null; Runnable caller; try { Zygote.initNativeState(isPrimaryZygote); zygoteServer = new ZygoteServer(isPrimaryZygote); …… if (!enableLazyPreload) { preload(boottimingsTraceLog); } else { Zygote.resetNicePriority(); } …… if (startSystemServer) { 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(); }}
ZygoteInit的main()方法是AndroID启动中的第一个Java进程的主方法。在ZygoteInit中,一般无特殊原因,都会调用preload()方法将AndroID Java层应用常用的资源预加装,其原因是:
1.AndroID是基于linux系统开发的,底层就是linux *** 作系统,而linux进程的fork机制有一个特点,就是写时拷贝机制;fork出来的进程是最初是共用一块内存,只有当发生写 *** 作时,才会将对应的内存块进行拷贝修改,而一些只读的内存块则会所有fork出来的进程共享。
2.preload()方法所加装的东西主要有以下几类:常用类文件、Resources资源、HALs资源、opengl、webvIEw等。这些资源一般都是只读的,不会进行修改,而且是很多应用都可能会用到的。因此预先加载后所有由zygote fork出来的应用进程都能共用一块内存。
preloadstatic voID preload(TimingsTraceLog boottimingsTraceLog) { beginPreload(); preloadClasses(); cacheNonbootclasspathClassLoaders(); preloadResources(); nativePreloadAppProcessHALs(); maybePreloadGraphicsDriver(); preloadSharedlibrarIEs(); preloadTextResources(); WebVIEwFactory.prepareWebVIEwInZygote(); endPreload(); warmUpJcaProvIDers(); sPreloadComplete = true;}
preload()方法中有很多是安全、trace和虚拟机相关的内容,我们主要关心一些我们常用的东西。
preloadClassesprivate static voID preloadClasses() { final vmruntime runtime = vmruntime.getRuntime(); inputStream is; try { is = new fileinputStream(PRELOADED_CLASSES); } catch (fileNotFoundException e) { Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + "."); return; } runtime.setTargetHeaputilization(0.8f); try { BufferedReader br = new BufferedReader(new inputStreamReader(is), Zygote.soCKET_BUFFER_SIZE); int count = 0; String line; while ((line = br.readline()) != null) { line = line.trim(); if (line.startsWith("#") || line.equals("")) { continue; } try { Class.forname(line, true, null); count++; } catch (ClassNotFoundException e) { } catch (UnsatisfIEdlinkError e) { } catch (Throwable t) { } } } catch (IOException e) { } finally { IoUtils.closeQuIEtly(is); runtime.setTargetHeaputilization(defaultutilization); runtime.preloadDexCaches(); }}
preloadClasses()方法主要是从/system/etc/preloaded-classes
文件中读取需要预加载的类名,然后通过Class.forname将该类加载到内存中,并会执行其中的一些静态方法(Java的类加载机制)。这里的重点是preloaded-classes文件,这个文件一般使用AndroID原生的文件,其路径在frameworks/base/config/preloaded-classes
,一般不需要我们去修改,格式如下:
androID.R$styleableandroID.accessibilityservice.AccessibilityServiceInfoandroID.accessibilityservice.AccessibilityServiceInfoandroID.accounts.AccountandroID.accounts.AccountandroID.accounts.AccountManagerandroID.accounts.AccountManagerandroID.accounts.AccountManagerandroID.accounts.AccountManagerandroID.accounts.AccountManagerandroID.accounts.AccountManagerandroID.accounts.AccountManager$AmsTaskandroID.accounts.AccountManager$AmsTask$ResponseandroID.accounts.AccountManager$AmsTaskandroID.accounts.AccountManager$BaseFutureTaskandroID.accounts.AccountManager$BaseFutureTask$ResponseandroID.accounts.AccountManager$BaseFutureTaskandroID.accounts.AccountManager$Future2TaskandroID.accounts.AccountManager$Future2TaskandroID.accounts.AccountManager
每一行都是一个类的全名。
preloadResourcesprivate static voID preloadResources() { final vmruntime runtime = vmruntime.getRuntime(); try { mResources = Resources.getSystem(); mResources.startpreloading(); if (PRELOAD_RESOURCES) { long startTime = SystemClock.uptimeMillis(); TypedArray ar = mResources.obtainTypedArray( com.androID.internal.R.array.preloaded_drawables); int N = preloadDrawables(ar); ar.recycle(); startTime = SystemClock.uptimeMillis(); ar = mResources.obtainTypedArray( com.androID.internal.R.array.preloaded_color_state_Lists); N = preloadcolorStateLists(ar); ar.recycle(); if (mResources.getBoolean( com.androID.internal.R.bool.config_freeformWindowManagement)) { startTime = SystemClock.uptimeMillis(); ar = mResources.obtainTypedArray( com.androID.internal.R.array.preloaded_freeform_multi_window_drawables); N = preloadDrawables(ar); ar.recycle(); } } mResources.finishpreloading(); } catch (RuntimeException e) { }}
preloadResources()方法主要是做了以下几件事:
1.在Resources.startpreloading()方法中,调用updateConfiguration()方法为系统创建Configuration,这是后面应用和系统的一些配置来源。
2.从preloaded_drawables中获取预加载的drawables资源,并将其加载到内存中。preloaded_drawables字段在frameworks/base/core/res/res/values/arrays.xml
中定义。
3.从preloaded_color_state_Lists中获取预加载的color资源,并将其加载到内存中,preloaded_color_state_Lists字段也是定义在frameworks/base/core/res/res/values/arrays.xml
中。
4.如果支持自由窗口模式,则将preloaded_freeform_multi_window_drawables字段中定义的预加载的freeform drawables也加载进来。
nativePreloadAppProcessHALs()方法是将Gralloc的HALs加载进来:
voID androID_internal_os_ZygoteInit_nativePreloadAppProcessHALs(jnienv* env, jclass) { ScopedSCSExit x; androID::GraphicBufferMapper::preloadHal();}voID GraphicBufferMapper::preloadHal() { Gralloc2Mapper::preload(); Gralloc3Mapper::preload();}
nativePreloadGraphicsDrivernativePreloadGraphicsDriver()方法是用于加载图形驱动(egl):
private static voID maybePreloadGraphicsDriver() { if (!SystemPropertIEs.getBoolean(PROPERTY_disABLE_GRAPHICS_DRIVER_preloading, false)) { nativePreloadGraphicsDriver(); }}
voID androID_internal_os_ZygoteInit_nativePreloadGraphicsDriver(jnienv* env, jclass) { ScopedSCSExit x; if (PropertIEs::peekRenderPipelineType() == RenderPipelineType::SkiaGL) { eglGetdisplay(EGL_DEFAulT_disPLAY); }}
forkSystemServerSystemServer是通过forkSystemServer()方法fork出来并开始执行,forkSystemServer()的代码树中有很多晦涩的代码, 我们将会跳过一些我们不相关的代码来分析。
private static Runnable forkSystemServer(String abiList, String socketname, ZygoteServer zygoteServer) { ZygoteArguments parsedArgs = null; int pID; try { boolean profileSystemServer = SystemPropertIEs.getBoolean( "dalvik.vm.profilesystemserver", false); if (profileSystemServer) { parsedArgs.mRuntimeFlags |= Zygote.PROfile_SYstem_SERVER; } /* Request to fork the system server process */ pID = Zygote.forkSystemServer( parsedArgs.mUID, parsedArgs.mGID, parsedArgs.mGIDs, parsedArgs.mRuntimeFlags, null, parsedArgs.mPermittedCapabilitIEs, parsedArgs.mEffectiveCapabilitIEs); } catch (IllegalArgumentException ex) { throw new RuntimeException(ex); } /* For child process */ if (pID == 0) { if (hasSecondZygote(abiList)) { waitForSecondaryZygote(socketname); } zygoteServer.closeServerSocket(); return handleSystemServerProcess(parsedArgs); } return null;}
forkSystemServer()中主要做了两件事:①调用Zygote.forkSystemServer()方法去fork一个新的进程出来。②fork()后的子进程是SystemServer进程,则等待zygote的启动完成,并执行真正的SystemServer代码。
// Zygote.javapublic static int forkSystemServer(int uID, int gID, int[] gIDs, int runtimeFlags, int[][] rlimits, long permittedCapabilitIEs, long effectiveCapabilitIEs) { ZygoteHooks.prefork(); // resets nice priority for zygote process. resetNicePriority(); int pID = nativeForkSystemServer( uID, gID, gIDs, runtimeFlags, rlimits, permittedCapabilitIEs, effectiveCapabilitIEs); // Enable tracing as soon as we enter the system_server. if (pID == 0) { Trace.setTracingEnabled(true, runtimeFlags); } ZygoteHooks.postForkCommon(); return pID;}
ZygoteHooks.prefork():将Daemons线程关掉,虚拟机进行一些copy前的处理。
resetNicePriority():将进程的优先级设回普通的级别。
nativeForkSystemServer():调用native层方法去fork一个新的进程。
ZygoteHooks.postForkCommon():重新启动Daemons线程,虚拟机进行copy后的处理。
fork *** 作是不会将进程中所有线程拷贝的,只会拷贝当前线程。
Daemons线程是指:①HeapTaskDaemon;②ReferenceQueueDaemon;③FinalizerDaemon;④FinalizerWatchdogDaemon。平时在trace文件(ANR或者其他方式获取的trace文件)中看到Java应用进程都会有这4个线程,这4个线程就是在这里创建的。
static jint com_androID_internal_os_Zygote_nativeForkSystemServer( jnienv* env, jclass, uID_t uID, gID_t gID, jintArray gIDs, jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilitIEs, jlong effective_capabilitIEs) { pID_t pID = ForkCommon(env, true, fds_to_close, fds_to_ignore); if (pID == 0) { SpecializeCommon(env, uID, gID, gIDs, runtime_flags, rlimits, permitted_capabilitIEs, effective_capabilitIEs, MOUNT_EXTERNAL_DEFAulT, nullptr, nullptr, true, false, nullptr, nullptr); } else if (pID > 0) { gSystemServerPID = pID; int status; if (waitpID(pID, &status, WNOHANG) == pID) { ALOGE("System server process %d has dIEd. Restarting Zygote!", pID); RuntimeAbort(env, __liNE__, "System server process has dIEd. Restarting Zygote!"); } if (UsePerAppMemcg()) { if (!SetTaskProfiles(pID, std::vector<std::string>{"SystemMemoryProcess"})) { ALOGE("Couldn't add process %d into system memcg group", pID); } } } return pID;}
ForkCommon():主要调用linux的fork系统调用,fork一个新的进程,子进程的pID为0,父进程返回子进程的pID值。
SpecializeCommon():子进程(SystemServer)需要做的处理,这里做了非常多的 *** 作,很多都是虚拟机相关的东西,其中有secure storage的挂载(MountEmulatedStorage),seandroid的配置,创建SystemServer的classLoader(ZygoteInit.createSystemServerClassLoader())以及hIDden API的检查等。
再回到ZygoteInit.forkSystemServer()方法,此时两个进程都会返回到此处,此时两个进程就到这里分道扬镳了。SystemServer进程将ZygoteServer的socket关闭,然后调用handleSystemServerProcess()方法去执行SystemServer的源码。
createSystemServerClassLoader(); ClassLoader cl = sCachedSystemServerClassLoader; if (cl != null) { Thread.currentThread().setContextClassLoader(cl); } return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion, parsedArgs.mRemainingArgs, cl);
handleSystemServerProcess()方法的核心代码就是上面那几行,先获取classloader,并将其设置为root classloader。然后调用ZygoteInit.zygoteInit()方法去执行。
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) { RuntimeInit.commonInit(); ZygoteInit.nativeZygoteInit(); return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);}
ZygoteInit.nativeZygoteInit()方法为进程创建Binder的环境(Processstatae),这个将会在新的文章中对binder进行分析。
RuntimeInit.applicationInit()方法则会去执行传参进来的类的main()方法,这里就是:com.androID.server.SystemServer
.
String args[] = { "--setuID=1000", "--setgID=1000", "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023," + "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010", "--capabilitIEs=" + capabilitIEs + "," + capabilitIEs, "--nice-name=system_server", "--runtime-args", "--target-sdk-version=" + vmruntime.SDK_VERSION_CUR_DEVELOPMENT, "com.androID.server.SystemServer", };
ZygoteInit.forkSystemServer()返回一个runnable,返回到ZygoteInit.main()方法后,SystemServer进程就会继续执行这个runnable。
ZygoteServer.runSelectLoop当zygote进程返回到main()方法后,就会继续执行ZygoteServer.runSelectLoop()方法,从名字上和注释来看,这个方法应该是一个死循环,是不断进行循环执行命令的方法:
Runnable runSelectLoop(String abiList) { ArrayList<fileDescriptor> socketFDs = new ArrayList<fileDescriptor>(); ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>(); socketFDs.add(mZygoteSocket.getfileDescriptor()); peers.add(null); while (true) { fetchUsapPoolPolicyPropsWithMinInterval(); int[] usapPipeFDs = null; StructPollfd[] pollFDs = null; if (mUsapPoolEnabled) { usapPipeFDs = Zygote.getUsapPipeFDs(); pollFDs = new StructPollfd[socketFDs.size() + 1 + usapPipeFDs.length]; } else { pollFDs = new StructPollfd[socketFDs.size()]; } int pollindex = 0; for (fileDescriptor socketFD : socketFDs) { pollFDs[pollindex] = new StructPollfd(); pollFDs[pollindex].fd = socketFD; pollFDs[pollindex].events = (short) PolliN; ++pollindex; } final int usapPoolEventFdindex = pollindex; if (mUsapPoolEnabled) { pollFDs[pollindex] = new StructPollfd(); pollFDs[pollindex].fd = mUsapPoolEventFD; pollFDs[pollindex].events = (short) PolliN; ++pollindex; for (int usapPipeFD : usapPipeFDs) { fileDescriptor managedFd = new fileDescriptor(); managedFd.setInt$(usapPipeFD); pollFDs[pollindex] = new StructPollfd(); pollFDs[pollindex].fd = managedFd; pollFDs[pollindex].events = (short) PolliN; ++pollindex; } } try { Os.poll(pollFDs, -1); } catch (ErrnoException ex) { throw new RuntimeException("poll Failed", ex); } boolean usapPoolfdread = false; while (--pollindex >= 0) { if ((pollFDs[pollindex].revents & PolliN) == 0) { continue; } if (pollindex == 0) { ZygoteConnection newPeer = acceptCommandPeer(abiList); peers.add(newPeer); socketFDs.add(newPeer.getfileDescriptor()); } else if (pollindex < usapPoolEventFdindex) { try { ZygoteConnection connection = peers.get(pollindex); final Runnable command = connection.processOneCommand(this); if (mIsForkChild) { if (command == null) { throw new IllegalStateException("command == null"); } return command; } else { if (command != null) { throw new IllegalStateException("command != null"); } if (connection.isClosedByPeer()) { connection.closeSocket(); peers.remove(pollindex); socketFDs.remove(pollindex); } } } catch (Exception e) { if (!mIsForkChild) { ZygoteConnection conn = peers.remove(pollindex); conn.closeSocket(); socketFDs.remove(pollindex); } else { throw e; } } finally { mIsForkChild = false; } } else { long messagePayload = -1; try { byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES]; int readBytes = Os.read(pollFDs[pollindex].fd, buffer, 0, buffer.length); if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) { DatainputStream inputStream = new DatainputStream(new ByteArrayinputStream(buffer)); messagePayload = inputStream.readLong(); } else { continue; } } catch (Exception ex) { if (pollindex == usapPoolEventFdindex) { } else { } continue; } if (pollindex > usapPoolEventFdindex) { Zygote.removeUsaptableEntry((int) messagePayload); } usapPoolfdread = true; } } if (usapPoolfdread) { int[] sessionSocketRawFDs = socketFDs.subList(1, socketFDs.size()) .stream() .mapToInt(fd -> fd.getInt$()) .toArray(); final Runnable command = fillUsapPool(sessionSocketRawFDs); if (command != null) { return command; } } }}
runSelectLoop()方法主要做两件事:
1.每次循环都重新构建监听文件列表,主要是ZygoteServer的socket文件(ZygoteServer的socket和其他应用进程连接过来的socket)和usap文件节点(目前看来,zygote默认是没有使用,作用未明,不做分析)。
2.监听文件列表,并从中获取命令执行。
Os.poll(pollFDs, -1)调用表示从监听队列中监听事件。usapPoolEventFdindex的值是socket fds最后的位置,处理监听文件事件时,分了三类:
1.ZygoteServer的socket,index为0,在runSelectLoop()方法的开始时就先将ZygoteServer的socket add到socketFDs中,因此该fd在监听列表中的index为0。
2.0< index < usapPoolEventFdindex,在这个区间的文件节点时其他应用进程连接过来的socket节点,其他应用会通过对应的socket来进行指令的传输。
3.index >= usapPoolEventFdindex,usap节点,作用不明,先不管。
对于第一种情况调用acceptCommandPeer()方法来获取申请连接的ZygoteConnection实例和socket fd。
对于第二种情况,先拿到对应的ZygoteConnection实例,调用其processOneCommand()方法来获取客户端传递过来的命令。
processOneCommandRunnable processOneCommand(ZygoteServer zygoteServer) { String args[]; ZygoteArguments parsedArgs = null; fileDescriptor[] descriptors; try { args = Zygote.readArgumentList(mSocketReader); // Todo (chriswailes): Remove this and add an assert. descriptors = mSocket.getAncillaryfileDescriptors(); } catch (IOException ex) { throw new IllegalStateException("IOException on command socket", ex); } // readArgumentList returns null only when it has reached EOF with no available // data to read. This will only happen when the remote socket has disconnected. if (args == null) { iSEOf = true; return null; } int pID = -1; fileDescriptor childPipeFd = null; fileDescriptor serverPipeFd = null; parsedArgs = new ZygoteArguments(args); if (parsedArgs.mAbiListquery) { handleAbiListquery(); return null; } if (parsedArgs.mPIDquery) { handlePIDquery(); return null; } if (parsedArgs.mUsapPoolStatusspecifIEd) { return handleUsapPoolStatusChange(zygoteServer, parsedArgs.mUsapPoolEnabled); } if (parsedArgs.mPreloadDefault) { handlePreload(); return null; } if (parsedArgs.mPreloadPackage != null) { handlePreloadPackage(parsedArgs.mPreloadPackage, parsedArgs.mPreloadPackagelibs, parsedArgs.mPreloadPackagelibfilename, parsedArgs.mPreloadPackageCacheKey); return null; } if (canPreloadApp() && parsedArgs.mPreloadApp != null) { byte[] rawParcelData = Base64.getDecoder().decode(parsedArgs.mPreloadApp); Parcel appInfoParcel = Parcel.obtain(); appInfoParcel.unmarshall(rawParcelData, 0, rawParcelData.length); appInfoParcel.setDataposition(0); ApplicationInfo appInfo = ApplicationInfo.CREATOR.createFromParcel(appInfoParcel); appInfoParcel.recycle(); if (appInfo != null) { handlePreloadApp(appInfo); } else { throw new IllegalArgumentException("Failed to deserialize --preload-app"); } return null; } if (parsedArgs.mAPIBlackListExemptions != null) { return handleAPIBlackListExemptions(zygoteServer, parsedArgs.mAPIBlackListExemptions); } if (parsedArgs.mHIDdenAPIAccessLogSampleRate != -1 || parsedArgs.mHIDdenAPIAccessstatslogSampleRate != -1) { return handleHIDdenAPIAccessLogSampleRate(zygoteServer, parsedArgs.mHIDdenAPIAccessLogSampleRate, parsedArgs.mHIDdenAPIAccessstatslogSampleRate); } if (parsedArgs.mPermittedCapabilitIEs != 0 || parsedArgs.mEffectiveCapabilitIEs != 0) { throw new ZygoteSecurityException("ClIEnt may not specify capabilitIEs: " + "permitted=0x" + Long.toHexString(parsedArgs.mPermittedCapabilitIEs) + ", effective=0x" + Long.toHexString(parsedArgs.mEffectiveCapabilitIEs)); } Zygote.applyUIDSecurityPolicy(parsedArgs, peer); Zygote.applyInvokeWithSecurityPolicy(parsedArgs, peer); Zygote.applyDeBUGgerSystemProperty(parsedArgs); Zygote.applyInvokeWithSystemProperty(parsedArgs); int[][] rlimits = null; if (parsedArgs.mRlimits != null) { rlimits = parsedArgs.mRlimits.toArray(Zygote.INT_ARRAY_2D); } int[] fdsToIgnore = null; if (parsedArgs.mInvokeWith != null) { try { fileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC); childPipeFd = pipeFds[1]; serverPipeFd = pipeFds[0]; Os.fcntlint(childPipeFd, F_SETFD, 0); fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()}; } catch (ErrnoException errnoEx) { throw new IllegalStateException("Unable to set up pipe for invoke-with", errnoEx); } } /** * In order to avoID leaking descriptors to the Zygote child, * the native code must close the two Zygote socket descriptors * in the child process before it switches from Zygote-root to * the UID and privileges of the application being launched. * * In order to avoID "bad file descriptor" errors when the * two LocalSocket objects are closed, the Posix file * descriptors are released via a dup2() call which closes * the socket and substitutes an open descriptor to /dev/null. */ int [] fdsToClose = { -1, -1 }; fileDescriptor fd = mSocket.getfileDescriptor(); if (fd != null) { fdsToClose[0] = fd.getInt$(); } fd = zygoteServer.getZygoteSocketfileDescriptor(); if (fd != null) { fdsToClose[1] = fd.getInt$(); } fd = null; 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.mTargetSdkVersion); try { if (pID == 0) { // in child zygoteServer.setForkChild(); zygoteServer.closeServerSocket(); IoUtils.closeQuIEtly(serverPipeFd); serverPipeFd = null; return handleChildProc(parsedArgs, descriptors, childPipeFd, parsedArgs.mStartChildZygote); } else { // In the parent. A pID < 0 indicates a failure and will be handled in // handleParentProc. IoUtils.closeQuIEtly(childPipeFd); childPipeFd = null; handleParentProc(pID, descriptors, serverPipeFd); return null; } } finally { IoUtils.closeQuIEtly(childPipeFd); IoUtils.closeQuIEtly(serverPipeFd); }}
processOneCommand通过mSocketReader读取客户端传过来的参数,然后调用ZygoteArguments来进行解析。不同的参数对应不同的 *** 作:
参数 | *** 作 |
---|---|
“–query-abi-List” / mAbiListquery = true | handleAbiListquery |
“–get-pID” / mPIDquery = true | handlePIDquery |
“–usap-pool-enabled” / mUsapPoolStatusspecifIEd = true | handleUsapPoolStatusChange |
“–preload-default” / mPreloadDefault = true | handlePreload |
“–preload-package” / mPreloadPackage = true | handlePreloadPackage |
“–preload-app” / mPreloadApp | handlePreloadApp |
“–set-API-blackList-exemptions” / mAPIBlackListExemptions != null | handleAPIBlackListExemptions |
“–hIDden-API-log-sampling-rate” / mHIDdenAPIAccessLogSampleRate != -1 | handleHIDdenAPIAccessLogSampleRate |
“–hIDden-API-statslog-sampling-rate” / mHIDdenAPIAccessstatslogSampleRate != -1 | handleHIDdenAPIAccessLogSampleRate |
other | forkAndSpecialize + handleChildProc |
前面的指令我们所对应的 *** 作不展开分析,以后用到再进行分析。
Process的启动经过上面的分析,我们已经了解到zygote的基本运行,但是ZygoteConnection.processOneCommand()方法的具体使用没有展开说明。我们在这里以启动一个新的应用为例展开分析。
当启动一个新的应用时,AMS会调用Process.start()方法去让zygote fork一个新的进程来:
// frameworks/base/core/java/androID/os/Process.javapublic static ProcessstartResult start(@NonNull final String processClass, @Nullable final String nicename, int uID, int gID, @Nullable int[] gIDs, int runtimeFlags, int mountExternal, int targetSdkVersion, @Nullable String seInfo, @NonNull String abi, @Nullable String instructionSet, @Nullable String appDataDir, @Nullable String invokeWith, @Nullable String packagename, @Nullable String[] zygoteArgs) { return ZYGOTE_PROCESS.start(processClass, nicename, uID, gID, gIDs, runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, invokeWith, packagename, /*useUsapPool=*/ true, zygoteArgs);}
ZYGOTE_PROCESS是ZygoteProcess的实例对象。ZygoteProcess.start()方法会调用到ZygoteProcess.startViaZygote()方法来设置启动参数,processClass是"androID.app.ActivityThread",在ProcessList.startProcessLocked()中设置的。
经过ZygoteProcess.startViaZygote()方法的参数设置后,调用ZygoteProcess.attemptZygoteSendArgsAndGetResult()方法将这些命令和参数通过socket发送到ZygoteSocket中:
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"); } return result; } catch (IOException ex) { zygoteState.close(); Log.e(LOG_TAG, "IO Exception while communicating with Zygote - " + ex.toString()); throw new ZygoteStartFailedEx(ex); }}
attemptZygoteSendArgsAndGetResult()方法通过向Zygote Socket发送命令(zygoteWriter.write())来启动新的应用进程,并等待返回结果。
当客户端的socket将命令发送后,我们继续回到Zygote进程的服务端socket的处理。我们回顾上一章中ZygoteServer.processOneCommand()方法,此时zygote进程做了以下3件事:
1.Zygote.forkAndSpecialize(),fork新的进程。
2.zygoteServer.closeServerSocket(),关闭fork后子进程的socket节点。
3.handleChildProc()返回entrypoint的main()方法,有fork后子进程进行。
总结@H_404_417@
问答1.zygote启动时进行preload的作用是什么?
zygote作为AndroID的虚拟机,很多应用(java/kotlin)的资源都是共用的,zygote利用了linux *** 作系统的copy-on-write机制,预先加载了常用的资源,然后其他的应用通过fork后,所有的进程都能共享一份只能的资源,而不需要为每个应用进程都单独加载一份。
2.zygote在fork进程后,使用runnable的方式返回到main()方法后才执行的原因?
减少线程堆栈的长度,因为fork后进行执行的内容与之前zygote的堆栈内容并无关系,因此不需要为每个进程都保留前面的堆栈信息,而且还能减少进程的堆栈容量限制。
3.zygote的作用。
zygote作为AndroID的虚拟机,最主要的作用就是启动SystemServer进程,和fork新的应用进程。我们也可以单独使用app_process命令来运行我们的Java代码。
总结以上是内存溢出为你收集整理的Android Zygote分析全部内容,希望文章能够帮你解决Android Zygote分析所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)