Remember the four processes and three ways.

Four process

1. The process of the Launcher

2. System_server process

3. The process of the App

4. The Zygote process

Three ways

1. The Binder

2. The Socket

3. The Handler

Click on your desktop APP icon, Launcher call startActivitySafely

/** * Default launcher application. */
public final class Launcher extends Activity
        implements View.OnClickListener.OnLongClickListener.LauncherModel.Callbacks.View.OnTouchListener {.../**
     * Launches the intent referred by the clicked shortcut.
     *
     * @param v The view representing the clicked shortcut.
     */
    public void onClick(View v) {
        // Make sure that rogue clicks don't get through while allapps is launching, or after the
        // view has detached (it's possible for this to happen if the view is removed mid touch).. Object tag = v.getTag();if (tag instanceof ShortcutInfo) {
            // Open shortcut
            final Intent intent = ((ShortcutInfo) tag).intent;
            int[] pos = new int[2];
            v.getLocationOnScreen(pos);
            intent.setSourceBounds(new Rect(pos[0], pos[1],
                    pos[0] + v.getWidth(), pos[1] + v.getHeight()));

            boolean success = startActivitySafely(v, intent, tag);// Notice here

            if (success && v instanceof BubbleTextView) {
                mWaitingForResume = (BubbleTextView) v;
                mWaitingForResume.setStayPressed(true); }}else if (tag instanceof FolderInfo) {
           ...
        } else if(v == mAllAppsButton) { ... }}Copy the code
    boolean startActivitySafely(View v, Intent intent, Object tag) {
        boolean success = false;
        try {
            success = startActivity(v, intent, tag);// Notice here
        } catch (ActivityNotFoundException e) {
            ...
        }
        return success;
    }
Copy the code

Then see startActivity

boolean startActivity(View v, Intent intent, Object tag) {
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);// Start the activity in a new task

        try {
            // Only launch using the new animation if the shortcut has not opted out (this is a
            // private contract between launcher and may be ignored in the future).
             
            // Start with a new animation only if the shortcut does not select exit (this is one
		  // Private contracts between startup and may be ignored in the future). // This is Youdao Translation
             
            // If the shortcut has not already quit, just start with a new animation (this is
		  // Private contracts between initiators may be ignored in the future. // This is Google translate
             
             // What does youdao mean
            booleanuseLaunchAnimation = (v ! =null) &&
                    !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
            UserHandle user = (UserHandle) intent.getParcelableExtra(ApplicationInfo.EXTRA_PROFILE);
            LauncherApps launcherApps = (LauncherApps)
                    this.getSystemService(Context.LAUNCHER_APPS_SERVICE);
            if (useLaunchAnimation) {
                ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(v, 0.0,
                        v.getMeasuredWidth(), v.getMeasuredHeight());
                if (user == null || user.equals(android.os.Process.myUserHandle())) {
                    // Could be launching some bookkeeping activity
                    startActivity(intent, opts.toBundle());// Notice here
                } else{ launcherApps.startMainActivity(intent.getComponent(), user, intent.getSourceBounds(), opts.toBundle()); }}else{... }return true;
        } catch (SecurityException e) {
            ...
        }
        return false;
    }
Copy the code

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Indicates that you want to start the Activity in a new Task

Each Activity in the Android system is located in a Task, a Task can contain multiple activities, the same Activity may also have multiple instances. In Androidmanifest.xml, we can use Android :launchMode to control an instance of an Activity in a Task. In startActivity, we can also use setFlag to control the instance of the started Activity in the Task.

In addition to Task, there is another layer of container, which application developers and users may not feel or use, but which is very important: Stack. The multi-window management in Android system is built on the data structure of Stack. A Stack contains multiple tasks, and a Task contains multiple activities (Windows).

Binder initiates startActivity requests to the system_server process. Now let’s start with the most familiar startAcitivty. StartActivity can be reloaded in several ways, following the source code layer by layer until startActivityForResult is called.

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);// Notice here
            if(ar ! =null) { mMainThread.sendActivityResult( mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData()); }... }else{... }}Copy the code

The ActivityGroup was originally used to embed multiple child activities in an interface, but has been deprecated in API13. You are advised to use fragments instead of ActivityGroup.

Continue with, see mInstrumentation execStartActivity, mInstrumentation is Instrumentation instances, Instrumentation has the function of tracking applications and activities.

public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) { IApplicationThread whoThread = (IApplicationThread) contextThread; .try{...intresult = ActivityManager.getService() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target ! =null ? target.mEmbeddedID : null,
                        requestCode, 0.null, options);// Notice here
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
            ...
        }
        return null;
    }
Copy the code

The last call

ActivityManager. GetService (). StartActivity start to finish.

Point into the ActivityManager. GetService () look at it

/ * * *@hide* /
    public static IActivityManager getService(a) {
        return IActivityManagerSingleton.get();
    }

    private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create(a) {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    returnam; }};Copy the code

Discovery is a singleton of IActivityManager.

IActivityManager is a Binder interface, and ActivityManagerService (AMS) inherits iActivityManager.stub, The iActivityManager. Stub is an interface class generated by iActivityManager. aidl. Here we generate an AMS proxy for the Launcher process. AMS is the implementation of IActivityManager, so here we need to look at the AMS startActivity method. (called in the system_server process)

@Override
    public final int startActivity(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
                resultWho, requestCode, startFlags, profilerInfo, bOptions,
                UserHandle.getCallingUserId());
    }

    @Override
    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
                resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
                true /*validateIncomingUser*/);
    }

    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId,
            boolean validateIncomingUser) {
        enforceNotIsolatedCaller("startActivity");

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

        // TODO: Switch to user app stacks here.
        return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
                .setCaller(caller)
                .setCallingPackage(callingPackage)
                .setResolvedType(resolvedType)
                .setResultTo(resultTo)
                .setResultWho(resultWho)
                .setRequestCode(requestCode)
                .setStartFlags(startFlags)
                .setProfilerInfo(profilerInfo)
                .setActivityOptions(bOptions)
                .setMayWait(userId)
                .execute();

    }
Copy the code

MActivityStartController is an instance of ActivityStartController

/ * * *@return A starter to configure and execute starting an activity. It is valid until after
 * {@link ActivityStarter#execute} is invoked. At that point, the starter should be
 * considered invalid and no longer modified or used.
 */
ActivityStarter obtainStarter(Intent intent, String reason) {
    return mFactory.obtain().setIntent(intent).setReason(reason);
}
Copy the code

MFactory is an internal interface to ActivityStarter, so let’s look at ActivityStarter’s execute method

/**
     * Starts an activity based on the request parameters provided earlier.
     * @return The starter result.
     */
    int execute(a) {
        try {
            // TODO(b/64750076): Look into passing request directly to these methods to allow
            // for transactional diffs and preprocessing.
            if (mRequest.mayWait) {
                return startActivityMayWait(mRequest.caller, mRequest.callingUid,
                        ...
            } else {
                returnstartActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent, ... }}finally{... }}Copy the code

The setMayWait method of ActivityStarter was called earlier

ActivityStarter setMayWait(int userId) {
        mRequest.mayWait = true;
        mRequest.userId = userId;

        return this;
    }
Copy the code

Mrequest. mayWait = true

private int startActivityMayWait(IApplicationThread caller, int callingUid,
            String callingPackage, Intent intent, String resolvedType,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int startFlags,
            ProfilerInfo profilerInfo, WaitResult outResult,
            Configuration globalConfig, SafeActivityOptions options, boolean ignoreTargetSecurity,
            int userId, TaskRecord inTask, String reason,
            boolean allowPendingRemoteAnimationRegistryLookup) {...final ActivityRecord[] outRecord = new ActivityRecord[1];
            intres = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity, componentSpecified, outRecord, inTask, reason, allowPendingRemoteAnimationRegistryLookup); Binder.restoreCallingIdentity(origId); .returnres; }}Copy the code

Next, I’m going to hook up the three overloaded methods of startActivity, and then startActivityUnchecked, Behind a string of call startActivityUnchecked – > ActivityStackSupervisor. ResumeFocusedStackTopActivityLocked – > ActivityStack. ResumeTopActivi tyUncheckedLocked->ActivityStack.resumeTopActivityUncheckedLocked->ActivityStack.resumeTopActivityInnerLocked->ActivityS tackSupervisor.startSpecificActivityLocked

void startSpecificActivityLocked(ActivityRecord r,
        boolean andResume, boolean checkConfig) {
    // Is the application for this activity already running?
    ProcessRecord app = mService.getProcessRecordLocked(r.processName,
            r.info.applicationInfo.uid, true);

    getLaunchTimeTracker().setLaunchTime(r);

    if(app ! =null&& app.thread ! =null) {ProcessRecord objects record process-related information. App. thread is IApplicationThread. Both objects are null when the process is created
        try{... realStartActivityLocked(r, app, andResume, checkConfig);// Hot start direction, notice here, enter branch 2
            return;
        } catch (RemoteException e) {
            ...
        }

        // If a dead object exception was thrown -- fall through to
        // restart the application.
    }

    mService.startProcessLocked(r.processName, r.info.applicationInfo, true.0."activity", r.intent.getComponent(), false.false.true);// Cold start direction, notice here, enter branch 1
}
Copy the code

Branch 1: The process has not been created

ActivityManagerService.startProcessLocked

@GuardedBy("this")
final ProcessRecord startProcessLocked(String processName,
        ApplicationInfo info, boolean knownToBeDead, int intentFlags,
        String hostingType, ComponentName hostingName, boolean allowWhileBooting,
        boolean isolated, boolean keepIfLarge) {
    return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
            hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
            null /* ABI override */.null /* entryPoint */.null /* entryPointArgs */.null /* crashHandler */);// Interprocess communication is carried out through socket. Tell Zygote fork to exit the app process
}

@GuardedBy("this")
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
        boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
        boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
        String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
    long startTime = SystemClock.elapsedRealtime();
    ProcessRecord app;
    if(! isolated) {// this is false
        app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
        checkTime(startTime, "startProcess: after getProcessRecord"); . }else {
        // If this is an isolated process, it can't re-use an existing process.
        // If this is a separate process, it cannot reuse existing processes.
        app = null; }...if (app == null) {
        checkTime(startTime, "startProcess: creating new process record");
        app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
         // Create and lock. }else {
        // If this is a new package in the process, add the package to the list. }... checkTime(startTime,"startProcess: stepping in to startProcess");
    final boolean success = startProcessLocked(app, hostingType, hostingNameStr, abiOverride);// Notice here
    checkTime(startTime, "startProcess: done starting proc!");
    return success ? app : null;
}
Copy the code

Enter the startProcessLocked

@GuardedBy("this")
private final boolean startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride) {
    return startProcessLocked(app, hostingType, hostingNameStr,
            false /* disableHiddenApiChecks */, abiOverride);
}

/ * * *@return {@code true} if process start is successful, false otherwise.
 */
@GuardedBy("this")
private final boolean startProcessLocked(ProcessRecord app, String hostingType,
        String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride) {...return startProcessLocked(hostingType, hostingNameStr, entryPoint, app, uid, gids,
                runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith,
                startTime);// Notice here
    } catch (RuntimeException e) {
       ...
        return false; }}@GuardedBy("this")
    private boolean startProcessLocked(String hostingType, String hostingNameStr, String entryPoint,
            ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
            String seInfo, String requiredAbi, String instructionSet, String invokeWith,
            long startTime) {
        app.pendingStart = true;
        app.killedByAm = false;
        app.removed = false;
        app.killed = false;
        final long startSeq = app.startSeq = ++mProcStartSeqCounter;
        app.setStartParams(uid, hostingType, hostingNameStr, seInfo, startTime);
        if (mConstants.FLAG_PROCESS_START_ASYNC) {
            ...
                    final ProcessStartResult startResult = startProcess(app.hostingType, entryPoint,
                            app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo,
                            requiredAbi, instructionSet, invokeWith, app.startTime);// Notice here
                    synchronized (ActivityManagerService.this) { handleProcessStartedLocked(app, startResult, startSeq); }... });return true;
        } else{...final ProcessStartResult startResult = startProcess(hostingType, entryPoint, app,
                        uid, gids, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet,
                        invokeWith, startTime);// Notice here
                handleProcessStartedLocked(app, startResult.pid, startResult.usingWrapper,
                        startSeq, false); .return app.pid > 0; }}Copy the code

Continue to see startProcess

private ProcessStartResult startProcess(String hostingType, String entryPoint,
        ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
        String seInfo, String requiredAbi, String instructionSet, String invokeWith,
        long startTime) {...if (hostingType.equals("webview_service")) {... }else {
            startResult = Process.start(entryPoint,
                    app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                    app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                    app.info.dataDir, invokeWith,
                    newString[] {PROC_START_SEQ_IDENT + app.startSeq}); }...returnstartResult; . }Copy the code

Continue to look at the Process. The start

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

ZygoteProcess is an instance of zygoteProcess, continuing with the start of zygoteProcess

public final Process.ProcessStartResult start(finalString processClass, ... {try {
        return startViaZygote(processClass, niceName, uid, gid, gids,
                runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */,
                zygoteArgs);
    } catch(ZygoteStartFailedEx ex) { ... }}Copy the code

Continue to

private Process.ProcessStartResult startViaZygote(final String processClass,
                                                      ...
    synchronized(mLock) {
        return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);// Notice here, and notice the openZygoteSocketIfNeeded method}}Copy the code

Continue to

@GuardedBy("mLock")
private static Process.ProcessStartResult zygoteSendArgsAndGetResult( ZygoteState zygoteState, ArrayList
       
         args)
       
        throws ZygoteStartFailedEx {...// Should there be a timeout on this?
        Process.ProcessStartResult result = new Process.ProcessStartResult();// Notice here.return result;
    } catch(IOException ex) { ... }}Copy the code

OpenZygoteSocketIfNeeded () implements Zygote interconnect with system_sever via Socket, and finally calls the native method nativeForkandWte to fork a new process. This line, read, track the source code. Remember: point into line, line into surface, do not greedy, otherwise a face meng force.

At this point, the APP process is created, and the main method of the ActivityThread executing the APP process is reflected, which is the entry point to the APP process.

public static void main(String[] args) {... Looper.prepareMainLooper();// Create a main thread Looper. ActivityThread thread =new ActivityThread();
    thread.attach(false, startSeq);// Notice here

    if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); }... Looper.loop();// Start the loop

    throw new RuntimeException("Main thread loop unexpectedly exited");
}
Copy the code

Continue to look at the attach

private void attach(boolean system, long startSeq) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if(! system) { ...final IActivityManager mgr = ActivityManager.getService();// Get the AMS proxy object on app client
        try {
            mgr.attachApplication(mAppThread, startSeq);// Notice that the APP process is suspended and attachApplication of the SYSTEM process AMS is performed
        } catch (RemoteException ex) {
            throwex.rethrowFromSystemServer(); }... }Copy the code

Continue to attachApplication

@Override
public final void attachApplication(IApplicationThread thread, long startSeq) {
    synchronized (this) {... attachApplicationLocked(thread, callingPid, callingUid, startSeq);// Notice here. }}Copy the code

Continue to attachApplicationLocked

@GuardedBy("this")
private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid, int callingUid, long startSeq) {...if(app.isolatedEntryPoint ! =null) {
            // This is an isolated process which should just call an entry point instead of
            // being bound to an application.
            thread.runIsolatedEntryPoint(app.isolatedEntryPoint, app.isolatedEntryPointArgs);
        } else if(app.instr ! =null) { thread.bindApplication(processName, appInfo, providers, app.instr.mClass, profilerInfo, app.instr.mArguments, app.instr.mWatcher, app.instr.mUiAutomationConnection, testMode, mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || ! normalMode, app.persistent,new Configuration(getGlobalConfiguration()), app.compat,
                    getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked(),
                    buildSerial, isAutofillCompatEnabled);
        } else {
            thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
                    null.null.null, testMode, mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || ! normalMode, app.persistent,newConfiguration(getGlobalConfiguration()), app.compat, getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial, isAutofillCompatEnabled); }... }catch (Exception e) {
        ...
    }
	// See if the top visible activity is waiting to run in this process...
	// See if the activity visible at the top is waiting to run in this process...
        if (normalMode) {
            try {
                if (mStackSupervisor.attachApplicationLocked(app)) {// Notice here
                    didSomething = true; }}catch(Exception e) { .. }}...return true;
}
Copy the code

Thread for IApplicationThread, here call app system process ActivityThrad. ApplicationThread bindApplication, at the same time

Continue to look at

public final void bindApplication(String processName, ApplicationInfo appInfo,
        List<ProviderInfo> providers, ComponentName instrumentationName,
        ProfilerInfo profilerInfo, Bundle instrumentationArgs,
        IInstrumentationWatcher instrumentationWatcher,
        IUiAutomationConnection instrumentationUiConnection, int debugMode,
        boolean enableBinderTracking, boolean trackAllocation,
        boolean isRestrictedBackupMode, boolean persistent, Configuration config,
        CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
        String buildSerial, boolean autofillCompatibilityEnabled) {... sendMessage(H.BIND_APPLICATION, data); }Copy the code

As the situation becomes clearer, continue sendMessage with a couple of overloads, ending with H.bin_application for H

case BIND_APPLICATION:
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
    AppBindData data = (AppBindData)msg.obj;
    handleBindApplication(data);// Notice here
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    break;
Copy the code

Continue to handleBindApplication

private void handleBindApplication(AppBindData data) {...final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
                appContext.getClassLoader(), false.true.false);// Get and save the directory of code and resources contained in ApplicationInfo
        final ContextImpl instrContext = ContextImpl.createAppContext(this, pi);// Create the context in which to start the Activity

        try {
            final ClassLoader cl = instrContext.getClassLoader();
            mInstrumentation = (Instrumentation)
                cl.loadClass(data.instrumentationName.getClassName()).newInstance();// Use the class loader to create Instrumentation instances
        } catch (Exception e) {
            ...
        }

        final ComponentName component = new ComponentName(ii.packageName, ii.name);// This class holds the Activity class name and package name
        mInstrumentation.init(this, instrContext, appContext, component, data.instrumentationWatcher, data.instrumentationUiAutomationConnection); . }else {
        mInstrumentation = new Instrumentation();
        mInstrumentation.basicInit(this);
    }
	app = data.info.makeApplication(data.restrictedBackupMode, null);// Generate Application here.try {
            mInstrumentation.callApplicationOnCreate(app);// Notice here
        } catch(Exception e) { ... }}finally{... }... }Copy the code

Continue to

public void callApplicationOnCreate(Application app) {
    app.onCreate();// Execute Application's onCreate() method
}
Copy the code

This Application by the data. The info. MakeApplication generation, data. The info for LoadedApk object, so look at LoadedApk makeApplication here

public Application makeApplication(boolean forceDefaultAppClass,
        Instrumentation instrumentation) {... ContextImpl appContext = ContextImpl.createAppContext(mActivityThread,this);
        app = mActivityThread.mInstrumentation.newApplication(
                cl, appClass, appContext);
        appContext.setOuterContext(app);
    } catch (Exception e) {
        ...
    }
    mActivityThread.mAllApplications.add(app);
    mApplication = app;

    if(instrumentation ! =null) {/ / this incoming instrumentation is null, the data. The info. MakeApplication (data restrictedBackupMode, null);
        try {
            instrumentation.callApplicationOnCreate(app);
        } catch(Exception e) { ... }}...return app;
}
Copy the code

Remember attachApplicationLocked inside of attachApplicationLocked is also calling ActivityStackSupervisor attachApplicationLocked

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
    finalString processName = app.processName; .if (realStartActivityLocked(activity, app,
                                top == activity /* andResume */.true /* checkConfig */)) {// Notice here
                            didSomething = true; }}catch(RemoteException e) { ... }}...return didSomething;
}
Copy the code

Moving on to Real Start Active Locked and then branch two below

Branch 2: The process has been created

ActivityStackSupervisor.realStartActivityLocked

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
            boolean andResume, boolean checkConfig) throws RemoteException {...// Create activity launch transaction.
                final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
                        r.appToken);
                clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
                        System.identityHashCode(r), r.info,
                        // TODO: Have this take the merged configuration instead of separate global
                        // and override configs.
                        mergedConfiguration.getGlobalConfiguration(),
                        mergedConfiguration.getOverrideConfiguration(), r.compat,
                        r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                        r.persistentState, results, newIntents, mService.isNextTransitionForward(),
                        profilerInfo));

                // Set desired final state.
                final ActivityLifecycleItem lifecycleItem;
                if (andResume) {
                    lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
                } else {
                    lifecycleItem = PauseActivityItem.obtain();
                }
                clientTransaction.setLifecycleStateRequest(lifecycleItem);

                // Schedule Transaction. Execute the Activity to start the transaction
                mService.getLifecycleManager().scheduleTransaction(clientTransaction);// Notice here.return true;
    }
Copy the code

MService is AMS, and getLifecycleManager() returns a ClientLifecycleManager object

/**
     * Schedule a transaction, which may consist of multiple callbacks and a lifecycle request.
     * @param transaction A sequence of client transaction items.
     * @throws RemoteException
     *
     * @see ClientTransaction
     */
    void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
        final IApplicationThread client = transaction.getClient();
        transaction.schedule();
        if(! (clientinstanceof Binder)) {
            // If client is not an instance of Binder - it's a remote call and at this point it is
            // safe to recycle the object. All objects used for local calls will be recycled after
            // the transaction is executed on client in ActivityThread.transaction.recycle(); }}Copy the code

ScheduleTransaction internal call ClientTransaction. The schedule

/**
 * Schedule the transaction after it was initialized. It will be send to client and all its
 * individual parts will be applied in the following sequence:
 * 1. The client calls {@link#preExecute(ClientTransactionHandler)}, which triggers all work * that needs to be done before actually scheduling the transaction for callbacks and * lifecycle  state request. * 2. The transaction message is scheduled. * 3. The client calls {@link TransactionExecutor#execute(ClientTransaction)}, which executes
 * all callbacks and necessary lifecycle transitions.
 */
public void schedule(a) throws RemoteException {
    mClient.scheduleTransaction(this);
}
Copy the code

MClient executes ClientTransaction. Obtain (app. Thread, R.aptoken); The app. Thread, also known as IApplicationThread, is passed in.

/** Obtain an instance initialized with provided params. */
    public static ClientTransaction obtain(IApplicationThread client, IBinder activityToken) {
        ClientTransaction instance = ObjectPool.obtain(ClientTransaction.class);
        if (instance == null) {
            instance = new ClientTransaction();
        }
        instance.mClient = client;
        instance.mActivityToken = activityToken;

        return instance;
    }
Copy the code

The implementation of IApplicationThread is the inner class ApplicationThread of ActivityThread, which comes full circle back to ApplicationThread

@Override
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    ActivityThread.this.scheduleTransaction(transaction);
}
Copy the code

ActivityThread has no internal scheduleTransaction() method, see ClientTransactionHandler of the parent class

/** Prepare and schedule transaction for execution. */
    void scheduleTransaction(ClientTransaction transaction) {
        transaction.preExecute(this);
        sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
    }
Copy the code

ClientTransactionHandler’s sendMessage is an abstract method, so implement the ActivityThread class to find it and eventually call ActivityThread’s sendMessage method

private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        if (DEBUG_MESSAGES) Slog.v(
            TAG, "SCHEDULE " + what + "" + mH.codeToString(what)
            + ":" + arg1 + "/" + obj);
        Message msg = Message.obtain();
        msg.what = what;//ActivityThread.H.EXECUTE_TRANSACTION
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        if (async) {
            msg.setAsynchronous(true);
        }
        mH.sendMessage(msg);
    }
Copy the code

MH is an instance of Handler that continues with EXECUTE_TRANSACTION from mH

case EXECUTE_TRANSACTION:
                    final ClientTransaction transaction = (ClientTransaction) msg.obj;
                    mTransactionExecutor.execute(transaction);
                    if (isSystem()) {
                        // Client transactions inside system process are recycled on the client side
                        // instead of ClientLifecycleManager to avoid being cleared before this
                        // message is handled.
                        transaction.recycle();
                    }
                    // TODO(lifecycler): Recycle locally scheduled transactions.
                    break;
Copy the code

MTransactionExecutor is an instance of TransactionExecutor. Continue

public void execute(ClientTransaction transaction) {
        final IBinder token = transaction.getActivityToken();
        log("Start resolving transaction for client: " + mTransactionHandler + ", token: " + token);

        executeCallbacks(transaction);

        executeLifecycleState(transaction);
        mPendingActions.clear();
        log("End resolving transaction");
    }
Copy the code

Call executeCallbacks and ExecutelifeccleState, and continue

/** Cycle through all states requested by callbacks and execute them at proper times. */
    @VisibleForTesting
    public void executeCallbacks(ClientTransaction transaction) {...final int size = callbacks.size();
        for (int i = 0; i < size; ++i) {
            final ClientTransactionItem item = callbacks.get(i);
            log("Resolving callback: " + item);
            final int postExecutionState = item.getPostExecutionState();
            final int closestPreExecutionState = mHelper.getClosestPreExecutionState(r,
                    item.getPostExecutionState());
            if(closestPreExecutionState ! = UNDEFINED) { cycleToPath(r, closestPreExecutionState); } item.execute(mTransactionHandler, token, mPendingActions); item.postExecute(mTransactionHandler, token, mPendingActions);if (r == null) {
                // Launch activity request will create an activity record.
                r = mTransactionHandler.getActivityClient(token);
            }

            if(postExecutionState ! = UNDEFINED && r ! =null) {
                // Skip the very last transition and perform it by explicit state request instead.
                final booleanshouldExcludeLastTransition = i == lastCallbackRequestingState && finalState == postExecutionState; cycleToPath(r, postExecutionState, shouldExcludeLastTransition); }}}/** Transition to the final state if requested by the transaction. */
    private void executeLifecycleState(ClientTransaction transaction) {...// Cycle to the state right before the final requested state.
        cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */);

        // Execute the final transition with proper parameters.
        lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
        lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);
    }
Copy the code

ExecuteCallbacks and ExecutelifeccleState both call cycleToPath and continue

/** Transition the client between states. */
    @VisibleForTesting
    public void cycleToPath(ActivityClientRecord r, int finish) {
        cycleToPath(r, finish, false /* excludeLastState */);
    }

    /** * Transition the client between states with an option not to perform the last hop in the * sequence. This is used when resolving lifecycle state request, when the last transition must * be performed with some specific parameters. */
    private void cycleToPath(ActivityClientRecord r, int finish,
            boolean excludeLastState) {
        final int start = r.getLifecycleState();
        log("Cycle from: " + start + " to: " + finish + " excludeLastState:" + excludeLastState);
        final IntArray path = mHelper.getLifecyclePath(start, finish, excludeLastState);
        performLifecycleSequence(r, path);// Notice here
    }
Copy the code

Follow up on PerformLife Clesequence

/** Transition the client through previously initialized state sequence. */
    private void performLifecycleSequence(ActivityClientRecord r, IntArray path) {
        final int size = path.size();
        for (int i = 0, state; i < size; i++) {
            state = path.get(i);
            log("Transitioning to state: " + state);
            switch (state) {
                case ON_CREATE:// Notice here
                    mTransactionHandler.handleLaunchActivity(r, mPendingActions,
                            null /* customIntent */);
                    break;
                case ON_START:
                    mTransactionHandler.handleStartActivity(r, mPendingActions);
                    break;
                case ON_RESUME:
                    mTransactionHandler.handleResumeActivity(r.token, false /* finalStateRequest */,
                            r.isForward, "LIFECYCLER_RESUME_ACTIVITY");
                    break;
                case ON_PAUSE:
                    mTransactionHandler.handlePauseActivity(r.token, false /* finished */.false /* userLeaving */.0 /* configChanges */, mPendingActions,
                            "LIFECYCLER_PAUSE_ACTIVITY");
                    break;
                case ON_STOP:
                    mTransactionHandler.handleStopActivity(r.token, false /* show */.0 /* configChanges */, mPendingActions, false /* finalStateRequest */."LIFECYCLER_STOP_ACTIVITY");
                    break;
                case ON_DESTROY:
                    mTransactionHandler.handleDestroyActivity(r.token, false /* finishing */.0 /* configChanges */.false /* getNonConfigInstance */."performLifecycleSequence. cycling to:" + path.get(size - 1));
                    break;
                case ON_RESTART:
                    mTransactionHandler.performRestartActivity(r.token, false /* start */);
                    break;
                default:
                    throw new IllegalArgumentException("Unexpected lifecycle state: "+ state); }}}Copy the code

MTransactionHandler is the passed ClientTransactionHandler whose handleLaunchActivity is an abstract method that is implemented by subclass ActivityThread

/** * Extended implementation of activity launch. Used when server requests a launch or relaunch. */
    @Override
    public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) {...finalActivity a = performLaunchActivity(r, customIntent); .return a;
    }
Copy the code

Continue to performLaunchActivity

/** Core implementation of activity launch. */
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ActivityInfo aInfo = r.activityInfo;// Get the ActivityInfo class
        if (r.packageInfo == null) {
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);// Get the APK file describing LoadedApk. LoadedApk, when constructed, takes and saves the directory of code and resources contained in ApplicationInfo
        }

        ComponentName component = r.intent.getComponent();// Gets the ComponentName class for the Activity to start, which holds the Activity class name and package name
        if (component == null) {
            component = r.intent.resolveActivity(
                mInitialApplication.getPackageManager());
            r.intent.setComponent(component);
        }

        if(r.activityInfo.targetActivity ! =null) {
            component = new ComponentName(r.activityInfo.packageName,
                    r.activityInfo.targetActivity);
        }

        ContextImpl appContext = createBaseContextForActivity(r);// Create the context in which to start the Activity
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();// Use the class loader to create the Activity instanceactivity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); StrictMode.incrementExpectedActivityCount(activity.getClass()); r.intent.setExtrasClassLoader(cl); r.intent.prepareToEnterProcess(); . }catch (Exception e) {
            ...
        }

        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);/ / create Application, makeApplication method will be called to create internal Application of onCreate (). activity.attach(appContext,this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback);// Initialize the Activity. The attach method creates a window object and associates it with the Activity.if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else{ mInstrumentation.callActivityOnCreate(activity, r.state); }... }... }catch (SuperNotCalledException e) {
           ...
        } catch (Exception e) {
            ...
        }

        return activity;
    }
Copy the code

r.isPersistable()

public boolean isPersistable(a) {
    return activityInfo.persistableMode == ActivityInfo.PERSIST_ACROSS_REBOOTS;
}
Copy the code

Continue with the Instrumentation callActivityOnCreate(activity, R.state, R.persistentState);

/**
     * Perform calling of an activity's {@link Activity#onCreate}
     * method.  The default implementation simply calls through to that method.
     *  @param activity The activity being created.
     * @param icicle The previously frozen state (or null) to pass through to
     * @param persistentState The previously persisted state (or null)
     */
    public void callActivityOnCreate(Activity activity, Bundle icicle, PersistableBundle persistentState) {
        prePerformCreate(activity);
        activity.performCreate(icicle, persistentState);// Notice here
        postPerformCreate(activity);
    }
Copy the code

To continue, the Activity. PerformCreate

final void performCreate(Bundle icicle, PersistableBundle persistentState) {
        mCanEnterPictureInPicture = true;
        restoreHasCurrentPermissionRequest(icicle);
        if(persistentState ! =null) {
            onCreate(icicle, persistentState);
        } else {
            onCreate(icicle);
        }
        writeEventLog(LOG_AM_ON_CREATE_CALLED, "performCreate"); mActivityTransitionState.readState(icicle); mVisibleFromClient = ! mWindow.getWindowStyle().getBoolean( com.android.internal.R.styleable.Window_windowNoDisplay,false);
        mFragments.dispatchActivityCreated();
        mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
    }
Copy the code

Finally see The familiar onCreate, moved, Read The Fucking Source Code.


Conclusion:

  • So let’s figure out what the APP startup process is. As for Binder, Socket, Handler, reflection, etc., involved in the process, I will gradually expand my study and understanding later
  • What does fat person have to understand wrong, welcome everybody to point out, discuss together, study, progress
  • Fatty’s writing is not very good, the first time to write blog, try to walk a road, fork road and then slowly fill up
  • Write a blog, to understand, learn, deepen the internal mechanism of the source code, there is a great help
  • Looking forward to Fatty’s second Android Messaging post

reference

Android 9.0 Click on the desktop App icon, start the Activity process analysis Android click on the desktop App icon Activity start process Android development art exploration