Android App进程创建过程分析

在分析Activity启动的文章《Android Activity启动过程分析》中,我们遗留了一个小尾巴——App冷启动的情况下,当时没有讲解进程创建的过程,现在我们就把这个尾巴接上,一起看看Android中App进程创建的过程(本文分析过程是基于Android Q源码)。

 先给结论:在Android系统中创建App进程是由zygote进程负责创建的;在一个App种冷启动另一个App时,首先会经过system_server进程种的ActivityManagerSrevice生成创建进程的请求,创建进程的请求由system_server进程发给zygote进程的;system_server和zygote进程之间是通过socket(UNIX Domain Socket)进行通信的。

Android App进程创建过程分析_第1张图片

在了解上面逻辑后,我们先看下看下zygote socket是如何创建的。

Zygote Socket创建

  zyoget socket创建是在解析init.zygote32.rc(也可能是init.zygote64.rc、init.zygote32_64.rc等文件)后创建的,我们看下这个文件的内容:

//文件位置:system/core/rootdir/init.zygote32.rc
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

关于init.zygote32.rc文件的解析可参考《Android系统启动之Zygote》,这里就不再重复了。socket zygote stream 660 root systemsocket usap_pool_primary stream 660 root system 这两个命令被解析后会创建两个本地socket,分别对应Android设备的/dev/socket/zygote/dev/socket/usap_pool_primary两个节点。Socket创建和绑定过程如下:
Android App进程创建过程分析_第2张图片

//system/init/descriptors.cpp
void DescriptorInfo::CreateAndPublish(const std::string& globalContext) const {
  // Create
  const std::string& contextStr = context_.empty() ? globalContext : context_;
  //创建Socket并返回文件描述符,Create()函数会调用system/init/util.cpp中的CreateSocket()函数
  int fd = Create(contextStr);
  if (fd < 0) return;
  std::string publishedName = key() + name_;
  LOG(INFO) << "CreateAndPublish publishedName: " << publishedName << "";
  std::for_each(publishedName.begin(), publishedName.end(),
                [] (char& c) { c = isalnum(c) ? c : '_'; });

  std::string val = std::to_string(fd);
  //将文件描述符保存在环境变量中。
  setenv(publishedName.c_str(), val.c_str(), 1);

  // make sure we don't close on exec
  fcntl(fd, F_SETFD, 0);
}

DescriptorInfo::CreateAndPublish()函数主要作用是创建socket和将socket节点的文件描述符存入环境变量中。我们看下CreateSocket()函数

//system/init/util.cpp
/*
 * 在/dev/socket目录下创建unix domain socket
 */
int CreateSocket(const char* name, int type, bool passcred, mode_t perm, uid_t uid, gid_t gid,
                 const char* socketcon) {
    if (socketcon) {
        if (setsockcreatecon(socketcon) == -1) {
            PLOG(ERROR) << "setsockcreatecon(\"" << socketcon << "\") failed";
            return -1;
        }
    }
    //创建socket
    android::base::unique_fd fd(socket(PF_UNIX, type, 0));
    if (fd < 0) {
        PLOG(ERROR) << "Failed to open socket '" << name << "'";
        return -1;
    }

    if (socketcon) setsockcreatecon(NULL);

    struct sockaddr_un addr;
    memset(&addr, 0 , sizeof(addr));
    addr.sun_family = AF_UNIX;
    snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",
             name);

    if ((unlink(addr.sun_path) != 0) && (errno != ENOENT)) {
        PLOG(ERROR) << "Failed to unlink old socket '" << name << "'";
        return -1;
    }

    std::string secontext;
    if (SelabelLookupFileContext(addr.sun_path, S_IFSOCK, &secontext) && !secontext.empty()) {
        setfscreatecon(secontext.c_str());
    }

    if (passcred) {
        int on = 1;
        if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
            PLOG(ERROR) << "Failed to set SO_PASSCRED '" << name << "'";
            return -1;
        }
    }
    //绑定socket,为socket分配地址
    int ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
    int savederrno = errno;

    if (!secontext.empty()) {
        setfscreatecon(nullptr);
    }

    if (ret) {
        errno = savederrno;
        PLOG(ERROR) << "Failed to bind socket '" << name << "'";
        goto out_unlink;
    }

    if (lchown(addr.sun_path, uid, gid)) {
        PLOG(ERROR) << "Failed to lchown socket '" << addr.sun_path << "'";
        goto out_unlink;
    }
    if (fchmodat(AT_FDCWD, addr.sun_path, perm, AT_SYMLINK_NOFOLLOW)) {
        PLOG(ERROR) << "Failed to fchmodat socket '" << addr.sun_path << "'";
        goto out_unlink;
    }

    LOG(INFO) << "Created socket '" << addr.sun_path << "'"
              << ", mode " << std::oct << perm << std::dec
              << ", user " << uid
              << ", group " << gid;

    return fd.release();

out_unlink:
    unlink(addr.sun_path);
    return -1;
}

CreateSocket()函数实现了创建socket节点并为其分配地址;至此Zygote socket就创建完成了。

Zygote Socket 服务端

 在知道zygote socket是怎么创建后,我们看下zygote socket的服务端是怎么创建并监听的。

Android App进程创建过程分析_第3张图片

socket服务端是在ZygoteInit.main()方法中创建并初始化的,整个流程可参考上面的时序图;整个过程分为两步:一、创建LocalServerSocket,并监听/dev/socket/zygote节点;二、进入一个死循环,等待客户端发送数据。我们先看下创建LocalServerSocket的过程:

//ZygoteServer.java
ZygoteServer(boolean isPrimaryZygote) {
    mUsapPoolEventFD = Zygote.getUsapPoolEventFD();
    //isPrimaryZygote是在ZygoteInit.main()方法中传入的,
    //如果没有init.zygote32.rc中没有通过`--socket-name=`指定socket名字,则该值为true.
    if (isPrimaryZygote) {
        mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);
        mUsapPoolSocket =
                Zygote.createManagedSocketFromInitSocket(
                        Zygote.USAP_POOL_PRIMARY_SOCKET_NAME);
    } else {
        mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.SECONDARY_SOCKET_NAME);
        mUsapPoolSocket =
                Zygote.createManagedSocketFromInitSocket(
                        Zygote.USAP_POOL_SECONDARY_SOCKET_NAME);
    }

    fetchUsapPoolPolicyProps();

    mUsapPoolSupported = true;
}

在ZygoteServer构造方法中主要是初始化mZygoteSocket、mUsapPoolSocket;我们看下createManagedSocketFromInitSocket()方法的实现

//Zygote.java
static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {
    int fileDesc;
    final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;

    try {
        //从系统环境变量中获取socket的文件描述符,该描述符是在创建socket节点后写入了系统环境变量中;
        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);
        //创建LocalServerSocket对象,并返回该对象
        return new LocalServerSocket(fd);
    } catch (IOException ex) {
        throw new RuntimeException(
            "Error building socket from file descriptor: " + fileDesc, ex);
    }
}

注释中已经做了说明,我们继续看LocalServerSocket构造方法

//LocalServerSocket.java
public LocalServerSocket(FileDescriptor fd) throws IOException
{   //创建LocalSocketImpl对象,LocalSocketImpl为Socekt功能实现类;
    impl = new LocalSocketImpl(fd);
    //监听`/dev/socket/zygote`
    impl.listen(LISTEN_BACKLOG);
    localAddress = impl.getSockAddress();
}

上面就是服务端LocalServerSocket创建并监听/dev/socket/zygote的过程,现在我们看下等待客户端连接和处理客户端命令的实现,这个实现是在ZygoteServer.runSelectLoop()方法中。

//ZygoteServer.java
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;
        }
        //省略部分代码.....

        try {
            //阻塞等待文件描述符上的POLLIN事件发生,最终是通过linux系统函数poll实现;
            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);
                    // 如果创建了子进程,mIsForkChild为true,然后返回command命令
                    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) {
                        Slog.e(TAG, "Exception executing zygote command: ", e);

                        ZygoteConnection conn = peers.remove(pollIndex);
                        conn.closeSocket();

                        socketFDs.remove(pollIndex);
                    } else {

                        Log.e(TAG, "Caught post-fork exception in child process.", e);
                        throw e;
                    }
                } finally {

                    mIsForkChild = false;
                }
            } else {
              //省略部分代码.....
        }
      //省略部分代码.....
    }
}


private ZygoteConnection acceptCommandPeer(String abiList) {
    try {
        //mZygoteSocket.accept()最终会调用系统accept()函数,
        //关于accept()函数可参考 https://man7.org/linux/man-pages/man2/accept.2.html
        return createNewConnection(mZygoteSocket.accept(), abiList);
    } catch (IOException ex) {
        throw new RuntimeException(
                "IOException during accept()", ex);
    }
}

在这个方法中主要做了以下几件事:

  • 阻塞式监听zygote文件描述符的POLLIN事件;
  • 处理建立socket连接请求;
  • 处理客户端创建进程命令;

前面两点已经在注释中说明,第三点我们稍后讲解,我们先看zygote socket客户端创建过程

Zygote Socket客户端

 在了解socket服务端的创建和监听过程后,你肯定会想,那客户端是怎么创建并和服务端建立连接的呢,现在我们就来了解下。在《Android系统启动之SystemServer(二)》中,我们知道在SystemServer启动过程中会创建一系列的系统服务,我们zygote socket 客户端也是在这个过程中创建并和服务端建立连接的。整个过程如下时序图所示:
Android App进程创建过程分析_第4张图片
  在SystemServer.startOtherService()方法中会调用ZygoteProcess的preloadDefault()方法,在ZygoteProcess.attemptConnectionToPrimaryZygote()方法种会判断其成员变量primaryZygoteState对象(ZygoteState实例对象,ZygoteState是ZygoteProcess的私有静态内部类)是否为空和是否关闭,这实际上就是判断客户端和zygote socket服务端是否建立会话连接;如果没有建立连接或者连接已关闭则走后续的创建客户端socket并连接的过程。客户端socket为LocalSocket对象,服务端socket为LocalServerSocket,他们功能实现类都是LocaSocketImpl,最终也都借助Linux系统函数实现。整个客户端创建的过程比较简单,大家可以根据上面的时序图跟下代码。接下来,我们开始回到最初的问题,App进程是怎么创建的,有了前面的基础,我们再来看这个问题就比较简单了。

App进程创建过程

 讲了大半天,终于回到了文章的主题——App进程创建过程,进程创建分为两个过程:

  • system_server 进程通过socket 发出创建进程命令;
  • zygote 进程接收到创建进程命令创建进程,在父进程(也就是zygote进程)中通过服务端socket告诉客户端子进程pid等信息;在子进程中调用ActivityThread.main()方法;

客户端发送创建进程命令

我们先看system_server发出创建进程命令的过程,在前一篇《Android Activity启动过程分析》文章中,讲到Activity启动过程中,如果Activity所在的进程没有创建,则会创建进程,我们还是以从Activity冷启动分析,看下应用进程创建过程是怎样的。回到Activity启动过程中调用ActivityStackSupervisor.startSpecificActivityLocked()方法。

void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) {
    final WindowProcessController wpc =
            mService.getProcessController(r.processName, r.info.applicationInfo.uid);

    boolean knownToBeDead = false;
    //如果进程已创建,则继续启动Activity的流程,并return
    if (wpc != null && wpc.hasThread()) {
        try {
            realStartActivityLocked(r, wpc, andResume, checkConfig);
            return;
        } catch (RemoteException e) {
            Slog.w(TAG, "Exception when starting activity "
                    + r.intent.getComponent().flattenToShortString(), e);
        }
        knownToBeDead = true;
    }

    if (getKeyguardController().isKeyguardLocked()) {
        r.notifyUnknownVisibilityLaunched();
    }

    try {
        if (Trace.isTagEnabled(TRACE_TAG_ACTIVITY_MANAGER)) {
            Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "dispatchingStartProcess:"
                    + r.processName);
        }
        //进程没有创建的情况,这个情况下会创建一个Message对象,
        //该Message的Callback即为调用ActivityManagerInternal.startProcess()方法
        //参数为mService.mAmInternal, r.processName, r.info.applicationInfo, knownToBeDead,
        //"activity", r.intent.getComponent()
        final Message msg = PooledLambda.obtainMessage(
                ActivityManagerInternal::startProcess, mService.mAmInternal, r.processName,
                r.info.applicationInfo, knownToBeDead, "activity", r.intent.getComponent());
        mService.mH.sendMessage(msg);
    } finally {
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    }
}

注释中已做了说明,整个过程如下时序图所示(图中省略了ProcessList.startProcessLocked()重载方法的调用):
Android App进程创建过程分析_第5张图片
最后创建进程的请求是由ZygoteProcess.attemptZygoteSendArgsAndGetResult()方法发出的,在讲Zygote Socket客户端 创建过程,我们知道ZygoteProcess的成员变量primaryZygoteState是zygote socket客户端和服务端通信的桥梁,它封装了输入输出流。所以最终的命令就是通过primaryZygoteState中的字符输出流发送给服务端的。我们看下具体流程,先从ActivityManagerService.startProcessLocked()方法开始

//ActivityManagerService.java
@GuardedBy("this")
final ProcessRecord startProcessLocked(String processName,
        ApplicationInfo info, boolean knownToBeDead, int intentFlags,
        HostingRecord hostingRecord, boolean allowWhileBooting,
        boolean isolated, boolean keepIfLarge) {
    return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
            hostingRecord, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
            null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
            null /* crashHandler */);
}

在ActivityManagerService.startProcessLocked()方法中会调用ProcessList类中的startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord,boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge, String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler),这个方法经过几个重载方法的调用最终会调用startProcess()方法

//ProcessList.java
private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint,
        ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
        String seInfo, String requiredAbi, String instructionSet, String invokeWith,
        long startTime) {
    //entryPoint值为"android.app.ActivityThread",赋值的地方是在
    /**
    *boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
    *       boolean disableHiddenApiChecks, boolean mountExtStorageFull,
    *       String abiOverride) {
    *       // 省略部分代码....
    *       final String entryPoint = "android.app.ActivityThread";
    *       return startProcessLocked(hostingRecord, entryPoint, app, uid, gids,
    *               runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith,
    *               startTime);
    *       // 省略部分代码....
    *}
    */
    try {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                app.processName);
        checkSlow(startTime, "startProcess: asking zygote to start proc");
        final Process.ProcessStartResult startResult;
		    //这里判断HostingRecord.mHostingZygote变量的值,该值用于描述用那种类型的Zygote创建新的进程
		    //这个值在HostingRecord的构造函数中赋值,在ActivityManagerSerice.LocalService.startProcess()方法中
		    //创建HostingRecord时,mHostingZygote为默认值HostingZygote.REGULAR_ZYGOTE,此时对应的是最后的else情况
        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,
                    new String[] {PROC_START_SEQ_IDENT + app.startSeq});
        } else if (hostingRecord.usesAppZygote()) {
            final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app);

            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,
                    /*useUsapPool=*/ false,
                    new String[] {PROC_START_SEQ_IDENT + app.startSeq});
        } else {
            startResult = Process.start(entryPoint,
                    app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                    app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                    app.info.dataDir, invokeWith, app.info.packageName,
                    new String[] {PROC_START_SEQ_IDENT + app.startSeq});
        }
        checkSlow(startTime, "startProcess: returned from zygote!");
        return startResult;
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    }
}

这个方法判断是通过什么方式启动发送启动进程的,实际上行最终都是会调用ZygoteProcess.start()方法;这个方法有一个比较重要的参数entryPoint,这个决定了zygote进程创建进程后会调用哪个类的main()方法,关于这个参数的初始化已经注释中说明。接着start()方法会调用startViaZygote()方法,这个方法的作用是封装创建进程的命令。

//ZygoteProcess.java
private Process.ProcessStartResult startViaZygote(@NonNull final String processClass,
                                                  @Nullable final String niceName,
                                                  final int uid, final int gid,
                                                  @Nullable final int[] gids,
                                                  int runtimeFlags, int mountExternal,
                                                  int targetSdkVersion,
                                                  @Nullable String seInfo,
                                                  @NonNull String abi,
                                                  @Nullable String instructionSet,
                                                  @Nullable String appDataDir,
                                                  @Nullable String invokeWith,
                                                  boolean startChildZygote,
                                                  @Nullable String packageName,
                                                  boolean useUsapPool,
                                                  @Nullable String[] extraArgs)
                                                  throws ZygoteStartFailedEx {
    ArrayList<String> argsForZygote = new ArrayList<>();

    //封装创建进程的命令
    argsForZygote.add("--runtime-args");
    argsForZygote.add("--setuid=" + uid);
    argsForZygote.add("--setgid=" + gid);
    argsForZygote.add("--runtime-flags=" + runtimeFlags);
    if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
        argsForZygote.add("--mount-external-default");
    } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
        argsForZygote.add("--mount-external-read");
    } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
        argsForZygote.add("--mount-external-write");
    } else if (mountExternal == Zygote.MOUNT_EXTERNAL_FULL) {
        argsForZygote.add("--mount-external-full");
    } else if (mountExternal == Zygote.MOUNT_EXTERNAL_INSTALLER) {
        argsForZygote.add("--mount-external-installer");
    } else if (mountExternal == Zygote.MOUNT_EXTERNAL_LEGACY) {
        argsForZygote.add("--mount-external-legacy");
    }

    argsForZygote.add("--target-sdk-version=" + targetSdkVersion);

    // --setgroups is a comma-separated list
    if (gids != null && gids.length > 0) {
        StringBuilder sb = new StringBuilder();
        sb.append("--setgroups=");

        int sz = gids.length;
        for (int i = 0; i < sz; i++) {
            if (i != 0) {
                sb.append(',');
            }
            sb.append(gids[i]);
        }

        argsForZygote.add(sb.toString());
    }

    if (niceName != null) {
        argsForZygote.add("--nice-name=" + niceName);
    }

    if (seInfo != null) {
        argsForZygote.add("--seinfo=" + seInfo);
    }

    if (instructionSet != null) {
        argsForZygote.add("--instruction-set=" + instructionSet);
    }

    if (appDataDir != null) {
        argsForZygote.add("--app-data-dir=" + appDataDir);
    }

    if (invokeWith != null) {
        argsForZygote.add("--invoke-with");
        argsForZygote.add(invokeWith);
    }

    if (startChildZygote) {
        argsForZygote.add("--start-child-zygote");
    }

    if (packageName != null) {
        argsForZygote.add("--package-name=" + packageName);
    }

    argsForZygote.add(processClass);

    if (extraArgs != null) {
        Collections.addAll(argsForZygote, extraArgs);
    }

    synchronized(mLock) {
        //openZygoteSocketIfNeeded(abi)会先判断是否需要创建客户端socket,如果已经创建则返回ZygoteState对象。
        //实际上这个时候ZygoteState对象在ZygoteProcess.preloadDefault()被调用后已经创建了,
        //这个我们已经在Socket客户端小节中讲过。
        //zygoteSendArgsAndGetResult()最后会调用attemptZygoteSendArgsAndGetResult()方法,
        //在这个方法中实现了通过字符流发送创建进程命令和接收结果
        return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
                                          useUsapPool,
                                          argsForZygote);
    }
}

如注释所述startViaZygote()方法会将方法的参数封装成创建进程的字符串形式的命令,最后通过attemptZygoteSendArgsAndGetResult()方法发送给socket 服务端。


private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult(
        ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx {
    try {
		Slog.d(LOG_TAG, "attemptZygoteSendArgsAndGetResult, msgStr: " + msgStr);
        final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
        final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;
        //通过输出字符流将命名发送给服务端
        zygoteWriter.write(msgStr);
        zygoteWriter.flush();

        Process.ProcessStartResult result = new Process.ProcessStartResult();
        //读取服务端返回的进程创建后分配的pid
        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);
    }
}

以上就是冷启动App时,客户端发送创建进程请求的过程,接下来我们看下服务端是如何响应的。

服务端响应创建进程命令

在Zygote Socket 服务端章节,我们知道在ZygoteServer.runSelectLoop()方法中会一直等待客户端发送过来的命令,而处理客户端的命令是由ZygoteConnection.processOneCommand()实现的,我们看下这个方法

//ZygoteConnection.java
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);
    // 查询abi列表命令
    if (parsedArgs.mAbiListQuery) {
        handleAbiListQuery();
        return null;
    }
    // 查询pid的命令
    if (parsedArgs.mPidQuery) {
        handlePidQuery();
        return null;
    }
    //是否采用pre-fork方式
    if (parsedArgs.mUsapPoolStatusSpecified) {
        return handleUsapPoolStatusChange(zygoteServer, parsedArgs.mUsapPoolEnabled);
    }
    // 预加载资源和类命令
    if (parsedArgs.mPreloadDefault) {
        handlePreload();
        return null;
    }
    // 预加载apk命令
    // 关于命令含义可参考ZygoteArguments中的定义
    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);
        }
    }

    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;
    //创建进程命令,forkAndSpecialize()方法最终实现是调用了Linux系统fork()函数创建进程。
    //如果创建成功,fork()函数会返回两次pid;一次是在父进程中返回子进程的pid(不为0),一次是在子进程中返回pid(值为0)
    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) {
            // 在子进程中,setForkChild()方法会将ZygoteServer中的mIsForkChild设为true。
            zygoteServer.setForkChild();

            zygoteServer.closeServerSocket();
            IoUtils.closeQuietly(serverPipeFd);
            serverPipeFd = null;

            return handleChildProc(parsedArgs, descriptors, childPipeFd,
                    parsedArgs.mStartChildZygote);
        } else {
            //在父进程中,
            IoUtils.closeQuietly(childPipeFd);
            childPipeFd = null;
            handleParentProc(pid, descriptors, serverPipeFd);
            //注意这里返回的是null
            return null;
        }
    } finally {
        IoUtils.closeQuietly(childPipeFd);
        IoUtils.closeQuietly(serverPipeFd);
    }
}

processOneCommand()方法并不只是处理创建进程的逻辑,还处理包括查询abi列表、pid、是否采用USAP方式创建进程等功能。这里我们看下非USAP方式创建进程的过程,也就是上面调用Zygote.forkAndSpecialize()及之后的过程。Zygote.forkAndSpecialize()方法最终会调用Linux系统函数fork()创建进程,到此我们终于看到进程创建的地方了,在创建进程完成后会先后从父进程和子进程中返回,分别调用handleParentProc()和handleChildProc()方法,我们看下这两个方法。

//ZygoteConnection.java
private void handleParentProc(int pid, FileDescriptor[] descriptors, FileDescriptor pipeFd) {
    if (pid > 0) {
        setChildPgid(pid);
    }

    if (descriptors != null) {
        for (FileDescriptor fd: descriptors) {
            IoUtils.closeQuietly(fd);
        }
    }

    boolean usingWrapper = false;
    // 省略部分代码......    
    try {
        mSocketOutStream.writeInt(pid);
        mSocketOutStream.writeBoolean(usingWrapper);
    } catch (IOException ex) {
        throw new IllegalStateException("Error writing to command socket", ex);
    }
}

handleParentProc()方法比较简单,它的主要作用是将进程的pid和usingWapper变量的值通过输出流告诉客户端,客户端在ZygoteProcess.attemptZygoteSendArgsAndGetResult()方法中会去读取这两个值。

Process.ProcessStartResult result = new Process.ProcessStartResult();
//读取服务端返回的进程创建后分配的pid
result.pid = zygoteInputStream.readInt();
result.usingWrapper = zygoteInputStream.readBoolean();

接下来我们继续看下handleChildProc()实现

//ZygoteConnection.java
private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor[] descriptors,
        FileDescriptor pipeFd, boolean isZygote) {
    closeSocket();
    if (descriptors != null) {
        try {
            Os.dup2(descriptors[0], STDIN_FILENO);
            Os.dup2(descriptors[1], STDOUT_FILENO);
            Os.dup2(descriptors[2], STDERR_FILENO);

            for (FileDescriptor fd: descriptors) {
                IoUtils.closeQuietly(fd);
            }
        } catch (ErrnoException ex) {
            Log.e(TAG, "Error reopening stdio", ex);
        }
    }

    if (parsedArgs.mNiceName != null) {
        Process.setArgV0(parsedArgs.mNiceName);
    }
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    if (parsedArgs.mInvokeWith != null) {
        WrapperInit.execApplication(parsedArgs.mInvokeWith,
                parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
                VMRuntime.getCurrentInstructionSet(),
                pipeFd, parsedArgs.mRemainingArgs);

        // Should not get here.
        throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
    } else {
        //isZygote值却决于创建进程命令参数是否包含‘--start-child-zygote’
        if (!isZygote) {
            return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
                    parsedArgs.mRemainingArgs, null /* classLoader */);
        } else {
            return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,
                    parsedArgs.mRemainingArgs, null /* classLoader */);
        }
    }
}

这里我们看下isZygote值为false的情况(实际上为true的情况最终都会调用到RuntimeInit.findStaticMain()方法),Zygote.zygoteInit()会调用RuntimeInit.applicationInit()方法,我们直接看下applicationInit()方法。

//RuntimeInit.java
protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
        ClassLoader classLoader) {
    nativeSetExitWithoutCleanup(true);

    //设置虚拟机的堆内存利用率的百分比,当实际的利用率偏离这个百分比的时候,
    //虚拟机会在GC的时候调整堆内存大小,让实际占用率向个百分比靠拢,默认为0.75
    VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
    //设置目标sdk版本
    VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
    final Arguments args = new Arguments(argv);
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    return findStaticMain(args.startClass, args.startArgs, classLoader);
}

这个方法设置了虚拟机堆内存利用率百分比和目标SDK版本,然后调用了findStaticMain()方法,我们接着看下这个方法,

//RuntimeInit.java
protected static Runnable findStaticMain(String className, String[] argv,
        ClassLoader classLoader) {
    Class<?> cl;

    try {
        cl = Class.forName(className, true, classLoader);
    } catch (ClassNotFoundException ex) {
        throw new RuntimeException(
                "Missing class when invoking static main " + className,
                ex);
    }

    Method m;
    try {
        m = cl.getMethod("main", new Class[] { String[].class });
    } catch (NoSuchMethodException ex) {
        throw new RuntimeException(
                "Missing static main on " + className, ex);
    } catch (SecurityException ex) {
        throw new RuntimeException(
                "Problem getting static main on " + className, ex);
    }

    int modifiers = m.getModifiers();
    if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
        throw new RuntimeException(
                "Main method is not public and static on " + className);
    }
    return new MethodAndArgsCaller(m, argv);
}

这个方法比较简单,就是通过反射的方式找到参数className类的main()函数,并传入argv参数,在冷启动app的情况下,参数className的值为android.app.ActivityThread;然后封装成MethodAndArgsCaller对象返回。MethodAndArgsCaller实现了Ruannable接口,在run方法中调用了Method.invoke()方法,也就是会真正调用className的main()方法。或许你就有个疑问了,这个任务的run方法是什么时候被调用的,在一个新的线程或者线程池中执行的吗。我们知道ZygoteConnection.processOneCommand()方法中在子进程的情况下会调用zygoteServer.setForkChild()并返回这个MethodAndArgusCaller对象。那我们现在回过头来看下processOneCommand()被调用的地方——ZygoteServer.runSelectLoop()。

//ZygoteServer.java
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) {
      //省略部分代码.....
                    ZygoteConnection connection = peers.get(pollIndex);
                    // 处理客户端发送过来的命令
                    final Runnable command = connection.processOneCommand(this);
                    // 在processOneCommand()方法中,子进程情况下会将mIsForkChild设置为true
                    // 所以从子进程中返回时会返回command对象。
                    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);
                        }
                    }
     //省略部分代码.....

    }
}

既然在子进程中runSelectLoop()方法会返回Runnable实例command,那我们再看下runSelectLoop()被调用的地方

//ZygoteInit.java
public static void main(String argv[]) {
    ZygoteServer zygoteServer = null;

    // Mark zygote start. This ensures that thread creation will throw
    // an error.
    ZygoteHooks.startZygoteNoThreadCreation();

    // Zygote goes into its own process group.
    try {
        Os.setpgid(0, 0);
    } catch (ErrnoException ex) {
        throw new RuntimeException("Failed to setpgid(0,0)", ex);
    }

    Runnable caller;
    try {
        // 省略部分代码.....

        // The select loop returns early in the child process after a fork and
        // loops forever in the zygote.
        caller = zygoteServer.runSelectLoop(abiList);
    } catch (Throwable ex) {
        Log.e(TAG, "System zygote died with exception", ex);
        throw ex;
    } finally {
        if (zygoteServer != null) {
            zygoteServer.closeServerSocket();
        }
    }

    // 在子进程中从runSelectLoop()返回后,调用Runnable.run()方法,实际上就是调用了MethodAndArgsCaller的run()方法
    if (caller != null) {
        caller.run();
    }
}

现在我们知道了MethodAndArgsCaller.run()方法调用的时机了,以App冷启动为例,后面经过一系列方法调用,最后最调用到Activity StackSupervisor.realStartActivityLocked(),再之后的流程就和《Android Activity启动过程分析》启动流程分析章节中从realStartActivityLocked()方法开始是一样的,后面的流程就不在重复了;至此服务端响应创建进程命令就分析完了,最后附上服务端处理创建进程和启动Activity的流程时序图供大家参考。

Android App进程创建过程分析_第6张图片

总结

 讲了这么一大堆,实际上总结起来就下面几点

  • 系统启动过程中会创建/dev/socket/zygote 节点;
  • zygote进程创建后会创建服务端socket,并一直等待客户端连接和发送命令;
  • system_server进程创建过程中会创建客户端socket,当某个App冷启动另一个app时,会通过system_server进程中的ActivityManagerService对象经过一系列方法调用,最后通过客户端socket发送创建进程的请求,并等待服务端socket返回pid等信息。
  • zygote进程中的服务端socket接收到创建进程命令后,调用linux系统fork()函数创建进程。在父进程(也就是zygote进程)中通过服务端socket告诉客户端子进程pid等信息;在子进程中会调用ActivityThread.main()方法,然后就是Application和Activity创建流程。

最后附上文中内容涉及到的类关系图,供大家参考。
Android App进程创建过程分析_第7张图片

你可能感兴趣的:(android,源码分析,android,Android进程,Zygote,socket)