Android 应用启动流程

431 阅读8分钟

1. 点击启动
LauncherActivity.java -> onListItemClick
构造一个Intent
Intent intent = intentForPosition(position);
startActivity(intent)
实际启动
android.support.v4.app.ActivityCompat#startActivityForResult Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options); 交给Instrumentation
android.app.Instrumentation#execStartActivity(android.content.Context, android.os.IBinder, android.os.IBinder, android.app.Activity, android.content.Intent, int, android.os.Bundle) // Binder 调用 ATM 来启动 Activity int result = ActivityTaskManager.getService() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);

2. ATM\AMS 进行Activity的处理
通过binder 调用到ATM 的 startActivity ActivityTaskManagerService.java#startActivity()
--> startActivityAsUser

```
private int startActivityAsUser(IApplicationThread caller, String callingPackage,
        @Nullable String callingFeatureId, Intent intent, String resolvedType,
        IBinder resultTo, String resultWho, int requestCode, int startFlags,
        ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
    assertPackageMatchesCallingUid(callingPackage);
    enforceNotIsolatedCaller("startActivityAsUser");

    userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
            Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");

//获取 ActivityStarter 对象,最终调用ActivityStarter的execute()
      PS:getActivityStartController 拿到的是controller   而 .obtainStarter方法构造出ActivityStarter
    int res = getActivityStartController().obtainStarter(intent, "startActivityAsUser")
            .setCaller(caller)
            .setCallingPackage(callingPackage)
            .setCallingFeatureId(callingFeatureId)
            .setResolvedType(resolvedType)
            .setResultTo(resultTo)
            .setResultWho(resultWho)
            .setRequestCode(requestCode)
            .setStartFlags(startFlags)
            .setProfilerInfo(profilerInfo)
            .setActivityOptions(bOptions)
            .setUserId(userId)
            .execute();
    return res;
}
```
  
下来看execute()\
ActivityStarter.java#***execute()***
```
int execute() {
    try {
        ...
        final LaunchingState launchingState;
        synchronized (mService.mGlobalLock) {
            final ActivityRecord caller = ActivityRecord.forTokenLocked(mRequest.resultTo);
            final int callingUid = mRequest.realCallingUid == Request.DEFAULT_REAL_CALLING_UID
                    ?  Binder.getCallingUid() : mRequest.realCallingUid;
            launchingState = mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(
                    mRequest.intent, caller, callingUid);
        }
        
        ...

        int res;
        synchronized (mService.mGlobalLock) {
            final boolean globalConfigWillChange = mRequest.globalConfig != null
                    && mService.getGlobalConfiguration().diff(mRequest.globalConfig) != 0;
            final Task rootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
            if (rootTask != null) {
                rootTask.mConfigWillChange = globalConfigWillChange;
            }
            ProtoLog.v(WM_DEBUG_CONFIGURATION, "Starting activity when config "
                    + "will change = %b", globalConfigWillChange);

            final long origId = Binder.clearCallingIdentity();

            res = resolveToHeavyWeightSwitcherIfNeeded();
            if (res != START_SUCCESS) {
                return res;
            }
            res = executeRequest(mRequest);

            Binder.restoreCallingIdentity(origId);

            if (globalConfigWillChange) {
                // If the caller also wants to switch to a new configuration, do so now.
                // This allows a clean switch, as we are waiting for the current activity
                // to pause (so we will not destroy it), and have not yet started the
                // next activity.
                mService.mAmInternal.enforceCallingPermission(
                        android.Manifest.permission.CHANGE_CONFIGURATION,
                        "updateConfiguration()");
                if (rootTask != null) {
                    rootTask.mConfigWillChange = false;
                }
                ProtoLog.v(WM_DEBUG_CONFIGURATION,
                            "Updating to new configuration after starting activity.");

                mService.updateConfigurationLocked(mRequest.globalConfig, null, false);
            }

            // The original options may have additional info about metrics. The mOptions is not
            // used here because it may be cleared in setTargetRootTaskIfNeeded.
            final ActivityOptions originalOptions = mRequest.activityOptions != null
                    ? mRequest.activityOptions.getOriginalOptions() : null;
            // If the new record is the one that started, a new activity has created.
            final boolean newActivityCreated = mStartActivity == mLastStartActivityRecord;
            // Notify ActivityMetricsLogger that the activity has launched.
            // ActivityMetricsLogger will then wait for the windows to be drawn and populate
            // WaitResult.
            //通知ActivityMetricsLogger,activity已经被启动起来\
            //ActivityMetricsLogger 将等待windows被绘制出来\
            mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, res,
                    newActivityCreated, mLastStartActivityRecord, originalOptions);
            if (mRequest.waitResult != null) {
                mRequest.waitResult.result = res;
                res = waitResultIfNeeded(mRequest.waitResult, mLastStartActivityRecord,
                        launchingState);
            }
            return getExternalResult(res);
        }
    } finally {
        onExecutionComplete();
    }
}
```
***executeRequest***(mRequest);
```
/**
 * Executing activity start request and starts the journey of starting an activity. Here
 * begins with performing several preliminary checks. The normally activity launch flow will
 * go through {@link #startActivityUnchecked} to {@link #startActivityInner}.
 */
private int executeRequest(Request request) {
    ...
    final ActivityRecord r = new ActivityRecord.Builder(mService)
            .setCaller(callerApp)
            .setLaunchedFromPid(callingPid)
            .setLaunchedFromUid(callingUid)
            .setLaunchedFromPackage(callingPackage)
            .setLaunchedFromFeature(callingFeatureId)
            .setIntent(intent)
            .setResolvedType(resolvedType)
            .setActivityInfo(aInfo)
            .setConfiguration(mService.getGlobalConfiguration())
            .setResultTo(resultRecord)
            .setResultWho(resultWho)
            .setRequestCode(requestCode)
            .setComponentSpecified(request.componentSpecified)
            .setRootVoiceInteraction(voiceSession != null)
            .setActivityOptions(checkedOptions)
            .setSourceRecord(sourceRecord)
            .build();

    mLastStartActivityRecord = r;
  

    if (r.appTimeTracker == null && sourceRecord != null) {
        // If the caller didn't specify an explicit time tracker, we want to continue
        // tracking under any it has.
        r.appTimeTracker = sourceRecord.appTimeTracker;
    }

    // Only allow app switching to be resumed if activity is not a restricted background
    // activity and target app is not home process, otherwise any background activity
    // started in background task can stop home button protection mode.
    // As the targeted app is not a home process and we don't need to wait for the 2nd
    // activity to be started to resume app switching, we can just enable app switching
    // directly.
    WindowProcessController homeProcess = mService.mHomeProcess;
    boolean isHomeProcess = homeProcess != null
            && aInfo.applicationInfo.uid == homeProcess.mUid;
    if (!restrictedBgActivity && !isHomeProcess) {
        mService.resumeAppSwitches();
    }

    mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
            request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask,
            restrictedBgActivity, intentGrants);

    if (request.outActivity != null) {
        request.outActivity[0] = mLastStartActivityRecord;
    }

    return mLastStartActivityResult;
}
```
然后通过***startActivityUnchecked() startActivityInner()***来处理启动标记 flag ,要启动的任务栈等,最后恢复布局\
```
/**
 * Start an activity while most of preliminary checks has been done and caller has been
 * confirmed that holds necessary permissions to do so.
 * Here also ensures that the starting activity is removed if the start wasn't successful.
 */
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, Task inTask,
            boolean restrictedBgActivity, NeededUriGrants intentGrants) {
    int result = START_CANCELED;
    final Task startedActivityRootTask;

    // Create a transition now to record the original intent of actions taken within
    // startActivityInner. Otherwise, logic in startActivityInner could start a different
    // transition based on a sub-action.
    // Only do the create here (and defer requestStart) since startActivityInner might abort.
    final Transition newTransition = (!mService.getTransitionController().isCollecting()
            && mService.getTransitionController().getTransitionPlayer() != null)
            ? mService.getTransitionController().createTransition(TRANSIT_OPEN) : null;
    IRemoteTransition remoteTransition = r.takeRemoteTransition();
    if (newTransition != null && remoteTransition != null) {
        newTransition.setRemoteTransition(remoteTransition);
    }
    mService.getTransitionController().collect(r);
    try {
        mService.deferWindowLayout();
        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
        result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
                startFlags, doResume, options, inTask, restrictedBgActivity, intentGrants);
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
        startedActivityRootTask = handleStartResult(r, result);
        mService.continueWindowLayout();
        mSupervisor.mUserLeaving = false;

        // Transition housekeeping
        if (!ActivityManager.isStartResultSuccessful(result)) {
            if (newTransition != null) {
                newTransition.abort();
            }
        } else {
            if (!mAvoidMoveToFront && mDoResume
                    && mRootWindowContainer.hasVisibleWindowAboveButDoesNotOwnNotificationShade(
                        r.launchedFromUid)) {
                // If the UID launching the activity has a visible window on top of the
                // notification shade and it's launching an activity that's going to be at the
                // front, we should move the shade out of the way so the user can see it.
                // We want to avoid the case where the activity is launched on top of a
                // background task which is not moved to the front.
                StatusBarManagerInternal statusBar = mService.getStatusBarManagerInternal();
                if (statusBar != null) {
                    // This results in a async call since the interface is one-way
                    statusBar.collapsePanels();
                }
            }
            if (result == START_SUCCESS || result == START_TASK_TO_FRONT) {
                // The activity is started new rather than just brought forward, so record
                // it as an existence change.
                mService.getTransitionController().collectExistenceChange(r);
            }
            if (newTransition != null) {
                mService.getTransitionController().requestStartTransition(newTransition,
                        mTargetTask, remoteTransition);
            } else {
                // Make the collecting transition wait until this request is ready.
                mService.getTransitionController().setReady(false);
            }
        }
    }

    postStartActivityProcessing(r, result, startedActivityRootTask);

    return result;
}
```
```
int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, boolean doResume, ActivityOptions options, Task inTask,
        boolean restrictedBgActivity, NeededUriGrants intentGrants) {

    ....巨长...
    computeLaunchingTaskFlags();

    computeSourceRootTask();

    mIntent.setFlags(mLaunchFlags);


    // Compute if there is an existing task that should be used for.
    final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();
    final boolean newTask = targetTask == null;
    mTargetTask = targetTask;

    computeLaunchParams(r, sourceRecord, targetTask);


    if (newTask) {
        EventLogTags.writeWmCreateTask(mStartActivity.mUserId,
                mStartActivity.getTask().mTaskId);
    }
    mStartActivity.logStartActivity(
            EventLogTags.WM_CREATE_ACTIVITY, mStartActivity.getTask());

    mTargetRootTask.mLastPausedActivity = null;

    mRootWindowContainer.startPowerModeLaunchIfNeeded(
            false /* forceSend */, mStartActivity);


    mTargetRootTask.startActivityLocked(mStartActivity,
            topRootTask != null ? topRootTask.getTopNonFinishingActivity() : null, newTask,
            mKeepCurTransition, mOptions, sourceRecord);

    if (mDoResume) {
        final ActivityRecord topTaskActivity =
                mStartActivity.getTask().topRunningActivityLocked();
        if (!mTargetRootTask.isTopActivityFocusable()
                || (topTaskActivity != null && topTaskActivity.isTaskOverlay()
                && mStartActivity != topTaskActivity)) {
            // If the activity is not focusable, we can't resume it, but still would like to
            // make sure it becomes visible as it starts (this will also trigger entry
            // animation). An example of this are PIP activities.
            // Also, we don't want to resume activities in a task that currently has an overlay
            // as the starting activity just needs to be in the visible paused state until the
            // over is removed.
            // Passing {@code null} as the start parameter ensures all activities are made
            // visible.
            mTargetRootTask.ensureActivitiesVisible(null /* starting */,
                    0 /* configChanges */, !PRESERVE_WINDOWS);
            // Go ahead and tell window manager to execute app transition for this activity
            // since the app transition will not be triggered through the resume channel.
            mTargetRootTask.mDisplayContent.executeAppTransition();
        } else {
            // If the target root-task was not previously focusable (previous top running
            // activity on that root-task was not visible) then any prior calls to move the
            // root-task to the will not update the focused root-task.  If starting the new
            // activity now allows the task root-task to be focusable, then ensure that we
            // now update the focused root-task accordingly.
            if (mTargetRootTask.isTopActivityFocusable()
                    && !mRootWindowContainer.isTopDisplayFocusedRootTask(mTargetRootTask)) {
                mTargetRootTask.moveToFront("startActivityInner");
            }
            mRootWindowContainer.resumeFocusedTasksTopActivities(
                    mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);
        }
    }
    mRootWindowContainer.updateUserRootTask(mStartActivity.mUserId, mTargetRootTask);

    // Update the recent tasks list immediately when the activity starts
    mSupervisor.mRecentTasks.add(mStartActivity.getTask());
    mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(),
            mPreferredWindowingMode, mPreferredTaskDisplayArea, mTargetRootTask);

    return START_SUCCESS;
}
```

其中 mRootWindowContainer.resumeFocusedTasksTopActivities( mTargetRootTask, mStartActivity, mOptions, mTransientLaunch); 下来会调用 com.android.server.wm.Task#resumeTopActivityUncheckedLocked(ActivityRecord, ActivityOptions, boolean)
---->
com.android.server.wm.Task#resumeTopActivityInnerLocked
太长了,其中有一行

// If we are currently pausing an activity, then don't do anything until that is done.
final boolean allPausedComplete = mRootWindowContainer.allPausedActivitiesComplete();
if (!allPausedComplete) {
    ProtoLog.v(WM_DEBUG_STATES,
            "resumeTopActivityLocked: Skip resume: some activity pausing.");

    return false;
}

可以看出要等前面都pause了才能进行下面的
接下来--->\

mTaskSupervisor.startSpecificActivity(next, true, false);
or
mTaskSupervisor.startSpecificActivity(next, true, true);

下来就是比较重要的了startSpecificActivity发布消息以启动进程,以避免在ATM锁保持的情况下调用
AMS时可能出现死锁,最终调用到ATM的startProcess()

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");
}

com.android.server.wm.ActivityTaskManagerService#startProcessAsync

void startProcessAsync(ActivityRecord activity, boolean knownToBeDead, boolean isTop,
        String hostingType) {
    try {
        if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "dispatchingStartProcess:"
                    + activity.processName);
        }
        // Post message to start process to avoid possible deadlock of calling into AMS with the
        // ATMS lock held.
        发布消息以启动进程,以避免在ATM锁保持的情况下调用\
AMS时可能出现死锁\
        final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::startProcess,
                mAmInternal, activity.processName, activity.info.applicationInfo, knownToBeDead,
                isTop, hostingType, activity.intent.getComponent());
        mH.sendMessage(m);
    } finally {
        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
    }
}

com.android.server.am.ActivityManagerService.LocalService#startProcess(String, ApplicationInfo, boolean, boolean, String, ComponentName, String) ---> com.android.server.am.ActivityManagerService#startProcessLocked

return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
        hostingRecord, zygotePolicyFlags, allowWhileBooting, isolated, 0 /* isolatedUid */,
        null /* ABI override */, null /* entryPoint */,
        //null /* entryPointArgs */, null /* crashHandler */);
        null /* entryPointArgs */, null /* crashHandler */, callerPackage);

---> com.android.server.am.ProcessList#startProcessLocked(HostingRecord, String, ProcessRecord, int, int[], int, int, int, String, String, String, String, long)

if (mService.mConstants.FLAG_PROCESS_START_ASYNC) {
    if (DEBUG_PROCESSES) Slog.i(TAG_PROCESSES,
            "Posting procStart msg for " + app.toShortString());
    mService.mProcStartHandler.post(() -> handleProcessStart(
            app, entryPoint, gids, runtimeFlags, zygotePolicyFlags, mountExternal,
            requiredAbi, instructionSet, invokeWith, startSeq));
    return true;
} else {
    try {
        final Process.ProcessStartResult startResult = startProcess(hostingRecord,
                entryPoint, app,
                uid, gids, runtimeFlags, zygotePolicyFlags, mountExternal, seInfo,
                requiredAbi, instructionSet, invokeWith, startTime);
        handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,
                startSeq, false);
    } catch (RuntimeException e) {
        Slog.e(ActivityManagerService.TAG, "Failure starting process "
                + app.processName, e);
        app.setPendingStart(false);
        mService.forceStopPackageLocked(app.info.packageName, UserHandle.getAppId(app.uid),
                false, false, true, false, false, app.userId, "start failure");
    }
    return app.getPid() > 0;
}

com.android.server.am.ProcessList#startProcess

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) {
    try {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                app.processName);
        checkSlow(startTime, "startProcess: asking zygote to start proc");
        final boolean isTopApp = hostingRecord.isTopApp();
        if (isTopApp) {
            // Use has-foreground-activities as a temporary hint so the current scheduling
            // group won't be lost when the process is attaching. The actual state will be
            // refreshed when computing oom-adj.
            app.mState.setHasForegroundActivities(true);
        }

        Map<String, Pair<String, Long>> pkgDataInfoMap;
        Map<String, Pair<String, Long>> allowlistedAppDataInfoMap;
        boolean bindMountAppStorageDirs = false;
        boolean bindMountAppsData = mAppDataIsolationEnabled
                && (UserHandle.isApp(app.uid) || UserHandle.isIsolated(app.uid))
                && mPlatformCompat.isChangeEnabled(APP_DATA_DIRECTORY_ISOLATION, app.info);

        // Get all packages belongs to the same shared uid. sharedPackages is empty array
        // if it doesn't have shared uid.
        final PackageManagerInternal pmInt = mService.getPackageManagerInternal();
        final String[] sharedPackages = pmInt.getSharedUserPackagesForPackage(
                app.info.packageName, app.userId);
        final String[] targetPackagesList = sharedPackages.length == 0
                ? new String[]{app.info.packageName} : sharedPackages;

        pkgDataInfoMap = getPackageAppDataInfoMap(pmInt, targetPackagesList, uid);
        if (pkgDataInfoMap == null) {
            // TODO(b/152760674): Handle inode == 0 case properly, now we just give it a
            // tmp free pass.
            bindMountAppsData = false;
        }

        // Remove all packages in pkgDataInfoMap from mAppDataIsolationAllowlistedApps, so
        // it won't be mounted twice.
        final Set<String> allowlistedApps = new ArraySet<>(mAppDataIsolationAllowlistedApps);
        for (String pkg : targetPackagesList) {
            allowlistedApps.remove(pkg);
        }

        allowlistedAppDataInfoMap = getPackageAppDataInfoMap(pmInt,
                allowlistedApps.toArray(new String[0]), uid);
        if (allowlistedAppDataInfoMap == null) {
            // TODO(b/152760674): Handle inode == 0 case properly, now we just give it a
            // tmp free pass.
            bindMountAppsData = false;
        }

        int userId = UserHandle.getUserId(uid);
        StorageManagerInternal storageManagerInternal = LocalServices.getService(
                StorageManagerInternal.class);
        if (needsStorageDataIsolation(storageManagerInternal, app)) {
            // We will run prepareStorageDirs() after we trigger zygote fork, so it won't
            // slow down app starting speed as those dirs might not be cached.
            if (pkgDataInfoMap != null && storageManagerInternal.isFuseMounted(userId)) {
                bindMountAppStorageDirs = true;
            } else {
                // Fuse is not mounted or inode == 0,
                // so we won't mount it in zygote, but resume the mount after unlocking device.
                app.setBindMountPending(true);
                bindMountAppStorageDirs = false;
            }
        }

        // If it's an isolated process, it should not even mount its own app data directories,
        // since it has no access to them anyway.
        if (app.isolated) {
            pkgDataInfoMap = null;
            allowlistedAppDataInfoMap = null;
        }

       
        final Process.ProcessStartResult startResult;
        boolean regularZygote = false;
     
            regularZygote = true;
            startResult = Process.start(entryPoint,
                    app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                    app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                    app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags,
                    isTopApp, app.getDisabledCompatChanges(), pkgDataInfoMap,
                    allowlistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs
                    entryPointArgs);
    
        if ((hostingRecord.getType() != null)
                && ("activity".equals(hostingRecord.getType())
                || "pre-top-activity".equals(hostingRecord.getType()))) {
                    //TODO: not acting on pre-activity
            if (startResult != null) {
                mPerfHint.perfColdLaunchBoost(
                        app.processName, startResult.pid, IPerf.Launch.TYPE_START_PROC);
            }
        }

        if (!regularZygote) {
            // webview and app zygote don't have the permission to create the nodes
            if (Process.createProcessGroup(uid, startResult.pid) < 0) {
                Slog.e(ActivityManagerService.TAG, "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);
        }
        checkSlow(startTime, "startProcess: returned from zygote!");
        return startResult;
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    }
}

appZygote.getProcess().start(...); ---> android.os.ZygoteProcess#startViaZygote ---> android.os.ZygoteProcess#zygoteSendArgsAndGetResult --->\

//通过Socket连接Zygote进程,把之前组装的msg发给Zygote, //processClass="android.app.ActivityThread",
//通过Zygote进程来Fork出一个新的进程,并执行
//"android.app.ActivityThread"的main方法\

android.os.ZygoteProcess#attemptZygoteSendArgsAndGetResult

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

3. 第三阶段 Zygote Fork 应用进程
com.android.internal.os.ZygoteInit#main Zygote的启动过程我们前面有详细讲到过。
SystemServer的AMS服务向启动Home Activity发起一个fork请
求,Zygote进程通过Linux的fork函数,孵化出一个新的进程。
由于Zygote进程在启动时会创建Java虚拟机,因此通过fork而创建
的Launcher程序进程可以在内部获取一个Java虚拟机的实例拷
贝。
fork采用copy-on-write机制,有些类如果不做改变,甚至都不用
复制,子进程可以和父进程共享这部分数据,从而省去不少内存
的占用\

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

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

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

    Runnable caller;
    try {
        // Store now for StatsLogging later.
        final long startTime = SystemClock.elapsedRealtime();
        final boolean isRuntimeRestarted = "1".equals(
                SystemProperties.get("sys.boot_completed"));

        String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
        TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
                Trace.TRACE_TAG_DALVIK);
        bootTimingsTraceLog.traceBegin("ZygoteInit");
        RuntimeInit.preForkInit();

        boolean startSystemServer = false;
        String zygoteSocketName = "zygote";
        String abiList = null;
        boolean enableLazyPreload = false;
        for (int i = 1; i < argv.length; i++) {
            if ("start-system-server".equals(argv[i])) {
                startSystemServer = true;
            } else if ("--enable-lazy-preload".equals(argv[i])) {
                enableLazyPreload = true;
            } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                abiList = argv[i].substring(ABI_LIST_ARG.length());
            } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
            } else {
                throw new RuntimeException("Unknown command line argument: " + argv[i]);
            }
        }

        final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);
        if (!isRuntimeRestarted) {
            if (isPrimaryZygote) {
                FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
                        BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__ZYGOTE_INIT_START,
                        startTime);
            } else if (zygoteSocketName.equals(Zygote.SECONDARY_SOCKET_NAME)) {
                FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
                        BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SECONDARY_ZYGOTE_INIT_START,
                        startTime);
            }
        }

        if (abiList == null) {
            throw new RuntimeException("No ABI list supplied.");
        }

        // In some configurations, we avoid preloading resources and classes eagerly.
        // In such cases, we will preload things prior to our first fork.
        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
        }

        // Do an initial gc to clean up after startup
        bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
        gcAndFinalize();
        bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC

        bootTimingsTraceLog.traceEnd(); // ZygoteInit

        Zygote.initNativeState(isPrimaryZygote);

        ZygoteHooks.stopZygoteNoThreadCreation();

        zygoteServer = new ZygoteServer(isPrimaryZygote);

        if (startSystemServer) {
            Runnable r = forkSystemServer(abiList, zygoteSocketName, 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;
            }
        }

        Log.i(TAG, "Accepting command socket connections");

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

    // We're in the child process and have exited the select loop. Proceed to execute the
    // command.
    if (caller != null) {
        caller.run();
    }
}

zygoteServer就是socket的封装类 其中 接收到消息后,下面几行可以看出是要fork进程了

com.android.internal.os.ZygoteServer#runSelectLoop

--->

com.android.internal.os.ZygoteConnection#processCommand

--->

命名可以看出要fork进程了 Zygote.forkAndSpecialize 或者 Zygote.forkSimpleApps

--->

善后工作,关闭socket,设置进程名,回调ZygoteInit com.android.internal.os.ZygoteConnection#handleChildProc

--->

com.android.internal.os.ZygoteInit#zygoteInit

--->

com.android.internal.os.RuntimeInit#applicationInit

--->

这里通过反射 回调到了 android.app.ActivityThread 的 main 方法 com.android.internal.os.RuntimeInit#findStaticMain

--->

runSelectLoop

 if (pollIndex < usapPoolEventFDIndex) {
    // Session socket accepted from the Zygote server socket

    try {
        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;

processCommand

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;
    }
}

handleChildProc

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 */);
        }
    }
}

zygoteInit

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

    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
    RuntimeInit.redirectLogStreams();

    RuntimeInit.commonInit();  //初始化运行环境\
    ZygoteInit.nativeZygoteInit();  //启动Binder线程池\
    return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
            classLoader);
}

applicationInit

protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
        String[] argv, ClassLoader classLoader) {
    // If the application calls System.exit(), terminate the process
    // immediately without running any shutdown hooks.  It is not possible to
    // shutdown an Android application gracefully.  Among other things, the
    // Android runtime shutdown hooks close the Binder driver, which can cause
    // leftover running threads to crash before the process actually exits.
    nativeSetExitWithoutCleanup(true);

    VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
    VMRuntime.getRuntime().setDisabledCompatChanges(disabledCompatChanges);

    final Arguments args = new Arguments(argv);

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

    // Remaining arguments are passed to the start class's static main
    return findStaticMain(args.startClass, args.startArgs, classLoader);
}

findStaticMain

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

4. 进入应用进程,启动Activity的onCreate()\

android.app.ActivityThread#main

public static void main(String[] args) {
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");

    // Install selective syscall interception
    AndroidOs.install(); //没拿到源码,不清楚,不过看代码这里会new AndroidOs,具体就是文件操作类

    // 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); //这里英文注释很骚 so spammy

    Environment.initForCurrentUser(); //sd卡初始化

    // 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>");
    
    android.os.perfdebug.PerfDebugMonitor.get().prepareMonitor();
    Looper.prepareMainLooper();   //looper初始化

    // 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();   //ActivityThread开始啦

    thread.attach(false, startSeq);    // Application 开始啦  ,还有viewroot的回调   mConfigurationController


    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");
}

attach很关键 面试重点

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.makeApplication(true, null);
            mInitialApplication.onCreate();
        } catch (Exception e) {
            throw new RuntimeException(
                    "Unable to instantiate Application():" + e.toString(), e);
        }
    }

    ViewRootImpl.ConfigChangedCallback configChangedCallback = (Configuration globalConfig) -> {
        synchronized (mResourcesManager) {
            // TODO (b/135719017): Temporary log for debugging IME service.
            if (Build.IS_DEBUGGABLE && mHasImeComponent) {
                Log.d(TAG, "ViewRootImpl.ConfigChangedCallback for IME, "
                        + "config=" + globalConfig);
            }

            // 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 */,
                    mInitialApplication.getResources().getDisplayAdjustments())) {
                mConfigurationController.updateLocaleListFromAppContext(
                        mInitialApplication.getApplicationContext());

                // This actually changed the resources! Tell everyone about it.
                final Configuration updatedConfig =
                        mConfigurationController.updatePendingConfiguration(globalConfig);
                if (updatedConfig != null) {
                    mPendingConfiguration = updatedConfig;
                }
            }
        }
    };
    ViewRootImpl.addConfigCallback(configChangedCallback)
}

非系统进程, 走这里 调用AMS的attachApplication

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

然后是 ***attachApplicationLocked ***

---> bindApplication

thread.bindApplication(processName, appInfo, providerList, null, profilerInfo,
                        null, null, null, testMode,
                        mBinderTransactionTrackingEnabled, enableTrackAllocation,
                        isRestrictedBackupMode || !normalMode, app.isPersistent(),
                        new Configuration(app.getWindowProcessController().getConfiguration()),
                        app.compat, getCommonServicesLocked(app.isolated),
                        mCoreSettingsObserver.getCoreSettingsLocked(),
                        buildSerial, autofillOptions, contentCaptureOptions,
                        app.mDisabledCompatChanges);

---> ActivityThread.java#handleBindApplication --->

app = data.info.makeApplication(data.restrictedBackupMode, null);

            // Propagate autofill compat state
            app.setAutofillOptions(data.autofillOptions);

            // Propagate Content Capture options
            app.setContentCaptureOptions(data.contentCaptureOptions);

            mInitialApplication = app;

            Slog.d(TAG, "mInitialApplication   ee : " + data.toString());
            Slog.d(TAG, "mInitialApplication  package : " + data.appInfo.packageName);

            // don't bring up providers in restricted mode; they may depend on the
            // app's custom Application class
            if (!data.restrictedBackupMode) {
                Slog.d(TAG, "mInitialApplication   ee1 ");
                if (!ArrayUtils.isEmpty(data.providers)) {
                    Slog.d(TAG, "mInitialApplication   ee2 ");
                    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);
            }
            

--->

  public void callActivityOnCreate(Activity activity, Bundle icicle,
            PersistableBundle persistentState) {
        prePerformCreate(activity);
        activity.performCreate(icicle, persistentState);
        postPerformCreate(activity);
    }