The main methods of ActivityThread when creating applications with cold start are:
- main()
-- 1. Open the message loop
- 2. Notify Activity Manager Service
3. Add GC Watcher - handleBindApplication()
Create Loaded Apk
Create Instrumentation
Create Application
-- 4. Call the onCreate() method of Application through Instrumentation
main()
The main method is an entry point for application creation. It does three main things.
1. Open the message loop
Call Looper.prepareLoop() Looper.loop() to open the message loop of the main thread so that Application Thread can call the lifecycle method in ActivityThread.
public static void main(String[] args) { ... Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } ... Looper.loop(); }
2. Notify Activity Manager Service
Call the ActivityThread.attach() method, attach() method in the call attachApplication() will apply Thread this Binder to the ActivityManager Service, which means that ActivityManager Service can control our application through Application Thread, and establish a server-to-client communication channel.
private void attach(boolean system){ ... final IActivityManager mgr = ActivityManager.getService(); try { mgr.attachApplication(mAppThread); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } ... }
After SDK26, Native and Proxy are removed and Binder objects of Activity Manager Service are obtained directly from Activity Manager (Service Manager) for communication.
3. Add GC Watcher
In attach() method, GcWatcher is added to monitor dialvik memory usage. When the memory usage exceeds 3/4 of the total capacity, Log is printed to record, and release SomeActivities () of Activity Manager Service is called for memory release operation to prevent memory overflow from causing application crash.
private void attach(boolean system){ ... BinderInternal.addGcWatcher(new Runnable() { @Override public void run() { if (!mSomeActivitiesChanged) { return; } Runtime runtime = Runtime.getRuntime(); long dalvikMax = runtime.maxMemory(); long dalvikUsed = runtime.totalMemory() - runtime.freeMemory(); if (dalvikUsed > ((3*dalvikMax)/4)) { if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024) + " total=" + (runtime.totalMemory()/1024) + " used=" + (dalvikUsed/1024)); mSomeActivitiesChanged = false; try { mgr.releaseSomeActivities(mAppThread); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } }); ... }
handleBindApplication()
ActivityManagerService=AMS
handleBindApplication is called when:
- With AMS.attachApplication() above, AMS obtains the Binder object ApplicationThread that controls the application.
- After a series of operations (omitted here), AMS calls the bindApplication() of ApplicationThread.
- In bindApplication, the handleBindApplication() of ActivityThread is invoked by sendMessage to ActivityThread via message mechanism.
HandleBind Application is the gateway for creating the required components. It does four main things:
1. Create Loaded Apk
The LoadedApk object contains all the information about the application.
private void handleBindApplication(AppBindData data){ ... final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo, appContext.getClassLoader(), false, true, false); ... }
2. Create Instrumentation
Instrumentation is the housekeeper of application components. The lifecycle methods of components need to be invoked through it, which is the last step of communication between client and server.
private void handleBindApplication(AppBindData data){ ... final ContextImpl instrContext = ContextImpl.createAppContext(this, pi); try { final ClassLoader 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); } ... }
3. Create Application
LoadedApk.makeApplication() is called to create the Application
private void handleBindApplication(AppBindData data){ ... app = data.info.makeApplication(data.restrictedBackupMode, null); ... }
- Get the Content of the Application first through ContextImpl.createAppContext()
- Using Instrumentation.newApplication(), create Application with ClassLoder
- After creation, Applicaition calls its attach(Context) method, binds Context to Applicaition, and completes the creation.
LoadedApk.class public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) { ... Application app = null; ... ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this); app = mActivityThread.mInstrumentation.newApplication( cl, appClass, appContext); ... return app; }
4. Call the onCreate() method of Application through Instrumentation
private void handleBindApplication(AppBindData data){ ... mInstrumentation.callApplicationOnCreate(app); ... }