app启动流程

app启动流程

目录

  • app启动流程源码分析
  • 总结与思考
0.总结

Activity启动流程可以看到11.ActivityTaskSupervisor.startSpecificActivity()1有启动进程的方法,代码如下:

 // frameworks/base/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
final ActivityTaskManagerService mService;
void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
    ...
    final boolean isTop = andResume && r.isTopRunningActivity();
    // knownToBeDead = false,以新启动app为例,isTop = false
    mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
}

启动进程流程图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zZFibSrn-1667230648594)(assets/android/system/App启动流程.png)]​

总结:

整个过程大致可以分为三个阶段,

  • AMS执行过程:生成进程启动相关参数,通过socket通知uds
  • UDS处理过程:android系统启动时,开启以一个socket轮询器,收到AMS的创建进程通知后,通过linux fork()机制创建新的进程,并执行ActivityThread的main方法
  • ActivityThread创建Application过程:创建java层app入口ActivityThread,开启MainLooper,执行Application生命周期相关方法

1.AMS执行过程

1.1.ActivityTaskManagerService.startProcessAsync

通过Handler发送了消息,执行了ActivityManagerInternal::startProcess

// frameworks\base\services\core\java\com\android\server\wm\ActivityTaskManagerService.java
void startProcessAsync(ActivityRecord activity, boolean knownToBeDead, boolean isTop, String hostingType) {
    // Post message to start process to avoid possible deadlock of calling into AMS with theATMS lock held.
   final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::startProcess,
           mAmInternal, activity.processName, activity.info.applicationInfo, knownToBeDead,
           isTop, hostingType, activity.intent.getComponent());
   mH.sendMessage(m);
}

1.2.ActivityManagerService.startProcess

ActivityManagerInternal是一个抽象类,ActivityManagerService内部类LocalService继承了它,调用了startProcessLocked()

// frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
public void startProcess(String processName, ApplicationInfo info, boolean knownToBeDead,
        boolean isTop, String hostingType, ComponentName hostingName) {
    try {
        synchronized (ActivityManagerService.this) {
            // If the process is known as top app, set a hint so when the process is
            // started, the top priority can be applied immediately to avoid cpu being
            // preempted by other processes before attaching the process of top app.
            startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */,
                    new HostingRecord(hostingType, hostingName, isTop),
                    ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE, false /* allowWhileBooting */,
                    false /* isolated */);
        }
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    }
}

1.3.ActivityManagerService.startProcessLocked

调用了ProcessList.startProcessLocked()

// frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
/**
 * Process management.
 */
final ProcessList mProcessList

final ProcessRecord startProcessLocked(String processName,
    ApplicationInfo info, boolean knownToBeDead, int intentFlags,
    HostingRecord hostingRecord, int zygotePolicyFlags, boolean allowWhileBooting,
    boolean isolated) {
    return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
         hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */,
         false /* isSdkSandbox */, 0 /* sdkSandboxClientAppUid */,
         null /* sdkSandboxClientAppPackage */,
         null /* ABI override */, null /* entryPoint */,
         null /* entryPointArgs */, null /* crashHandler */);
}

1.4.ProcessList.startProcessLocked

startProcessLocked()方法有几个重载。前面做了一些检查处理,是否为isolated process、进程是否已启动、系统是否已启动等检查,最后通过Handler post 一个异步任务执行handleProcessStart()。这个方法有一个代码需要注意final String entryPoint = "android.app.ActivityThread"​,即java层app入口为ActivityThread,后面会用到

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-92MOzlSl-1667230648597)(assets/android/system/ProcessList_startProcessLocked.png)]​

// frameworks\base\services\core\java\com\android\server\am\ProcessList.java
ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
        boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord,
        int zygotePolicyFlags, boolean allowWhileBooting, boolean isolated, int isolatedUid,
        boolean isSdkSandbox, int sdkSandboxUid, String sdkSandboxClientAppPackage,
        String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
    long startTime = SystemClock.uptimeMillis();
    ProcessRecord app;
    // 前面一些检查逻辑
    // 判断isolated,是否为isolated process

    // We don't have to do anything more if:
    // (1) There is an existing application record; and
    // (2) The caller doesn't think it is dead, OR there is no thread
    //     object attached to it so we know it couldn't have crashed; and
    // (3) There is a pid assigned to it, so it is either starting or
    //     already running.

    // If the system is not ready yet, then hold off on starting this
    // process until it is.
   
    final boolean success =
            startProcessLocked(app, hostingRecord, zygotePolicyFlags, abiOverride);
    checkSlow(startTime, "startProcess: done starting proc!");
    return success ? app : null;
}

/**
 * @return {@code true} if process start is successful, false otherwise.
 */
boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord,
        int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean disableTestApiChecks,
        String abiOverride) {
    if (app.isPendingStart()) {
        return true;
    }
    if (app.getPid() > 0 && app.getPid() != ActivityManagerService.MY_PID) {
        mService.removePidLocked(app.getPid(), app);
        app.setBindMountPending(false);
        mService.mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
        app.setPid(0);
        app.setStartSeq(0);
    }
    // Clear any residual death recipient link as the ProcessRecord could be reused.
    app.unlinkDeathRecipient();
    app.setDyingPid(0);
    mService.mProcessesOnHold.remove(app);
    mService.updateCpuStats();
    try {
        final int userId = UserHandle.getUserId(app.uid);
        try {
            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;
        // packageMananger 分区挂载处理
        // 进程的一些标志参数处理

        String instructionSet = null;
        if (app.info.primaryCpuAbi != null) {
            // If ABI override is specified, use the isa derived from the value of ABI override.
            // Otherwise, use the isa derived from primary ABI
            instructionSet = VMRuntime.getInstructionSet(requiredAbi);
        }
        app.setGids(gids);
        app.setRequiredAbi(requiredAbi);
        app.setInstructionSet(instructionSet);
        // If this was an external service, the package name and uid in the passed in
        // ApplicationInfo have been changed to match those of the calling package;
        // that will incorrectly apply compat feature overrides for the calling package instead
        // of the defining one.
        ApplicationInfo definingAppInfo;
        if (hostingRecord.getDefiningPackageName() != null) {
            definingAppInfo = new ApplicationInfo(app.info);
            definingAppInfo.packageName = hostingRecord.getDefiningPackageName();
            definingAppInfo.uid = uid;
        } else {
            definingAppInfo = app.info;
        }
        // Start the process.  It will either succeed and return a result containing
        // the PID of the new process, or else throw a RuntimeException.
        final String entryPoint = "android.app.ActivityThread";
        return startProcessLocked(hostingRecord, entryPoint, app, uid, gids,
                runtimeFlags, zygotePolicyFlags, mountExternal, seInfo, requiredAbi,
                instructionSet, invokeWith, startUptime, startElapsedTime);
    } catch (RuntimeException e) {
        ...
        return false;
    }
}

boolean startProcessLocked(HostingRecord hostingRecord, String entryPoint, ProcessRecord app,
        int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags, int mountExternal,
        String seInfo, String requiredAbi, String instructionSet, String invokeWith,
        long startUptime, long startElapsedTime) {
    app.setPendingStart(true);
    app.setRemoved(false);
    synchronized (mProcLock) {
        app.setKilledByAm(false);
        app.setKilled(false);
    }
  
    app.setDisabledCompatChanges(null);
    if (mPlatformCompat != null) {
        app.setDisabledCompatChanges(mPlatformCompat.getDisabledChanges(app.info));
    }
    final long startSeq = ++mProcStartSeqCounter;
    app.setStartSeq(startSeq);
    app.setStartParams(uid, hostingRecord, seInfo, startUptime, startElapsedTime);
    app.setUsingWrapper(invokeWith != null
            || Zygote.getWrapProperty(app.processName) != null);
    mPendingStarts.put(startSeq, app);
    // 默认异步启动
    if (mService.mConstants.FLAG_PROCESS_START_ASYNC) {
        mService.mProcStartHandler.post(() -> handleProcessStart(
                app, entryPoint, gids, runtimeFlags, zygotePolicyFlags, mountExternal,
                requiredAbi, instructionSet, invokeWith, startSeq));
        return true;
    } else {  }
}
1.5.ProcessList.handleProcessStart

调用了startProcess()

// frameworks\base\services\core\java\com\android\server\am\ProcessList.java
/**
 * Main handler routine to start the given process from the ProcStartHandler.
 *
 * <p>Note: this function doesn't hold the global AM lock intentionally.</p>
 */
private void handleProcessStart(final ProcessRecord app, final String entryPoint,
        final int[] gids, final int runtimeFlags, int zygotePolicyFlags,
        final int mountExternal, final String requiredAbi, final String instructionSet,
        final String invokeWith, final long startSeq) {
    final Runnable startRunnable = () -> {
        try {
            final Process.ProcessStartResult startResult = startProcess(app.getHostingRecord(),
                    entryPoint, app, app.getStartUid(), gids, runtimeFlags, zygotePolicyFlags,
                    mountExternal, app.getSeInfo(), requiredAbi, instructionSet, invokeWith,
                    app.getStartTime());
            synchronized (mService) {
                handleProcessStartedLocked(app, startResult, startSeq);
            }
        } catch (RuntimeException e) {
            synchronized (mService) {
                Slog.e(ActivityManagerService.TAG, "Failure starting process "
                        + app.processName, e);
                mPendingStarts.remove(startSeq);
                app.setPendingStart(false);
                mService.forceStopPackageLocked(app.info.packageName,
                        UserHandle.getAppId(app.uid),
                        false, false, true, false, false, app.userId, "start failure");
            }
        }
    };
    // Use local reference since we are not using locks here
    final ProcessRecord predecessor = app.mPredecessor;
    if (predecessor != null && predecessor.getDyingPid() > 0) {
        handleProcessStartWithPredecessor(predecessor, startRunnable);
    } else {
        // Kick off the process start for real.
        startRunnable.run();
    }
}
1.6.ProcessList.startProcess

startProcess()做了sharedUid,APP存储分区挂载等一些检查处理,接下来就是判断进程类型,由谁孵化。可以知道一般情况是由appZygote进行创建进程,appZygote.getProcess()的是ChildZygoteProcess,继承于ZygoteProcess

// frameworks\base\services\core\java\com\android\server\am\ProcessList.java
private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint,
        ProcessRecord app, int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags,
        int mountExternal, String seInfo, String requiredAbi, String instructionSet,
        String invokeWith, long startTime) {
            final Process.ProcessStartResult startResult;
            boolean regularZygote = false;
            if (hostingRecord.usesWebviewZygote()) {
              ...
            } else if (hostingRecord.usesAppZygote()) {
                final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app);
                // We can't isolate app data and storage data as parent zygote already did that.
                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,
                        /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp,
                        app.getDisabledCompatChanges(), pkgDataInfoMap, allowlistedAppDataInfoMap,
                        false, false,
                        new String[]{PROC_START_SEQ_IDENT + app.getStartSeq()});
            } else {
          
            }
            if (!regularZygote) {
                // webview and app zygote don't have the permission to create the nodes
                if (Process.createProcessGroup(uid, startResult.pid) < 0) {
                    throw new AssertionError("Unable to create process group for " + app.processName
                            + " (" + startResult.pid + ")");
                }
            }
            // This runs after Process.start() as this method may block app process starting time
            // if dir is not cached. Running this method after Process.start() can make it
            // cache the dir asynchronously, so zygote can use it without waiting for it.
            if (bindMountAppStorageDirs) {
                storageManagerInternal.prepareStorageDirs(userId, pkgDataInfoMap.keySet(),
                        app.processName);
            }
            return startResult;
}
1.7.ZygoteProcess.start

这个方法参数很多,每个参数含义注释如下,接着的调用了startViaZygote(),这两个方法参数基本相同

// frameworks\base\core\java\android\os\ZygoteProcess.java
/**
 * Start a new process.
 *
 * <p>If processes are enabled, a new process is created and the
 * static main() function of a <var>processClass</var> is executed there.
 * The process will continue running after this function returns.
 *
 * <p>If processes are not enabled, a new thread in the caller's
 * process is created and main() of <var>processclass</var> called there.
 *
 * <p>The niceName parameter, if not an empty string, is a custom name to
 * give to the process instead of using processClass.  This allows you to
 * make easily identifyable processes even if you are using the same base
 * <var>processClass</var> to start them.
 *
 * When invokeWith is not null, the process will be started as a fresh app
 * and not a zygote fork. Note that this is only allowed for uid 0 or when
 * runtimeFlags contains DEBUG_ENABLE_DEBUGGER.
 *
 * @param processClass The class to use as the process's main entry
 *                     point.
 * @param niceName A more readable name to use for the process.
 * @param uid The user-id under which the process will run.
 * @param gid The group-id under which the process will run.
 * @param gids Additional group-ids associated with the process.
 * @param runtimeFlags Additional flags.
 * @param targetSdkVersion The target SDK version for the app.
 * @param seInfo null-ok SELinux information for the new process.
 * @param abi non-null the ABI this app should be started with.
 * @param instructionSet null-ok the instruction set to use.
 * @param appDataDir null-ok the data directory of the app.
 * @param invokeWith null-ok the command to invoke with.
 * @param packageName null-ok the name of the package this process belongs to.
 * @param zygotePolicyFlags Flags used to determine how to launch the application.
 * @param isTopApp Whether the process starts for high priority application.
 * @param disabledCompatChanges null-ok list of disabled compat changes for the process being
 *                             started.
 * @param pkgDataInfoMap Map from related package names to private data directory
 *                       volume UUID and inode number.
 * @param allowlistedDataInfoList Map from allowlisted package names to private data directory
 *                       volume UUID and inode number.
 * @param bindMountAppsData whether zygote needs to mount CE and DE data.
 * @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data.
 *
 * @param zygoteArgs Additional arguments to supply to the Zygote process.
 * @return An object that describes the result of the attempt to start the process.
 * @throws RuntimeException on fatal start failure
 */
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>>
                                                      allowlistedDataInfoList,
                                              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, allowlistedDataInfoList, bindMountAppsData,
                bindMountAppStorageDirs, zygoteArgs);
    } catch (ZygoteStartFailedEx ex) {}
}
1.8.ZygoteProcess.startViaZygote

添加进程启动的各种参数后,调用了zygoteSendArgsAndGetResult

// frameworks\base\core\java\android\os\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,
         int zygotePolicyFlags,
         boolean isTopApp,
         @Nullable long[] disabledCompatChanges,
         @Nullable Map<String, Pair<String, Long>>
                 pkgDataInfoMap,
         @Nullable Map<String, Pair<String, Long>>
                 allowlistedDataInfoList,
         boolean bindMountAppsData,
         boolean bindMountAppStorageDirs,
         @Nullable String[] extraArgs)
         throws ZygoteStartFailedEx {
    ArrayList<String> argsForZygote = new ArrayList<>();
    // --runtime-args, --setuid=, --setgid=,
    // and --setgroups= must go first
    argsForZygote.add("--runtime-args");
    argsForZygote.add("--setuid=" + uid);
    argsForZygote.add("--setgid=" + gid);
    argsForZygote.add("--runtime-flags=" + runtimeFlags);
    // 添加各种参数信息
    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.
        return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
                                          zygotePolicyFlags,
                                          argsForZygote);
	// openZygoteSocketIfNeeded(abi)新建socket
    }
}
1.9.ZygoteProcess.zygoteSendArgsAndGetResult

对上面添加的启动参数做了检查,调用了attemptZygoteSendArgsAndGetResult()

// frameworks\base\core\java\android\os\ZygoteProcess.java 
/**
 * Sends an argument list to the zygote process, which starts a new child
 * and returns the child's pid. Please note: the present implementation
 * replaces newlines in the argument list with spaces.
 *
 * @throws ZygoteStartFailedEx if process start failed for any reason
 */
private Process.ProcessStartResult zygoteSendArgsAndGetResult(
        ZygoteState zygoteState, int zygotePolicyFlags, @NonNull ArrayList<String> args)
        throws ZygoteStartFailedEx {
    // Throw early if any of the arguments are malformed. This means we can
    // avoid writing a partial response to the zygote.
    for (String arg : args) {
        // Making two indexOf calls here is faster than running a manually fused loop due
        // to the fact that indexOf is an optimized intrinsic.
        if (arg.indexOf('\n') >= 0) {
            throw new ZygoteStartFailedEx("Embedded newlines not allowed");
        } else if (arg.indexOf('\r') >= 0) {
            throw new ZygoteStartFailedEx("Embedded carriage returns not allowed");
        }
    }
    /*
     * See com.android.internal.os.ZygoteArguments.parseArgs()
     * Presently the wire format to the zygote process is:
     * a) a count of arguments (argc, in essence)
     * b) a number of newline-separated argument strings equal to count
     *
     * After the zygote process reads these it will write the pid of
     * the child or -1 on failure, followed by boolean to
     * indicate whether a wrapper process was used.
     */
    String msgStr = args.size() + "\n" + String.join("\n", args) + "\n";
    // 是否用非特定的应用程序进程池进行处理,默认不使用
    if (shouldAttemptUsapLaunch(zygotePolicyFlags, args)) {
        try {
            return attemptUsapSendArgsAndGetResult(zygoteState, msgStr);
        } catch (IOException ex) {
            // If there was an IOException using the USAP pool we will log the error and
            // attempt to start the process through the Zygote.
            Log.e(LOG_TAG, "IO Exception while communicating with USAP pool - "
                    + ex.getMessage());
        }
    }
    return attemptZygoteSendArgsAndGetResult(zygoteState, msgStr);
}
1.10.ZygoteProcess.attemptZygoteSendArgsAndGetResult

看到这,发现只进行了数据流的写入和读取,并没有创建进程啊?其实这里使用UDS机制,后面继续深究

// frameworks\base\core\java\android\os\ZygoteProcess.java 
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);
    }
}

2.UDS处理过程

2.1.ZygoteInit.main

采用libcore库,源码中没有,可以通过Android Studio下载Sdk源码中查看。我们知道init.rc脚本中启动了android第一个进程Zygote,从程序入口main函数中可以看出启动了循环器来读取socket数据(zygoteServer.runSelectLoop(abiList))。从注释中可以看出子进程的创建经过ZygoteConnection.handleChildProc,后面可以验证

// frameworks\base\core\java\com\android\internal\os\ZygoteInit.java

/**
 * This is the entry point for a Zygote process.  It creates the Zygote server, loads resources,
 * and handles other tasks related to preparing the process for forking into applications.
 *
 * This process is started with a nice value of -20 (highest priority).  All paths that flow
 * into new processes are required to either set the priority to the default value or terminate
 * before executing any non-system code.  The native side of this occurs in SpecializeCommon,
 * while the Java Language priority is changed in ZygoteInit.handleSystemServerProcess,
 * ZygoteConnection.handleChildProc, and Zygote.childMain.
 *
 * @param argv  Command line arguments used to specify the Zygote's configuration.
 */
@UnsupportedAppUsage
public static void main(String[] argv) {
    ZygoteServer zygoteServer = null;
    ZygoteHooks.startZygoteNoThreadCreation();
    try {
        Zygote.initNativeState(isPrimaryZygote);
        ZygoteHooks.stopZygoteNoThreadCreation();
        zygoteServer = new ZygoteServer(isPrimaryZygote);
        if (startSystemServer) {
            if (r != null) {
                r.run();
                return;
            }
        }
	// 开启循环器
        caller = zygoteServer.runSelectLoop(abiList);
    } catch (Throwable ex) {
        Log.e(TAG, "System zygote died with fatal exception", ex);
        throw ex;
    } finally {
        if (zygoteServer != null) {
            zygoteServer.closeServerSocket();
        }
    }
  
}
2.2.ZygoteServer.runSelectLoop
// frameworks\base\core\java\com\android\internal\os\ZygoteServer.java
/**
 * Runs the zygote process's select loop. Accepts new connections as
 * they happen, and reads commands from connections one spawn-request's
 * worth at a time.
 * @param abiList list of ABIs supported by this zygote.
 */
Runnable runSelectLoop(String abiList) {
    ...
    ArrayList<FileDescriptor> socketFDs = new ArrayList<>();
    ArrayList<ZygoteConnection> peers = new ArrayList<>();
    while (true) {
        ZygoteConnection connection = peers.get(pollIndex);
                        boolean multipleForksOK = !isUsapPoolEnabled()
                                && ZygoteHooks.isIndefiniteThreadSuspensionSafe();
                        final Runnable command =
                                connection.processCommand(this, multipleForksOK);
                        // TODO (chriswailes): Is this extra check necessary?
                        if (mIsForkChild) {
                            // We're in the child. We should always have a command to run at
                            // this stage if processCommand hasn't called "exec".
                            if (command == null) {
                                throw new IllegalStateException("command == null");
                            }
        return command;
    }
   
    ...
}
2.3.ZygoteConnection.processCommand

看到这终于见到了进程的fork(Zygote.forkAndSpecialize)

// frameworks\base\core\java\com\android\internal\os\ZygoteConnection.java
/**
 * Reads a command from the command socket. If a child is successfully forked, a
 * {@code Runnable} that calls the childs main method (or equivalent) is returned in the child
 * process. {@code null} is always returned in the parent process (the zygote).
 * If multipleOK is set, we may keep processing additional fork commands before returning.
 *
 * If the client closes the socket, an {@code EOF} condition is set, which callers can test
 * for by calling {@code ZygoteConnection.isClosedByPeer}.
 */
Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) {
    ZygoteArguments parsedArgs;
    try (ZygoteCommandBuffer argBuffer = new ZygoteCommandBuffer(mSocket)) {
        while (true) {
            ...
            if (parsedArgs.mInvokeWith != null || parsedArgs.mStartChildZygote
                    || !multipleOK || peer.getUid() != Process.SYSTEM_UID) {
                // Continue using old code for now. TODO: Handle these cases in the other path.
                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.mIsTopApp, parsedArgs.mPkgDataInfoList,
                        parsedArgs.mAllowlistedDataInfoList, parsedArgs.mBindMountAppDataDirs,
                        parsedArgs.mBindMountAppStorageDirs);
                try {
                    if (pid == 0) {
                        // in child
                        zygoteServer.setForkChild();
                        zygoteServer.closeServerSocket();
                        IoUtils.closeQuietly(serverPipeFd);
                        serverPipeFd = null;
                        return handleChildProc(parsedArgs, 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, serverPipeFd);
                        return null;
                    }
                } finally {
                    IoUtils.closeQuietly(childPipeFd);
                    IoUtils.closeQuietly(serverPipeFd);
                }
            } else {
                ZygoteHooks.preFork();
                Runnable result = Zygote.forkSimpleApps(argBuffer,
                        zygoteServer.getZygoteSocketFileDescriptor(),
                        peer.getUid(), Zygote.minChildUid(peer), parsedArgs.mNiceName);
                if (result == null) {
                    // parent; we finished some number of forks. Result is Boolean.
                    // We already did the equivalent of handleParentProc().
                    ZygoteHooks.postForkCommon();
                    // argBuffer contains a command not understood by forksimpleApps.
                    continue;
                } else {
                    // child; result is a Runnable.
                    zygoteServer.setForkChild();
                    Zygote.setAppProcessName(parsedArgs, TAG);  // ??? Necessary?
                    return result;
                }
            }
        }
    }
  ...
}
2.4.Zygote.forkAndSpecialize

// frameworks\base\core\java\com\android\internal\os\Zygote.java

// frameworks\base\core\jni\com_android_internal_os_Zygote.cpp

调用了nativeForkAndSpecialize(),最后调用了linux fork(),来创建新的进程。具体的源码,大家可以继续跟踪

2.5.ZygoteConnection.handleChildProc

从上面1.6.ProcessList.startProcess2中,可以知道mInvokeWith默认为null,创建的是新进程isZygote为false

   
// frameworks\base\core\java\com\android\internal\os\ZygoteConnection.java
/**
 * Handles post-fork setup of child proc, closing sockets as appropriate,
 * reopen stdio as appropriate, and ultimately throwing MethodAndArgsCaller
 * if successful or returning if failed.
 *
 * @param parsedArgs non-null; zygote args
 * @param pipeFd null-ok; pipe for communication back to Zygote.
 * @param isZygote whether this new child process is itself a new Zygote.
 */
private Runnable handleChildProc(ZygoteArguments parsedArgs,
        FileDescriptor pipeFd, boolean isZygote) {
    /*
     * By the time we get here, the native code has closed the two actual Zygote
     * socket connections, and substituted /dev/null in their place.  The LocalSocket
     * objects still need to be closed properly.
     */
    closeSocket();
    Zygote.setAppProcessName(parsedArgs, TAG);
    // End of the postFork event.
    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 {
        if (!isZygote) {
            return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
                    parsedArgs.mDisabledCompatChanges,
                    parsedArgs.mRemainingArgs, null /* classLoader */);
        } else {
            return ZygoteInit.childZygoteInit(
                    parsedArgs.mRemainingArgs  /* classLoader */);
        }
    }
}
2.6.ZygoteInit.childZygoteInit

调用了RuntimeInit.findStaticMain()

// frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
/**
 * The main function called when starting a child zygote process. This is used as an alternative
 * to zygoteInit(), which skips calling into initialization routines that start the Binder
 * threadpool.
 */
static Runnable childZygoteInit(String[] argv) {
    RuntimeInit.Arguments args = new RuntimeInit.Arguments(argv);
    return RuntimeInit.findStaticMain(args.startClass, args.startArgs, /* classLoader= */null);
}
2.7.RuntimeInit.findStaticMain

从上面1.4.ProcessList.startProcessLocked3,知道className是ActivityThread, 从下面代码来看,就执行了ActivityThread.main(),转到了我们熟悉的ActivityThread

// frameworks\base\core\java\com\android\internal\os\RuntimeInit.java
/**
 * Invokes a static "main(argv[]) method on class "className".
 * Converts various failing exceptions into RuntimeExceptions, with
 * the assumption that they will then cause the VM instance to exit.
 *
 * @param className Fully-qualified class name
 * @param argv Argument vector for main()
 * @param classLoader the classLoader to load {@className} with
 */
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);
    }
    /*
     * This throw gets caught in ZygoteInit.main(), which responds
     * by invoking the exception's run() method. This arrangement
     * clears up all the stack frames that were required in setting
     * up the process.
     */
    return new MethodAndArgsCaller(m, argv);
}

/**
 * Helper class which holds a method and arguments and can call them. This is used as part of
 * a trampoline to get rid of the initial process setup stack frames.
 */
static class MethodAndArgsCaller implements Runnable {
    /** method to call */
    private final Method mMethod;
    /** argument array */
    private final String[] mArgs;
    public MethodAndArgsCaller(Method method, String[] args) {
        mMethod = method;
        mArgs = args;
    }
    public void run() {
        try {
            mMethod.invoke(null, new Object[] { mArgs });
        } catch (IllegalAccessException ex) {
            throw new RuntimeException(ex);
        } catch (InvocationTargetException ex) {
            Throwable cause = ex.getCause();
            if (cause instanceof RuntimeException) {
                throw (RuntimeException) cause;
            } else if (cause instanceof Error) {
                throw (Error) cause;
            }
            throw new RuntimeException(ex);
        }
    }
}

3.ActivityThread创建Application过程

3.1.ActivityThread.main

ActivityThread是java层app的入口类,main()创建了ActivityThread实例,并开启了MainLooper

// frameworks\base\core\java\android\app\ActivityThread.java
public static void main(String[] args) {
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
    // Install selective syscall interception
    AndroidOs.install();
    // CloseGuard defaults to true and can be quite spammy.  We
    // disable it here, but selectively enable it later (via
    // StrictMode) on debug builds, but using DropBox, not logs.
    CloseGuard.setEnabled(false);
    Environment.initForCurrentUser();
    // Make sure TrustedCertificateStore looks in the right place for CA certificates
    final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
    TrustedCertificateStore.setDefaultUserDirectory(configDir);
    // Call per-process mainline module initialization.
    initializeMainlineModules();
    Process.setArgV0("<pre-initialized>");
    Looper.prepareMainLooper();
    // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
    // It will be in the format "seq=114"
    long startSeq = 0;
    if (args != null) {
        for (int i = args.length - 1; i >= 0; --i) {
            if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                startSeq = Long.parseLong(
                        args[i].substring(PROC_START_SEQ_IDENT.length()));
            }
        }
    }
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);
    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }
    if (false) {
        Looper.myLooper().setMessageLogging(new
                LogPrinter(Log.DEBUG, "ActivityThread"));
    }
    // End of event ActivityThreadMain.
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}
3.2.ActivityThread.attach

创建的app不是系统进程,看else分支即可。这里看到我们熟悉的Instrumentation

// frameworks\base\core\java\android\app\ActivityThread.java
private void attach(boolean system, long startSeq) {
    sCurrentActivityThread = this;
    mConfigurationController = new ConfigurationController(this);
    mSystemThread = system;
    if (!system) {
        android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                UserHandle.myUserId());
        RuntimeInit.setApplicationObject(mAppThread.asBinder());
        final IActivityManager mgr = ActivityManager.getService();
        try {
            mgr.attachApplication(mAppThread, startSeq);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
        // Watch for getting close to heap limit.
        BinderInternal.addGcWatcher(new Runnable() {
            @Override public void run() {
                if (!mSomeActivitiesChanged) {
                    return;
                }
                Runtime runtime = Runtime.getRuntime();
                long dalvikMax = runtime.maxMemory();
                long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
                if (dalvikUsed > ((3*dalvikMax)/4)) {
                    if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
                            + " total=" + (runtime.totalMemory()/1024)
                            + " used=" + (dalvikUsed/1024));
                    mSomeActivitiesChanged = false;
                    try {
                        ActivityTaskManager.getService().releaseSomeActivities(mAppThread);
                    } catch (RemoteException e) {
                        throw e.rethrowFromSystemServer();
                    }
                }
            }
        });
    } else {
        // Don't set application object here -- if the system crashes,
        // we can't display an alert, we just want to die die die.
        android.ddm.DdmHandleAppName.setAppName("system_process",
                UserHandle.myUserId());
        try {
            mInstrumentation = new Instrumentation();
            mInstrumentation.basicInit(this);
            ContextImpl context = ContextImpl.createAppContext(
                    this, getSystemContext().mPackageInfo);
            mInitialApplication = context.mPackageInfo.makeApplicationInner(true, null);
            mInitialApplication.onCreate();
        } catch (Exception e) {
            throw new RuntimeException(
                    "Unable to instantiate Application():" + e.toString(), e);
        }
    }

    ViewRootImpl.ConfigChangedCallback configChangedCallback = (Configuration globalConfig) -> {
        synchronized (mResourcesManager) {
            // We need to apply this change to the resources immediately, because upon returning
            // the view hierarchy will be informed about it.
            if (mResourcesManager.applyConfigurationToResources(globalConfig,
                    null /* compat */)) {
                mConfigurationController.updateLocaleListFromAppContext(
                        mInitialApplication.getApplicationContext());

                // This actually changed the resources! Tell everyone about it.
                final Configuration updatedConfig =
                        mConfigurationController.updatePendingConfiguration(globalConfig);
                if (updatedConfig != null) {
                    sendMessage(H.CONFIGURATION_CHANGED, globalConfig);
                    mPendingConfiguration = updatedConfig;
                }
            }
        }
    };
    ViewRootImpl.addConfigCallback(configChangedCallback);
}
3.3.ActivityManagerService.attachApplication
// frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
public final void attachApplication(IApplicationThread thread, long startSeq) {
    if (thread == null) {
        throw new SecurityException("Invalid application interface");
    }
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
        attachApplicationLocked(thread, callingPid, callingUid, startSeq);
        Binder.restoreCallingIdentity(origId);
    }
}
3.4.ActivityManagerService.attachApplicationLocked
// frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
        int pid, int callingUid, long startSeq) {
    final BackupRecord backupTarget = mBackupTargets.get(app.userId);
    try {
  
        final ProviderInfoList providerList = ProviderInfoList.fromList(providers);
        if (app.getIsolatedEntryPoint() != null) {
            // This is an isolated process which should just call an entry point instead of
            // being bound to an application.
            thread.runIsolatedEntryPoint(
                    app.getIsolatedEntryPoint(), app.getIsolatedEntryPointArgs());
        } else if (instr2 != null) {
            thread.bindApplication(processName, appInfo,
                    app.sdkSandboxClientAppVolumeUuid, app.sdkSandboxClientAppPackage,
                    providerList,
                    instr2.mClass,
                    profilerInfo, instr2.mArguments,
                    instr2.mWatcher,
                    instr2.mUiAutomationConnection, testMode,
                    mBinderTransactionTrackingEnabled, enableTrackAllocation,
                    isRestrictedBackupMode || !normalMode, app.isPersistent(),
                    new Configuration(app.getWindowProcessController().getConfiguration()),
                    app.getCompat(), getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked(),
                    buildSerial, autofillOptions, contentCaptureOptions,
                    app.getDisabledCompatChanges(), serializedSystemFontMap,
                    app.getStartElapsedTime(), app.getStartUptime());
        } else {
            thread.bindApplication(processName, appInfo,
                    app.sdkSandboxClientAppVolumeUuid, app.sdkSandboxClientAppPackage,
                    providerList, null, profilerInfo, null, null, null, testMode,
                    mBinderTransactionTrackingEnabled, enableTrackAllocation,
                    isRestrictedBackupMode || !normalMode, app.isPersistent(),
                    new Configuration(app.getWindowProcessController().getConfiguration()),
                    app.getCompat(), getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked(),
                    buildSerial, autofillOptions, contentCaptureOptions,
                    app.getDisabledCompatChanges(), serializedSystemFontMap,
                    app.getStartElapsedTime(), app.getStartUptime());
        }
    }
   
}
3.5.ApplicationThread.bindApplication

// frameworks\base\core\java\android\app\ActivityThread.java

代码比较简单,通过Handler发送了BIND_APPLICATION消息

3.6.ActivityThread.handleBindApplication
// frameworks\base\core\java\android\app\ActivityThread.java
private void handleBindApplication(AppBindData data) {

    try {
     Application app = data.info.makeApplicationInner(data.restrictedBackupMode, null);
        // don't bring up providers in restricted mode; they may depend on the
        // app's custom Application class
        if (!data.restrictedBackupMode) {
            if (!ArrayUtils.isEmpty(data.providers)) {
                installContentProviders(app, data.providers);
            }
        }

        // Do this after providers, since instrumentation tests generally start their
        // test thread at this point, and we don't want that racing.
        try {
            mInstrumentation.onCreate(data.instrumentationArgs);
        }
   
        try {
            mInstrumentation.callApplicationOnCreate(app);
        }
    } 
}
3.7.LoadedApk.makeApplicationInner

这个方法写入了R文件的值、创建了Application、将Application和Context关联了起来。注意传过来的instrumentation为null

// frameworks\base\core\java\android\app\LoadedApk.java
// allowDuplicateInstances=false
private Application makeApplicationInner(boolean forceDefaultAppClass,
        Instrumentation instrumentation, boolean allowDuplicateInstances) {
  
    Application app = null;
    final String myProcessName = Process.myProcessName();
    String appClass = mApplicationInfo.getCustomApplicationClassNameForProcess(
            myProcessName);
    if (forceDefaultAppClass || (appClass == null)) {
        appClass = "android.app.Application";
    }
    try {
        final java.lang.ClassLoader cl = getClassLoader();
        if (!mPackageName.equals("android")) {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                    "initializeJavaContextClassLoader");
            initializeJavaContextClassLoader();
        }
        // Rewrite the R 'constants' for all library apks.
        SparseArray<String> packageIdentifiers = getAssets().getAssignedPackageIdentifiers(
                false, false);
        for (int i = 0, n = packageIdentifiers.size(); i < n; i++) {
            final int id = packageIdentifiers.keyAt(i);
            if (id == 0x01 || id == 0x7f) {
                continue;
            }
            rewriteRValues(cl, packageIdentifiers.valueAt(i), id);
        }
        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
        // The network security config needs to be aware of multiple
        // applications in the same process to handle discrepancies
        NetworkSecurityConfigProvider.handleNewApplication(appContext);
        app = mActivityThread.mInstrumentation.newApplication(
                cl, appClass, appContext);
        appContext.setOuterContext(app);
    }
    mActivityThread.mAllApplications.add(app);
    mApplication = app;
    if (!allowDuplicateInstances) {
        synchronized (sApplications) {
            sApplications.put(mPackageName, app);
        }
    }
    if (instrumentation != null) {
        try {
            instrumentation.callApplicationOnCreate(app);
        }
    }
    return app;
}
3.8.Instrumentation.newApplication
// aosp\frameworks\base\core\java\android\app\Instrumentation.java
/**
 * Perform instantiation of the process's {@link Application} object.  The
 * default implementation provides the normal system behavior.
 * 
 * @param cl The ClassLoader with which to instantiate the object.
 * @param className The name of the class implementing the Application
 *                  object.
 * @param context The context to initialize the application with
 * 
 * @return The newly instantiated Application object.
 */
public Application newApplication(ClassLoader cl, String className, Context context)
        throws InstantiationException, IllegalAccessException, 
        ClassNotFoundException {
    Application app = getFactory(context.getPackageName())
            .instantiateApplication(cl, className);
    app.attach(context);
    return app;
}
3.9.AppComponentFactory.instantiateApplication

直接反射创建了Application对象

// frameworks\base\core\java\android\app\AppComponentFactory.java
public @NonNull Application instantiateApplication(@NonNull ClassLoader cl,
            @NonNull String className)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return (Application) cl.loadClass(className).newInstance();
}
3.10.Application.attach
// frameworks\base\core\java\android\app\Application.java
final void attach(Context context) {
    attachBaseContext(context);
    mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
3.11.Instrumentation.callApplicationOnCreate
// aosp\frameworks\base\core\java\android\app\Instrumentation.java
public void callApplicationOnCreate(Application app) {
    app.onCreate();
}


  1. 11.ActivityTaskSupervisor.startSpecificActivity()

    如果activity所在的app进程已经启动,则startActivity即可,否则要启动app进程。这里我们分析app进程已经启动的情形

     // frameworks/base/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
    void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
        // Is this activity's application already running?
        final WindowProcessController wpc =
                mService.getProcessController(r.processName, r.info.applicationInfo.uid);
    
        boolean knownToBeDead = false;
        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);
            }
    
            // If a dead object exception was thrown -- fall through to
            // restart the application.
            knownToBeDead = true;
        }
    
        r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
    
        final boolean isTop = andResume && r.isTopRunningActivity();
        mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
    }
    

    ↩︎

  2. 1.6.ProcessList.startProcess
    ↩︎
  3. 1.4.ProcessList.startProcessLocked
    ↩︎
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值