Android6.0之AMS如何啓動app中篇之Task的管理

前面分析到了ActivityStackSupervisor類中的startActivityLocked方法,現在接着分析.

startActivityLocked

利用傳入的IApplicationThread caller,從AMS中得到調用者進程信息,也就是Launcher進程的信息.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
final int startActivityLocked(
           IApplicationThread caller,//AMS通過這個參數可以和發起者進行交互
           Intent intent,// 啓動activity的intent
           String resolvedType, // intent的類型,也就是MIME type
           ActivityInfo aInfo,//要啓動的activity的信息
           IVoiceInteractionSession voiceSession,
           IVoiceInteractor voiceInteractor,
           IBinder resultTo,//用於接收startActivityForResult的結果,launcher啓動app這種情景下沒有用,爲null
           String resultWho,
           int requestCode,// 傳入的-1
           int callingPid,
           int callingUid,
           String callingPackage,
           int realCallingPid,
           int realCallingUid,
           int startFlags,// 傳入的爲0
           Bundle options,
           boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
           ActivityContainer container, // 啓動app時,傳入的爲null
           TaskRecord inTask) // 啓動app時,傳入爲null
{
       int err = ActivityManager.START_SUCCESS;

       ProcessRecord callerApp = null;
       if (caller != null) {
           callerApp = mService.getRecordForAppLocked(caller);
          ................
       }

這裏順便簡單的對startActivityLocked方法的幾個關鍵的參數根據代碼做一個解釋。
IApplicationThread caller :請求啓動當前Activity的應用方,IApplicationThread 類型是AMS IPC調用ActivityThread的IBinder接口,如下圖所示:

IBinder resultTo: 調用方Activity的ActivityRecord,每個Activity在啓動之後,AMS均會將這個Activity的ActivityRecord的IBinder再傳遞給Activity,作爲其在AMS中的標識。因此此時的resultTo經過2次IPC傳遞之後,已經不再是接口了,回到AMS之後就會再次變爲ActivityRecord。這個參數後面會詳解.

callingPid和callingUid: 如果caller爲空,其爲請求啓動Activity的進程的PID和UID;caller不爲空,爲caller activity所在的進程的PID和UID,基本上是一碼事。這個PID和UID爲了權限檢查用的,檢查當前的請求方是否有權限啓動這個Activity。

接着從intent中拿到啓動activity的flag.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
ActivityRecord sourceRecord = null;
ActivityRecord resultRecord = null;
// 啓動app時,傳入爲null
if (resultTo != null) {
    sourceRecord = isInAnyStackLocked(resultTo);
    if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
            "Will send result to " + resultTo + " " + sourceRecord);
    if (sourceRecord != null) {
        if (requestCode >= 0 && !sourceRecord.finishing) {
            resultRecord = sourceRecord;
        }
    }
}
// 從intent中拿到啓動activity的flag
final int launchFlags = intent.getFlags();
//因爲sourceRecord爲null,所以不走這段代碼
if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
}

這裏還要確定sourceRecord和resultRecord,這兩個變量均爲ActivityRecord類型,前者代表請求啓動當前activity的activity;後者表示當前的activity在啓動之後需要返回結果的ActivityRecord,一般情況下,如果sourceRecord的activity使用startActivityForResult()啓動當前activity並且requestCode>=0時,則resultRecord不爲空,且resultRecord=sourceRecord。

只不過當從launcher啓動app時,requestCode爲-1.

還有一種特殊的情況,當啓動一個activity時,啓動的Intent設置了Intent.FLAG_ACTIVITY_FORWARD_RESULT標誌,在這種情況resultRecord並不指向sourceRecord,而是指向sourceRecord的sourceRecord.

如下圖所示:

Activity A 啓動了Activity B,Activity B又啓動了C,A–>B–>C, 這種情況下,A啓動B要求B返回result給A,但是如果B在啓動C時,Intent設置了Intent.FLAG_ACTIVITY_FORWARD_RESULT標誌,那麼此時將會交由C向A setResult。爲了避免衝突,B啓動C時不得指定resultRecord>=0。

接着是檢查權限:

1
2
final int startAnyPerm = mService.checkPermission(
    START_ANY_ACTIVITY, callingPid, callingUid);

檢查權限的規則:

  1. Root uid(0), System Server uid (Process.SYSTEM_UID), own process(MY_PID),將授權permission

  2. 如果發起者是被隔離的app,那麼拒絕授權permission

  3. 如果請求啓動的activity的屬性android:exported=false, 並且請求的callingUid不等於請求啓動的activity的UID,不允許啓動;

  4. 請求啓動的activity沒有設定permission,只有當activity的permission和其所在的application的android:permission均沒有設置時才爲null,設置了application未設置activity,那麼activity的permission與application相同。activity的permission爲空,將授權permission

  5. 請求啓動的activity設定了permission,那麼檢查請求方的activity中是否聲明瞭使用這個permission,如果聲明,授權。

intent防火牆規則檢查,看是否防火牆屏蔽了啓動這個app的intent:

1
2
abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
                callingPid, resolvedType, aInfo.applicationInfo);

防火牆規則目錄在

1
/data/system/ifw

這個文件夾中,可以設置系統禁止某些intent.

接着將Activity啓動的消息通知監聽Activity變動的的接口IActivityController,AMS有任何動靜都將回調該監聽者.

1
2
3
4
5
6
7
8
9
10
11
if (mService.mController != null) {
          try {
              // The Intent we give to the watcher has the extra data
              // stripped off, since it can contain private information.
              Intent watchIntent = intent.cloneFilter();
              abort |= !mService.mController.activityStarting(watchIntent,
                      aInfo.applicationInfo.packageName);
          } catch (RemoteException e) {
              mService.mController = null;
          }
      }

一般情況下是不會設置這個監聽者的,只有當debug時纔會設置.例如在進行Monkey測試的時候,Monkey會設置該回調對象。這樣,Monkey就能根據AMS反饋的情況進行相應處理了.

接着是爲啓動的App的主activity創建ActivityRecord對象:

1
2
3
ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
             intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
             requestCode, componentSpecified, voiceSession != null, this, container, options);

接着是獲取恰當的ActivityStack:

1
final ActivityStack stack = mFocusedStack;

其中mFocusedStack前面已經介紹了,也是ActivityStackSupervisor類中的定義的:

1
2
/** The stack currently receiving input or launching the next activity. */
private ActivityStack mFocusedStack;

接着檢查啓動activity是否會引起進程切換,如果需要的話,還要檢查Android系統目前是否允許切換。

1
2
3
4
5
6
7
8
9
10
11
12
final ActivityStack stack = mFocusedStack;
     if (voiceSession == null && (stack.mResumedActivity == null
             || stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {
         if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
                 realCallingPid, realCallingUid, "Activity start")) {
             PendingActivityLaunch pal =
                     new PendingActivityLaunch(r, sourceRecord, startFlags, stack);
             mPendingActivityLaunches.add(pal);
             ActivityOptions.abort(options);
             return ActivityManager.START_SWITCHES_CANCELED;
         }
     }

什麼情況不允許切換呢?最常見的例子就是打電話的時候,如果是位於通話界面的話,可以通過AMS的stopAppSwitches來禁止切換掉當前進程,這個方法會使其他Task的Activity無法顯示在前端,但同一個Task中的Activity則不受制約.電話結束後再調用resumeAppSwitches來恢復切換。爲了防止使用者不調用resumeAppSwitches,系統設置了一個超時時間(5s),超時則自動resume。需要注意的是,這個接口一般的普通的app是不能調用的,因此這個操作一定是系統app操作的。

如果沒有則儲存起來,有機會再啓動它。將保存到mPendingActivityLaunchers中.

如果允許進程切換的話:

1
doPendingActivityLaunchesLocked(false);

啓動處於Pending狀態的Activity,即之前由於上一步被禁止切換而保存起來的請求。它將先於本次需要啓動的Activity處理.

然後再調用startActivityUncheckedLocked方法繼續處理當前方法繼續處理當前的activity。(其實處理Pending狀態的Activity,也是調用startActivityUncheckedLocked方法)

1
2
err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
              startFlags, true, options, inTask);

整個startActivityLocked方法主要調用時序圖如下所示:

startActivityUncheckedLocked

接下來分析startActivityUncheckedLocked,這個方法代碼很長,分爲若干階段. 該方法主要負責task的管理,也可以理解爲task的調度.在換句話說,也可以理解爲找到或者創建一個合適的task.

先分析參數:

1
2
3
4
5
6
7
8
9
10
final int startActivityUncheckedLocked(
        final ActivityRecord r,// 創建的activity
         ActivityRecord sourceRecord, // 啓動方
        IVoiceInteractionSession voiceSession,
        IVoiceInteractor voiceInteractor,
         int startFlags,//
        boolean doResume,// 傳入的true
         Bundle options,
          TaskRecord inTask // 在最近任務列表中的task,沒有的話 爲null
          )

獲取Activity的啓動模式,這些都是PMS從AndroidManifest.xml文件中獲取的.

1
2
3
final boolean launchSingleTop = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP;
final boolean launchSingleInstance = r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE;
final boolean launchSingleTask = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK;

接着獲取啓動Activity的flag:

1
int launchFlags = intent.getFlags();

然後就開始依據flag進行相應的處理,例如是否需要創建新的task等等.

首先處理AndroidManifest.xml和intent flag衝突的問題.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//launchSingleInstance與launchSingleTask都是從AndroidManifest.xml文件中獲取的
if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&
                (launchSingleInstance || launchSingleTask)) {
            // We have a conflict between the Intent and the Activity manifest, manifest wins.
            Slog.i(TAG, "Ignoring FLAG_ACTIVITY_NEW_DOCUMENT, launchMode is " +
                    "\"singleInstance\" or \"singleTask\"");
            // 當flag中包含FLAG_ACTIVITY_NEW_DOCUMENT,而activity啓動模式爲SingleInstance或者SingleTask時,
            // 這個標誌包括FLAG_ACTIVITY_MULTIPLE_TASK會被忽略.
            launchFlags &=
                    ~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
        } else {
           // 如果AndroidManifest.xml設置了documentLaunchMode
           // 那麼依據此來修改flag.
            switch (r.info.documentLaunchMode) {
                case ActivityInfo.DOCUMENT_LAUNCH_NONE:
                    break;
                case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
                    launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
                    break;
                case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
                    launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
                    break;
                case ActivityInfo.DOCUMENT_LAUNCH_NEVER:
                    launchFlags &= ~Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
                    break;
            }
        }

通過以上代碼可知,AndroidManifest.xml設置的documentLaunchMode標籤屬性優先級高於flag.

接下來處理當flag中設置Intent.FLAG_ACTIVITY_NEW_TASK時斷開與Caller依賴

1
2
3
4
5
6
7
8
if (r.resultTo != null && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0
               && r.resultTo.task.stack != null) {
           Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
           r.resultTo.task.stack.sendActivityResultLocked(-1,
                   r.resultTo, r.resultWho, r.requestCode,
                   Activity.RESULT_CANCELED, null);
           r.resultTo = null;
       }

如果啓動的activity需要新的task,那麼新啓動的activity將會與其caller斷開依賴關係,這個關係主要是指result反饋,A–>B,如果A是通過startActivityForResult()請求啓動的,並且requestCode >=0,那麼如果B是在新的task中,那麼B在finish的時候將不再向A反饋result,而是在啓動過程中就會向A反饋一個RESULT_CANCELED。

因爲FLAG_ACTIVITY_NEW_DOCUMENT,會在overview screen以一個task的形式展示,所以這裏要爲包含FLAG_ACTIVITY_NEW_DOCUMENT的的flag增添一個FLAG_ACTIVITY_NEW_TASK標誌:

1
2
3
if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
        launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
    }

因爲FLAG_ACTIVITY_NEW_TASK標誌,會首先檢查是他要啓動的activity的taskAffinity屬性指定的task是否存在(taskAffinity沒指定的話,默認就是其app包名),不存在的話,纔會嘗試去新建一個task.

所以FLAG_ACTIVITY_NEW_TASK標誌並不能保證一定要新建一個task.

1
2
3
4
5
6
7
8
9
final boolean launchTaskBehind = r.mLaunchTaskBehind
               && !launchSingleTask && !launchSingleInstance
               && (launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0;
if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
            if (launchTaskBehind
                    || r.info.documentLaunchMode == ActivityInfo.DOCUMENT_LAUNCH_ALWAYS) {
                launchFlags |= Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
            }
        }

當activity設置documentLaunchMode爲DOCUMENT_LAUNCH_ALWAYS時,就要在添加FLAG_ACTIVITY_MULTIPLE_TASK這個標誌,結合FLAG_ACTIVITY_NEW_TASK,就能保證每次都新建一個task了.

接着處理FLAG_ACTIVITY_NO_USER_ACTION:

1
2
3
4
5
6
7
8
mUserLeaving = (launchFlags & Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
        "startActivity() => mUserLeaving=" + mUserLeaving);

// 當從launcher啓動app時,傳入的爲true,所以部不執行
if (!doResume) {
    r.delayedResume = true;
}

在一般情況下,啓動一個Activity時都不使用該標識,如果不包含該標識,AMS會判斷一定的時間內是否有用戶交互。如果沒有用戶交互的話,AMS會通知Activity回調onUserLeaving()方法,然後再回調onPause()方法,如果使用了該標識,說明目標Activity不和用戶交互,所以也就不需要回調onUserLeaving()方法。

確定是否現在就Resume,如果不需要立即Resume,就把r.delayResume爲true,意思是延遲Resume。

接着處理FLAG_ACTIVITY_PREVIOUS_IS_TOP,這個標誌很奇葩.

1
2
3
4
5
6
7
8
9
10
11
12
ActivityRecord notTop =
              (launchFlags & Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
           ActivityRecord checkedCaller = sourceRecord;
           if (checkedCaller == null) {
               checkedCaller = mFocusedStack.topRunningNonDelayedActivityLocked(notTop);
           }
           if (!checkedCaller.realActivity.equals(r.realActivity)) {
               // Caller is not the same as launcher, so always needed.
               startFlags &= ~ActivityManager.START_FLAG_ONLY_IF_NEEDED;
           }
       }

它的註釋可以看出它的含義是指如果設置了該flag,那麼mHistory中最top的activity在後續的處理中將不被視爲top,而將前一個activity視爲top,如A–>B–>C,將B視爲top。

這個top activity的作用很大,涉及到後面對task的處理。但是目前來看這個flag並沒有起到該有的作用,代碼中判斷如果設置了該標誌,那麼AMS將會視當前正在啓動的activity爲top,然後去mHistory中去查找它的前一個activity爲後續task處理的top activity(topRunningNonDelayedActivityLocked()中實現),但是現在的問題是此時此刻,正在啓動的activity並不存在於mHistory中,因爲我們在前一個函數中剛剛創建了這個ActivityRecord。

所以這個flag基本沒用,而且當從launcher啓動app時,也沒有設置該flag.

接下來處理inTask不爲null的情況,當從launcher啓動app時,該參數爲null,所以略過這段代碼.其實該段代碼與從最近列表啓動activity有關係.後面會單獨講解.

1
2
3
4
5
if (sourceRecord == null && inTask != null && inTask.stack != null) {
      .........
        } else {
            inTask = null;
        }

下面的這段代碼,是給flag添加FLAG_ACTIVITY_NEW_TASK

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if (inTask == null) {
  if (sourceRecord == null) {
      // This activity is not being started from another...  in this
      // case we -always- start a new task.
      // 當初launcher啓動app時,走這裏
      if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0 && inTask == null) {
          Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
                  "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
          launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
      }
  } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
      // The original activity who is starting us is running as a single
      // instance...  this new activity it is starting must go on its
      // own task.
      launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
  } else if (launchSingleInstance || launchSingleTask) {
      // The activity being started is a single instance...  it always
      // gets launched into its own task.
      launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
  }
}

上面這段代碼可以知道,當sourceRecord爲null,且該activity不在最近列表中,那麼就要給flag添加FLAG_ACTIVITY_NEW_TASK(如果沒有的話).

當sourceRecord不爲null,也就是說是從另一個activity中啓動該activity的,那麼如果sourceRecord所代表的activity的啓動模式,是singleinstance的話,也要給flag添加FLAG_ACTIVITY_NEW_TASK.

最後就是當要啓動的activity自己設置了啓動模式爲SingleInstance或者SingleTask,也要給flag添加FLAG_ACTIVITY_NEW_TASK.

接下來的這段代碼是一個保險的檢查,可能啓動這個activity的activity要被銷燬了(從launcher啓動app,不走這段代碼,因爲sourceRecord爲null)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ActivityInfo newTaskInfo = null;
Intent newTaskIntent = null;
ActivityStack sourceStack;
if (sourceRecord != null) {
  if (sourceRecord.finishing) {
      if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
          Slog.w(TAG, "startActivity called from finishing " + sourceRecord
                  + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
          launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
          // 啓動activity的發起者的向關係
          newTaskInfo = sourceRecord.info;
          // 創建原task時的intent,也就是啓動這個task 根activity的intent
          newTaskIntent = sourceRecord.task.intent;
      }
      sourceRecord = null;
      sourceStack = null;
  } else {
      sourceStack = sourceRecord.task.stack;
  }
} else {
  sourceStack = null;
}

主要是檢查啓動它的activity是不是快要被銷燬了,那麼可能task也要銷燬,如果是的話那就後面需要啓動一個新的task,從而將這個activity放到這個task中去。,所以這裏提前保存一些相關信息.

接下來的一段代碼就開始着手尋找一個合適的task來存放這個即將啓動的activity,如果沒有的話,就創建一個新task.

AMS首先肯定是努力尋找一個已經存在的task:

FLAG_ACTIVITY_NEW_TASK標誌表示想要重新創建一個task,但是未必一定要新建.

當有FLAG_ACTIVITY_NEW_TASK,但沒有設置FLAG_ACTIVITY_MULTIPLE_TASK,或者當前啓動的activity是SingleInstance or SingleTask模式,通過前面文章的介紹可知,AMS會嘗試需找豁然activity中taskAffinity同名的task是否存在,不存在才創建.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
// if語句中的三個條件下需要查找是否有可複用的task
if (((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
             (launchFlags & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
             || launchSingleInstance || launchSingleTask)
{
            if (inTask == null && r.resultTo == null) {
                // 如果是非SingleInstance啓動模式,則利用findTaskLocked查找
                // 如果是 SingleInstance啓動模式,則利用findActivityLocked查找.
                // 這兩個方法返回的是找到的task的頂端的activity,並不一定是要啓動的activity
                ActivityRecord intentActivity = !launchSingleInstance ?
                        findTaskLocked(r) : findActivityLocked(intent, r.info);
                // 第一次啓動app的時候,不會走這個分支的
                if (intentActivity != null) {
                    // When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused
                    // but still needs to be a lock task mode violation since the task gets
                    // cleared out and the device would otherwise leave the locked task.
                    if (isLockTaskModeViolation(intentActivity.task,
                            (launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
                            == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
                        showLockTaskToast();
                        Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
                        return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
                    }
                    if (r.task == null) {
                        r.task = intentActivity.task;
                    }
                    // 如果找到的activity所在的task的intent爲null
                    // 這種情況發生在TaskReparenting之後,TaskReparenting之後,AMS爲這個activity創建一個新的task,並將啓動這個activity的Intent賦值給task.affinityIntent,並且此時的//task.Intent==null
                    if (intentActivity.task.intent == null) {
                        // 這時要設置task的intent爲要啓動activity的intent
                        intentActivity.task.setIntent(r);
                    }
                    // 找到task所在的ActivityStack
                    targetStack = intentActivity.task.stack;
                    targetStack.mLastPausedActivity = null;
                    // 找到當前處於前臺的ActivityStack
                    final ActivityStack focusStack = getFocusedStack();
                    // 找到 處於前臺的ActivityStack中的最頂端activity
                    // 實際就是編譯ActivityStack中的 mTaskHistory
                    //  mTaskHistory中記錄了該ActivityStack中最近所有的Task
                    // 首先遍歷最近運行的Task中activity,然後找到task中頂端的activity
                    ActivityRecord curTop = (focusStack == null)
                            ? null : focusStack.topRunningNonDelayedActivityLocked(notTop);
                    boolean movedToFront = false;
                    // 此時判斷運行在前臺的activity的task是否和要啓動的activity所需的task是否一致,
                    // 不一致的話,設置movedToFront爲true,預示着需要將啓動的activity所需的task調到前臺
                    //
                    if (curTop != null && (curTop.task != intentActivity.task ||
                            curTop.task != focusStack.topTask())) {
                        r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
                        if (sourceRecord == null || (sourceStack.topActivity() != null &&
                                sourceStack.topActivity().task == sourceRecord.task)) {
                            // We really do want to push this one into the user's face, right now.
                            if (launchTaskBehind && sourceRecord != null) {
                                intentActivity.setTaskToAffiliateWith(sourceRecord.task);
                            }
                            movedHome = true;
                            // 將待啓動的Activity的task移動到其所在的ActivityStack的最頂端
                            // 將ActivityStack調到前臺.
                            targetStack.moveTaskToFrontLocked(intentActivity.task, noAnimation,
                                    options, r.appTimeTracker, "bringingFoundTaskToFront");
                            movedToFront = true;
                            if ((launchFlags &
                                    (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
                                    == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
                                // Caller wants to appear on home activity.
                                intentActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
                            }
                            options = null;
                        }
                    }
                    if (!movedToFront) {
                        if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Bring to front target: " + targetStack
                                + " from " + intentActivity);

                        targetStack.moveToFront("intentActivityFound");
                    }

                    // 如果包含這個flag,那麼需要reset task
                    // 就是銷燬那麼使用FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET(API21已經廢棄取而代之的是FLAG_ACTIVITY_NEW_DOCUMENT)
                    // 啓動的activity
                    if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
                      // 首先檢查要啓動的activity,也就是r中的intent中的flag是否設置FLAG_CLEAR_TASK_ON_LAUNCH,設置的話,forceReset設置爲true
                      // 如果沒有設置FLAG_ALWAYS_RETAIN_TASK_STATE,forceReset設置爲true,設置的話,forceReset不做處理
                      // 也是就是說當FLAG_CLEAR_TASK_ON_LAUNCH和FLAG_ALWAYS_RETAIN_TASK_STATE都設置的話,引發衝突,此時忽略FLAG_ALWAYS_RETAIN_TASK_STATE
                      // 該方法內部會逆序索引mTaskHistory,一次和intentActivity.task做比較,一致的話,執行resetTargetTaskIfNeededLocked
                      // 不一致的話執行resetAffinityTaskIfNeededLocked,處理"allowTaskReparenting"的情況
                      // 總之該方法返回rest task之後task的頂端activity,rest時,FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET啓動的activity以及在其之上的activity都會被clear,
                      // FLAG_ALLOW_TASK_REPARENTING啓動的activity可能會被移到其他的task
                      // 如果新啓動activity帶有FLAG_FINISH_ON_TASK_LAUNCH,一律要求刪除除root activity之外的所有的activity
                        intentActivity = targetStack.resetTaskIfNeededLocked(intentActivity, r);
                    }
                    // 這裏如果startFlags中有START_FLAG_ONLY_IF_NEEDED的話,
                    // 表示只在需要的情況下才會啓動目標,即如果被啓動的對象和調用者是同一個的時候,那麼就沒有必要重複操作。
                    // 從launcher啓動app不會設置這個flag
                    if ((startFlags & ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
                        if (doResume) {
                            resumeTopActivitiesLocked(targetStack, null, options);

                            // Make sure to notify Keyguard as well if we are not running an app
                            // transition later.
                            if (!movedToFront) {
                                notifyActivityDrawnForKeyguard();
                            }
                        } else {
                            ActivityOptions.abort(options);
                        }
                        return ActivityManager.START_RETURN_INTENT_TO_CALLER;
                    }
                    if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
                            == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {

                        reuseTask = intentActivity.task;
                        // 清除task中所以已經存在的activity
                        reuseTask.performClearTaskLocked();
                        // 以啓動這個新activity的intent爲內容,重新設置這個task中的相關屬性,
                        // 例如 affinity等,也就是說新啓動的activity會成爲這個task的root activity
                        reuseTask.setIntent(r);
                    } else if ((launchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                            || launchSingleInstance || launchSingleTask) {
                        // 在上面if中的三個條件意味着,要清除task中要啓動的activity之上的所有activity(不包括這個這個要啓動的activity)
                        // 但是也有例外的清空,如果FLAG_ACTIVITY_CLEAR_TOP,但沒設置singleTop模式而是設置了standard模式(LAUNCH_MULTIPLE),那麼task中這個已經存在的要啓動的
                        // activity實例,也會被清除,這是由下面的這個方法完成的工作,並返回可複用的activity.返回null,表示清除了這個已經存在的實例,表示不希望複用相同的activity。
                        ActivityRecord top =
                                intentActivity.task.performClearTaskLocked(r, launchFlags);

                        // 不爲null 表示找到了可複用的activity
                        if (top != null) {
                          // 如果是root activity,還要利用新的intent修改task的相關屬性
                            if (top.frontOfTask) {
                                top.task.setIntent(r);
                            }
                            ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT,
                                    r, top.task);
                            // 將新intent發送給這個這個已經存在的activity實例的onNewIntent()
                            top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
                        } else {
                          // 爲null表示清除了這個已經存在的實例,表示不希望複用相同的activity
                         // 設置addingToTask爲true,表示需要將activity天價到可複用的task中
                            addingToTask = true;
                            // Now pretend like this activity is being started by the top of its
                            // task, so it is put in the right place.
                            sourceRecord = intentActivity;
                            TaskRecord task = sourceRecord.task;
                            if (task != null && task.stack == null) {
                                // Target stack got cleared when we all activities were removed
                                // above. Go ahead and reset it.
                                targetStack = computeStackFocus(sourceRecord, false /* newTask */);
                                targetStack.addTask(
                                        task, !launchTaskBehind /* toTop */, false /* moving */);
                            }

                        }// 下面的這個else  if 處理 standard和signaltop模式
                    } else if (r.realActivity.equals(intentActivity.task.realActivity)) {
                        // 如果是signaltop模式,而且要啓動的activity就是task的頂端activity,
                        if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 || launchSingleTop)
                                && intentActivity.realActivity.equals(r.realActivity)) {
                            ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r,
                                    intentActivity.task);
                            // 如果當前task頂端的activity就是其root activity,那麼就要使用新的intent重新修改task的相關屬性
                            if (intentActivity.frontOfTask) {
                                intentActivity.task.setIntent(r);
                            }
                            // 將新intent發送給這個這個已經存在的activity實例的onNewIntent()
                            intentActivity.deliverNewIntentLocked(callingUid, r.intent,
                                    r.launchedFromPackage);
                        } else if (!r.intent.filterEquals(intentActivity.task.intent)) {
                            // In this case we are launching the root activity
                            // of the task, but with a different intent.  We
                            // should start a new instance on top.
                            // 當前啓動的activity和task頂端activity不一致,而且啓動activity的的Intent和task的Intent不同,那麼將會重新啓動這個activity。
                            addingToTask = true;
                            sourceRecord = intentActivity;
                        }
                    } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
                        // 如果啓動的Intent沒有設置Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,那麼一定不會複用任何的activity。
                        // In this case an activity is being launched in to an
                        // existing task, without resetting that task.  This
                        // is typically the situation of launching an activity
                        // from a notification or shortcut.  We want to place
                        // the new activity on top of the current task.
                        addingToTask = true;
                        sourceRecord = intentActivity;
                            // rootWasReset爲 True if the intent at the root of the task had
                            // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag.
                    } else if (!intentActivity.task.rootWasReset) {
                        // In this case we are launching in to an existing task
                        // that has not yet been started from its front door.
                        // The current task has been brought to the front.
                        // Ideally, we'd probably like to place this new task
                        // at the bottom of its stack, but that's a little hard
                        // to do with the current organization of the code so
                        // for now we'll just drop it.
                        intentActivity.task.setIntent(r);
                    }
                    //  addingToTask爲false,表示不需要創建一個新activity,也就是說找到了可複用的activity,那麼
                     // activity的啓動過程至此結束,直接調用resumeTopActivityLocked()resume top的activity即可。
                    if (!addingToTask && reuseTask == null) {
                        // We didn't do anything...  but it was needed (a.k.a., client
                        // don't use that intent!)  And for paranoia, make
                        // sure we have correctly resumed the top activity.
                        if (doResume) {
                          // 顯示可複用的task中的頂端activity,與要啓動的activity不一致
                            targetStack.resumeTopActivityLocked(null, options);
                            if (!movedToFront) {
                                // Make sure to notify Keyguard as well if we are not running an app
                                // transition later.
                                notifyActivityDrawnForKeyguard();
                            }
                        } else {
                            ActivityOptions.abort(options);
                        }
                        return ActivityManager.START_TASK_TO_FRONT;
                    }
                }
            }
        }

上面的這段代碼很重要,主要描述了AMS何種情況下會查找是否有可複用的task,已經可複用的task中是否有可複用的activity.如果沒有可複用的activity,則需要啓動一個新的activity,如果有可複用的activity,那麼activity的啓動過程至此結束,直接調用resumeTopActivityLocked()resume top的activity即可。

上面已經對代碼進行了詳細的註釋,現在對其總結一下:

什麼情況下會去查找是否有可複用的task

以下3種條件需要檢查是否有有task可複用

  1. (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&

    (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0;
    
  2. r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK

  3. r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE

Intent.FLAG_ACTIVITY_MULTIPLE_TASK不能單獨使用,它是和Intent.FLAG_ACTIVITY_NEW_TASK或者FLAG_ACTIVITY_NEW_DOCUMENT結合起來使用的,如果設置了Intent.FLAG_ACTIVITY_MULTIPLE_TASK,那麼將會永遠啓動一個新的task,不管是否有可複用的task。

如何查找可複用的task

  1. launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE的情況,也就是前面兩個條件,遵循如下規則: findTaskLocked(r)

該函數的功能是找到目標ActivityRecord,也就是要啓動的activity所在的任務棧(TaskRecord),如果找到,則返回棧頂的ActivityRecord,否則,返回null

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
ActivityRecord findTaskLocked(ActivityRecord r) {
    if (DEBUG_TASKS) Slog.d(TAG, "Looking for task of " + r);
    for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
        final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityStack stack = stacks.get(stackNdx);
            if (!r.isApplicationActivity() && !stack.isHomeStack()) {
                if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: (home activity) " + stack);
                continue;
            }
            if (!stack.mActivityContainer.isEligibleForNewTasks()) {
                if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: (new task not allowed) " +
                        stack);
                continue;
            }
            // 實際調用ActivityStack的findTaskLocked
            final ActivityRecord ar = stack.findTaskLocked(r);
            if (ar != null) {
                return ar;
            }
        }
    }
    if (DEBUG_TASKS) Slog.d(TAG, "No task found");
    return null;
}

該方法是ActivityStackSupervisor中定義的,其中的變量mActivityDisplays,也是ActivityStackSupervisor中定義的,是一個SparseArray 的數組,有幾塊屏幕,就有幾個ActivityDisplay.

ActivityDisplay類也是ActivityStackSupervisor中定義的.Android支持多屏顯示,在不同的顯示設備上可以有不同的ActivityStack。

所有的ActivityStack都是通過ActivityStackSupervisor管理起來的。 在ActivityStackSupervisor內部,設計了ActivityDisplay這個內部類,它對應到一個顯示設備,默認的顯示設備是手機屏幕。 ActivityStackSupervisor間接通過ActivityDisplay來維護多個ActivityStack的狀態。 ActivityStack有一個屬性是mStacks,當mStacks不爲空時,表示ActivityStack已經綁定到了顯示設備, 其實ActivityStack.mStacks只是一個副本,真正的對象在ActivityDisplay中的mStacks.

ActivityStackSupervisor通過變量mActivityDisplays就能間接獲取所有ActivityStack的信息.

Activity的類型有三種:APPLICATION_ACTIVITY_TYPE(應用)、HOME_ACTIVITY_TYPE(桌面)、RECENTS_ACTIVITY_TYPE(最近使用).在ActivityRecord的構造方法中被初始化,當從launcher啓動app時,肯定是APPLICATION_ACTIVITY_TYPE.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if ((!_componentSpecified || _launchedFromUid == Process.myUid()
                 || _launchedFromUid == 0) &&
                 Intent.ACTION_MAIN.equals(_intent.getAction()) &&
                 _intent.hasCategory(Intent.CATEGORY_HOME) &&
                 _intent.getCategories().size() == 1 &&
                 _intent.getData() == null &&
                 _intent.getType() == null &&
                 (intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
                 isNotResolverActivity()) {
             // This sure looks like a home activity!
             mActivityType = HOME_ACTIVITY_TYPE;
             // "com.android.systemui.recents"
         } else if (realActivity.getClassName().contains(RECENTS_PACKAGE_NAME)) {
             mActivityType = RECENTS_ACTIVITY_TYPE;
         } else {
             mActivityType = APPLICATION_ACTIVITY_TYPE;
         }

實際調用ActivityStack的findTaskLocked方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
ActivityRecord findTaskLocked(ActivityRecord target) {
        Intent intent = target.intent;
        ActivityInfo info = target.info;
        ComponentName cls = intent.getComponent();//要啓動的activity的組件名:包名+類名

       ...........

       for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
         .........
         final Intent taskIntent = task.intent;
         final Intent affinityIntent = task.affinityIntent;
         ........
         if (task.rootAffinity.equals(target.taskAffinity)) {
                   if (DEBUG_TASKS) Slog.d(TAG, "Found matching affinity!");
                   return r;
         }else if (taskIntent != null && taskIntent.getComponent() != null &&
                taskIntent.getComponent().compareTo(cls) == 0 &&
                Objects.equals(documentData, taskDocumentData)) {
            return r;
        } else if (affinityIntent != null && affinityIntent.getComponent() != null &&
                affinityIntent.getComponent().compareTo(cls) == 0 &&
                Objects.equals(documentData, taskDocumentData)) {
            return r;
        }
         ...
       }
       ............

總的來說,這種情況下遵循如下規則:

遍歷所有顯示設備中的ActivityStack(一般情況下,只有一個顯示設備)中的所有TaskRecord:

a. 查找ActivityStack中的mTaskHistory是否有與要啓動的activity相同affinity的task,找到的話返回,返回這個task頂端的activity

這裏要說明下,TaskRecord中有兩個關於affinity的屬性,如下所示:

1
2
String affinity;        // The affinity name for this task, or null; may change identity.
String rootAffinity;    // Initial base affinity, or null; does not change from initial root.

兩者的區別代碼註釋也很清晰了,rootAffinity和affinity是存儲創建這個task時,activity的taskAffinity.當rest 這個task的時候,可能會修改task的affinity,但是不會修改rootAffinity.

b. 如果activity沒有affinity,即屬性android:taskAffinity設置爲“”,空字符串時。此時AMS就會去mHistory中去查找是否有task的root activity和啓動的activity相同,通過比較task.intent.getComponent()和啓動activity的Comeponent比較

c.如果task.Intent爲空,這種情況發生在TaskReparenting之後,TaskReparenting之後,AMS爲這個activity創建一個新的task,並將啓動這個activity的Intent賦值給task.affinityIntent,並且此時的task.Intent==null。此時就需要比較task.affinityIntent.getComponent()和啓動activity的Comeponent比較,看是否和啓動的activity相同

以上3個規則中,均是返回找的task中最上面的activity,而不一定是要啓動的activity,至於如何處理要啓動的activity和task中已有的activity,後面會介紹。

  1. launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE的情況,遵循如下規則: findActivityLocked(intent, r.info)

根據Intent和ActivityInfo這兩個參數可以獲取一個Activity的包名,該函數會從棧頂至棧底遍歷ActivityStack中的所有Activity,如果包名匹配成功,就返回

1
2
3
4
5
6
7
8
9
10
11
12
ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) {
     for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
         final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
         for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
             final ActivityRecord ar = stacks.get(stackNdx).findActivityLocked(intent, info);
             if (ar != null) {
                 return ar;
             }
         }
     }
     return null;
 }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) {
    ComponentName cls = intent.getComponent();
    if (info.targetActivity != null) {
        cls = new ComponentName(info.packageName, info.targetActivity);
    }
    final int userId = UserHandle.getUserId(info.applicationInfo.uid);

    for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
        TaskRecord task = mTaskHistory.get(taskNdx);
        if (!isCurrentProfileLocked(task.userId)) {
            return null;
        }
        final ArrayList<ActivityRecord> activities = task.mActivities;
        for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
            ActivityRecord r = activities.get(activityNdx);
                return r;
            }
        }
    }

    return null;
}

對於ActivityInfo.LAUNCH_SINGLE_INSTANCE啓動模式來說,它所處的task中只允許有它一個activity,因此它的規則只符合上面規則中的b.

對於規則a,由於設置了ActivityInfo.LAUNCH_SINGLE_INSTANCE啓動模式的activity,它只能自己獨處一個task,不可能和別人共享同一個task,因此ActivityStack中的mTaskHistory即使存在了與該activity有相同的affinity的activity,如果這個activity和啓動的activity不同,那麼ActivityInfo.LAUNCH_SINGLE_INSTANCE啓動模式的activity也不可能和它共用一個task,因此這規則a完全可以不用檢查。

對於規則b,由於該模式的activity獨處一個task,因此完全沒有可能所處的task的affinity和自己的affinity不同,因此,假如ActivityStack中的mTaskHistory存在相同的activity與啓動的activity相同,那麼這個activity的affinity必然和自己的相同。所以對於這種模式,規則b囊括了其他模式的規則a,b。

對於規則c,同樣的道理,ActivityInfo.LAUNCH_SINGLE_INSTANCE啓動模式的activity不可能處在與自己不同affinity的task中,因此不可能出現TaskReparenting操作,所以這條也不需要。

如何處理找到的可複用的task

首先得到當前前臺的activity,以從launcher啓動app這個場景來說,當前前臺activity就是home.

1
2
3
final ActivityStack lastStack = getLastStack();
ActivityRecord curTop = lastStack == null?
                            null : lastStack.topRunningNonDelayedActivityLocked(notTop);

接着判斷urTop.task != intentActivity.task,其實說白了,就是爲了確定當前的task是否就是要啓動的activity所在的task,不是的話調用

targetStack.moveTaskToFrontLocked()方法,該方法會調用insertTaskAtTop()方法將task移動其所在的ActivityStack的頂端,然後調用moveToFront()方法將這個Activity移動到前臺.也就是預示着要啓動的activity所在的task被移動到了前臺.

將task移動到前臺後檢查是否需要rest task

如果啓動activity的flag設置了FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,則需要進行rest task.

最常見的情況,當從Home啓動應用程序時,會設置這個flag;從recently task進入應用程序,則不會設置這個falg。

設置了FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,AMS會對複用的task作如下處理:

⑴ 對於複用task中的除root activity外的activity,有如下處理

在此之前,先介紹activity的幾個關鍵屬性(task的root activity 設置了下面所提的屬性的話,task也就具備了這樣的特性):

① 如果複用task在後臺時間超過一定的時間,那麼在這個過程中將clear除root activity之外的所有的activity;

② 如果新啓動的activity設置了屬性ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE,那麼表明不需要clear task中的activity;

③ 如果新啓動的activity設置了屬性ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH,那麼表明只要task離開前臺,一律要求刪除除root activity之外的所有的activity;

④ 複用task中的activity設置了屬性ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH,那麼複用task從home中再次被啓動到前臺時,這個activity會被刪除;

⑤ 複用task中的activity設置了屬性ActivityInfo.FLAG_ALLOW_TASK_REPARENTIN,並且這個activity的resultTo爲空,那麼也就是說這個activity和它的caller沒有依賴關係,需要對其進行TaskReparenting操作

⑥ 複用task中的activity的Intent設置屬性Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET,那麼下次再從home中進入到task中,那麼將刪除設置了該屬性的activity以上所有的activity,例如A–>B–>C–>D–>E,假如在C啓動D時設置了該屬性,那麼下次從HOME中再次進入到這個task中時,將會是A–>B–>C。

⑦ 如果複用task中的activity的resultTo不爲空,也就是啓動這個activity的是一個activity,那麼這個activity的處理將按照它的前一個activity的處理方式來處理,不管在何時情況下,它的前一個activity都是啓動它的activity,即便resultTo不是前一個activity,如設置了Intent.FLAG_ACTIVITY_FORWARD_RESULT。如果複用task中每個activity的resultTo都不爲空,並且上述處理優先級在其前面的屬性沒有設置的話,那麼這個複用task中的activity將不作任何的處理。

一般情況下,activity的resultTo都不爲空,除非設置了Intent.FLAG_ACTIVITY_FORWARD_RESULT,那麼此時被啓動的activity的caller的resultTo將會爲空。

task中的activity的屬性設置是上述屬性的組合,因此reset task過程要按照一定的優先級來處理,上述屬性的處理優先級是:⑥=④>⑦>⑤>③=②>①

具體操作順序如下:

  1. 根據⑥,④條件來刪除複用task中相應的activity;

2 .條件下,將會暫時不做處理,再根據它的前一個activity的屬性來做處理,即使這個activity設置了allowTaskReparenting;

  1. 如果activity的resultTo爲空,並且滿足條件⑤,那麼將其及其以上未作處理的,滿足條件⑦的所有activity,一併進行TaskReparenting操作,並放置在mHistory棧底。它們在mHistory棧底順序如同在複用task中的順序;

  2. 根據①②③的條件來刪除複用task中相應的activity。

⑵ 不屬於複用task的activity,並且它的resultTo不爲空,那麼將根據它的前一個activity的處理來處理;

⑶ 不屬於複用task,但是和當前啓動的activity有相同affinity,並且允許TaskReparenting操作,那麼將進行以下操作:

如果滿足上述的①②③④的條件,但是其中的task不是複用task,而是這個activity所處的task,那麼將輸出這個activity,而不是進行TaskReparenting操作。

爲什麼非複用task中的activity,和當前啓動的activity有相同affinity,並且允許TaskReparenting操作,滿足了①②③④的條件之後要刪除呢,爲什麼非複用task中的其他activity,不需要刪除呢?

正因爲它和啓動的activity有相同的affinity,因此AMS認爲這個activity是和啓動activity相關的,以後可能會重新調用,所以當其滿足刪除條件後,這時它將不允許TaskReparenting操作,並且不應該再允許它存在於其他的task中,此時應該刪除。

如果沒有滿足①②③④的條件,那麼將會對其進行TaskReparenting操作,重新將其移動到複用task或新啓動的task中。

判斷可複用的task中是否有可複用的activity

(1)Intent設置了Intent.FLAG_ACTIVITY_CLEAR_TOP,或者launchMode == ActivityInfo.LAUNCH_SINGLE_TASK,或者r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE;這3種條件有一個共同點,就是啓動的activity啓動之後,在這個task中,這個activity之上不能有其他的activity。

一般情況下,需要將複用task中啓動的activity之上的所有的activity刪除,

當activity的launchMode == ActivityInfo.LAUNCH_MULTIPLE,即standard模式,並且Intent並未要求singletop模式,這種情況是連複用task中與啓動activity相同的activity都要刪除,也就是不希望複用相同的activity。

performClearTaskLocked()實現了上述功能,並返回可複用的activity。

如果有可複用的activity,並且這個activity是task的root activity,由於task的Intent是root activity的Intent,所以需要重新設置task的Intent。

向可複用的activity發送新的Intent,通知它Intent的變化,最終會調用到這個activity的onNewIntent()方法。

如果沒找到可複用的activity,那麼設置addingToTask = true;sourceRecord = intentActivity;

⑵ 如果不滿足⑴條件的話,但是啓動的activity與複用task的root activity相同。

如果此時Intent設置了Intent.FLAG_ACTIVITY_SINGLE_TOP,並且複用task的top activity正好是要啓動的activity,則複用這個activity,同時更新activity的Intent,如果需要更新task的Intent。

如果Intent沒有設置了Intent.FLAG_ACTIVITY_SINGLE_TOP,即使設置了,但是當前的top activity不是正要啓動的activity,那麼會判斷當前啓動的Intent和task的Intent不同,那麼將會重新啓動這個activity。

其他情況,將直接resume top的activity(不是要啓動的activity)。

⑶ 如果⑴ ⑵條件均不滿足,其實如果不滿足⑴ ⑵條件的話,複用的task中就不存在與啓動的activity相同的activity了,如果啓動的Intent沒有設置Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,那麼一定不會複用任何的activity。

(4) 如果⑴ ⑵條件均不滿足,並且Intent設置了Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,那麼需要檢查當前複用task的Intent是否設置了Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED。如果沒有設置,重新設置新的Intent,這種情況下同樣不可能複用activity,因爲task中不存在與啓動的activity相同的activity。

在4這種情況,當複用的task中沒有找到要啓動的activity的時候,將不會顯示要啓動的activity,addingToTask爲false,而是改爲顯示覆用的task中頂端的activity.比如從launcher中啓動app,隨便進入app中的另一個activity中,然後按home健,然後在點擊app圖標,如果剛剛進入的activity沒有設置FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET,那麼將顯示這個activity而不是app的主activity.

至此,整個Task複用,以及activity複用的過程就介紹完了,如果沒有可複用的activity,且沒沒有可複用的task則需要啓動一個新的activity,或者有可複用的task但是沒設置FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,也要重啓動一個新的activity,但是如果有可複用的activity而且設置了FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,則不會啓動要啓動的activity,而是啓動可複用task的頂端的task.

singleTop和singleTask屬性的處理

餘下代碼是針對singleTop和singleTask屬性的處理,前面分析Task複用的時候,也有對singleTop和singleTask屬性的處理,兩者有什麼不同呢?

前面是在有可複用task的前提下分析的.

接下來分析都是在沒有可複用task前提下.

當設置Intent.FLAG_ACTIVITY_SINGLE_TOP或者launchMode == ActivityInfo.LAUNCH_SINGLE_TOP或者launchMode == ActivityInfo.LAUNCH_SINGLE_TASK這幾種情況下,如果top activity與啓動的activity爲同一個activity,那麼將複用top activity,並直接resume top activity。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
ActivityStack topStack = getFocusedStack();
           ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(notTop);
           if (top != null && r.resultTo == null) {
               // 如果頂端activity就是要啓動activity,那就啓動頂端的就可以了
               if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
                   if (top.app != null && top.app.thread != null) {
                       if ((launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
                           || launchSingleTop || launchSingleTask) {
                           ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top,
                                   top.task);
                           // For paranoia, make sure we have correctly
                           // resumed the top activity.
                           topStack.mLastPausedActivity = null;
                           if (doResume) {
                               resumeTopActivitiesLocked();
                           }
                           ActivityOptions.abort(options);
                           if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
                               // We don't need to start a new activity, and
                               // the client said not to do anything if that
                               // is the case, so this is it!
                               return ActivityManager.START_RETURN_INTENT_TO_CALLER;
                           }
                           top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
                           return ActivityManager.START_DELIVERED_TO_TOP;
                       }
                   }
               }
           }

       }else {
            if (r.resultTo != null) {
                r.resultTo.task.stack.sendActivityResultLocked(-1, r.resultTo, r.resultWho,
                        r.requestCode, Activity.RESULT_CANCELED, null);
            }
            ActivityOptions.abort(options);
            return ActivityManager.START_CLASS_NOT_FOUND;
        }

r.resultTo == null這個條件是在startActivityForResult()的requestCode<0時成立。

standard和singleInstance模式

沒有可複用的task,那麼必須要創建新的task嗎? 不一定!!!

比如說從一個app中的一個activity啓動另外一個app的一個activity,如果沒有添加FLAG_ACTIVITY_NEW_TASK,那麼這個activity就會添加到當前的task中.如果有FLAG_ACTIVITY_NEW_TASK,則會新創建一個task.

第一次從桌面啓動app時,是有這個標記的,所以會新創建一個task.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// Should this be considered a new task?
// 如果有可複用的task,addingToTask爲true
        if (r.resultTo == null && inTask == null && !addingToTask
                && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {

          .....
          newTask = true;
          // 找到一個合適的ActivityStack
          targetStack = computeStackFocus(r, newTask);
          // 確保放在ActivityStack中的mstacks的尾端也就是棧頂端.
          // 實際上是ActivityDisplay.mstakcks
          // 也就是確保找到的這個ActivityStack調整到當前顯示屏幕的頂端
          // 如果targetStack和homestack處於同一個屏幕中時,要調用ActivityStackSupervisor.moveHomeStack方法
          // 因爲要啓動新的activity了(在沒有分屏時,都符合這種情況)
          targetStack.moveToFront("startingNewTask");
          .....
          // reuseTask兩情況下不爲null,一是intask不爲null,也就是說從最近任務列表啓動;
          // 二是有可複用task,但是設置有FLAG_ACTIVITY_NEW_TASK 和 FLAG_ACTIVITY_CLEAR_TASK
          f (reuseTask == null) {
            // 創建Task的同時,會把task加入到activityStack中,launchTaskBehind爲false,那麼這個task通過insertTaskAtTop加入到activitystack的頂端
            // 也就是mTaskHistory的末尾
                    r.setTask(targetStack.createTaskRecord(getNextTaskId(),
                            newTaskInfo != null ? newTaskInfo : r.info,
                            newTaskIntent != null ? newTaskIntent : intent,
                            voiceSession, voiceInteractor, !launchTaskBehind /* toTop */),
                            taskToAffiliate);
                    if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " +
                            r.task);
                } else {
                    r.setTask(reuseTask, taskToAffiliate);
                }
          .....

          mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
                       intent, r.getUriPermissionsLocked(), r.userId);
          ..........
          targetStack.mLastPausedActivity = null;
      // 調用startActivityLocked繼續啓動activity
      targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
      if (!launchTaskBehind) {
          // Don't set focus on an activity that's going to the back.
          mService.setFocusedActivityLocked(r, "startedActivity");
      }
      return ActivityManager.START_SUCCESS;
    }

這裏需要強調一下computeStackFocus這個方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 ActivityStack computeStackFocus(ActivityRecord r, boolean newTask){
...........
if (mFocusedStack != mHomeStack && (!newTask ||
                mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
            if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
                    "computeStackFocus: Have a focused stack=" + mFocusedStack);
            return mFocusedStack;
        }

final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks;
        for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
            stack = homeDisplayStacks.get(stackNdx);
            if (!stack.isHomeStack()) {
                if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
                        "computeStackFocus: Setting focused stack=" + stack);
                return stack;
            }
        }
// Need to create an app stack for this user.
 stack = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY);
 if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r="
         + r + " stackId=" + stack.mStackId);
 return stack;
.......

}

當沒有啓動過app,例如剛開機時,那麼mFocusedStack就是mHomeStack.

此時如果從launcher中啓動一個app,那麼就會調用createStackOnDisplay,創建一個 ActivityStack供運行衆多的app使用的ActivityStack.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
int getNextStackId() {
       while (true) {
           if (++mLastStackId <= HOME_STACK_ID) {
               mLastStackId = HOME_STACK_ID + 1;
           }
           if (getStack(mLastStackId) == null) {
               break;
           }
       }
       return mLastStackId;
   }
    // 在顯示屏幕中創建ActivityStack
    ActivityStack createStackOnDisplay(int stackId, int displayId) {
        ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
        if (activityDisplay == null) {
            return null;
        }
        // 相當於創建了一個ActivityStack
        ActivityContainer activityContainer = new ActivityContainer(stackId);
        mActivityContainers.put(stackId, activityContainer);
        // 將ActivityStack與activityDisplay綁定
        activityContainer.attachToDisplayLocked(activityDisplay);
        return activityContainer.mStack;
    }
    void attachToDisplayLocked(ActivityDisplay activityDisplay) {
               if (DEBUG_STACK) Slog.d(TAG_STACK, "attachToDisplayLocked: " + this
                       + " to display=" + activityDisplay);
               // ActivityStack綁定的顯示屏幕
               mActivityDisplay = activityDisplay;
               // ActivityStack綁定的顯示屏幕的id
               mStack.mDisplayId = activityDisplay.mDisplayId;
               // ActivityStack中的mstack來自於activityDisplay.mStacks
               // ActivityStack.mstack記錄的是與之綁定的顯示屏幕中的其他ActivityStack
               mStack.mStacks = activityDisplay.mStacks;
               // 將此ActivityStack加入到顯示屏也就是ActivityDisplay.mStacks中
               // ActivityDisplay.mStacks記錄的是這個快屏幕中所有的ActivityStack
               // 此時,ActivityStack.mstack也包括了自己.
               activityDisplay.attachActivities(mStack);
               mWindowManager.attachStack(mStackId, activityDisplay.mDisplayId);
           }
     void attachActivities(ActivityStack stack) {
             if (DEBUG_STACK) Slog.v(TAG_STACK,
                     "attachActivities: attaching " + stack + " to displayId=" + mDisplayId);
             mStacks.add(stack);
         }

activityDisplay代表一個顯示屏幕,activityContainer是ActivityStack的馬甲.

當從launcnher啓動過一個app之後,按home鍵回到桌面,此時mFocusedStack被設置爲mHomeStack.但是第一次從launcher啓動app的時候,創建了ActivityStack並且執行了attachToDisplayLocked()方法.

在該方法中執行了activityDisplay.attachActivities(mStack);將創建的ActivityStack加入到了顯示屏幕(默認爲DEFAULT_DISPLAY)中mStacks中.mHomeStack也是一個ActivityStack,綁定的顯示屏幕是DEFAULT_DISPLAY.代碼中註釋也說了,ActivityStack的mStacks記錄的是與之綁定的顯示屏幕中的所有ActivityStack.自然也包括前面創建的app stack 了.

所以啓動另一個app時執行:

1
2
3
4
5
6
7
8
9
10
11
12
//拿到DEFAULT_DISPLAY屏幕綁定的所有ActivityStack
final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks;
        for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
          stack = homeDisplayStacks.get(stackNdx);
            // 找到一個不是mHomeStack的ActivityStack並返回
            // 當之前在這個快屏幕中創建過一個app stack時,就返回這個stack.
            if (!stack.isHomeStack()) {
                if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
                        "computeStackFocus: Setting focused stack=" + stack);
                return stack;
            }
        }

⑴ 設置了Intent.FLAG_ACTIVITY_NEW_TASK,則爲該activity創建一個新的task;

上述貼出的代碼是從launcher啓動app時的代碼的流程,未貼出的代碼總結如下:

⑵ 在當前的task中啓動新的activity,

①當前的caller是一個activity,如果設置Intent.FLAG_ACTIVITY_CLEAR_TOP,當前的task如果存在要啓動的activity(這個和上一節中的Task複用時的clear top過程不同,兩者是互斥的過程,不衝突),清除其上的所有的activity;

 當前的caller是一個activity,如果設置Intent.FLAG_ACTIVITY_REORDER_TO_FRONT,這個flag表示如果啓動的activity已經在當前的task中,那麼如果當前啓動的Intent設置了該flag,那麼則會將這個activity從task中移動到top。

     如果A-->B-->C-->D,D啓動B時,設置了該flag,那麼將變爲A-->C-->D-->B

     ①②兩個條件,則不需要再啓動新的activity,直接resume top。

  當前的caller是一個activity,其他情況則需要啓動新的activity。

⑶ 當前的caller不是activity,那麼仍將新啓動的activity放在top的task中。

發佈了14 篇原創文章 · 獲贊 26 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章