1. Introduction

Activity is the most commonly used component in daily development, the system has done a lot of packaging for us, so that we usually use it very simple, very smooth. But have you ever wondered how an Activity is started inside the system? How is the Activity object created and how is the lifecycle method called back? Learning the underlying working principle is the only way to become a senior engineer. We must know ourselves and our enemies about the starting principle of Activity, so as to deal with various difficult and complicated diseases in daily development. This article is mainly on the Activity start process of the main process explained, the purpose is to give us a perceptual understanding, without deep buckle code details, can have guiding significance to the upper development. Unless ROM development is involved, that low-level detail still needs attention.

Interstitios :ActivityManagerService(AMS) is a core service in Android that manages startup, switching, and scheduling of four major components, as well as the management and scheduling of application processes. Communication with AMS is cross-process.

Ps: This article uses API 28 as an example

1.1 A brief introduction to the main classes

  • Instrumentation

Instrumentation is instantiated before any code in the application runs and allows you to monitor all interactions between the application and the system. It also builds applications, builds activities, and life cycles through this object.

  • ActivityManagerService

Android core service, referred to as AMS, is responsible for scheduling various application processes and managing four components. The IActivityManager interface is implemented and application processes can invoke system services through Binder mechanism.

  • LaunchActivityItem

This is a message object that starts the Activity when the ActivityThread receives the message. Execute the execute method to start the activity after receiving the message.

  • ActivityThread

The main thread of the application. The entry point of the application. Open the loop in the main method to continuously receive messages and process tasks.

2. Application startup process

2.1 introduction of the Launcher

Launcher, the android desktop we’re familiar with, is actually an APP. However, this APP is a little special because it is the first APP to be launched after the system is turned on, and the APP is resident in the system and will not be killed. As soon as the user presses the home button, it will return to the desktop (back to the APP). There are many apps installed by ourselves or the system on the desktop. We can open the APP by clicking the shortcut of the APP. The current version of Android’s native Launcher is Launcher3. The Launcher. Java mentioned below is an Activity in Launcher3. The Activity displays shortcut ICONS for each application.

2.2 Start application source code analysis

The onClick method of the Activity Launcher is called by clicking the shortcut

public void onClick(View v) {... Object tag = v.getTag();if (tag instanceof ShortcutInfo) {
        // Click the shortcut ->onClickAppShortcutonClickAppShortcut(v); }... }protected void onClickAppShortcut(final View v) {...// Start activities
    startAppShortcutOrInfoActivity(v);
}

private void startAppShortcutOrInfoActivity(View v) {
    // Put the startup information in the click View tag
    ItemInfo item = (ItemInfo) v.getTag();
    // The application is parsed and saved by PackageManagerService according to androidmanifest.xml when installed
    Intent intent;
    if (item instanceof PromiseAppInfo) {
        PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item;
        intent = promiseAppInfo.getMarketIntent();
    } else {
        intent = item.getIntent();
    }
    
    booleansuccess = startActivitySafely(v, intent, item); . }public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {...// Prepare intentintent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); .// Could be launching some bookkeeping activitystartActivity(intent, optsBundle); . }Copy the code

In dealing with a click event, after onClickAppShortcut method call startAppShortcutOrInfoActivity method, Intent information, and then call startActivitySafely method, call the star, we often use in it TActivity method. Since the Launcher class is an Activity, it makes sense to call the startActivity method. Calling the startActivity method here launches the first Activity of the APP.

3. Start the Activity

Take the source code for API 28 as an example

3.1 Starting a Process

Go to the Activity’s startActivity method, which ends up calling startActivityForResult()

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
        @Nullable Bundle options) {
    / / mMainThread ActivityThread mMainThread. GetApplicationThread () is to obtain ApplicationThread
    Instrumentation.ActivityResult ar =
        mInstrumentation.execStartActivity(
            this, mMainThread.getApplicationThread(), mToken, this,
            intent, requestCode, options);
}
Copy the code

StartActivityForResult calls the execStartActivity method of the Instrumentation, where mMainThread is ActivityThread(which is the starting point for an application),mMainThread. GetApplicationThread () is to obtain ApplicationThread ApplicationThread is ActivityThread inner classes, will introduce to you later.

public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
    //1. Convert ApplicationThread to IApplicationThread
    IApplicationThread whoThread = (IApplicationThread) contextThread;
    
    //2. Get the AMS instance and call startActivity
    intresult = ActivityManager.getService() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target ! =null ? target.mEmbeddedID : null,
                requestCode, 0.null, options);
    checkStartActivityResult(result, intent);

    return null;
}
Copy the code

IApplicationThread is a Binder interface, it inherits from IInterface. ApplicationThread is inherited IApplicationThread Stub, realized IApplicationThread, so can be converted to the I ApplicationThread.

The next step is to get the AMS instance and call the AMS startActivity method.

public static IActivityManager getService(a) {
    return IActivityManagerSingleton.get();
}

private static final Singleton<IActivityManager> IActivityManagerSingleton =
        new Singleton<IActivityManager>() {
            @Override
            protected IActivityManager create(a) {
                //1. Obtain service Binder objects
                final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                //2. Aidl gets AMS
                final IActivityManager am = IActivityManager.Stub.asInterface(b);
                returnam; }};Copy the code

ServiceManager is an important class in Android. It manages all system services and maintains communication between the binder services and the client. Binder objects are returned for communication between applications and system services.

Let’s move on to the AMS startActivity method

@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) {

    // 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

The AMS startActivity method calls the AMS startActivityAsUser method, which then calls another startActivityAsUser method. This leads to a series of chain calls, culminating in ActivityStarter’s execute method.

int execute(a) {
    return startActivityMayWait(mRequest.caller, mRequest.callingUid,
            mRequest.callingPackage, mRequest.intent, mRequest.resolvedType,
            mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
            mRequest.resultWho, mRequest.requestCode, mRequest.startFlags,
            mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig,
            mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId,
            mRequest.inTask, mRequest.reason,
            mRequest.allowPendingRemoteAnimationRegistryLookup);
}
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) {...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); . }private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
        String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
        String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
        SafeActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
        ActivityRecord[] outActivity, TaskRecord inTask, String reason,
        boolean allowPendingRemoteAnimationRegistryLookup) {... mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord, inTask, allowPendingRemoteAnimationRegistryLookup); . }private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
        String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
        String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
        SafeActivityOptions options,
        boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
        TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup) {...return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
            true /* doResume */, checkedOptions, inTask, outActivity);
}

Copy the code

The ActivityStarter execute method will continue to call the startActivityMayWait method, which will then call the startActivity method and then another startActivity method. And then we call another startActivity method,

I have to say, the parameters of these methods are really long,,,, probably due to historical reasons.

private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity) {... result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, startFlags, doResume, options, inTask, outActivity); . }private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
        ActivityRecord[] outActivity) {... mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity, mOptions);return START_SUCCESS;
}

Copy the code

Finally don’t need to call startActivity method, call startActivityUnchecked method, call the ActivityStackSupervisor resumeFocusedStackTopActivityLocked method in it

 boolean resumeFocusedStackTopActivityLocked( ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {...returntargetStack.resumeTopActivityUncheckedLocked(target, targetOptions); . }Copy the code

TargetStack ActivityStack, invoked ActivityStack resumeTopActivityUncheckedLocked method, and then call resumeTopActivityInnerLocked method.

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {... result = resumeTopActivityInnerLocked(prev, options); .return result;
}


private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {... mStackSupervisor.startSpecificActivityLocked(next,true.false); .return true;
}

Copy the code

And then will return to ActivityStackSupervisor startSpecificActivityLocked method


void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {...// Start if the process exists
    if(app ! =null&& app.thread ! =null) {
        realStartActivityLocked(r, app, andResume, checkConfig);
        return;
    }
    
    // The process is created if it does not exist
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true.0."activity", r.intent.getComponent(), false.false.true);
}

Copy the code

This checks to see if the process exists and creates one if it does not. The mService here is AMS, which calls the startProcessLocked method of AMS.

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

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) {...final booleansuccess = startProcessLocked(app, hostingType, hostingNameStr, abiOverride); . }private final boolean startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride) {
    return startProcessLocked(app, hostingType, hostingNameStr,
            false /* disableHiddenApiChecks */, abiOverride);
}

private final boolean startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, boolean disableHiddenApiChecks, String abiOverride) {...returnstartProcessLocked(hostingType, hostingNameStr, entryPoint, app, uid, gids, runtimeFlags, mountExternal, seInfo, requiredAbi, instructionSet, invokeWith, startTime); . }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) {...finalProcessStartResult startResult = startProcess(app.hostingType, entryPoint, app, app.startUid, gids, runtimeFlags, mountExternal, app.seInfo, requiredAbi, instructionSet, invokeWith, app.startTime); . }private ProcessStartResult startProcess(String hostingType, String entryPoint,
        ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
        String seInfo, String requiredAbi, String instructionSet, String invokeWith,
        long startTime) {... startResult = Process.start(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, invokeWith,newString[] {PROC_START_SEQ_IDENT + app.startSeq}); . }Copy the code

Here AMS calls many layers of startProcessLocked, eventually calling the startProcess method and then the start method through Process.

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

private static ProcessStartResult startViaZygote(final String processClass,
                              final String niceName,
                              final int uid, final int gid,
                              final int[] gids,
                              int debugFlags, int mountExternal,
                              int targetSdkVersion,
                              String seInfo,
                              String abi,
                              String instructionSet,
                              String appDataDir,
                              String[] extraArgs)
                              throws ZygoteStartFailedEx {...// If necessary, open the Socket to communicate with zygote
    return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}

private static Process.ProcessStartResult zygoteSendArgsAndGetResult( ZygoteState zygoteState, ArrayList
       
         args)
       
        throws ZygoteStartFailedEx {...final BufferedWriter writer = zygoteState.writer;
    final DataInputStream inputStream = zygoteState.inputStream;

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

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

    writer.flush();

    // Should there be a timeout on this?
    Process.ProcessStartResult result = new Process.ProcessStartResult();

    // Always read the entire result from the input stream to avoid leaving
    // bytes in the stream for future process starts to accidentally stumble
    // upon.
    result.pid = inputStream.readInt();
    result.usingWrapper = inputStream.readBoolean();

    if (result.pid < 0) {
        throw new ZygoteStartFailedEx("fork() failed");
    }
    returnresult; . }Copy the code

The zygoteState is obtained in the previous step. Now communicate with zygote, first passing it to the zygote with a write method, one argument at a time. Zygote will get these parameters and create the required process for you. The result is then returned as read. The process created here is the APP process. Zygote forks out child processes.

3.2 Starting the main thread

The process entry, also known as ActivityThread’s main method, is exceptionally clear and concise. Of course, this is also the entrance to the main thread.

public static void main(String[] args) {
    
    // Analyze 1 main thread on Looper arrangementLooper.prepareMainLooper(); .2 / / analysis
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);
    
    // Analyze 3 dead loop, receive message on main thread
    Looper.loop();

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

All you need to know about analysis 1 and analysis 3 in the Android_Handler mechanism has been described in detail and will not be repeated here.

Let’s analyze point 2:

final ApplicationThread mAppThread = new ApplicationThread();
private void attach(boolean system, long startSeq) {...if(! system) {// This step is to get the AMS instance, as shown above
        final IActivityManager mgr = ActivityManager.getService();
        // Then communicate across processesmgr.attachApplication(mAppThread, startSeq); }}Copy the code

Obtain AMS for cross-process communication and invoke attachApplication of AMS

public final void attachApplication(IApplicationThread thread, long startSeq) {
    synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final longorigId = Binder.clearCallingIdentity(); attachApplicationLocked(thread, callingPid, callingUid, startSeq); Binder.restoreCallingIdentity(origId); }}@GuardedBy("this")
private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid, int callingUid, long startSeq) {...// Thread is the ApplicationThread in ActivityThreadthread.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);

    // See if the top visible activity is waiting to run in this process...
    // See if there is an Activity to run
    if (normalMode) {
        try {
            if (mStackSupervisor.attachApplicationLocked(app)) {
                didSomething = true; }}catch (Exception e) {
            Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
            badApp = true; }}...return true;
}

Copy the code

There are two things to note here

  • The first is to call AMS’s attachApplication methods across processes, and then continue to call attachApplicationLocked, while calling the MappThreads in ActivityThreads across processes BindApplication method in. Create Application
  • The second is to start the first Activity, calling attachApplicationLocked on ActivityStackSupervisor.

3.3 create Application

Let’s start with the bindApplication method of ApplicationThread

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) {

    AppBindData data = newAppBindData(); .// Basically send a message
    sendMessage(H.BIND_APPLICATION, data);
}

void sendMessage(int what, Object obj) {
    sendMessage(what, obj, 0.0.false);
}

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;
    msg.obj = obj;
    msg.arg1 = arg1;
    msg.arg2 = arg2;
    if (async) {
        msg.setAsynchronous(true);
    }
    // the mH is a Handler that sends a message
    mH.sendMessage(msg);
}


 class H extends Handler {
        // Bind the Application, bind the Service, stop the Service, etc. This Handler has a lot to do with how these components start and stop and stuff like that.
        // Before API 28, there were more messages in this Handler. Before API 28, the Activity's various life cycle callbacks had corresponding message names. Now it's a fusion.
        public static final int BIND_APPLICATION        = 110;
        public static final int EXIT_APPLICATION        = 111;
        public static final int RECEIVER                = 113;
        public static final int CREATE_SERVICE          = 114;
        public static final int SERVICE_ARGS            = 115;
        public static final int STOP_SERVICE            = 116;
        public static final int CONFIGURATION_CHANGED   = 118;
        public static final int CLEAN_UP_CONTEXT        = 119;
        public static final int GC_WHEN_IDLE            = 120;
        public static final int BIND_SERVICE            = 121;
        public static final int RELAUNCH_ACTIVITY = 160;
}
Copy the code

In the ApplicationThread’s bindApplication, the sendMessage method (which is in the ActivityThread and can be called because ApplicationThread is an inner class) is called to send A message through H(this class is A) CtivityThread inner class) this Handler receives the message. Because ApplicationThreads run in the Binder thread pool, they need to switch to the main thread to perform UI operations such as starting activities. Finally, it will come to the BIND_APPLICATION message of H

public void handleMessage(Message msg) {
    switch (msg.what) {
        case BIND_APPLICATION:
            AppBindData data = (AppBindData)msg.obj;
            handleBindApplication(data);
            break; . }}private void handleBindApplication(AppBindData data) {

    // Continue loading instrumentation.
    if(ii ! =null) {
        ApplicationInfo instrApp;
        instrApp = getPackageManager().getApplicationInfo(ii.packageName, 0,
                UserHandle.myUserId());
        / / build ContextImpl
        final ContextImpl instrContext = ContextImpl.createAppContext(this, pi);
        // Get its classLoader
        final ClassLoader cl = instrContext.getClassLoader();
        / / build Instrumentation
        mInstrumentation = (Instrumentation)
            cl.loadClass(data.instrumentationName.getClassName()).newInstance();
    } else {
        mInstrumentation = new Instrumentation();
        mInstrumentation.basicInit(this);
    }

    Application app;
    // If the app is being launched for full backup or restore, bring it up in
    // a restricted environment with the base application class.
    / / build the Application
    app = data.info.makeApplication(data.restrictedBackupMode, null);

    // Call Application's onCreate method
    mInstrumentation.callApplicationOnCreate(app);
}

//sources/android-28/android/app/LoadedApk.java#makeApplication
public Application makeApplication(boolean forceDefaultAppClass,
        Instrumentation instrumentation) {
    // Note that if the Application is already initialized, it will not be reinitialized
    if(mApplication ! =null) {
        return mApplication;
    }

    Application app = null;

    String appClass = mApplicationInfo.className;
    if (forceDefaultAppClass || (appClass == null)) {
        appClass = "android.app.Application";
    }
    / / build the Application
    app = mActivityThread.mInstrumentation.newApplication(
            cl, appClass, appContext);
    appContext.setOuterContext(app);

    return app;
}

//sources/android-28/android/app/Instrumentation.java#newApplication
public Application newApplication(ClassLoader cl, String className, Context context)
        throws InstantiationException, IllegalAccessException, 
        ClassNotFoundException {
    // Build Application with reflection
    Application app = getFactory(context.getPackageName())
            .instantiateApplication(cl, className);
    / / assignment Context
    app.attach(context);
    return app;
}
public @NonNull Application instantiateApplication(@NonNull ClassLoader cl, @NonNull String className)
        throws InstantiationException, IllegalAccessException, ClassNotFoundException {
    return (Application) cl.loadClass(className).newInstance();
}
Copy the code

The BIND_APPLICATION message is processed in the H Handler, which first loads the Instrumentation object by ClassLoader, and then calls the newApplication of the Instrumentation by LoadedApk Method (it’s a little strange here, why not call the newApplication method directly with the built mInstrumentation..) Create the Application object as loadClass and call the Application’s onCreate lifecycle method.

3.4 create the Activity

Next we continue the attachApplicationLocked methods for ActivityStackSupervisor

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {... realStartActivityLocked(activity, app,top == activity,true); . }final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
            boolean andResume, boolean checkConfig) throws RemoteException {...// Create activity launch transaction.
    // Create the activity to start the transaction.
    final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
            r.appToken);
    // Build the LaunchActivityItem object and pass it into clientTransaction as a callback
    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));

    // Schedule transaction.
    ClientLifecycleManager = ClientLifecycleManagermService.getLifecycleManager().scheduleTransaction(clientTransaction); . }//ClientLifecycleManager#scheduleTransaction
void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    // Go further
    transaction.schedule();
}

//ClientTransaction#schedule
public void schedule(a) throws RemoteException {
    // mClient is ApplicationThread
    mClient.scheduleTransaction(this);
}

//ApplicationThread#scheduleTransaction
@Override
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
    //ActivityThread inherits from ClientTransactionHandler, and scheduleTransaction is in ClientTransactionHandler
    ActivityThread.this.scheduleTransaction(transaction);
}

//ClientTransactionHandler#scheduleTransaction
void scheduleTransaction(ClientTransaction transaction) {
    transaction.preExecute(this);
    // Note that an EXECUTE_TRANSACTION message is sent to the Handler H inside the ActivityThread, and the ClientTransaction object is also passed in
    sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
/ / ClientTransactionHandler# sendMessage this method is abstract methods, are implemented in ActivityThread, certainly is for H the Handler to send news
abstract void sendMessage(int what, Object obj);

Copy the code

In Android8.0 is through ApplicationThread scheduleLaunchActivity () to the related data encapsulation, and then by calling ActivityThread class sendMessage () sent out. But in Android9.0, ClientLifecycleManager and ClientTransactionHandler were introduced to help manage the Activity life cycle. The life cycle is abstracted out, and a life cycle is replaced by an object.

Through the tossing and turning of the above method calls, I ended up in ClientTransactionHandler’s scheduleTransaction method, which then sent an EXECUTE_TRANSACTION message to ActivityThread H. The API The LAUNCH_ACTIVITY, PAUSE_ACTIVITY, RESUME_ACTIVITY Handler for ActivityThread H has been removed and replaced with EXECUTE_TRANSACTION This is the news.

// H in ActivityThread
private final TransactionExecutor mTransactionExecutor = new TransactionExecutor(this);  / / here is the incoming ClientTransactionHandler object (namely ActivityThread), ClientTransactionHandler is ActivityThread parent class
class H extends Handler {
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case EXECUTE_TRANSACTION:
                // First fetch the ClientTransaction object
                final ClientTransaction transaction = (ClientTransaction) msg.obj;
                Pass ClientTransaction into the execute methodmTransactionExecutor.execute(transaction); }}}//TransactionExecutor#execute
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");
}

//TransactionExecutor#executeCallbacks
public void executeCallbacks(ClientTransaction transaction) {
    // Retrieve the ClientTransaction object callback, the LaunchActivityItem above
    final List<ClientTransactionItem> callbacks = transaction.getCallbacks();

    final int size = callbacks.size();
    for (int i = 0; i < size; ++i) {
        final ClientTransactionItem item = callbacks.get(i);
        final int postExecutionState = item.getPostExecutionState();
        final intclosestPreExecutionState = mHelper.getClosestPreExecutionState(r, item.getPostExecutionState()); item.execute(mTransactionHandler, token, mPendingActions); item.postExecute(mTransactionHandler, token, mPendingActions); }}//LaunchActivityItem#execute
@Override
public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) {
    // Call the handleLaunchActivity method of ActivityThread
    client.handleLaunchActivity(r, pendingActions, null);
}

Copy the code

In the EXECUTE_TRANSACTION message in the ActivityThread, we execute the Execute method of the TransactionExecutor object, and then we execute the executeCallbacks method inside. Inside the executeCallbacks method, retrieve the ClientTransaction object’s callback, which is the LaunchActivityItem stored above. Executing the Execute method on the LaunchActivityItem calls the handleLaunchActivity method on the ActivityThread.

//ActivityThread#handleLaunchActivity
@Override
public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) {...// It's time to call the familiar performLaunchActivity method
    finalActivity a = performLaunchActivity(r, customIntent); . }//ActivityThread#performLaunchActivity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {... ContextImpl appContext = createBaseContextForActivity(r); Activity activity =null;

    / / for this
    java.lang.ClassLoader cl = appContext.getClassLoader();
    
    // Create cl.loadClass(className).newinstance () with (Activity)
    The Activity is created using the ClassLoader in the performLaunchActivity method of the ActivityThread.
    activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
    
    // The underlying Application is also built by reflection. If it is already built, it will not be built again. After all, a process can only have one Application
    Application app = r.packageInfo.makeApplication(false, mInstrumentation);

    if(activity ! =null) {
        Window window = null;
        appContext.setOuterContext(activity);
        // Here the PhoneWindow is instantiated, the Activity is set as the PhoneWindow Callback, and WindowManager is initialized
        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);
                
        // Call the Activity's performCreate method indirectly, and call the Activity's onCreate method indirectly.
        mInstrumentation.callActivityOnCreate(activity, r.state);
        
        // This is similar to the onCreate procedure above, calling the Activity's onStart method
        if(! r.activity.mFinished) { activity.performStart(); r.stopped =false; }... }return activity;
}

Copy the code

The ** Activity is created using the ClassLoader in the performLaunchActivity method of the ActivityThread. Once created, the Activity’s onCreate and onStart methods are called.

For drawing the View after the Activity is created, see here

reference

  • Launcher3 – Launcher3 person
  • App launch process (including the Activity start) | android offers harvest
  • Android App startup Process: process.start (3)
  • Android9.0 Activity Startup Process (2)
  • Android Render(a)Activity window structure and rendering parsing