Small knowledge, big challenge! This paper is participating in theEssentials for programmers”Creative activities

The startup entry class for your App is ActivityThread

ActivityThread is not a thread but a handler class

public final class ActivityThread extends ClientTransactionHandler
Copy the code

The ActivityThread class has a main function that is the entry point to the entire program

public static void main(String[] args) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain"); // Install selective syscall interception AndroidOs.install(); // CloseGuard defaults to true and can be quite spammy. We // disable it here, but selectively enable it later (via // StrictMode) on debug builds, but using DropBox, not logs. CloseGuard.setEnabled(false); Environment.initForCurrentUser(); // Make sure TrustedCertificateStore looks in the right place for CA certificates final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId()); TrustedCertificateStore.setDefaultUserDirectory(configDir); // Call per-process mainline module initialization. initializeMainlineModules(); Process.setArgV0("<pre-initialized>"); PrepareMainLooper (); // Initialize the looper object in handler looper.prepareMainLooper (); // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line. // It will be in the format "seq=114" long startSeq = 0; if (args ! = null) { for (int i = args.length - 1; i >= 0; --i) { if (args[i] ! = null && args[i].startsWith(PROC_START_SEQ_IDENT)) { startSeq = Long.parseLong( args[i].substring(PROC_START_SEQ_IDENT.length())); ActivityThread thread = new activityThread (); thread.attach(false, startSeq); If (sMainThreadHandler == null) {sMainThreadHandler = thread.gethandler (); } if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } // End of event ActivityThreadMain. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); // Start messageQueue looper.loop (); throw new RuntimeException("Main thread loop unexpectedly exited"); }Copy the code

There are several important classes in ActivityThread:

ApplicationThread The ApplicationThread is the bridge to AMS and acts as a server that receives and executes instructions from ActivityManagerService. Instrumentation is the class that really manages the Application and Activity lifecycleCopy the code

Looper.prepareMainLooper(); The loop object is initialized to not exit

@deprecated public static void prepareMainLooper() {prepare(false); synchronized (Looper.class) { if (sMainLooper ! = null) { throw new IllegalStateException("The main Looper has already been prepared."); } // assign the main thread to sMainLooper sMainLooper = myLooper(); }}Copy the code

Create ActivityThread:

    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);
Copy the code
private void attach(boolean system, long startSeq) { ... RuntimeInit.setApplicationObject(mAppThread.asBinder()); // Get the proxy object for ActivityManagerService (IActivityManager is a // interface, Specific implementation class is ActivityManagerService) final IActivityManager MGR. = ActivityManager getService (); try { mgr.attachApplication(mAppThread, startSeq); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); }... }Copy the code
Protected IActivityManager create() {// Process communication with binder mechanism From the android service final IBinder b = ServiceManager. GetService (Context. ACTIVITY_SERVICE); / / access to AMS proxy object final IActivityManager am = IActivityManager. The Stub. AsInterface (b); return am; }Copy the code

Call attachApplication in AMS

public final void attachApplication(IApplicationThread thread, long startSeq) { if (thread == null) { throw new SecurityException("Invalid application interface"); 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
private boolean attachApplicationLocked(@NonNull IApplicationThread thread, int pid, int callingUid, Long startSeq) {// ProcessRecord app; long startTime = SystemClock.uptimeMillis(); long bindApplicationTimeMillis; if (pid ! = MY_PID && pid >= 0) { synchronized (mPidsSelfLocked) { app = mPidsSelfLocked.get(pid); } if (app ! = null && (app.startUid ! = callingUid || app.startSeq ! = startSeq)) { String processName = null; final ProcessRecord pending = mProcessList.mPendingStarts.get(startSeq); if (pending ! = null) { processName = pending.processName; } final String msg = "attachApplicationLocked process:" + processName + " startSeq:" + startSeq + " pid:" + pid + " belongs to another existing app:" + app.processName + " startSeq:" + app.startSeq; Slog.wtf(TAG, msg); // SafetyNet logging for b/131105245. EventLog.writeEvent(0x534e4554, "131105245", app.startUid, msg); // If there is already an app occupying that pid that hasn't been cleaned up cleanUpApplicationRecordLocked(app, false, false, -1, true /*replacingPid*/); removePidLocked(app); app = null; } } else { app = null; }... 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 (instr2 ! = null) {/ / call activityThread bindApplication method inside 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); } if (profilerInfo ! = null) { profilerInfo.closeFd(); profilerInfo = null; }}Copy the code

The ActivityThread bindApplication

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) { ... AppBindData data = new AppBindData(); data.processName = processName; data.appInfo = appInfo; data.providers = providerList.getList(); data.instrumentationName = instrumentationName; data.instrumentationArgs = instrumentationArgs; data.instrumentationWatcher = instrumentationWatcher; data.instrumentationUiAutomationConnection = instrumentationUiConnection; data.debugMode = debugMode; data.enableBinderTracking = enableBinderTracking; data.trackAllocation = trackAllocation; data.restrictedBackupMode = isRestrictedBackupMode; data.persistent = persistent; data.config = config; data.compatInfo = compatInfo; data.initProfilerInfo = profilerInfo; data.buildSerial = buildSerial; data.autofillOptions = autofillOptions; data.contentCaptureOptions = contentCaptureOptions; data.disabledCompatChanges = disabledCompatChanges; sendMessage(H.BIND_APPLICATION, data); }Copy the code

HandleMessage handles this message

public void handleMessage(Message msg) { switch (msg.what) { case BIND_APPLICATION: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication"); AppBindData data = (AppBindData)msg.obj; handleBindApplication(data); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; . }}Copy the code

The logic of handleBindApplication

private void handleBindApplication(AppBindData data) { ... Try {/ / by reflecting initialization mInstrumentation 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; final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites(); final StrictMode.ThreadPolicy writesAllowedPolicy = StrictMode.getThreadPolicy(); Try {/ / to create Application app = data. Info. MakeApplication (data restrictedBackupMode, null); // Propagate autofill compat state app.setAutofillOptions(data.autofillOptions); // Propagate Content Capture options app.setContentCaptureOptions(data.contentCaptureOptions); mInitialApplication = app; // don't bring up providers in restricted mode; they may depend on the // app's custom Application class if (! data.restrictedBackupMode) { if (! ArrayUtils.isEmpty(data.providers)) { installContentProviders(app, data.providers); } } // Do this after providers, since instrumentation tests generally start their // test thread at this point, and we don't want that racing. try { mInstrumentation.onCreate(data.instrumentationArgs); } catch (Exception e) { throw new RuntimeException( "Exception thrown in onCreate() of " + data.instrumentationName + ":  " + e.toString(), e); } try { 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 { // If the app targets < O-MR1, or doesn't change the thread policy // during startup, clobber the policy to maintain behavior of b/36951662 if (data.appInfo.targetSdkVersion < Build.VERSION_CODES.O_MR1 || StrictMode.getThreadPolicy().equals(writesAllowedPolicy)) { StrictMode.setThreadPolicy(savedPolicy); }}... }Copy the code

Call makeApplication in LoaderApk

public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) { if (mApplication ! = null) { return mApplication; } Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication"); Application app = null; String appClass = mApplicationInfo.className; if (forceDefaultAppClass || (appClass == null)) { appClass = "android.app.Application"; } try { final java.lang.ClassLoader cl = getClassLoader(); if (! mPackageName.equals("android")) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "initializeJavaContextClassLoader"); initializeJavaContextClassLoader(); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } // Rewrite the R 'constants' for all library apks. SparseArray<String> packageIdentifiers = getAssets().getAssignedPackageIdentifiers( false, false); for (int i = 0, n = packageIdentifiers.size(); i < n; i++) { final int id = packageIdentifiers.keyAt(i); if (id == 0x01 || id == 0x7f) { continue; } rewriteRValues(cl, packageIdentifiers.valueAt(i), id); } ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this); // The network security config needs to be aware of multiple // applications in the same process to handle discrepancies  NetworkSecurityConfigProvider.handleNewApplication(appContext); app = mActivityThread.mInstrumentation.newApplication( cl, appClass, appContext); appContext.setOuterContext(app); } catch (Exception e) { if (! mActivityThread.mInstrumentation.onException(app, e)) { Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); throw new RuntimeException( "Unable to instantiate application " + appClass + ": " + e.toString(), e); } } mActivityThread.mAllApplications.add(app); mApplication = app; if (instrumentation ! = null) { try { instrumentation.callApplicationOnCreate(app); } catch (Exception e) { if (! instrumentation.onException(app, e)) { Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); throw new RuntimeException( "Unable to create application " + app.getClass().getName() + ": " + e.toString(), e); } } } Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); return app; }Copy the code

The Instrumentation

public Application newApplication(ClassLoader cl, String className, Context context)
        throws InstantiationException, IllegalAccessException, 
        ClassNotFoundException {
    Application app = getFactory(context.getPackageName())
            .instantiateApplication(cl, className);
    app.attach(context);
    return app;
}
Copy the code

Create an application in the AppComponentFactory class

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

Go back to the ActivityThread class

try {
    mInstrumentation.onCreate(data.instrumentationArgs);
}
Copy the code

The startup of AppliAction is now complete.