Based on the Android11 – API30

The overview

  1. Get applicationThread and AMS

  2. When attach is attached, the obtained applicationThread object is also passed to the AMS process, requesting a remote call to notify the AMS Application process that it wants to create an Application, at which point AMS is the server

  3. AMS receives a message requesting a call to the remote interface of applicationThread, in which case AMS is the client

  4. ApplicationThread receives the AMS request and initiates the process of creating the Application through the Handler. There are no further remote interface calls

  5. Create an instance of the Application with reflection, and start the onCreate method of the Application with Instrumentation

Detailed process analysis

Start with activityThread. Java’s main method;

public static void main(String[] args) {... ActivityThread thread =new ActivityThread();
    thread.attach(system=false, startSeq);/ / 1. }Copy the code

Enter attach method;

if(! system){final IActivityManager mgr = ActivityManager.getService();
    try {
        mgr.attachApplication(mAppThread, startSeq);/ / 1
    } catch (RemoteException ex) {
        throwex.rethrowFromSystemServer(); }}Copy the code

Non-system application flow, as can be inferred from getSeervice and captured RemoteException, where Binder is used for remote interface calls.

Turn around and see what mAppThread is.

final ApplicationThread mAppThread = new ApplicationThread();

private class ApplicationThread extends IApplicationThread.Stub {
    // Batch schedule* interfaces, such as scheduleReceiver and scheduleCreateService
    public final void schedule*
    
    //TODO key method
    public final void bindApplication(some args){}/ / 1
    
    // A bunch of dump methods, such as dumpMemory, dumpActivity, etc
    
}

Copy the code

As you can see, ApplicationThread is a Binder client that implements the remote interface. The inner wrapper implements many of the remote interfaces. The bindService keyword is not found, but the client should already be connected to the corresponding Service. It should be started during application process startup in the Runtimeinit. Java class.

Come back look at the instance of the previous step services IActivityManager. AttachApplication () the internal implementation.

1.Obtain an INSTANCE of AMS first, and obtain the AMS instance code as in the Activity startup processpublic 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; }}; . Access to AMS Binder, continue to view the ActivityManagerService. AttachApplication methods in Javapublic final void attachApplication(IApplicationThread thread, long startSeq) {
    
   	synchronized (this) {
        int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
        attachApplicationLocked(thread, callingPid, callingUid, startSeq); / / 1Binder.restoreCallingIdentity(origId); }}Copy the code

A singleton obtains an AMS instance. The AMS service has been registered with a ServiceManager since system startup. The ServiceManager manages registered servers as a Binder pool.

AttachApplicationLocked AMS access attachApplicationLocked and find the code that can be read. Follow the thread argument to view the code.

private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
            int pid, int callingUid, long startSeq) {

    try {
        AppDeathRecipient adr = new AppDeathRecipient(
                app, pid, thread);
        thread.asBinder().linkToDeath(adr, 0);/ / 1
        app.deathRecipient = adr;
    } catch (RemoteException e) {
        app.resetPackageList(mProcessStats);
        mProcessList.startProcessLocked(app,
                new HostingRecord("link fail", processName),
                ZYGOTE_POLICY_FLAG_EMPTY);
        return false;
    }

    final ActiveInstrumentation instr2 = app.getActiveInstrumentation();

    if(instr2 ! =null) {/ / 2thread.bindApplication(processName, appInfo, providerList, instr2.mClass, profilerInfo, instr2.mArguments, instr2.mWatcher, instr2.mUiAutomationConnection, testMode, mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || ! normalMode, app.isPersistent(),new Configuration(app.getWindowProcessController().getConfiguration()),
                app.compat, getCommonServicesLocked(app.isolated),
                mCoreSettingsObserver.getCoreSettingsLocked(),
                buildSerial, autofillOptions, contentCaptureOptions,
                app.mDisabledCompatChanges);
    } else {
        thread.bindApplication(processName, appInfo, providerList, null, profilerInfo,
                null.null.null, testMode, mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || ! normalMode, app.isPersistent(),newConfiguration(app.getWindowProcessController().getConfiguration()), app.compat, getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial, autofillOptions, contentCaptureOptions, app.mDisabledCompatChanges); }}Copy the code

Bind death proxies to ApplicationThread. Bind death proxies to ApplicationThread. Bind death proxies to ApplicationThread.

This calls the Thread. bindApplication interface, which we saw when we looked at ApplicationThread.

private class ApplicationThread extends IApplicationThread.Stub {
    // Batch schedule* interfaces, such as scheduleReceiver and scheduleCreateService
    public final void schedule*
    
    //TODO key method
    public final void bindApplication(some args){
        AppBindData data = newAppBindData(); . A bunch of arguments sendMessage(h.bin_application, data);/ / 1
    }
    
    // A bunch of dump methods, such as dumpMemory, dumpActivity, etc
    
}
Copy the code

After encapsulating a bunch of parameters, the Handler object H sends a BIND_APPLICATION message. Let’s see where the message goes, and directly follow up the capture location of the BIND_APPLICATION message.

// Message distribution
class H extends Handler{
    public void handleMessage(Message msg){
        swich(msg.what){
            case BIND_APPLICATION: 
                AppBindData data = (AppBindData)msg.obj;
                handleBindApplication(data);/ / 1
                break; . Omit}}}Copy the code

Enter the message distribution processing method, this method is relatively long, pay attention to read can understand the code, not very well, track the processing of data.

private void handleBindApplication(AppBindData data) {
    // Various initializations such as process name, application name, AsyncTask thread pool configuration, time zone, network discovery
    
    //Context initialization
    final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
    
    try {
        final ClassLoader cl = instrContext.getClassLoader();
        mInstrumentation = (Instrumentation)/ / 1
            cl.loadClass(data.instrumentationName.getClassName()).newInstance();
    } catch (Exception e) {
        throw new RuntimeException(
            "Unable to instantiate instrumentation "
            + data.instrumentationName + ":" + e.toString(), e);
    }
    
    final ComponentName component = new ComponentName(ii.packageName, ii.name);
    mInstrumentation.init(this, instrContext, appContext, component,/ / 1data.instrumentationWatcher, data.instrumentationUiAutomationConnection); . Application app; app = data.info.makeApplication(data.restrictedBackupMode,null);/ / 2

    mInstrumentation.onCreate(data.instrumentationArgs);
    mInstrumentation.callApplicationOnCreate(app);/ / 3
}
Copy the code

The reflection instantiates the mInstrumentation object, which is the butler of the Android system components and currently controls the lifecycle of the Application and Activity.

Create the Application object and go in and look at the created code

//LoadApk.java #makeApplication
public Application makeApplication(boolean forceDefaultAppClass,
    Instrumentation instrumentation){... app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);/ / 1appContext.setOuterContext(app); . }//Instrumentation.java #newApplication
public Application newApplication(ClassLoader cl, String className, Context context)
        throws InstantiationException, IllegalAccessException, 
        ClassNotFoundException {
    Application app = getFactory(context.getPackageName())
            .instantiateApplication(cl, className);/ / 2
    app.attach(context);// First call back to the attachBaseContext method
    return app;
}

//AppComponentFactory #instantiateApplication
public @NonNull Application instantiateApplication(@NonNull ClassLoader cl,
        @NonNull String className)
        throws InstantiationException, IllegalAccessException, ClassNotFoundException {
    return (Application) cl.loadClass(className).newInstance();/ / 3
}
Copy the code

You can see that the Application is finally initialized by reflection.

The onCreate method of the Application class is finally called via the mInstrumentation object.

mInstrumentation.callApplicationOnCreate(app);/ / 1

//Instrumentation.java #callApplicationOnCreate
public void callApplicationOnCreate(Application app) {
    app.onCreate();
}

Copy the code