Jimmy Chen

A Programmer

基于Android 9之应用冷启动过程分析(三)之进程创建过程

Advertisements
Advertisements
Advertisements

  上一篇最后分析到:因为我们现在做的假设是应用的冷启动,所以系统中是还没有对应的进程的,需要通过startSpecificActivityLocked方法来创建对应的进程。这一篇我们从这个方法开始

void startSpecificActivityLocked(ActivityRecord r,
        boolean andResume, boolean checkConfig) {
    // 这里再次检查应用进程是否已经启动
    ProcessRecord app = mService.getProcessRecordLocked(r.processName,
            r.info.applicationInfo.uid, true);

    // 如果不为空,代表Activity所在进程已经启动
    if (app != null && app.thread != null) {
        try {
            if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                    || !"android".equals(r.info.packageName)) {
                app.addPackage(r.info.packageName, r.info.applicationInfo.longVersionCode,
                        mService.mProcessStats);
            }
            // 这里会真正的startActivity
            realStartActivityLocked(r, app, andResume, checkConfig);
            return;
        } catch (RemoteException e) {
            Slog.w(TAG, "Exception when starting activity "
                    + r.intent.getComponent().flattenToShortString(), e);
        }
    }
    // 进程不存在,会调用ActivityManagerService的startProcessLocked
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
            "activity", r.intent.getComponent(), false, false, true);
}

上面的过程很简单,在启动Activity所在进程前会再次检查进程是否已经启动,只有确认进程没有启动的情况下才会调用ActivityManagerService的startProcessLocked方法来启动进程。

// 由另一个同名重载函数调进来
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
        boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
        boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
        String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
    long startTime = SystemClock.elapsedRealtime();
    ProcessRecord app;
    if (!isolated) {
        // 这里和前一步一样,还是检查进程是否已经启动了
        app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
        checkTime(startTime, "startProcess: after getProcessRecord");

        .................................
    } else {
        // 是isolated应用
        app = null;
    }

    if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "startProcess: name=" + processName
            + " app=" + app + " knownToBeDead=" + knownToBeDead
            + " thread=" + (app != null ? app.thread : null)
            + " pid=" + (app != null ? app.pid : -1));
    // app不为空,而且app的pid大于零表示已经存在对应的进程了
    if (app != null && app.pid > 0) {
        if ((!knownToBeDead && !app.killed) || app.thread == null) {
            // 有pid表示应用已经加载,但是需要等待线程起来
            if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App already running: " + app);
            app.addPackage(info.packageName, info.versionCode, mProcessStats);
            checkTime(startTime, "startProcess: done, added package to proc");
            return app;
        }
        
        if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_PROCESSES, "App died: " + app);
        checkTime(startTime, "startProcess: bad proc running, killing");
        killProcessGroup(app.uid, app.pid);
        handleAppDiedLocked(app, true, true);
        checkTime(startTime, "startProcess: done killing old proc");
    }

    String hostingNameStr = hostingName != null
            ? hostingName.flattenToShortString() : null;

    // app为空表示进程还没有起来,这里符合我们冷启动的假设
    if (app == null) {
        checkTime(startTime, "startProcess: creating new process record");
        // 创建一个进程Record,这个方法比较简单,下面就不分析了
        app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
        if (app == null) {
            Slog.w(TAG, "Failed making new process record for "
                    + processName + "/" + info.uid + " isolated=" + isolated);
            return null;
        }
        app.crashHandler = crashHandler;
        app.isolatedEntryPoint = entryPoint;
        app.isolatedEntryPointArgs = entryPointArgs;
        checkTime(startTime, "startProcess: done creating new process record");
    } else {
        ............................
    }

    // 如果系统还没有准备好,需要挂起改应用的启动
    if (!mProcessesReady
            && !isAllowedWhileBooting(info)
            && !allowWhileBooting) {
        if (!mProcessesOnHold.contains(app)) {
            mProcessesOnHold.add(app);
        }
        if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES,
                "System not ready, putting on hold: " + app);
        checkTime(startTime, "startProcess: returning with proc on hold");
        return app;
    }

    checkTime(startTime, "startProcess: stepping in to startProcess");
    // 调用startProcessLocked
    final boolean success = startProcessLocked(app, hostingType, hostingNameStr, abiOverride);
    checkTime(startTime, "startProcess: done starting proc!");
    return success ? app : null;
}

最后会调用到startProcessLocked,之后会调用到几个同名的startProcessLocked方法,我们只看最后一个有实质内容的startProcessLocked方法好了。

private final boolean startProcessLocked(ProcessRecord app, String hostingType,
        String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride) 
    // 延迟启动
    if (app.pendingStart) {
        return true;
    }
    long startTime = SystemClock.elapsedRealtime();
    // 对应用的PID进行处理
    if (app.pid > 0 && app.pid != MY_PID) {
        checkTime(startTime, "startProcess: removing from pids map");
        synchronized (mPidsSelfLocked) {
            mPidsSelfLocked.remove(app.pid);
            mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
        }
        checkTime(startTime, "startProcess: done removing from pids map");
        app.setPid(0);
    }

    if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES,
            "startProcessLocked removing on hold: " + app);
    mProcessesOnHold.remove(app);

    checkTime(startTime, "startProcess: starting to update cpu stats");
    updateCpuStats();
    checkTime(startTime, "startProcess: done updating cpu stats");

    try {
        try {
            // 根据应用的uid获取当前userid
            final int userId = UserHandle.getUserId(app.uid);
            AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);
        } catch (RemoteException e) {
            throw e.rethrowAsRuntimeException();
        }

        int uid = app.uid;
        int[] gids = null;
        int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
        if (!app.isolated) {
            int[] permGids = null;
            try {
                // 这里通过PackageManagerService获取应用所归属的组id
                // Linux的组id会映射到框架层的不同权限
                checkTime(startTime, "startProcess: getting gids from package manager");
                final IPackageManager pm = AppGlobals.getPackageManager();
                permGids = pm.getPackageGids(app.info.packageName,
                        MATCH_DEBUG_TRIAGED_MISSING, app.userId);
                StorageManagerInternal storageManagerInternal = LocalServices.getService(
                        StorageManagerInternal.class);
                mountExternal = storageManagerInternal.getExternalStorageMountMode(uid,
                        app.info.packageName);
            } catch (RemoteException e) {
                throw e.rethrowAsRuntimeException();
            }

            // 添加一些共享的权限,例如共享一些共享库和访问一下用户资源
            if (ArrayUtils.isEmpty(permGids)) {
                gids = new int[3];
            } else {
                gids = new int[permGids.length + 3];
                System.arraycopy(permGids, 0, gids, 3, permGids.length);
            }
            gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
            gids[1] = UserHandle.getCacheAppGid(UserHandle.getAppId(uid));
            gids[2] = UserHandle.getUserGid(UserHandle.getUserId(uid));

            // Replace any invalid GIDs
            if (gids[0] == UserHandle.ERR_GID) gids[0] = gids[2];
            if (gids[1] == UserHandle.ERR_GID) gids[1] = gids[2];
        }
        checkTime(startTime, "startProcess: building args");
        if (mFactoryTest != FactoryTest.FACTORY_TEST_OFF) {
            ........................
        }
        int runtimeFlags = 0;
        // 应用是否带有调试标志
        if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
            .......................
        }

        // 应用是否带有安全模式启动的标志或者系统以安全模式启动
        if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 ||
            mSafeMode == true) {
            runtimeFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
        }
        // 省略的内容都是根据app或者系统状态设置一些调试状态位
        .............................
        
        // 判断是否是特权APP,如果是特权APP需要从system分区中加载OAT文件
        // 以确保应用的完整和安全
        if (app.info.isPrivilegedApp() &&
                DexManager.isPackageSelectedToRunOob(app.pkgList.keySet())) {
            runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
        }

        // 对滴啊用Hidden API的处理????
        if (!disableHiddenApiChecks && !mHiddenApiBlacklist.isDisabled()) {
            app.info.maybeUpdateHiddenApiEnforcementPolicy(
                    mHiddenApiBlacklist.getPolicyForPrePApps(),
                    mHiddenApiBlacklist.getPolicyForPApps());
            @HiddenApiEnforcementPolicy int policy =
                    app.info.getHiddenApiEnforcementPolicy();
            int policyBits = (policy << Zygote.API_ENFORCEMENT_POLICY_SHIFT);
            if ((policyBits & Zygote.API_ENFORCEMENT_POLICY_MASK) != policyBits) {
                throw new IllegalStateException("Invalid API policy: " + policy);
            }
            runtimeFlags |= policyBits;
        }

        String invokeWith = null;
        // 可调试的app内部可能会包含一个wrap.sh脚本
        if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
            String wrapperFileName = app.info.nativeLibraryDir + "/wrap.sh";
            StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
            try {
                if (new File(wrapperFileName).exists()) {
                    invokeWith = "/system/bin/logwrapper " + wrapperFileName;
                }
            } finally {
                StrictMode.setThreadPolicy(oldPolicy);
            }
        }

        String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;
        if (requiredAbi == null) {
            requiredAbi = Build.SUPPORTED_ABIS[0];
        }

        String instructionSet = null;
        if (app.info.primaryCpuAbi != null) {
            instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi);
        }

        app.gids = gids;
        app.requiredAbi = requiredAbi;
        app.instructionSet = instructionSet;

        // the per-user SELinux context must be set
        if (TextUtils.isEmpty(app.info.seInfoUser)) {
            Slog.wtf(TAG, "SELinux tag not defined",
                    new IllegalStateException("SELinux tag not defined for "
                    + app.info.packageName + " (uid " + app.uid + ")"));
        }
        final String seInfo = app.info.seInfo
                + (TextUtils.isEmpty(app.info.seInfoUser) ? "" : app.info.seInfoUser);

        // 启动应用的入口类
        final String entryPoint = "android.app.ActivityThread";

        // 调用startProcessLocked启动应用,如果成功会返回启动应用的PID,否则会抛出RuntimeException
        return startProcessLocked(hostingType, hostingNameStr, entryPoint, app, uid, gids,
                runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith,
                startTime);
    } catch (RuntimeException e) {
        Slog.e(TAG, "Failure starting process " + app.processName, e);

        forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid), false,
                false, true, false, false, UserHandle.getUserId(app.userId), "start failure");
        return false;
    }
}

上面的过程比较容易理解,主要是进行一些启动前的处理,紧接着分析startProcessLocked方法

private boolean startProcessLocked(String hostingType, String hostingNameStr, String entryPoint,
        ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
        String seInfo, String requiredAbi, String instructionSet, String invokeWith,
        long startTime) {
    // 设置app的状态
    app.pendingStart = true;
    app.killedByAm = false;
    app.removed = false;
    app.killed = false;
    final long startSeq = app.startSeq = ++mProcStartSeqCounter;
    app.setStartParams(uid, hostingType, hostingNameStr, seInfo, startTime);
    // 同步创建还是异步创建
    if (mConstants.FLAG_PROCESS_START_ASYNC) {
        if (DEBUG_PROCESSES) Slog.i(TAG_PROCESSES,
                "Posting procStart msg for " + app.toShortString());
        mProcStartHandler.post(() -> {
            ........................
                final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint,
                        app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo,
                        requiredAbi, instructionSet, invokeWith, app.startTime);
                synchronized (ActivityManagerService.this) {
                    handleProcessStartedLocked(app, startResult, startSeq);
                }
        ........................
        return true;
    } else {
        try {
            final ProcessStartResult startResult = startProcess(hostingType, entryPoint, app,
                    uid, gids, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet,
                    invokeWith, startTime);
            handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,
                    startSeq, false);
        } catch (RuntimeException e) {
            Slog.e(TAG, "Failure starting process " + app.processName, e);
            app.pendingStart = false;
            forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid),
                    false, false, true, false, false,
                    UserHandle.getUserId(app.userId), "start failure");
        }
        return app.pid > 0;
    }
}

上面具体大的过程中分两种情况:同步还是异步,最终不管同步创建还是异步创建,最后都会调用startProcess进行进程创建。下面我们简单分析一下整个的调用流程,在必要的地方我们再详细分析

private ProcessStartResult startProcess(String hostingType, String entryPoint,
        ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
        String seInfo, String requiredAbi, String instructionSet, String invokeWith,
        long startTime) {
        
            startResult = Process.start(entryPoint,
                    app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                    app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                    app.info.dataDir, invokeWith,
                    new String[] {PROC_START_SEQ_IDENT + app.startSeq});
--------------------------------------------------------------------------------->>>>>>>

public static final ProcessStartResult start(final String processClass,
                              final String niceName,
                              int uid, int gid, int[] gids,
                              int runtimeFlags, int mountExternal,
                              int targetSdkVersion,
                              String seInfo,
                              String abi,
                              String instructionSet,
                              String appDataDir,
                              String invokeWith,
                              String[] zygoteArgs) {
    return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
}

----------------------------------------------------------------------->>>>>>>

public final Process.ProcessStartResult start(final String processClass,
                                              final String niceName,
                                              int uid, int gid, int[] gids,
                                              int runtimeFlags, int mountExternal,
                                              int targetSdkVersion,
                                              String seInfo,
                                              String abi,
                                              String instructionSet,
                                              String appDataDir,
                                              String invokeWith,
                                              String[] zygoteArgs) {
        return startViaZygote(processClass, niceName, uid, gid, gids,
                runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */,
                zygoteArgs);

上面整个的调用过程,最后会调用到startViaZygote,我们都知道进行最后肯定是需要通过zygote通过fork进程来创建的。

private Process.ProcessStartResult startViaZygote(final String processClass,
                                                  final String niceName,
                                                  final int uid, final int gid,
                                                  final int[] gids,
                                                  int runtimeFlags, int mountExternal,
                                                  int targetSdkVersion,
                                                  String seInfo,
                                                  String abi,
                                                  String instructionSet,
                                                  String appDataDir,
                                                  String invokeWith,
                                                  boolean startChildZygote,
                                                  String[] extraArgs)
                                                  throws ZygoteStartFailedEx {
    ArrayList 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");
    }
    argsForZygote.add("--target-sdk-version=" + targetSdkVersion);

    // --setgroups设置应用所属gid组,前面也介绍过
    // Android上层的权限机制映射到底层是通过gid组来实现的
    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);
    }

    // selinux权限设置
    if (seInfo != null) {
        argsForZygote.add("--seinfo=" + seInfo);
    }

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

    // app应用的home目录
    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");
    }

    argsForZygote.add(processClass);

    if (extraArgs != null) {
        for (String arg : extraArgs) {
            argsForZygote.add(arg);
        }
    }

    synchronized(mLock) {
        // 讲构造的启动字串传送到zygote服务
        return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
    }
}

上面是对参数进行解析,然后构造出zygote服务端能够识别的方式,再将构造好的参数发送到zygote服务。最后调用openZygoteSocketIfNeeded就是为应用的abi找到合适的zygote服务,因为从Android 5.0之后,Android支持64位系统了,需要通过应用的abi寻找合适的zygote服务。下面分析openZygoteSocketIfNeeded方法

private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
    Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");

    // 判断主zygote是否启动,主zygote在64位系统是zygote64,32位系统就只有zygote了
    if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
        try {
            primaryZygoteState = ZygoteState.connect(mSocket);
        } catch (IOException ioe) {
            throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
        }
        // 向zygote中设置Api黑名单
        maybeSetApiBlacklistExemptions(primaryZygoteState, false);
        maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
    }
    if (primaryZygoteState.matches(abi)) {
        return primaryZygoteState;
    }

    // 如果主zygote不匹配的话,尝试使用次zygote
    if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
        try {
            // 通过connect连接到zygote
            secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
        } catch (IOException ioe) {
            throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
        }
        maybeSetApiBlacklistExemptions(secondaryZygoteState, false);
        maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
    }

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

    throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
}

openZygoteSocketIfNeeded的内容比较简单,主要是为改应用寻找合适的zygote去执行。另外要提一下的是,上面还设置了API黑名单,目前猜测可能是有一些API已经不能被反射调用了,具体情况还需要后续做深入分析。这里我们先接着前一步进行分析,openZygoteSocketIfNeeded已经找到合适的zygote了,那么接着就是zygoteSendArgsAndGetResult调用了。

private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
        ZygoteState zygoteState, ArrayList args)
        throws ZygoteStartFailedEx {
    try {
        // 首先分析传进来的参数,如果有恶意的参数,直接跑出异常,停止执行
        int sz = args.size();
        for (int i = 0; i < sz; i++) {
            if (args.get(i).indexOf('\n') >= 0) {
                throw new ZygoteStartFailedEx("embedded newlines not allowed");
            }
        }

        // 对参数进行解析,目前写到zygote服务的格式是:
        // 1. 首先讲参数的个数写到对端
        // 2. 然后讲参数一行一行的写到对端,需要换行符分割每个参数
        // 如果zygote读取参数并执行成功,会将新进程pid写回给请求端
        final BufferedWriter writer = zygoteState.writer;
        final DataInputStream inputStream = zygoteState.inputStream;

        writer.write(Integer.toString(args.size()));
        writer.newLine();

        for (int i = 0; i < sz; i++) {
            String arg = args.get(i);
            writer.write(arg);
            writer.newLine();
        }

        writer.flush();

        Process.ProcessStartResult result = new Process.ProcessStartResult();

        // 读取对端返回的结果
        result.pid = inputStream.readInt();
        result.usingWrapper = inputStream.readBoolean();

        if (result.pid < 0) {
            throw new ZygoteStartFailedEx("fork() failed");
        }
        return result;
    } catch (IOException ex) {
        zygoteState.close();
        throw new ZygoteStartFailedEx(ex);
    }
}

这上面都只是在准备一些数据,然后传送给zygote,但是没有看到和zygote是如何连接的。其实zygote连接的过程还是在openZygoteSocketIfNeeded方法里面完成的,这里的连接过程就是一个文件socket的创建过程一样,所以这里就不细说了,有兴趣的同学可以openZygoteSocketIfNeeded方法里面primaryZygoteState = ZygoteState.connect(mSocket);这行代码就行。

zygote处理

如果上面的内容没问题,那么现在已经连接到zygote去了。我们在分析zygote的时候有提到,zygote会在他的main方法中等待请求的到来,具体如下:

public static void main(String argv[]) {
    ZygoteServer zygoteServer = new ZygoteServer();

    // 创建zygote
    ZygoteHooks.startZygoteNoThreadCreation();

    .........................

    // 预加载资源
    if (!enableLazyPreload) {
        bootTimingsTraceLog.traceBegin("ZygotePreload");
        EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
            SystemClock.uptimeMillis());
        preload(bootTimingsTraceLog);
        EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
            SystemClock.uptimeMillis());
        bootTimingsTraceLog.traceEnd(); // ZygotePreload
    } else {
        Zygote.resetNicePriority();
    }

    ..........................

    // 启动systemServer进程
    if (startSystemServer) {
        Runnable r = forkSystemServer(abiList, socketName, zygoteServer);

        // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
        // child (system_server) process.
        if (r != null) {
            r.run();
            return;
        }
    }

    // runSelectLoop方法就和我们这的关系比较大了。等待客户端连接
    caller = zygoteServer.runSelectLoop(abiList);
    } catch (Throwable ex) {
        Log.e(TAG, "System zygote died with exception", ex);
        throw ex;
    } finally {
        zygoteServer.closeServerSocket();
    }
}

所以zygote的具体处理的事情都是在runSelectLoop里面完成。我们下面来看看,一些不相干代码就省略了。

Runnable runSelectLoop(String abiList) {
    .........................
    // 一个死循环处理
    while (true) {
        // 通过pull方式处理连接
        StructPollfd[] pollFds = new StructPollfd[fds.size()];
        for (int i = 0; i < pollFds.length; ++i) {
            pollFds[i] = new StructPollfd();
            pollFds[i].fd = fds.get(i);
            pollFds[i].events = (short) POLLIN;
        }
        try {
            Os.poll(pollFds, -1);
        } catch (ErrnoException ex) {
            throw new RuntimeException("poll failed", ex);
        }
        for (int i = pollFds.length - 1; i >= 0; --i) {
            // 有新的连接到来
            if (i == 0) {
            ......................
            } else {
                try {
                    // 获取客户端发送过来的事件
                    ZygoteConnection connection = peers.get(i);
                    // 处理事件
                    final Runnable command = connection.processOneCommand(this);
                    .......................
    }
}

上面可以看出,具体处理客户端请求的代码都运行在processOneCommand方法里面。我们来看看这个方法是怎么处理的

Runnable processOneCommand(ZygoteServer zygoteServer) {
    String args[];
    Arguments parsedArgs = null;
    FileDescriptor[] descriptors;

    try {
        // 读取参数
        args = readArgumentList();
        descriptors = mSocket.getAncillaryFileDescriptors();
    } catch (IOException ex) {
        throw new IllegalStateException("IOException on command socket", ex);
    }

    if (args == null) {
        isEof = true;
        return null;
    }

    int pid = -1;
    FileDescriptor childPipeFd = null;
    FileDescriptor serverPipeFd = null;

    // 创建一个Arguments对象,之后一大段代码都是在对相应的参数进行处理
    parsedArgs = new Arguments(args);

    if (parsedArgs.abiListQuery) {
        handleAbiListQuery();
        return null;
    }

    if (parsedArgs.preloadDefault) {
        handlePreload();
        return null;
    }
    // 下面的代码类似上面的处理过程,略过
    .................................

    // 处理zygote中打开的端口,以避免传递到子进程导致内存泄露
    int [] fdsToClose = { -1, -1 };

    FileDescriptor fd = mSocket.getFileDescriptor();

    if (fd != null) {
        fdsToClose[0] = fd.getInt$();
    }

    fd = zygoteServer.getServerSocketFileDescriptor();

    if (fd != null) {
        fdsToClose[1] = fd.getInt$();
    }

    fd = null;

    // 调用forkAndSpecialize创建子进程
    pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
            parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
            parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
            parsedArgs.instructionSet, parsedArgs.appDataDir);

    try {
        // pid == 0 表示子进程
        if (pid == 0) {
            zygoteServer.setForkChild();

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

            // 子进程进行具体的事务处理
            return handleChildProc(parsedArgs, descriptors, childPipeFd,
                    parsedArgs.startChildZygote);
        } 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);
    }
}

上面的代码处理过后就非常简单了,先对参数进行处理之后就是通过forkAndSpecialize创建进程,而forkAndSpecialize最后会通过JNI调用到底层去,通过Linux的fork方法产生子进程,然后父子进程在分别完成不同的任务。forkAndSpecialize的内容比较简单,这里就不分析了,我们接着看子进程具体处理那些事务

private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
        FileDescriptor pipeFd, boolean isZygote) {
    
    // 关闭一些不使用的文件描述符和socket端口
    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.niceName != null) {
        Process.setArgV0(parsedArgs.niceName);
    }

    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    // 理论上不会走这里,不然就跑出异常终止运行了
    if (parsedArgs.invokeWith != null) {
        WrapperInit.execApplication(parsedArgs.invokeWith,
                parsedArgs.niceName, parsedArgs.targetSdkVersion,
                VMRuntime.getCurrentInstructionSet(),
                pipeFd, parsedArgs.remainingArgs);

        // Should not get here.
        throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
    } else {
        if (!isZygote) {
            // 普通的应用最后调用zygoteInit方法,下面接着分析
            return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
                    null /* classLoader */);
        } else {
            return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
                    parsedArgs.remainingArgs, null /* classLoader */);
        }
    }
}

public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
    if (RuntimeInit.DEBUG) {
        Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
    }

    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
    // 重定位log输出,没什么好说的
    RuntimeInit.redirectLogStreams();

    // Android运行时初始化
    RuntimeInit.commonInit();
    // 这里也是通过JNI调用,看样子是做一些底层的初始化,这里也不分析
    ZygoteInit.nativeZygoteInit();
    // 最后通过Android运行时创建application对象,下面接着分析
    return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}

protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
        ClassLoader classLoader) {
    // 如果应用调用了System.exit(),在这里需要做一些处理
    nativeSetExitWithoutCleanup(true);

    // 设置栈和targetSDK版本
    VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
    VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

    final Arguments args = new Arguments(argv);

    // The end of of the RuntimeInit event (see #zygoteInit).
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

    // 最最最重要的还是这个方法
    return findStaticMain(args.startClass, args.startArgs, classLoader);
}

上面的方法进过一连串的调用、处理后,最后会调用到findStaticMain方法,findStaticMain才是最最最关键的,因为这里是具体执行之前传经来的方法的main方法的地方。

protected static Runnable findStaticMain(String className, String[] argv,
        ClassLoader classLoader) {
    Class cl;

    try {
        // 获取具体执行的类名,这里查看本篇前面的内容可以知道
        // 这里传进来的类名是:android.app.ActivityThread
        cl = Class.forName(className, true, classLoader);
    } catch (ClassNotFoundException ex) {
        throw new RuntimeException(
                "Missing class when invoking static main " + className,
                ex);
    }

    Method m;
    try {
        // 获取ActivityThread的main方法
        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);
    }

     // 调用ActivityThread的main方法并返回
    return new MethodAndArgsCaller(m, argv);
}

这最后是通过反射的方法调用到android.app.ActivityThread的main方法,之后都会在android.app.ActivityThread中执行,具体内容我们下一篇再进行分析,这一篇我们就到这里了。

Advertisements
Advertisements
Advertisements

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据

%d 博主赞过: