The article shows you how the startup process of Android Application is

  • 2021-12-21 05:08:28
  • OfStack

Based on Android11-API30

Overview

When obtaining two Binder2.attach, applicationThread and AMS, the obtained applicationThread object is also passed to the AMS process, and the remote call is requested to inform the AMS application process that it wants to create Application, and AMS is the server at this time AMS receives a message requesting to invoke the remote interface of applicationThread, at which point AMS is the client applicationThread receives the request from AMS, initiates the processing task of creating Application through Handler, and then there is no remote interface call Create an instance of Application through reflection, and start the onCreate method of Application through Instrumentation

Detailed process analysis

From the main method of ActivityThread. java;


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

Enter attach Methods;


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

Non-system application flow, according to getSeervice and captured RemoteException, it can be concluded that Binder is used for remote interface call here.
Turn around and see what mAppThread is.


final ApplicationThread mAppThread = new ApplicationThread();

private class ApplicationThread extends IApplicationThread.Stub {
    // Batch schedule* Interfaces, such as scheduleReceiver , scheduleCreateService Etc 
    public final void schedule*
    
    //TODO  Key methods 
    public final void bindApplication(some args){}//1
    
    //1 Heap dump Methods, such as dumpMemory , dumpActivity Etc 
    
}

As you can see, ApplicationThread is an Binder client that implements remote interfaces, and many remote interfaces are implemented in internal encapsulation. However, it is not known when this client will connect to the server, and the bindService keyword has not been found. Anyway, the corresponding Service should have been connected at this time. It should be started when the application process starts in the RuntimeInit. java class.

Back to the internal implementation of the instance IActivityManager. attachApplication () of the previous step service.

First, get the instance of AMS. Here, get the instance code of AMS and 1 in the startup process of Activity


public static IActivityManager getService() {
    return IActivityManagerSingleton.get();
}
private static final Singleton<IActivityManager> IActivityManagerSingleton =
        new Singleton<IActivityManager>() {
            @Override
            protected IActivityManager create() {
                final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                final IActivityManager am = IActivityManager.Stub.asInterface(b);
                return am;
            }
        };

... After obtaining Binder for AMS, continue to view the attachApplication method in ActivityManagerService. java


public 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); //1
        Binder.restoreCallingIdentity(origId);
    }
}

The AMS instance is obtained by a single case, and the AMS service has been registered to ServiceManager when the system starts. Here, it is enough to obtain the Binder instance directly, and ServiceManager manages the registered Server in the way of Binder pool.

AMS attachApplication method into the attachApplicationLocked method, pick up the code to see, follow the thread parameters to see 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) {//2
        thread.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(),
                new Configuration(app.getWindowProcessController().getConfiguration()),
                app.compat, getCommonServicesLocked(app.isolated),
                mCoreSettingsObserver.getCoreSettingsLocked(),
                buildSerial, autofillOptions, contentCaptureOptions,
                app.mDisabledCompatChanges);
    }

}

First, give ApplicationThread, Binder, a death agent. According to this death agent, we should be able to find out how the corresponding Service is restarted. If we are interested, we can continue to go further. Let's continue to go down.
The interface thread. bindApplication is called here. We saw it when we looked at ApplicationThread earlier, so we cut in directly.


private class ApplicationThread extends IApplicationThread.Stub {
    // Batch schedule* Interfaces, such as scheduleReceiver , scheduleCreateService Etc 
    public final void schedule*
    
    //TODO  Key methods 
    public final void bindApplication(some args){
        AppBindData data = new AppBindData();
        ...1 Heap parameter 
        sendMessage(H.BIND_APPLICATION, data);//1
    }
    
    //1 Heap dump Methods, such as dumpMemory , dumpActivity Etc 
    
}

We have reached a familiar point for Android development engineers. After encapsulating a pile of parameters, we sent an BIND_APPLICATION message through H, an Handler object. Let's see where this message went and directly follow up the capture location of BIND_APPLICATION.


// 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;
            ... Omission 
        }
    }
}

Enter the message distribution processing method, this method is relatively long, pay attention to read the code that can be understood, do not ask for a good understanding, 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 of 
    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,//1
            data.instrumentationWatcher, data.instrumentationUiAutomationConnection);
            
    ...
    Application app;
    app = data.info.makeApplication(data.restrictedBackupMode, null);//2

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

Instantiate the mInstrumentation object through reflection, which is the housekeeper of Android system components and can control the life cycle of Application and Activity at present.

To create an Application object, 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);//1
    appContext.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);// Callback first 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
}

It can be seen that Application is finally initialized by reflection.

Finally, the onCreate method of Application class is called by mInstrumentation object.


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

Related articles: