Read Android Source - Activity Thread at Cold Start

 

The main methods of ActivityThread when creating applications with cold start are:

  1. main()
    -- 1. Open the message loop
    - 2. Notify Activity Manager Service
    3. Add GC Watcher
  2. 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:

  1. With AMS.attachApplication() above, AMS obtains the Binder object ApplicationThread that controls the application.
  2. After a series of operations (omitted here), AMS calls the bindApplication() of ApplicationThread.
  3. 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);
    ...
}

 

Keywords: Mobile

Added by Cinquecento on Fri, 21 Jun 2019 04:11:24 +0300