Android Zygote分析

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.cpp
int 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方法。

@UnsupportedAppUsage
public 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$styleable
android.accessibilityservice.AccessibilityServiceInfo$1
android.accessibilityservice.AccessibilityServiceInfo
android.accounts.Account$1
android.accounts.Account
android.accounts.AccountManager$10
android.accounts.AccountManager$11
android.accounts.AccountManager$18
android.accounts.AccountManager$1
android.accounts.AccountManager$20
android.accounts.AccountManager$2
android.accounts.AccountManager$AmsTask$1
android.accounts.AccountManager$AmsTask$Response
android.accounts.AccountManager$AmsTask
android.accounts.AccountManager$BaseFutureTask$1
android.accounts.AccountManager$BaseFutureTask$Response
android.accounts.AccountManager$BaseFutureTask
android.accounts.AccountManager$Future2Task$1
android.accounts.AccountManager$Future2Task
android.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.java
public 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.java
public 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后子进程进行。

总结

Zygote运行流程

问答

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代码。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值