1. 程式人生 > >Android進階(三):Application啟動過程(最詳細&最簡單)

Android進階(三):Application啟動過程(最詳細&最簡單)

1.前言

  • 最近一直在看 《Android進階解密》 的一本書,這本書編寫邏輯、流程都非常好,而且很容易看懂,非常推薦大家去看看(沒有收廣告費,單純覺得作者寫的很好)。
  • 上一篇簡單的介紹了Android進階(二): 應用程序啟動過程,最終知道了ActivityThread就是代表應用程序
  • 今天就介紹ActivityThread啟動之後,是如何啟動 Application (基於Android 8.0 系統)。
  • 文章中例項 linhaojian的Github

2.Application啟動過程的時序圖

Application啟動流程.png


3.原始碼分析

3.1 ActivityThread初始化

public static void main(String[] args) {
        //...
        //建立ActivityThread物件 & 呼叫attach()
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);
        //建立主執行緒的Handler
        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); //建立主執行緒的Looper Looper.
loop(); }
  • 主要做了2件事,例項化ActivityThread & 建立主執行緒Handler與Looper接收資訊

3.2 ActivityThread的attach函式

    private void attach(boolean system, long startSeq) {
        //...
            RuntimeInit.setApplicationObject(mAppThread.asBinder());
            // 獲取ActivityManagerService的代理物件
            final IActivityManager mgr = ActivityManager.getService();// 1
            try {
                //通知AMS進行application的初始化
                mgr.attachApplication(mAppThread, startSeq);// 2
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
    }
  • 註釋1:獲取ActivityManagerService的代理物件
  • 註釋2:通過代理物件呼叫attachApplication(),獲取啟動application所需資訊(應用程序相關資料)

3.3 ActivityManagerService的attachApplication函式

    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);// 1
            Binder.restoreCallingIdentity(origId);
        }
    }
  • 註釋1:呼叫attachApplicationLocked()

3.4 ActivityManagerService的attachApplicationLocked函式

    private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid, int callingUid, long startSeq) {
        // 根據pid獲取儲存在AMS中,對應程序的相關資訊
        ProcessRecord app;
        long startTime = SystemClock.uptimeMillis();
        if (pid != MY_PID && pid >= 0) {
            synchronized (mPidsSelfLocked) {
                app = mPidsSelfLocked.get(pid);// 1
            }
        } else {
            app = null;
        }
        // ...
        thread.bindApplication(processName, appInfo, providers, null, profilerInfo, // 2
            null, null, null, testMode,
            mBinderTransactionTrackingEnabled, enableTrackAllocation,
            isRestrictedBackupMode || !normalMode, app.persistent,
            new Configuration(getGlobalConfiguration()), app.compat,
            getCommonServicesLocked(app.isolated),
            mCoreSettingsObserver.getCoreSettingsLocked(),
            buildSerial, isAutofillCompatEnabled);
         // ...
    }
  • 註釋1:根據pid獲取儲存在AMS中,對應應用程序的相關資訊
  • 註釋2:通知ActivityThread啟動application(IApplicationThread是ActivityThread的內部類,負責與ActivityManagerService通訊)

3.5 ActivityThread的handleBindApplication函式

  • AMS中呼叫了ActivityThread的bindApplication函式,其內部其實是完成了Handler切換到主執行緒,並且最後活呼叫handleBindApplication(),下面我們看看其內部原始碼;
    private void handleBindApplication(AppBindData data) {
        // 將UI執行緒註冊為執行時的虛擬機器.
        VMRuntime.registerSensitiveThread();
        if (data.trackAllocation) {
            DdmVmInternal.enableRecentAllocations(true);
        }
        // ...
        // 建立上下文物件
        final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
        updateLocaleListFromAppContext(appContext,
                mResourcesManager.getConfiguration().getLocales());
        if (!Process.isIsolated()) {
            final int oldMask = StrictMode.allowThreadDiskWritesMask();
            try {
                setupGraphicsSupport(appContext);
            } finally {
                StrictMode.setThreadPolicyMask(oldMask);
            }
        } else {
            ThreadedRenderer.setIsolatedProcess(true);
        }
        // Continue loading instrumentation.
        if (ii != null) {
            // ...
        } else {
            mInstrumentation = new Instrumentation();// 1
            mInstrumentation.basicInit(this);
        }
        Application app;
        final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
        final StrictMode.ThreadPolicy writesAllowedPolicy = StrictMode.getThreadPolicy();
        try {
            // If the app is being launched for full backup or restore, bring it up in
            // a restricted environment with the base application class.
            // 初始化Applcation類
            app = data.info.makeApplication(data.restrictedBackupMode, null); // 2
            // Propagate autofill compat state
            app.setAutofillCompatibilityEnabled(data.autofillCompatibilityEnabled);
            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);
                    // 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);
                }
            }
            // 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); // 3
            }
            catch (Exception e) {
                throw new RuntimeException(
                    "Exception thrown in onCreate() of "
                    + data.instrumentationName + ": " + e.toString(), e);
            }
            try {
                //呼叫Applcation的OnCreate函式
                mInstrumentation.callApplicationOnCreate(app); // 4
            } 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);
            }
        }
        // Preload fonts resources
        FontsContract.setApplicationContextForResources(appContext);
        if (!Process.isIsolated()) {
            try {
                final ApplicationInfo info =
                        getPackageManager().getApplicationInfo(
                                data.appInfo.packageName,
                                PackageManager.GET_META_DATA /*flags*/,
                                UserHandle.myUserId());
                if (info.metaData != null) {
                    final int preloadedFontsResource = info.metaData.getInt(
                            ApplicationInfo.METADATA_PRELOADED_FONTS, 0);
                    if (preloadedFontsResource != 0) {
                        data.info.getResources().preloadFonts(preloadedFontsResource);
                    }
                }
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    }
  • 註釋1:**建立Instrumentation,負責跟蹤Application還在Activity的生命週期
  • 註釋2:建立Application物件 & 呼叫其attach()
  • 註釋3:呼叫Instrumentation的onCreate(),內部是空實現
  • 註釋4:呼叫Instrumentation的callApplicationOnCreate(),內部是呼叫application的onCreate,如下程式碼;
public class Instrumentation {
    public void callApplicationOnCreate(Application app) {
        app.onCreate();
    }
}

4.類關係

Application啟動類結構.png

  • ActivityThread :通過IActivityManager類,通知AMS準備application啟動所需程序資料 ;
  • ActivityManagerService :獲取application啟動所需程序資料 ;
  • Instrumentation :建立&啟動Application;跟蹤Application的生命週期;

5.總結

  • 到此,**Application啟動過程**介紹完畢。
  • 如果喜歡我的分享,可以點選 關注 或者 ,你們支援是我分享的最大動力 。
  • linhaojian的Github

歡迎關注linhaojian_CSDN部落格或者linhaojian_簡書

不定期分享關於安卓開發的乾貨。


寫技術文章初心

  • 技術知識積累
  • 技術知識鞏固
  • 技術知識分享