1. 程式人生 > >AMS之開機啟動Launcher、開機廣告後啟動Launcher、Launcher啟動activity

AMS之開機啟動Launcher、開機廣告後啟動Launcher、Launcher啟動activity

activity的啟動關閉最終都是由AMS控制的。從刷了rom到第一開機引導、launcher啟動、點選啟動特定app,這之間ams控制開機引導activity、launcher、app啟動有什麼不同嗎?還是same流程?下面讓我們一探究竟。

文章分三部分:第一部總體概述、第二部分流程圖、第三部分講解下具體一些細節點。

一、總體概述:

無所做什麼,一定先是瞭解概況,然後在看細節,不然就是隻見樹木不見森林。

這裡就會有區分,開機廣告/開機引導類似(電視現在都是先播放廣告,然後啟動launcher)、launcher、其他app;

本文也從這個角度進行一下分析。

簡單的說,啟動一個activity,先看是否已經有activity是resume狀態,沒有則直接啟動;有則先pause掉當前resume的,然後啟動想啟動的;這裡也不關注activity如何呼叫到AMS的,只關注AMS內部如何排程最終啟動相關的activity的。

除了開機廣告,launcher和app啟動都是兩個階段:一pause當前resume的activity;二resume需要啟動的activity。(先finish後pause)

牢記,就這兩個階段,不過launcher和app啟動在這兩個階段有些許的區別而已。

開機廣告就不多說了,後面也會給出AMS新增的方案,從AMS直接啟動廣告Activity播放廣告,然後主動finish;系統會啟動Launcher;點選相關app,啟動自己想開啟的應用(順序三個階段)

二、流程圖

1.正常啟動Launcher

這裡先看下正常情況下的Luancher啟動,即開機即啟動Launcher。然後在看下先播放開機廣告,然後在自動Launcher,看下異同點。

AMS被SystemServer啟動之後,SystemServer會通過AMS呼叫startHomeActtivity啟動Launcher,流程見上流程圖。

其中有幾個關鍵函式,需要關注一下:startHomeActivityLocked、startActivityLocked、addActivityToTop、resumeTopActivityLocked、realStartActivityLocked、attachApplicationLocked;幾個點記住:ProcessLocked中有Process.start,最終會觸發AMS的attachApplication。

從流程途中看到,起點可以算startHomeActivityLocked

,終點是realStartActivityLocked

第一階段是startHomeActivity,觸發activity的程序建立;第二階段就是AMS的attachApplication在程序建立後被呼叫,最終執行realStartActivityLocked會回撥Activity的onCreate函式。

這裡第一階段和上面說的不太一樣,不過沒關係,下面看下先播開機廣告在啟動launcher的流程。

2.開機廣告之後啟動Launcher

AMS啟動廣告的就不看了,看下廣告finish之後,Launcher啟動的流程:

先看下呼叫棧:

第一階段:開機廣告finish掉,觸發paused:
06-28 18:07:14.098  4200  4391 W System.err:    at com.android.server.am.ActivityStack.startPausingLocked(ActivityStack.java:825)
06-28 18:07:14.098  4200  4391 W System.err:    at com.android.server.am.ActivityStack.finishActivityLocked(ActivityStack.java:2745)
06-28 18:07:14.098  4200  4391 W System.err:    at com.android.server.am.ActivityStack.requestFinishActivityLocked(ActivityStack.java:2572)
06-28 18:07:14.098  4200  4391 W System.err:    at com.android.server.am.ActivityManagerService.finishActivity(ActivityManagerService.java:4543)
06-28 18:07:14.098  4200  4391 W System.err:    at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:325)
06-28 18:07:14.098  4200  4391 W System.err:    at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2267)
06-28 18:07:14.098  4200  4391 W System.err:    at android.os.Binder.execTransact(Binder.java:446)

第二階段:paused並啟動launcher
06-29 15:18:57.860  4196  4213 W System.err:    at com.android.server.am.ActivityStackSupervisor.realStartActivityLocked(ActivityStackSupervisor.java:1182)
06-29 15:18:57.860  4196  4213 W System.err:    at com.android.server.am.ActivityStackSupervisor.startSpecificActivityLocked(ActivityStackSupervisor.java:1285)
06-29 15:18:57.860  4196  4213 W System.err:    at com.android.server.am.ActivityStack.resumeTopActivityInnerLocked(ActivityStack.java:1898)
06-29 15:18:57.860  4196  4213 W System.err:    at com.android.server.am.ActivityStack.resumeTopActivityLocked(ActivityStack.java:1459)
06-29 15:18:57.860  4196  4213 W System.err:    at com.android.server.am.ActivityStackSupervisor.resumeTopActivitiesLocked(ActivityStackSupervisor.java:2477)
06-29 15:18:57.860  4196  4213 W System.err:    at com.android.server.am.ActivityStack.startActivityLocked(ActivityStack.java:2097)
06-29 15:18:57.860  4196  4213 W System.err:    at com.android.server.am.ActivityStackSupervisor.startActivityUncheckedLocked(ActivityStackSupervisor.java:2217)
06-29 15:18:57.860  4196  4213 W System.err:    at com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:1519)
06-29 15:18:57.860  4196  4213 W System.err:    at com.android.server.am.ActivityStackSupervisor.startHomeActivity(ActivityStackSupervisor.java:833)
06-29 15:18:57.860  4196  4213 W System.err:    at com.android.server.am.ActivityManagerService.startHomeActivityLocked(ActivityManagerService.java:3248)
06-29 15:18:57.860  4196  4213 W System.err:    at com.android.server.am.ActivityStackSupervisor.resumeHomeStackTask(ActivityStackSupervisor.java:459)
06-29 15:18:57.860  4196  4213 W System.err:    at com.android.server.am.ActivityStack.resumeTopActivityInnerLocked(ActivityStack.java:1504)
06-29 15:18:57.860  4196  4213 W System.err:    at com.android.server.am.ActivityStack.resumeTopActivityLocked(ActivityStack.java:1459)
06-29 15:18:57.860  4196  4213 W System.err:    at com.android.server.am.ActivityStackSupervisor.resumeTopActivitiesLocked(ActivityStackSupervisor.java:2477)
06-29 15:18:57.860  4196  4213 W System.err:    at com.android.server.am.ActivityStack.completePauseLocked(ActivityStack.java:998)
06-29 15:18:57.860  4196  4213 W System.err:    at com.android.server.am.ActivityStack.activityPausedLocked(ActivityStack.java:896)
06-29 15:18:57.860  4196  4213 W System.err:    at com.android.server.am.ActivityManagerService.activityPaused(ActivityManagerService.java:6591)
06-29 15:18:57.860  4196  4213 W System.err:    at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:512)
06-29 15:18:57.860  4196  4213 W System.err:    at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2267)
06-29 15:18:57.860  4196  4213 W System.err:    at android.os.Binder.execTransact(Binder.java:446)

流程圖:


這裡是開機廣告播放完畢,主動呼叫finish();系統主動啟動launcher。這裡看差別還是蠻大的。

直接啟動launcher,通過程序建立,觸發attach就起來了;而開機廣告這種情況則複雜很多,先是finish掉開機廣告,然後由pause流程觸發startHomeActivity並遞迴呼叫了一次resume的流程之後才走到realStartActivityLocked,回撥launcher的onCreate函式。

3.Launcher啟動之後啟動app

流程圖:


和正常點選圖示得區別不一樣;主要區別是startActivity呼叫時機;都有兩個階段:launcher一階段:finish呼叫pause,二階段pause呼叫到startHome並先呼叫resume之後才呼叫得startActivityLocked;
正常啟動:一階段:先呼叫startActivityLocked,並呼叫pause,二階段pause呼叫resume直接啟動activity了。
正常啟動activity,會走startActivity(這裡會將ActivityRecord資訊加入task頂,並也呼叫startPausingLocked);
在後續流程中,也不同,主要是2中launcher啟動遞迴呼叫了resume得幾個函式;而正常啟動則不會遞迴,
原因就是正常啟動在首次就將ActivityRecord資訊入task頂了,而2中launcher則沒有;

三、一些注意點

1.addActivityToTop這個函式比較重要,會將要啟動的activity的AcitivityRecord加入TASK頂端;這個非常重要,決定著realStartActivityLocked會不會被呼叫,還是啟動launcher;如果執行了,即加入了Task的棧頂則這裡next!=null而是相關的ActivityRecord,否則為nullfinal ActivityRecord next = topRunningActivityLocked(null);

    final boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {

        if (!mService.mBooting && !mService.mBooted) {
            // Not ready yet!
            return false;
        }

        // Find the first activity that is not finishing.
        final ActivityRecord next = topRunningActivityLocked(null);

        final TaskRecord prevTask = prev != null ? prev.task : null;
        if (next == null) {
            // There are no more activities!  Let's just start up the
            // Launcher...
            // Only resume home if on home display
            return isOnHomeDisplay() &&
                    mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, "noMoreActivities");
        }


2.resumeTopActivityLocked這個函式比較坑(5.1~9.0都這樣),函式裡有個判斷會導致2.2部分的launcher啟動不起來,2.2中的呼叫邏輯是我將AOSP程式碼註釋掉一行以後,啟動的。

看下這個函式:注意標誌位:inResumeTopActivity

  final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
        if (mStackSupervisor.inResumeTopActivity) {
            // Don't even start recursing.
            return false;
        }

        boolean result = false;
        try {
            // Protect against recursion.
            mStackSupervisor.inResumeTopActivity = true;//註釋掉即可,既能如2.2中所示呼叫流程,否則巢狀呼叫就返回,launcher無法啟動
            if (mService.mLockScreenShown == ActivityManagerService.LOCK_SCREEN_LEAVING) {
                mService.mLockScreenShown = ActivityManagerService.LOCK_SCREEN_HIDDEN;
                mService.updateSleepIfNeededLocked();
            }
            result = resumeTopActivityInnerLocked(prev, options);
        } finally {
            mStackSupervisor.inResumeTopActivity = false;
        }
        return result;
    }

可以看到這個函式使用標誌位inResumeTopActivity ,但是2.2中開機廣告這種情況下,就會出現問題;

在2.2中,第一階段只是進行finish處理和pause呼叫;第二階段才會通過pause進行resume,但是先走到這個函式而後觸發的startActivityLocked(呼叫addActivityToTop),隨後又走到這裡的時候就返回了,並沒有繼續執行,所以luancher就沒有啟動,會出現開機廣告播放完成之後,一直黑屏的現象。

相關關鍵函式:

startHomeActivityLocked:呼叫啟動Launcher;

startActivityLocked(ActivityStack中 ):呼叫觸發addActivityToTop將ActivityRecord加入棧頂;

resumeTopActivityLocked:這個函式是3.1中說的函式,不修改會導致廣告後launcher不啟動;

realStartActivityLocked:觸發app.thread.scheduleLaunchActivity,去回撥mainactivity的onCreate函式;

attachApplicationLocked:由建立相關程序之後觸發,此函式會觸發realStartActivityLocked的呼叫。

總結:

整體上,這篇文章涉及較多,AMS管理task即生命週期都有涉及,如果之前沒有接觸過,基本看不懂,很頭痛。

這裡放上幾篇基礎文章,可以閱讀後再來讀本篇文章,應該會又更深刻的理解。

附上AMS關係圖:

大元件之ActivityRecord