This article analyzes the source code based on Android30

Sequence diagram of code execution

Starts with the main() method

The action of launching an APP by clicking an icon is to start a process, which in the Java world starts with the main method. The MAIN method in the SDK is in the class ActivityThread.

[1]

android.app.ActivityThread public static void main(String[] args) { ...... Looper.prepareMainLooper(); . ActivityThread thread = new ActivityThread(); thread.attach(false, startSeq); . Looper.loop(); .Copy the code

Create an ActivityThread instance and invoke the Attach method

[2]

android.app.ActivityThread private void attach(boolean system, long startSeq){ ...... final IActivityManager mgr = ActivityManager.getService(); try { mgr.attachApplication(mAppThread, startSeq); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); }... }Copy the code

Here mention ActivityManager. GetService () before 28 (maybe sooner) code for performance

ActivityManagerNative.getDefault()
Copy the code

Get an instance of ActivityManagerService using AIDL. Look at the getService() method in the ActivityManager class

[3]

android.app.ActivityManager @UnsupportedAppUsage public static IActivityManager getService() { return IActivityManagerSingleton.get(); } @UnsupportedAppUsage 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; }};Copy the code

Stub returns an iActivityManager. Stub type, and the ActivityManagerService class does inherit iActivityManager.stub, This alone does not determine ActivityManager. GetService () must be returned to the ActivityManagerService, though other articles online said here who is familiar with the AIDL will look see.. I didn’t get it anyway, but when I make sure that ActivityManagerService does have attachApplication under it, I can confirm that the thread. In the attach ActivityManager. GetService () returns is ActivityManagerService types.

ActivityManagerService starts to work

[4]

com.android.server.am.ActivityManagerService public class ActivityManagerService extends IActivityManager.Stub implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { ...... @Override public final void attachApplication(IApplicationThread thread, long startSeq) { if (thread == null) { throw new SecurityException("Invalid application interface"); } synchronized (this) { int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); AttachApplicationLocked (Thread, callingPid, callingUid, startSeq); Binder.restoreCallingIdentity(origId); }}... }Copy the code

In the attachApplication method, the first argument is the type IApplicationThread. The implementation class is ApplicationThread, which is an inner class of ActivityThread

private class ApplicationThread extends IApplicationThread.Stub {
        ......
}
Copy the code

ApplicationThread is the key class, internally responsible for sending the Activity lifecycle and other messages last. By the way, there is another key inner class H in ActivityThread

class H extends Handler { public static final int BIND_APPLICATION = 110; @UnsupportedAppUsage public static final int EXIT_APPLICATION = 111; .Copy the code

This H is a Handler, which is inside the four components of Android, including all the handlers of other important processes. The messages sent by ApplicationThread are finally processed in H as well.

Go back to [2] and see

 mgr.attachApplication(mAppThread, startSeq);
Copy the code

MAppThread is a member variable of ActivityThread and is final. This indicates that the system does not want this variable to be modified. So this variable has a very specific and very important function.

@UnsupportedAppUsage
   final ApplicationThread mAppThread = new ApplicationThread();
Copy the code

Continuing [4], attachApplicationLocked is executed

com.android.server.am.ActivityManagerService @GuardedBy("this") private boolean attachApplicationLocked(@NonNull IApplicationThread thread, int pid, int callingUid, long startSeq) { ...... 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); . }Copy the code

This method is long, but the key code is to execute the bindApplication method in ApplicationThread.

ActivityThread ->ActivityManagerService->ApplicationThread ->ApplicationThread ->ActivityManagerService->ApplicationThread

Copy the code

package android.app;

ApplicationThread message

[5]

android.app.ApplicationThread @Override public final void bindApplication(String processName, ApplicationInfo appInfo, ProviderInfoList providerList, 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, AutofillOptions autofillOptions, ContentCaptureOptions contentCaptureOptions, long[] disabledCompatChanges) { ...... Key code sendMessage(H.Bind_application, data); }Copy the code

So a message is sent to h. bind_application, and we will see how H handles the message when it receives it.

Big brother H

android.app.ApplicationThread ...... class H extends Handler { ...... public void handleMessage(Message msg) { ...... switch (msg.what) { case BIND_APPLICATION: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,"bindApplication"); AppBindData data = (AppBindData)msg.obj; Key code handleBindApplication(data); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; . } } @UnsupportedAppUsage private void handleBindApplication(AppBindData data) { ...... Try {1 through reflection for Instrumentation final this cl = instrContext. GetClassLoader (); mInstrumentation = (Instrumentation) cl.loadClass(data.instrumentationName.getClassName()).newInstance(); } catch (Exception e) { throw new RuntimeException( "Unable to instantiate instrumentation " + data.instrumentationName + ": " + e.toString(), e); }... Application app; . try { // If the app is being launched for full backup or restore, bring it up in // a restricted environment with the base application class. 2. Create Application (internal reflection) app = data. Info. MakeApplication (data restrictedBackupMode, null); Try {3. Create Application mInstrumentation. CallApplicationOnCreate (app); } catch (Exception e) { if (! mInstrumentation.onException(app, e)) { throw new RuntimeException( "Unable to create application " + app.getClass().getName() + ": " + e.toString(), e); } } }finally { ...... }}... }Copy the code
  • The Instrumentation class is an important class for monitoring application interactions with the system. Appilcation, Activityd creation and lifecycle control are also here

The process is also quite clear. In 1 place, the Instrumentation class instance is obtained by reflection, and in 2 places, the Application instance is obtained by reflection. The callApplicationOnCreate method in Instrumentation is invoked to initialize the Application

Instrumentation monitors application interactions with the system

Let’s start with the callApplicationOnCreate method

android.app.Instrumentation

public void callApplicationOnCreate(Application app) {
        app.onCreate();
    }
Copy the code

Simply call Application’s onCreate() to do the initialization. The remaining question is how to create the Application in the second step. This data is the only argument to the handleBindApplication method. You can see that it is of type AppBindData, so go to this class and see what type its info is to find out the actual execution of the makeApplication method.

android.app.ActivityThread ...... static final class AppBindData { @UnsupportedAppUsage AppBindData() { } @UnsupportedAppUsage LoadedApk info; . }Copy the code

This is also an inner class of ActivityThread. You can see that info is of type LoadedApk. Go ahead and find the makeApplication method

android.app.LoadedApk @UnsupportedAppUsage public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) { ...... app = mActivityThread.mInstrumentation.newApplication( cl, appClass, appContext); . return app; }Copy the code

Familiar with Instrumentation, it now appears that Application creation and initialization are handled in Instrumentation.

android.app.Instrumentation public Application newApplication(ClassLoader cl, String className, Context context) throws InstantiationException, IllegalAccessException, ClassNotFoundException {keycode Application app = getFactory(context.getPackagename ()).instantiateApplication(cl, className); app.attach(context); return app; } private AppComponentFactory getFactory(String pkg) { ...... LoadedApk apk = mThread.peekPackageInfo(pkg, true); // This is in the case of starting up "android". if (apk == null) apk = mThread.getSystemContext().mPackageInfo; return apk.getAppFactory(); Returns an AppComponentFactory}Copy the code

As you can see, it is the instantiateApplication return in the AppComponentFactory that completes the instantiateApplication creation

android.app.AppComponentFactory

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

The Application is created by reflection as well as by creating Instrumentation

At this point, the Application is created and initialized. When the Application is initialized, the system sends an Intent to start the corresponding Activity with the specified start Activity in the Manifests.

conclusion

  1. Create an ActivityThread instance in the main method of the ActivityThread class and call the attach method
  2. The Attach method retrieves the ActivityManagerService instance in AIDL mode, and uses attachApplication to transfer the ApplicationThread instance to the ActivityManagerService for processing
  3. The attachApplication method internally calls the bindApplication method of the ApplicationThread through the attachApplicationLocked method, and the process is transferred to the ApplicationThread
  4. The bindApplication method internally sends the message H.bind_application, and the process goes to H
  5. In H, the handling of the H. bind_application message is handleBindApplication, which obtains Instrumentation and Application instances internally through reflection, Finally, use the callApplicationOnCreate method in Instrumentation to initialize the Application

After the speech

  1. Why is so much code omitted from the code, leaving only key lines. Because there is so much code, it is difficult to copy it all to find the point, and the reader will get visual fatigue. Secondly, the length will also be the process.

  2. A method is so long why you can find the key code. It wasn’t that I was able to find the key code, it was that I was standing on the shoulders of giants, reading through the material, figuring out the main flow. So you can also find key points in the new Android30. For ignored code. I don’t know what most of it means, and I don’t want to. Too much attention to detail will lead to “lost”.