Android M應用啟動流程分析

Android M應用啟動流程分析

更新:
2016-10-29:更新handleBindApplication部分。

我這個版本的原則是,有話則長,無話則短.

以下分析基于6.0.1_r10版本。
先看一張大圖:


android_app_startup
android_app_startup

1. 桌面的onClick事件(進程:桌面應用的進程)

我們暫時忽略Input處理的過程,以桌面的onClick事件被觸發為起點。
這部分根據Launcher的不同而大同小異。

2. ActivityManagerService之startActivity(進程AmS)

路徑:frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
桌面調用framework,最后會調到AmS的startActivity方法.
現在是多用戶時代了,startActivity現在唯一做的事兒,就是通過UserHandle.getCallingUserId()去獲取當前的user id,然后調用startActivityAsUser方法。

3848    @Override
3849    public final int startActivity(IApplicationThread caller, String callingPackage,
3850            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
3851            int startFlags, ProfilerInfo profilerInfo, Bundle options) {
3852        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
3853            resultWho, requestCode, startFlags, profilerInfo, options,
3854            UserHandle.getCallingUserId());
3855    }

3. ActivityManagerService之startActivityAsUser

這個方法如其名,還真是只處理跟user相關的工作,調用handleIncomingUser。
之后,調用ActivityStackSupervisor來去處理跟Activity狀態相關真正邏輯。

3857    @Override
3858    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
3859            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
3860            int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
3861        enforceNotIsolatedCaller("startActivity");
3862        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
3863                false, ALLOW_FULL_ONLY, "startActivity", null);
3864        // TODO: Switch to user app stacks here.
3865        return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
3866                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
3867                profilerInfo, null, null, options, false, userId, null, null);
3868    }

4. ActivityStackSupervisor之startActivityMayWait(進程AmS)

路徑:frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
先解釋一下為什么叫MayWait,因為調用startActivity是可能要等待結果的startActivityForResult,那就要掛起調用者。
首先,startActivityMayWait要讀取一些信息。從4.4開始,這部分邏輯寫到resolveActivity方法中,它會調用PackageManagerService的resolveIntent方法。這個方法會先調用queryIntentActivities方法出查詢相關的列表,然后再調用chooseBestActivity方法去選擇。為了不影響主線,這些支線內容后面再講。
主線往下走,進入startActivityLocked。Locked意思是調用者需要保證加鎖保護,不能重復調用,在startActivityMayWait中,是采用mService對象,也就是構造ActivityStackSupervisor時傳進來的ActivityManagerService的對象。
調用成功了之后,如果需要wait,就讓mService.wait()去等待吧。新Activity還在征途上。

925    final int startActivityMayWait(IApplicationThread caller, int callingUid,
926            String callingPackage, Intent intent, String resolvedType,
927            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
928            IBinder resultTo, String resultWho, int requestCode, int startFlags,
929            ProfilerInfo profilerInfo, WaitResult outResult, Configuration config,
930            Bundle options, boolean ignoreTargetSecurity, int userId,
931            IActivityContainer iContainer, TaskRecord inTask) {
...
941        // Collect information about the target of the Intent.
942        ActivityInfo aInfo =
943                resolveActivity(intent, resolvedType, startFlags, profilerInfo, userId);
...
1045            int res = startActivityLocked(caller, intent, resolvedType, aInfo,
1046                    voiceSession, voiceInteractor, resultTo, resultWho,
1047                    requestCode, callingPid, callingUid, callingPackage,
1048                    realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity,
1049                    componentSpecified, null, container, inTask);
...

5. ActivityStackSupervisor之startActivityLocked

路徑:frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

前面先做一系列檢查的工作,比如權限,比如Intent防火墻檢查。
準備做好之后,就new一個ActivityRecord,用于存儲Activity的各種狀態和歷史信息。
然后,通過getFocusedStack方法獲取當前獲取焦點的ActivityStack。ActivityStackSupervisor中的mFocusedStack中保存了當前的前臺ActivityStack。
下面就準備切換新進程了,先判斷一下是否可以切換,如果處于通話中界面等無法馬上切換的情況。通過ActivityManagerService的checkAppSwitchAllowedLocked方法來做檢查,如果當前不允許做進程切換,就先存到PendingActivityLaunch的列表中,等待以后有機會再調用。
如果允許做切換,那么先檢查一下當前是否有以前的等待任務,如果有就先執行它們,調用doPendingActivityLaunchesLocked方法去執行這個循環。
如果以上都完成了,就調用startActivityUncheckedLocked。

1399    final int startActivityLocked(IApplicationThread caller,
1400            Intent intent, String resolvedType, ActivityInfo aInfo,
1401            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
1402            IBinder resultTo, String resultWho, int requestCode,
1403            int callingPid, int callingUid, String callingPackage,
1404            int realCallingPid, int realCallingUid, int startFlags, Bundle options,
1405            boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
1406            ActivityContainer container, TaskRecord inTask) {
...
1675        err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
1676                startFlags, true, options, inTask);
1677
1678        if (err < 0) {
1679            // If someone asked to have the keyguard dismissed on the next
1680            // activity start, but we are not actually doing an activity
1681            // switch...  just dismiss the keyguard now, because we
1682            // probably want to see whatever is behind it.
1683            notifyActivityDrawnForKeyguard();
1684        }
1685        return err;
1686    }

6. ActivityStackSupervisor之startActivityUncheckedLocked

路徑:frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
通過一系列分析,找到了該執行的目標ActivityStack,然后調用該ActivityStack的startActivityLocked方法針對該任務做具體的操作。

1828    final int startActivityUncheckedLocked(final ActivityRecord r, ActivityRecord sourceRecord,
1829            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
1830            boolean doResume, Bundle options, TaskRecord inTask) {
...
2457        ActivityStack.logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
2458        targetStack.mLastPausedActivity = null;
2459        targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
2460        if (!launchTaskBehind) {
2461            // Don't set focus on an activity that's going to the back.
2462            mService.setFocusedActivityLocked(r, "startedActivity");
2463        }
2464        return ActivityManager.START_SUCCESS;
2465    }

7. ActivityStack之startActivityLocked

路徑:frameworks/base/services/core/java/com/android/server/am/ActivityStack.java
如果需要的話,這一步中會調用到WmS的setAppStartingWindow,開始準備新應用的啟動窗口。
這其中,有重要一步是調用WindowManagerService的addAppToken方法去將信息共步給WmS,為下一步的顯示做準備。
最后,調用ActivityStackSupervisor的resumeTopActivitiesLocked方法,將顯示的Activities都resume一下。

2074    final void startActivityLocked(ActivityRecord r, boolean newTask,
2075            boolean doResume, boolean keepCurTransition, Bundle options) {
...
2232        if (doResume) {
2233            mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
2234        }
2235    }

8. ActivityStackSupervisor之resumeTopActivitiesLocked

先獲取當前焦點顯示的ActivityStack,調其resumeTopActivityLocked。完成后,遍歷所有能顯示的Activity的stack。

2727    boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,
2728            Bundle targetOptions) {
2729        if (targetStack == null) {
2730            targetStack = mFocusedStack;
2731        }
2732        // Do targetStack first.
2733        boolean result = false;
2734        if (isFrontStack(targetStack)) {
2735            result = targetStack.resumeTopActivityLocked(target, targetOptions);
2736        }
2737
2738        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
2739            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
2740            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
2741                final ActivityStack stack = stacks.get(stackNdx);
2742                if (stack == targetStack) {
2743                    // Already started above.
2744                    continue;
2745                }
2746                if (isFrontStack(stack)) {
2747                    stack.resumeTopActivityLocked(null);
2748                }
2749            }
2750        }
2751        return result;
2752    }

9. ActivityStack之resumeTopActivityLocked

調用resumeTopActivityInnerLocked

1540    final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
1541        if (mStackSupervisor.inResumeTopActivity) {
1542            // Don't even start recursing.
1543            return false;
1544        }
1545
1546        boolean result = false;
1547        try {
1548            // Protect against recursion.
1549            mStackSupervisor.inResumeTopActivity = true;
1550            if (mService.mLockScreenShown == ActivityManagerService.LOCK_SCREEN_LEAVING) {
1551                mService.mLockScreenShown = ActivityManagerService.LOCK_SCREEN_HIDDEN;
1552                mService.updateSleepIfNeededLocked();
1553            }
1554            result = resumeTopActivityInnerLocked(prev, options);
1555        } finally {
1556            mStackSupervisor.inResumeTopActivity = false;
1557        }
1558        return result;
1559    }

10. ActivityStack之resumeTopActivityInnerLocked

這是第一次進入這個方法,這次我們是走pause桌面這一支,下一次我們就走到最后的startSpecificActivityLocked那一支。
調用startPausingLocked去pause。

1561    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
...
1729        if (mResumedActivity != null) {
1730            if (DEBUG_STATES) Slog.d(TAG_STATES,
1731                    "resumeTopActivityLocked: Pausing " + mResumedActivity);
1732            pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
1733        }

11. ActivityStack之startPausingLocked

路徑:frameworks/base/services/core/java/com/android/server/am/ActivityStack.java
AmS開始發起pause桌面的操作
如果不是從桌面啟動的話,就要去為上一個應用抓個用于顯示在近期任務里的圖。
prev.updateThumbnailLocked(screenshotActivities(prev), null);
處理完成之后,通知桌面應用去執行onPause。
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,userLeaving, prev.configChangeFlags, dontWait);
這個thread就是IPC的ApplicationThreadNative對象。

802    /**
803     * Start pausing the currently resumed activity.  It is an error to call this if there
804     * is already an activity being paused or there is no resumed activity.
805     *
806     * @param userLeaving True if this should result in an onUserLeaving to the current activity.
807     * @param uiSleeping True if this is happening with the user interface going to sleep (the
808     * screen turning off).
809     * @param resuming True if this is being called as part of resuming the top activity, so
810     * we shouldn't try to instigate a resume here.
811     * @param dontWait True if the caller does not want to wait for the pause to complete.  If
812     * set to true, we will immediately complete the pause here before returning.
813     * @return Returns true if an activity now is in the PAUSING state, and we are waiting for
814     * it to tell us when it is done.
815     */
816    final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,
817            boolean dontWait) {
...
860        if (prev.app != null && prev.app.thread != null) {
861            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
862            try {
863                EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
864                        prev.userId, System.identityHashCode(prev),
865                        prev.shortComponentName);
866                mService.updateUsageStats(prev, false);
867                prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
868                        userLeaving, prev.configChangeFlags, dontWait);

12. ApplicationThreadNative的schedulePauseActivity

路徑:frameworks/base/core/java/android/app/ApplicationThreadNative.java
AmS要通過IPC來通知給桌面,于是通過Proxy來發送IPC操作.

718    public final void schedulePauseActivity(IBinder token, boolean finished,
719            boolean userLeaving, int configChanges, boolean dontReport) throws RemoteException {
720        Parcel data = Parcel.obtain();
721        data.writeInterfaceToken(IApplicationThread.descriptor);
722        data.writeStrongBinder(token);
723        data.writeInt(finished ? 1 : 0);
724        data.writeInt(userLeaving ? 1 :0);
725        data.writeInt(configChanges);
726        data.writeInt(dontReport ? 1 : 0);
727        mRemote.transact(SCHEDULE_PAUSE_ACTIVITY_TRANSACTION, data, null,
728                IBinder.FLAG_ONEWAY);
729        data.recycle();
730    }

13. ActivityThread之schedulePauseActivity (桌面進程)

路徑:frameworks/base/core/java/android/app/ActivityThread.java
通過IPC,運行桌面應用的ActivityThread的schedulePauseActivity。此處ActivityThread會將這個請求放入隊列中,等待運行。

588        public final void schedulePauseActivity(IBinder token, boolean finished,
589                boolean userLeaving, int configChanges, boolean dontReport) {
590            sendMessage(
591                    finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
592                    token,
593                    (userLeaving ? 1 : 0) | (dontReport ? 2 : 0),
594                    configChanges);
595        }

在這段期間,WmS也沒閑著,類似于之前我們在startActivityLocked時做的addWindow之類的操作一直在干活。

14. ActivityThread之handlePauseActivity (桌面進程)

終于從隊列中輪到出場了,開始執行桌面的onPause吧。

不過先別急,執行onPause之前,先執行performUserLeavingActivity,最后會調到Activity的performUserLeaving。
這個方法做兩步:

final void performUserLeaving() {
    onUserInteraction();
    onUserLeaveHint();
}

這些都做完了,調用performPauseActivity。

3305    private void handlePauseActivity(IBinder token, boolean finished,
3306            boolean userLeaving, int configChanges, boolean dontReport) {
...
3310            if (userLeaving) {
3311                performUserLeavingActivity(r);
3312            }
...
3315            performPauseActivity(token, finished, r.isPreHoneycomb());
...
3325                    ActivityManagerNative.getDefault().activityPaused(token);
...
}

15. ActivityThread之performPauseActivity

首先判斷一下狀態,如果已經pause了,那就需要先resume之。當然,如果pause了之后正在finishing中,就算了,不是的話,拋個RuntimeException,問問調用者不先resume是為哪般。
沒有異常的話,先調用callCallActivityOnSaveInstanceState,這個會通過Instrumentation的callActivityOnSaveInstanceState去調用Activity的performSaveInstanceState, 然后會調到Activity的onSaveInstanceState。還會將對話框的信息做保存操作。
保存完狀態之后,再調用Instrumentation的callActivityOnPause。然后調用Activity的performPause。
Activity在onPause之前,先通知各個Fragment去onPause,再調用Activity的onPause.
performPauseActivity結束后,回到launchPauseActivity,下面通知AMS,調IPC來做activityPaused。

16. ActivityManagerNative 之activityPaused

路徑:frameworks/base/core/java/android/app/ActivityManagerNative.java
桌面的onPause執行完了,通過IPC通知AmS,可以啟動新應用了。

17. ActivityManagerService之activityPaused

路徑:services/core/java/com/android/server/am/ActivityManagerService.java
AmS收到activityPaused的消息,然后找到對應的ActivityStack的activityPausedLocked。

18. ActivityStack之activityPausedLocked

路徑:frameworks/base/services/core/java/com/android/server/am/ActivityStack.java
然后調用completePausedLocked。

19. ActivityStack之completePauseLocked

路徑:frameworks/base/services/core/java/com/android/server/am/ActivityStack.java
到此,桌面的onPause正式告一段落。
結束之后,再次調用前面我們已經遇到過的ActivityStackSupervisor的resumeTopActivitiesLocked,前一次我們走了一半就調pause過程去了,這次我們將走到最后。

20. ActivityStackSupervisor之resumeTopActivitiesLocked

還跟上次一樣,調相應的ActivityStack的resumeTopActivityLocked。

21. ActivityStack之resumeTopActivityLocked

路徑:frameworks/base/services/core/java/com/android/server/am/ActivityStack.java
這個方法只是一個十幾行的wrapper,除了設了個flag和處理鎖屏之外,直接調用resumeTopActivityInnerLocked方法。

22. ActivityStack之resumeTopActivityInnerLocked

這個大方法走到最后,執行ActivityStackSupervisor的startSpecificActivityLocked。
(注:這個方法是5.0之后分出來的,4.4上還在resumeTopActivityLocked里面)

23. ActivityStackSupervisor之startSpecificActivityLocked (AmS進程)

路徑:frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
從這里,又從ActivityStackSupervisor調回ActivityManagerService,調用startProcessLocked。

24. ActivityManagerService 之startProcessLocked

路徑:frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
通過調用android.os.Process的start去啟動新進程。

25. Process.start

路徑:frameworks/base/ core/java/android/os/Process.java
其實就是startViaZygote的一個簡單封裝。

481    public static final ProcessStartResult start(final String processClass,
482                                  final String niceName,
483                                  int uid, int gid, int[] gids,
484                                  int debugFlags, int mountExternal,
485                                  int targetSdkVersion,
486                                  String seInfo,
487                                  String abi,
488                                  String instructionSet,
489                                  String appDataDir,
490                                  String[] zygoteArgs) {
491        try {
492            return startViaZygote(processClass, niceName, uid, gid, gids,
493                    debugFlags, mountExternal, targetSdkVersion, seInfo,
494                    abi, instructionSet, appDataDir, zygoteArgs);
495        } catch (ZygoteStartFailedEx ex) {
496            Log.e(LOG_TAG,
497                    "Starting VM process through Zygote failed");
498            throw new RuntimeException(
499                    "Starting VM process through Zygote failed", ex);
500        }
501    }

26. Process.startViaZygote

路徑:frameworks/base/core/java/android/os/Process.java
主要是處理參數,然后調用zygoteSendArgsAndGetResult去通過socket通信去通知zygote。

27. Process.zygoteSendArgsAndGetResult

路徑:frameworks/base/core/java/android/os/Process.java
通過socket通知Zygote進程去fork新進程。接收方是ZygoteConnection。

28. ZygoteConnection.runOnce

路徑:frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
從socket中讀取命令并執行。
這個可以往下再分為4步:

  • readArgumentList
  • apply security policies
  • apply security policies
  • preForkAndSpecialize

29. Zygote之forkAndSpecialize

路徑:/frameworks/base/core/java/com/android/internal/os/Zygote.java
這步分為三個子步驟:

  • preFork
  • nativeForkAndSpecialize
  • postForkCommon

29-1. ZygoteHooks.PreFork

路徑:/libcore/dalvik/src/main/java/dalvik/system/ ZygoteHooks.java
這步離開了frameworks/base,進入了libcore。這里面要注意,不能調用Android的API,打個log什么的都要注意。

  • Daemons.stop()
    停掉GC,停掉finalizer等,fork進程時不需要這些
  • waitUntilAllThreadsStopped()
    確保fork之前只有一個線程在運行
  • nativePreFork()
    給虛擬機一個機會去在fork之前做點處理

29-2. com_android_internal_os_Zygote_nativeForkAndSpecialize

路徑:/frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
這是我們第一次進入C++層。真正做事的函數是ForkAndSpecializeCommon。

真正開始fork新進程

  • SetSigChldHandler
  • Fork and detach(新進程從這一步開始誕生)
  • child process setup

這一步是值得大書特書的一步,因為從這一步開始,更具體地說是從Fork and detach開始,新應用的進程終于fork出來了。從此zygote老進程的事情我們不再關心,我們來看新進程號就好了。

Child process setup之后,有一個重要的函數會被執行到,這就是ZygoteHooks_nativePostForkChild。
在這個函數中,ART版本號會被打印出來。說明Android Runtime已經正式開始工作了。

29-3. postForkCommon

路徑:/libcore/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
只干一件事,把preFork里面stop的monitor們重新打開。這一步要注意,原來的Zygote里面的不要去管了,只看新進程的就好。

30. RuntimeInit.zygoteInit

路徑:frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

31. RuntimeInit.invokeStaticMain

路徑:frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
初始化完成,通過反射來調用ActivityThread的main方法

32. ActivityThread main

路徑:frameworks/base/ core/java/android/app/ActivityThread.java
執行ActivityThread的main方法,新的應用正式上路

33. Proxy:attachApplication

路徑:frameworks/base/
新的Activity建好了,要通知AmS,走IPC。

34. ActivityManagerService之attachApplication

路徑: frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
AmS收到attach的通知,一切準備就緒。

35. AMS:attachApplicationLocked

路徑:frameworks/base/ services/core/java/com/android/server/am/ActivityManagerService.java
其它部分都是線性的,這部分我們不得不分成兩個部分各表一支了。這兩部分分別走IPC,最后在ActivityThread的隊列中匯合。
首先是bindApplication。

36. ApplicationThreadProxy之bindApplication

IPC調用
路徑:frameworks/base/core/java/android/app/ApplicationThreadNative.java

37. ActivityThread之bindApplication

路徑:frameworks/base/core/java/android/app/ActivityThread.java
主要包括兩部分的操作,雖然這個方法不叫做scheduleXXX,但是實際上兩步的操作都是放到隊列中。
到這一步的時候,其實我們只是啟動了一個空進程而己,跟實際的apk還一點關系也沒有。
首先,如果services不為空的話,先初始化一下services cache。
ServiceManager.initServiceCache(services);
然后,schedule第一個任務,setCoreSettings(coreSettings);
這個最終會走到handleSetCoreSettings。
下面,PM才出場去讀真正的package的信息。讀好之后,再去將BIND_APPLICATION消息放到隊列里去,這時候可能正在執行setCoreSettings。

38. ActivityThread之handleBindApplication

真正啟動Activity之前,還得做一些準備工作。比如install provider就是在這時候做的。

38-1 LoadedApk之makeApplication

我們都知道,在Activity之外,對于每個應用,還對應一個Application類。這個Application就是在LoadApk的makeApplication方法時構造的。

554    public Application makeApplication(boolean forceDefaultAppClass,
555            Instrumentation instrumentation) {
556        if (mApplication != null) {
557            return mApplication;
558        }
559
560        Application app = null;
561
562        String appClass = mApplicationInfo.className;
563        if (forceDefaultAppClass || (appClass == null)) {
564            appClass = "android.app.Application";
565        }

下面調用ClassLoader,并且生成ApplicationContext.

567        try {
568            java.lang.ClassLoader cl = getClassLoader();
569            if (!mPackageName.equals("android")) {
570                initializeJavaContextClassLoader();
571            }
572            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);

下面將通過Intrumentation的newApplication方法去真正創建Application

573            app = mActivityThread.mInstrumentation.newApplication(
574                    cl, appClass, appContext);
575            appContext.setOuterContext(app);
576        } catch (Exception e) {
577            if (!mActivityThread.mInstrumentation.onException(app, e)) {
578                throw new RuntimeException(
579                    "Unable to instantiate application " + appClass
580                    + ": " + e.toString(), e);
581            }
582        }
583        mActivityThread.mAllApplications.add(app);
584        mApplication = app;

38-2 Application之newApplication

通過反射構造對象,然后調用Application的attach方法。

993    static public Application newApplication(Class<?> clazz, Context context)
994            throws InstantiationException, IllegalAccessException,
995            ClassNotFoundException {
996        Application app = (Application)clazz.newInstance();
997        app.attach(context);
998        return app;
999    }

38-3 Application之attach

attach再調用attachBaseContext。

183    /**
184     * @hide
185     */
186    /* package */ final void attach(Context context) {
187        attachBaseContext(context);
188        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
189    }
?????```

### 38-4 ContextThemeWrapper之attachBaseContext

```java
50    @Override
51    protected void attachBaseContext(Context newBase) {
52        super.attachBaseContext(newBase);
53    }

38-5 ContextWrapper的attachBaseContext

65    protected void attachBaseContext(Context base) {
66        if (mBase != null) {
67            throw new IllegalStateException("Base context already set");
68        }
69        mBase = base;
70    }

Application構造好之后,將調用Application的onCreate方法。

586        if (instrumentation != null) {
587            try {
588                instrumentation.callApplicationOnCreate(app);
589            } catch (Exception e) {
590                if (!instrumentation.onException(app, e)) {
591                    throw new RuntimeException(
592                        "Unable to create application " + app.getClass().getName()
593                        + ": " + e.toString(), e);
594                }
595            }
596        }

最后更新所有R常量的值

598        // Rewrite the R 'constants' for all library apks.
599        SparseArray<String> packageIdentifiers = getAssets(mActivityThread)
600                .getAssignedPackageIdentifiers();
601        final int N = packageIdentifiers.size();
602        for (int i = 0; i < N; i++) {
603            final int id = packageIdentifiers.keyAt(i);
604            if (id == 0x01 || id == 0x7f) {
605                continue;
606            }
607
608            rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);
609        }
610
611        return app;
612    }

下面花開兩朵說另一枝,回到attachApplicationLocked方法,它將會調用到realStartActivityLocked。

39. ActivityStackSupervisor之realStartActivityLocked(AmS進程)

路徑:frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
這時算是真正啟動,通過Activity,可以執行onCreate了。

40. ApplicationThreadNative之scheduleLaunchActivity

路徑:frameworks/base/core/java/android/app/ApplicationThreadNative.java
IPC通道,通知本地進程

41. ActivityThread之scheduleLaunchActivity

路徑:frameworks/base/ core/java/android/app/ActivityThread.java
ActivityThread收到,將命令放入隊列。

42. ActivityThread之handleLaunchActivity

路徑:frameworks/base/ core/java/android/app/ActivityThread.java
正式開始Activity的啟動流程。

43. ActivityThread之performLaunchActivity

路徑:frameworks/base/ core/java/android/app/ActivityThread.java
負責new出Activity的實例,makeApplication,然后調用Activity.attach向系統注冊。
最后,通過callActivityOnCreate來調用應用的onCreate方法。

44. ActivityThread之handleResumeActivity

路徑:frameworks/base/ core/java/android/app/ActivityThread.java
首先,通過performResumeActivity方法調用應用的onResume方法。
如大家所熟知的,執行完onResume之后,真正的繪制工作就才真正開始。
ActivityThread通過ViewManager對象調用其addView方法,開始正式通知WmS要添加窗口了。實際上,獲取的這個ViewManager,是其子接口WindowManager的實現類WindowManagerImpl的方法。這個WindowManagerImpl的對象是通過
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE)調用從系統服務獲取到的。

45. WindowManagerImpl之addView

路徑:frameworks/base/core/java/android/view/WindowManagerImpl.java
ViewManager只是一個接口,用于定義功能,本身并不與WmS打交道。它通過單例對象WindowManagerGlobal去訪問ViewRootImpl,再由ViewRootImpl去跟WmS通信。

46. WindowManagerGlobal之addView

路徑:frameworks/base/core/java/android/view/WindowManagerGlobal.java
WindowManagerGlobal也只是個二傳手,最終調用ViewRootImpl類的setView來真正與WmS交互。

47. ViewRootImpl之setView

路徑:frameworks/base/core/java/android/view/ViewRootImpl.java
ViewRootImpl被構造出來后,會通過WindowManagerGlobal的getWindowSession方法去創建一個與WmS之間的連接。構造中會調到這一句:

mWindowSession = WindowManagerGlobal.getWindowSession();

在正式添加到WmS之前,首先要保證這個View樹可以正常接收事件,于是先發起一次requestLayout。

48. ViewRootImpl之requestLayout

這個方法本身是WmS最簡單的方法之一,先檢查一下是不是UI線程,如果是,就scheduleTraversals,申請做一次遍歷。
準備好了之后,setView就會通過mWindowSession去IPC通知WmS去添加一個窗口。

49. Session之addToDisplay

路徑:frameworks/base/services/core/java/com/android/server/wm/Session.java
IPC調用WmS的addWindow方法。

50. WindowManagerService之addWindow

路徑:frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
第一步先檢查權限,比如部分系統窗口就不是應用可以添加的。
第二步去檢查是不是重復添加了。

if (mWindowMap.containsKey(client.asBinder())) {
    Slog.w(TAG, "Window " + client + " is already added");
    return WindowManagerGlobal.ADD_DUPLICATE_ADD;
}

第三步,如果是子窗口,就尋找父窗口。
第四步,檢查窗口的有效性。
第五步,用WindowState對象來管理窗口的狀態。

win = new WindowState(this, session, client, token,attachedWindow, appOp0, seq, attrs, viewVisibility, displayContent);

第六步,調整Window屬性
第七步,將token加入到mTokenMap中。
第八步,將client.asBinder()加到mWindowMap中。
第九步,將Window們按順序排列,調用addWindowToListInOrderLocked方法。
這些做完,addView就算完成了,剩下的事情就看遍歷的了。

51. ViewRootImpl之scheduleTraversals

準備好了之后,放入隊列等待被遍歷。

52. ViewRootImpl之doTraversal

遍歷操作,實際邏輯都在performTraversals中。

53. ViewRootImpl之performTraversals

遍歷的核心邏輯,主要有三個步驟:measure, layout和draw。
如果是第一次調用,所有的子對象還沒有attach到窗口上,需要首先dispatchAttachedToWindow。Attach到哪里呢,PhoneWindow的DecorView。
這個方法沒有被DecorView重載,直接調用的是ViewGroup的dispatchAttachedToWindow。

54. ViewGroup之dispatchAttachedToWindow

根元素被attach到Window上之后,開始遞歸它的子節點,使每個子節點都attach到父節點上。
執行結束后,通過回調onAttachedToWindow來通知節點已經被attach到Window上了。
在被attach到Window之前,View實際上是沒有大小的,因為還不知道被用到哪里呢,無法去做測量。
然后,回到performTraversals中,在執行三大操作之前,先去看看隊列里還有什么未執行的任務沒有,有的話就先執行之。

getRunQueue().executeActions(mAttachInfo.mHandler);

由于是第一次畫,所以mLayoutRequested為true,我們還不知道窗口大小是多大,于是來一次測量,調用measureHierarchy.

windowSizeMayChange |= measureHierarchy(host, lp, res,desiredWindowWidth, desiredWindowHeight);

測量完成之后,就可以開始布局了,調用relayoutWindow.

55. ViewRootImpl之relayoutWindow

relayoutWindow當然不是本地能搞得定的,于是通過IPC調,mWindowSession的relayout去通知WmS去干這事兒。

56. Session之relayout

IPC調用,調用WmS的relayoutWindow。

57. WindowManagerService之relayoutWindow

WmS準備第一次畫之前,先來個進場動畫吧。

winAnimator.applyEnterAnimationLocked();

然后創建個新的Surface吧。

SurfaceControl surfaceControl = winAnimator.createSurfaceLocked();

最后調用performLayoutAndPlaceSurfacesLocked方法

58. WindowManagerService之performLayoutAndPlaceSurfacesLocked

這里邊還要走一個最多6次的循環,每次都調用performLayoutAndPlaceSurfacesLockedLoop。

59. WindowManagerService之performLayoutAndPlaceSurfacesLockedLoop

調用performLayoutAndPlaceSurfacesLockedInner

60. WindowManagerService之performLayoutAndPlaceSurfacesLockedInner

真正執行layout的邏輯。
Measure和layout完成了,最后終于可以畫了。回到performTraversals中,調用performDraw。

61. ViewRootImpl之performDraw

先調用draw去通知繪制線程開始畫。
然后把所有的動畫全停掉。

62. ViewRootImpl之draw

如果支持硬件加速,就調用HardwareRenderer抽象類的draw方法去畫。

63. ThreadedRenderer之draw

路徑:frameworks/base/core/java/android/view/ThreadedRenderer.java

64. ThreadedRenderer之nSyncAndDrawFrame

這是個native方法,真正實現調用GPU去繪制。調用的是android_view_ThreadedRender_syncAndDrawFrame函數。

65. android_view_ThreadedRenderer_syncAndDrawFrame函數

路徑:frameworks/base/core/jni/android_view_ThreadedRenderer.cpp
再調用RenderProxy的syncAndDrawFrame。

66. RenderProxy::syncAndDrawFrame

路徑:frameworks/base/libs/hwui/renderthread/RenderProxy.cpp
調用DrawFrameTask的drawFrame函數。

67. DrawFrameTask::drawFrame

路徑:frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp
調用postAndWait。

68. DrawFrameTask::postAndWait

放到隊列里,等著VSYNC信號來了就調用吧。

void DrawFrameTask::postAndWait() {
AutoMutex \_lock(mLock);
mRenderThread->queue(this);
mSignal.wait(mLock);
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,269評論 25 708
  • 相關文章Android深入理解四大組件系列 前言 Content Provider做為四大組件之一,通常情況下并沒...
    劉望舒閱讀 1,283評論 4 5
  • 1)https://github.com/LuaDist/luaxml下載壓縮包解壓到指定目錄 2)修改Makef...
    veraxs閱讀 3,999評論 0 0
  • 2017-02-20 凌晨02:11分 變天了,白天伴有雷陣雨 寶貝出生18天了,無意間發現了這個APP,寶貝...
    簡心2017閱讀 274評論 0 3
  • 五個月前給大班娃報了Rise K階段,此前娃在某私立雙語兩年,加上在家教的算是簡單入門,簡單單詞能輸出,簡單句子能...
    Nerissaonly閱讀 138評論 0 0