应用进程启动流程分析(客户端篇)

631 阅读5分钟

「这是我参与2022首次更文挑战的第25天,活动详情查看:2022首次更文挑战」。

应用进程启动流程分析

在此前的Launcher应用进程启动流程中,我们分析过,Launcher应用进程的启动的前序,接下来这篇文章,我们将分析一下,应用进程启动流程。我们将继续以Launcher应用进程作为主要分析的目标。

前篇中,我们分析到,Launcher应用进程启动的最终会调用到ProcessList.java文件的startProcess函数,并最终通过Process.java文件的start函数启动进程,如下我们将接着流程分析。

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,
                                       int zygotePolicyFlags,
                                       boolean isTopApp,
                                       @Nullable long[] disabledCompatChanges,
                                       @Nullable Map<String, Pair<String, Long>>
                                               pkgDataInfoMap,
                                       @Nullable Map<String, Pair<String, Long>>
                                               whitelistedDataInfoMap,
                                       boolean bindMountAppsData,
                                       boolean bindMountAppStorageDirs,
                                       @Nullable String[] zygoteArgs) {
    return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
                runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, invokeWith, packageName,
                zygotePolicyFlags, isTopApp, disabledCompatChanges,
                pkgDataInfoMap, whitelistedDataInfoMap, bindMountAppsData,
                bindMountAppStorageDirs, zygoteArgs);
}

当然,在梳理整个流程的时候,我们有必要对其传入参数进行整理一下

// 注:此处参数信息通过日志打印和代码追踪得到
第一个参数processClass的定义在ProcessList.java文件中的startProcessLocked函数中,其值为"android.app.ActivityThread"
第二个参数niceName为当前所需要启动的进程名称,此处为Launcher应用进程名称"com.android.launcher3"
第三、四、五个参数,为对应的uid、uid和gids
第六个参数runtimeFlags为运行时的flags
第七个参数mountExternal为
第八个参数targetSdkVersion为对应的SDK版本
第九个参数seInfo是进程所具有的selinux权限相关的信息
第十个参数abi为系统所对应的abi信息,此处为
第十一个参数instructionSet为null
第十二个参数appDataDir为对应的data数据存放的地址
第十三个参数invokeWith为null
第十四个参数packageName为所需要启动应用的包名,此处为Launcher应用进程名称"com.android.launcher3"
第十五个参数zygotePolicyFlags的值在AMS调用startProcess函数时传入的Process.ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE
第十六个参数isTopApp为false
第十七个参数disabledCompatChanges为应用中的信息
第十八个参数pkgDataInfoMap为对应的应用的MAP对象,此处为launcher3应用的对应信息
第十九个参数whitelistedDataInfoMap为对应的空数据
第二十个参数bindMountAppsData为true
第二十一个参数bindMountAppStorageDirs为false
第二十二个参数zygoteArgs表明的startReq=20

此后,调用的是ZYGOTE_PROCESS的start函数

// 从名字来看,我们也知道这边肯定跟ZYGOTE进程有关系
public static final ZygoteProcess ZYGOTE_PROCESS = new ZygoteProcess();

public final Process.ProcessStartResult start(@NonNull final String processClass,
                                              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,
                                              int zygotePolicyFlags,
                                              boolean isTopApp,
                                              @Nullable long[] disabledCompatChanges,
                                              @Nullable Map<String, Pair<String, Long>>
                                                      pkgDataInfoMap,
                                              @Nullable Map<String, Pair<String, Long>>
                                                      whitelistedDataInfoMap,
                                              boolean bindMountAppsData,
                                              boolean bindMountAppStorageDirs,
                                              @Nullable String[] zygoteArgs) {
    // .......

    try {
        return startViaZygote(processClass, niceName, uid, gid, gids,
                runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,
                packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges,
                pkgDataInfoMap, whitelistedDataInfoMap, bindMountAppsData,
                bindMountAppStorageDirs, zygoteArgs);
    }
    // ...... catch exception log delete
}

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,
                                                  int zygotePolicyFlags,
                                                  boolean isTopApp,
                                                  @Nullable long[] disabledCompatChanges,
                                                  @Nullable Map<String, Pair<String, Long>>
                                                          pkgDataInfoMap,
                                                  @Nullable Map<String, Pair<String, Long>>
                                                          whitelistedDataInfoMap,
                                                  boolean bindMountAppsData,
                                                  boolean bindMountAppStorageDirs,
                                                  @Nullable String[] extraArgs)
                                                  throws ZygoteStartFailedEx {
    // ...... 此处主要是配置所需要启动的Process的参数argsForZygote,此处不做赘述,主要是生成argsForZygote参数
    synchronized(mLock) {
        // The USAP pool can not be used if the application will not use the systems graphics
        // driver.  If that driver is requested use the Zygote application start path.
        // 最终,通过zygoteSendArgsAndGetResult函数来跟zygote通信,此处是如何实现跟zygote通信的呢?
        return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
                                          zygotePolicyFlags,
                                          argsForZygote);
    }
}

通过如上的代码可知,在最终,会通过zygoteSendArgsAndGetResult函数来跟zygote通信的,具体如何通信的,我们需要看下其第一个参数openZygoteSocketIfNeeded(abi)

打开和zygote之间的通信链路

首先先来分析下openZygoteSocketIfNeeded函数是如何打开zygote通信链路的吧

private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
    try {
        // 尝试连接到primary zygote
        attemptConnectionToPrimaryZygote();

        if (primaryZygoteState.matches(abi)) {
            return primaryZygoteState;
        }

        // ......
    }
    // ......
}

// 尝试连接对应的primary zygote socket
@GuardedBy("mLock")
private void attemptConnectionToPrimaryZygote() throws IOException {
    if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
        // socket通信连接
        primaryZygoteState =
                ZygoteState.connect(mZygoteSocketAddress, mUsapPoolSocketAddress);

        maybeSetApiBlacklistExemptions(primaryZygoteState, false);
        maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
    }
}

// mZygoteSocketAddress是一个名称为zygote的socket链接地址
mZygoteSocketAddress = new LocalSocketAddress(Zygote.PRIMARY_SOCKET_NAME, LocalSocketAddress.Namespace.RESERVED);
public static final String PRIMARY_SOCKET_NAME = "zygote";

// 使用mZygoteSocketAddress链接地址连接后返回对应的ZygoteState对象
static ZygoteState connect(@NonNull LocalSocketAddress zygoteSocketAddress,
        @Nullable LocalSocketAddress usapSocketAddress)
        throws IOException {
    // ......
    try {
        // 连接socket服务器
        zygoteSessionSocket.connect(zygoteSocketAddress);
        zygoteInputStream = new DataInputStream(zygoteSessionSocket.getInputStream());
        // 写入和传递socket数据
        zygoteOutputWriter =
                new BufferedWriter(new OutputStreamWriter(zygoteSessionSocket.getOutputStream()), Zygote.SOCKET_BUFFER_SIZE);
    }
    // catch exception中关闭socket通信
    // 初始化ZygoteState对象
    return new ZygoteState(zygoteSocketAddress, usapSocketAddress, zygoteSessionSocket, zygoteInputStream, zygoteOutputWriter, getAbiList(zygoteOutputWriter, zygoteInputStream));
}

此处会跟名称为zygote的一个socket建立连接关系。还记得在zygote启动中分析过,其对应的配置文件中有一个socket的名称就是zygote么?

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    ......
    socket zygote stream 660 root system
    ......

在解析配置文件的过程中,会将这个socket服务端初始化,等待连接

而此处,我们就会作为服务端直接跟zygote服务端进行连接,连接成功后,将能够直接进行通信

通过zygote分裂出对应进程

通过zygoteSendArgsAndGetResult函数

private Process.ProcessStartResult zygoteSendArgsAndGetResult(
        ZygoteState zygoteState, int zygotePolicyFlags, @NonNull ArrayList<String> args)
        throws ZygoteStartFailedEx {
    // ...... 参数判空操作代码省略

    // 参数重定义
    String msgStr = args.size() + "\n" + String.join("\n", args) + "\n";
    // ......功能无关代码省略
    // 继续调用函数
    return attemptZygoteSendArgsAndGetResult(zygoteState, msgStr);
}

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();

        // 获取ZYGOTE进程运行结束后对应的返回结果
        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 exception code delete
}

如上代码,通过对应的参数传递给zygote服务侧,然后从服务端侧获取到对应的运行结果,此处包含对应的初始化进程pid和usingWrapper参数