Android Zygote分析

Android Zygote分析,第1张

概述AndroidZygoteAndroid的zygote本质上是Android的虚拟机,是Android的SystemServer和几乎所有Java应用的卵化器,它们的父进程都是zygote。没有zygote就没有Android,Android的启动也离不开zygote。zygote是很重要的一个服务进程,我们在本文档中分析以下zygote在Android中所扮演的 AndroID Zygote

AndroID的zygote本质上是AndroID的虚拟机,是AndroID的SystemServer和几乎所有Java应用的卵化器,它们的父进程都是zygote。没有zygote就没有AndroID,AndroID的启动也离不开zygote。

zygote是很重要的一个服务进程,我们在本文档中分析以下zygote在AndroID中所扮演的角色、作用以及一些设计的特点。
AndroID版本:AndroidQ。

zygote的启动

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出来的应用进程都能共用一块内存。

preload
static voID preload(TimingsTraceLog boottimingsTraceLog) {    beginPreload();    preloadClasses();    cacheNonbootclasspathClassLoaders();    preloadResources();    nativePreloadAppProcessHALs();    maybePreloadGraphicsDriver();    preloadSharedlibrarIEs();    preloadTextResources();    WebVIEwFactory.prepareWebVIEwInZygote();    endPreload();    warmUpJcaProvIDers();    sPreloadComplete = true;}

preload()方法中有很多是安全、trace和虚拟机相关的内容,我们主要关心一些我们常用的东西。

preloadClasses
private 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

每一行都是一个类的全名。

preloadResources
private 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

nativePreloadAppProcessHALs()方法是将Gralloc的HALs加载进来:

voID androID_internal_os_ZygoteInit_nativePreloadAppProcessHALs(jnienv* env, jclass) {    ScopedSCSExit x;    androID::GraphicBufferMapper::preloadHal();}voID GraphicBufferMapper::preloadHal() {    Gralloc2Mapper::preload();    Gralloc3Mapper::preload();}
nativePreloadGraphicsDriver

nativePreloadGraphicsDriver()方法是用于加载图形驱动(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);    }}
forkSystemServer

SystemServer是通过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()方法来获取客户端传递过来的命令。

processOneCommand
Runnable 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 = truehandleAbiListquery
“–get-pID” / mPIDquery = truehandlePIDquery
“–usap-pool-enabled” / mUsapPoolStatusspecifIEd = truehandleUsapPoolStatusChange
“–preload-default” / mPreloadDefault = truehandlePreload
“–preload-package” / mPreloadPackage = truehandlePreloadPackage
“–preload-app” / mPreloadApphandlePreloadApp
“–set-API-blackList-exemptions” / mAPIBlackListExemptions != nullhandleAPIBlackListExemptions
“–hIDden-API-log-sampling-rate” / mHIDdenAPIAccessLogSampleRate != -1handleHIDdenAPIAccessLogSampleRate
“–hIDden-API-statslog-sampling-rate” / mHIDdenAPIAccessstatslogSampleRate != -1handleHIDdenAPIAccessLogSampleRate
otherforkAndSpecialize + 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分析所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1038357.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-24
下一篇 2022-05-24

发表评论

登录后才能评论

评论列表(0条)

保存