App process Application creation, start-up process source code analysis (Android P)

On the user's mobile phone, the launch of an App is usually started by the user clicking the icon on the Launcher. Where is the starting point when the app starts? How is the Application object created?

Next, we analyze the specific implementation process through the source code of Android P and solve our doubts.

Process startup process and application object creation process analysis

An App system initiates a startup command until it starts up. Its first step is to start a process corresponding to an App, which carries the business we will run.

ActivityThread's main () method and attach () method

ActivityThread is a very important class in our Android system, it also represents the main thread corresponding to the operation of our App. Then a process starts from the main function of ActivityThread class.

Code location: /frameworks/base/core/java/android/app/ActivityThread.java

Entry function main

ActivityThread is a very important class during App startup and operation. The main method of ActivityThread is the entry method of App, and ActivityThread represents the main thread or UI thread of App.

    public static void main(String[] args) {
        ……
        Process.setArgV0("<pre-initialized>"); //设置进程参数

        Looper.prepareMainLooper();

        ……
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        ……
        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

Mainly carried out the following operations:

  1. Initialize MainLooper.
  2. Create an ActivityThread instance object and call the attach instance method.
  3. Initialize the Handler of the main thread and assign it to the sMainThreadHandler attribute.
  4. The main process enters Looper loop.

After the main method is executed, the process of the App has a main thread that has MainLooper and has entered the Looper loop to listen. The ActivityThread object has also been created and initialized accordingly, and the Handler of the main thread has also been initialized, ready to accept messages at any time and perform message processing.

ActivityThread constructor

When the ActivityThread constructor is called, the ResourcesManager object is initialized.

    ActivityThread() {
        mResourcesManager = ResourcesManager.getInstance();
    }

ActivityThread attach method

Attach method of ActivityThread:

    private void attach(boolean system, long startSeq) {
        sCurrentActivityThread = this;
        mSystemThread = system; //是否是系统进程,我们的App这个值是false
        if (!system) {
            ViewRootImpl.addFirstDrawHandler(new Runnable() {
                @Override
                public void run() {
                    ensureJitEnabled();
                }
            });
            android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                    UserHandle.myUserId());
            RuntimeInit.setApplicationObject(mAppThread.asBinder());//ApplicationThread的binder对象,用于通信
            final IActivityManager mgr = ActivityManager.getService();//获取AMS服务
            try {
                mgr.attachApplication(mAppThread, startSeq);//远程调用AMS服务的attachApplication来启动一个Application
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
            // Watch for getting close to heap limit. 注册GC检测器,当可用内存较低时,清理隐藏Activity
            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); //执行隐藏Activity栈的内存清理
                        } catch (RemoteException e) {
                            throw e.rethrowFromSystemServer();
                        }
                    }
                }
            });
        } else {
            // Don't set application object here -- if the system crashes,
            // we can't display an alert, we just want to die die die.
            android.ddm.DdmHandleAppName.setAppName("system_process",
                    UserHandle.myUserId());
            try {
                mInstrumentation = new Instrumentation();
                mInstrumentation.basicInit(this);
                ContextImpl context = ContextImpl.createAppContext(
                        this, getSystemContext().mPackageInfo);
                mInitialApplication = context.mPackageInfo.makeApplication(true, null);
                mInitialApplication.onCreate();
            } catch (Exception e) {
                throw new RuntimeException(
                        "Unable to instantiate Application():" + e.toString(), e);
            }
        }

        // add dropbox logging to libcore
        DropBox.setReporter(new DropBoxReporter());

        ViewRootImpl.ConfigChangedCallback configChangedCallback
                = (Configuration globalConfig) -> {
            synchronized (mResourcesManager) {
                // We need to apply this change to the resources immediately, because upon returning
                // the view hierarchy will be informed about it.
                if (mResourcesManager.applyConfigurationToResourcesLocked(globalConfig,
                        null /* compat */)) {
                    updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
                            mResourcesManager.getConfiguration().getLocales());

                    // This actually changed the resources! Tell everyone about it.
                    if (mPendingConfiguration == null
                            || mPendingConfiguration.isOtherSeqNewer(globalConfig)) {
                        mPendingConfiguration = globalConfig;
                        sendMessage(H.CONFIGURATION_CHANGED, globalConfig);
                    }
                }
            }
        };
        ViewRootImpl.addConfigCallback(configChangedCallback);
    }
parameter:

system: whether it is a system process.
startSeq: The value passed through the command line (PROC_START_SEQ_IDENT), the default value is 0.

Logical analysis:
  1. First detect that the process release is a system process, here we focus on non-system processes.
  2. RuntimeInit.setApplicationObject passes the binder object of ApplicationThread to prepare for process communication.
  3. Remotely call attachApplication of AMS service to start an Application, we will focus on the analysis later.
  4. Register the GC detector, when the available memory is low, clean up hidden activities.
  5. ViewRootImpl.ConfigChangedCallback registers configuration change monitoring.

Clean up hidden Activity stack

Let's first look at point 4 above, register the GC detector, and when the available memory is low, clean up the hidden Activity.

Let's analyze its technical realization.

BinderInternal.addGcWatcher registers a GC listener to start the cleanup of the hidden Activity stack when the memory usage reaches a certain percentage to free up more memory.

Let's see how this GC listener is registered to take effect?

1. BinderInternal implementation

/frameworks/base/core/java/com/android/internal/os/BinderInternal.java

    static WeakReference<GcWatcher> sGcWatcher
            = new WeakReference<GcWatcher>(new GcWatcher());
    static ArrayList<Runnable> sGcWatchers = new ArrayList<>();
    static Runnable[] sTmpWatchers = new Runnable[1];
    static long sLastGcTime;
    static final BinderProxyLimitListenerDelegate sBinderProxyLimitListenerDelegate =
            new BinderProxyLimitListenerDelegate();

    static final class GcWatcher {
        @Override
        protected void finalize() throws Throwable {
            handleGc();
            sLastGcTime = SystemClock.uptimeMillis();
            synchronized (sGcWatchers) {
                sTmpWatchers = sGcWatchers.toArray(sTmpWatchers);
            }
            for (int i=0; i<sTmpWatchers.length; i++) {
                if (sTmpWatchers[i] != null) {
                    sTmpWatchers[i].run();
                }
            }
            sGcWatcher = new WeakReference<GcWatcher>(new GcWatcher());
        }
    }

    public static void addGcWatcher(Runnable watcher) {
        synchronized (sGcWatchers) {
            sGcWatchers.add(watcher);
        }
    }

Logical analysis:

Its principle is implemented using the finalize () method. details as follows:

  1. First register a weak reference GcWatcher object, when the GC looks back at the weak reference, it will trigger its finalize () method;
  2. The sTmpWatchers array stores the registered monitors that need to be processed. It is a Runnable array;
  3. In the finalize () method, we traverse the sTmpWatchers array and call the run () method of the Runnable object to execute the listening event;
  4. After the completion of the notification event, the previous GcWatcher object has been collected as garbage, and we need to regenerate a monitoring entry for the next GC.

The condition for performing hidden activity memory cleaning is dalvikUsed> ((3 * dalvikMax) / 4), that is, when the currently used memory is greater than 3/4 of the total memory, the execution conditions are met.

The cleanup is performed by the releaseSomeActivities method of AMS.

2. releaseSomeActivities方法

ActivityManagerService's releaseSomeActivities method:

/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

    @Override
    public void releaseSomeActivities(IApplicationThread appInt) {
        synchronized(this) {
            final long origId = Binder.clearCallingIdentity();
            try {
                ProcessRecord app = getRecordForAppLocked(appInt); //从最近运行App列表中找到对应的ProcessRecord对象
                mStackSupervisor.releaseSomeActivitiesLocked(app, "low-mem"); //执行隐藏Activity栈的清理工作
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
        }
    }

The instance method releaseSomeActivitiesLocked of ActivityStackSupervisor is called here to perform the operation of Activity work stack.

Code location: frameworks / base / services / core / java / com / android / server / am / ActivityStackSupervisor.java

Recycling rules:
  1. For a single stack (TaskRecord) application, all interfaces will not be recycled when in the foreground. Only in the case of multiple stacks, the system will recycle the activity of the invisible stack.
  2. ActivityStack uses maxTasks to ensure that tasks.size () / 4 are cleared at most, and at least one TaskRecord is cleared.

ActivityManagerService's attachApplication () method

The attachApplication () method of ActivityManagerService is the core logic created by Process Application. Let's analyze its implementation process.

The attach method of ActivityThread, remotely call attachApplication of AMS service to start an Application, the parameter here is an instance of ApplicationThread, ApplicationThread class is an internal class of ActivityThread, responsible for Binder communication with services such as AMS

    @Override
    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);
            Binder.restoreCallingIdentity(origId);
        }
    }

The attachApplicationLocked method is called here:

    private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid, int callingUid, long startSeq) {

        // Find the application record that is being attached...  either via
        // the pid if we are running in multiple processes, or just pull the
        // next app record if we are emulating process with anonymous threads.
        ProcessRecord app;
        ……
        //获取进程所对应的ProcessRecord对象。
        if (app == null) {
            ……
            //获取失败,退出进程
            return false;
        }

        // If this application record is still attached to a previous
        // process, clean it up now.
        if (app.thread != null) {//如果该ProcessRecord对象之前attached到了一个进程,则进行清理操作
            handleAppDiedLocked(app, true, true);
        }
        ……
        final String processName = app.processName;
        ……
        //注册Binder死亡监听
        ……
        //以下进行ProcessRecord对象的相关初始化操作
        app.makeActive(thread, mProcessStats);//绑定ApplicationThread对象
        app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;//进程优先级设置
        app.curSchedGroup = app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
        app.forcingToImportant = null;
        updateProcessForegroundLocked(app, false, false);//前台服务相关设置
        app.hasShownUi = false;
        app.debugging = false;
        app.cached = false;
        app.killedByAm = false;
        app.killed = false;


        // We carefully use the same state that PackageManager uses for
        // filtering, since we use this flag to decide if we need to install
        // providers when user is unlocked later
        app.unlocked = StorageManager.isUserKeyUnlocked(app.userId);

        mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);

        ……
        provider相关处理
        ……
        ……
        try {
            ……
            ApplicationInfo appInfo = app.instr != null ? app.instr.mTargetInfo : app.info;
            app.compat = compatibilityInfoForPackageLocked(appInfo);

            ……

            //Build.SERIAL获取,Android P以下可以获取到

            ……
            //Instrumentation处理,多进程的使用同一个Instrumentation(后续进程并入第一个进程)。

            ……
            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 (app.instr != null) {//Instrumentation不为空
                thread.bindApplication(processName, appInfo, providers,
                        app.instr.mClass,
                        profilerInfo, app.instr.mArguments,
                        app.instr.mWatcher,
                        app.instr.mUiAutomationConnection, testMode,
                        mBinderTransactionTrackingEnabled, enableTrackAllocation,
                        isRestrictedBackupMode || !normalMode, app.persistent,
                        new Configuration(getGlobalConfiguration()), app.compat,
                        getCommonServicesLocked(app.isolated),
                        mCoreSettingsObserver.getCoreSettingsLocked(),
                        buildSerial, isAutofillCompatEnabled);
            } else {
                thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
                        null, null, null, testMode,
                        mBinderTransactionTrackingEnabled, enableTrackAllocation,
                        isRestrictedBackupMode || !normalMode, app.persistent,
                        new Configuration(getGlobalConfiguration()), app.compat,
                        getCommonServicesLocked(app.isolated),
                        mCoreSettingsObserver.getCoreSettingsLocked(),
                        buildSerial, isAutofillCompatEnabled);
            }
            ……
            checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
            updateLruProcessLocked(app, false, null);
            checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked");
            app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
        } catch (Exception e) {
            ……
            return false;
        }

        // 从正在启动进程列表删除
        mPersistentStartingProcesses.remove(app);
        ……
        if (normalMode) {
            try {
                if (mStackSupervisor.attachApplicationLocked(app)) {//查看顶部可展示Activity是否正在等待在当前进程中运行。也就是处理Activity展示
                    didSomething = true;
                }
            } catch (Exception e) {
                Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
                badApp = true;
            }
        }

        // Find any services that should be running in this process...
        if (!badApp) {
            try {
                didSomething |= mServices.attachApplicationLocked(app, processName); //处理需要运行在当前进程中的Service
                checkTime(startTime, "attachApplicationLocked: after mServices.attachApplicationLocked");
            } catch (Exception e) {
                Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
                badApp = true;
            }
        }

        // Check if a next-broadcast receiver is in this process...
        //处理需要运行在当前进程中的broadcast receiver
        if (!badApp && isPendingBroadcastProcessLocked(pid)) {
            try {
                didSomething |= sendPendingBroadcastsLocked(app);
                checkTime(startTime, "attachApplicationLocked: after sendPendingBroadcastsLocked");
            } catch (Exception e) {
                // If the app died trying to launch the receiver we declare it 'bad'
                Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);
                badApp = true;
            }
        }

        ……

        if (!didSomething) {
            updateOomAdjLocked();
            checkTime(startTime, "attachApplicationLocked: after updateOomAdjLocked");
        }

        return true;
    }      
            
Logical analysis:
  1. Get the ProcessRecord object corresponding to the process.
  2. Sign up for Binder death monitoring
  3. Perform initialization operations related to the ProcessRecord object
  4. Instrumentation processing, multiple processes use the same Instrumentation (subsequent processes merge into the first process).
  5. Call thread.bindApplication to actually start Application. Here is the startup process of Application.
  6. Handle Activity display, Service, BroadcastReceiver, etc. This involves the activation process of Activity, we will analyze later.

Call mStackSupervisor.attachApplicationLocked (app) to start the Activity page in the Activity stack that needs to be displayed.

The thread.bindApplication method call here is where the Application object is actually created, let's focus on it.

Application start

The attachApplicationLocked method in ActivityManagerService in the service AMS process, remotely call the current process's ApplicationThread's bindApplication to create and start the Application corresponding to the App.

ApplicationThread inherits from IApplicationThread.Stub, which also proves that its important function is to realize Binder communication between AMS and Client.

ApplicationThread's bindApplication method

bindApplication method:
/frameworks/base/core/java/android/app/ActivityThread.java

        public final void bindApplication(String processName, ApplicationInfo appInfo,
                List<ProviderInfo> providers, 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, boolean autofillCompatibilityEnabled) {

            if (services != null) {
                …… 调试日志
                // Setup the service cache in the ServiceManager
                ServiceManager.initServiceCache(services);
            }

            setCoreSettings(coreSettings);

            AppBindData data = new AppBindData();
            data.processName = processName;
            data.appInfo = appInfo;
            data.providers = providers;
            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.autofillCompatibilityEnabled = autofillCompatibilityEnabled;
            sendMessage(H.BIND_APPLICATION, data);
        }
Logical analysis:
  • Services save some basic system service services, here call the initServiceCache method of ServiceManager, add these Serivce services to the cache list "sCache" in SM
  • Generate AppBindData object and set the initialization information of Application.
  • Send BIND_APPLICATION message to continue processing.

ActivityThread's handleBindApplication method

H's handleMessage processes the BIND_APPLICATION message:

        public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            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;
                    
        }

Here directly call the handleBindApplication method to formally start the Application process.

handleBindApplication:

    private void handleBindApplication(AppBindData data) {
        ……

        mBoundApplication = data;//mBoundApplication赋值
        ……
        Process.setArgV0(data.processName);//设置进程名称
        android.ddm.DdmHandleAppName.setAppName(data.processName,
                                                UserHandle.myUserId());
        VMRuntime.setProcessPackageName(data.appInfo.packageName);//设置相关包名

        ……
        //解码Bitmap使用的规则,Android P之前使用BitmapFactory,之后使用ImageDecoder
        ImageDecoder.sApiLevel = data.appInfo.targetSdkVersion;

        //重置系统时区
        TimeZone.setDefault(null);
        ……

        data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);//生成LoadedApk对象

        ……

        // 设置Build的SERIAL属性值
        try {
            Field field = Build.class.getDeclaredField("SERIAL");
            field.setAccessible(true);
            field.set(Build.class, data.buildSerial);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            /* ignore */
        }

        ……
        //debug相关设置
        ……
        //设置Instrumentation
        ……
        //创建appContext对象
        ……
        if (ii != null) {
            ……
            //创建Instrumentation对象,并执行init初始化
            final ComponentName component = new ComponentName(ii.packageName, ii.name);
            mInstrumentation.init(this, instrContext, appContext, component,
                    data.instrumentationWatcher, data.instrumentationUiAutomationConnection);

            ……
        } else {
            mInstrumentation = new Instrumentation();
            mInstrumentation.basicInit(this);
        }

        ……
        // 在进程启动过程中或Provider安装过程中,暂时允许访问磁盘权限
        Application app;
        final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
        final StrictMode.ThreadPolicy writesAllowedPolicy = StrictMode.getThreadPolicy();
        try {
            // 创建Application对象
            app = data.info.makeApplication(data.restrictedBackupMode, null);
            ……
            mInitialApplication = app;

            // don't bring up providers in restricted mode; they may depend on the
            // app's custom Application class
            if (!data.restrictedBackupMode) {//如果应用正在安装或恢复这类特殊状态,restrictedBackupMode值为true。这里正常情况下为false
                if (!ArrayUtils.isEmpty(data.providers)) {
                    installContentProviders(app, data.providers); //此处安装ContentProvider
                    // For process that contains content providers, we want to
                    // ensure that the JIT is enabled "at some point".
                    mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
                }
            }

            // 在providers安装之后,执行Instrumentation对象的onCreate方法,启动Instrumentation线程
            try {
                mInstrumentation.onCreate(data.instrumentationArgs);
            }
            ……
            try {
                mInstrumentation.callApplicationOnCreate(app);//通过callApplicationOnCreate,调用Application对象的onCreate方法
            }
            ……
        } finally {
            ……
        }
        ……
        // 预加载字体资源相关处理
        
    }
Logic analysis

This method has a lot of logic, let's see what processing it mainly does:

  1. Set mBoundApplication = data (parameter AppBindData object).
  2. Process.setArgV0 (data.processName) sets the process name.
  3. VMRuntime.setProcessPackageName(data.appInfo.packageName)设置包名。
  4. Set the rules for decoding Bitmap.
  5. Reset the system time zone.
  6. Generate LoadedApk object.
  7. Set the SERIAL attribute value of Build.
  8. Set up Instrumentation.
  9. Create an appContext object.
  10. Create an Instrumentation object and initialize it.
  11. During the process startup or Provider installation process, set the permission flag to temporarily allow access to the disk.
  12. Create an Application object.
  13. Install ContentProvider.
  14. After the providers are installed, execute the onCreate method of the Instrumentation object to start the Instrumentation thread.
  15. Call the onCreate method of the Application object through the callApplicationOnCreate of the Instrumentation object.
  16. Pre-loading font resource related processing.

After executing the handleBindApplication method, our application will be launched.

The process of creating an Application object is very important, and we analyze it in detail.

Application object creation

In the handleBindApplicaiton method of the ActivityThread object, the Application object is created, the code:

// 创建Application对象
app = data.info.makeApplication(data.restrictedBackupMode, null);

Here data is an AppBindData object, and its info property is a LoadedApk object, so that we know that the makeApplicaiton method of the LoadedApk object is actually called here.

MakeApplication method of LoadedApk class

/frameworks/base/core/java/android/app/LoadedApk.java

    public Application makeApplication(boolean forceDefaultAppClass, //如果应用正在安装或恢复这类特殊状态,restrictedBackupMode值(这里是第一个参数)为true,正常启动应用,这里是false。
            Instrumentation instrumentation) { //instrumentation参数这里传递进来的是null
        if (mApplication != null) { //已经存在,直接返回
            return mApplication;
        }
        ……
        Application app = null;
        //设置正在启动的App的Application的类名
        String appClass = mApplicationInfo.className;
        if (forceDefaultAppClass || (appClass == null)) {
            appClass = "android.app.Application";
        }

        try {
            //创建并处理ClassLoader对象
            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);
            }
            //创建ContextImpl对象作为application的Context环境
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            //这里调用Instrumentation对象的newApplication方法来创建Application对象。
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app); //ContextImpl对象绑定Application对象
        } 
        ……
        mActivityThread.mAllApplications.add(app); //添加到mAllApplications列表
        mApplication = app;

        if (instrumentation != null) { //这里在App启动过程中传递进来的是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);
                }
            }
        }
        ……
        // Rewrite the R 'constants' for all library apks.
        ……

        return app;
    }
Logical analysis:
  1. If mApplication has been assigned, then return directly, otherwise continue.
  2. Set the Application class name of the App being started.
  3. Create and process ClassLoader objects.
  4. Create a ContextImpl object as the Context environment of the application.
  5. Call the newApplication method of the Instrumentation object to create the Application object, where the Instrumentation object is obtained through ActivityThread.
  6. The ContextImpl object is bound to the Application object.
  7. Add to mAllApplications list.

Continue to see that thread.bindApplication really starts the Application method.

NewApplication method of Instrumentation class

The creation of the Application object is ultimately created by reflection in the newApplication method of the Instrumentation object.

    public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        return newApplication(cl.loadClass(className), context);
    }
    
    static public Application newApplication(Class<?> clazz, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        Application app = (Application)clazz.newInstance();
        app.attach(context);
        return app;
    }
Logical analysis:
  1. First, load the class name corresponding to Application through the ClassLoader object.
  2. Use Java reflection call, newInstance an Application object.
  3. Finally, call the attach method of the Application object, the parameter is context. Here is the attach method of the Application that we are familiar with, we can handle some initialization work when the application starts.

At this point, the creation and startup process of our Application has been analyzed and completed, and you will also have a clearer understanding of this in detail. The whole process involves the Client side where our App is located and the Server side represented by ActivityManagerService. The communication process between them is of course based on Binder. ApplicationThread serves as a reference for the server to call the client, and realizes the communication between them.

Published 9 original articles · liked 0 · views 3226

Guess you like

Origin blog.csdn.net/u011578734/article/details/105654761