??????Activity啟動流程原始碼實作詳解(一)
Android四大組件原始碼實作詳解系列博客目錄:
Android應用行程創建流程大揭秘
Android四大組件之bindService原始碼實作詳解
Android四大組件之Activity啟動流程原始碼實作詳解概要
Android四大組件之Activity啟動流程原始碼實作詳解(一)
前言
??在正式開始Android四大組件之Activity啟動流程原始碼實作詳解之前,如果小伙們還沒有閱讀Activity啟動流程原始碼實作詳解概要,強烈建議先行閱讀該概要,因為該篇博客從整體概要和Activity啟動的前期知識點出發為我們提供了提綱和將要涉及到的知識點的梳理,在本篇博客中我們將重點分析目標行程發送Activity啟動請求和AMS服務對啟動Activity的請求的初步處理,即重點闡述如下階段流程:
-
Souruce端行程發送請求目標Activity啟動階段:
?1.Source端發起顯示/隱式啟動請求啟動Activity -
System_server行程通過AMS處理啟動Activity請求:
?2.決議啟動目標Activity的Intent
?3.創建目標Activity對應的ActivityRecord -
注意:本篇的介紹是基于Android 7.xx平臺為基礎的,其中涉及的代碼路徑如下:
frameworks/base/services/core/java/com/android/server/am/
--- ActivityManagerService.java
--- ProcessRecord.java
--- ActivityRecord.java
--- ActivityResult.java
--- ActivityStack.java
--- ActivityStackSupervisor.java
--- ActivityStarter.java
--- TaskRecord.java
frameworks/base/services/core/java/com/android/server/pm、
--- PackageManagerService.java
frameworks/base/core/java/android/app/
--- IActivityManager.java
--- ActivityManagerNative.java (內部包含AMP)
--- ActivityManager.java
--- AppGlobals.java
--- Activity.java
--- ActivityThread.java(內含AT)
--- LoadedApk.java
--- AppGlobals.java
--- Application.java
--- Instrumentation.java
--- IApplicationThread.java
--- ApplicationThreadNative.java (內部包含ATP)
--- ActivityThread.java (內含ApplicationThread)
--- ContextImpl.java
- 并且在后續的原始碼分析程序中為了簡述方便,會將做如下簡述:
ApplicationThreadProxy簡稱為ATP
ActivityManagerProxy簡稱為AMP
ActivityManagerService簡稱為AMS
ActivityManagerNative簡稱AMN
ApplicationThreadNative簡稱ATN
PackageManagerService簡稱為PKMS
ApplicationThread簡稱為AT
ActivityStarter簡稱為AS,這里不要和ActivityServices搞混淆了
ActivityStackSupervisor簡稱為ASS
在正式開始相關的原始碼分析前,還是先奉上呼叫的時序圖以便小伙們先從整體上有個清晰的概括,然后再從細節開擼!

一. Source端開始請求執行啟動Activity
??Source端開始請求執行啟動Activity的核心偽代碼如下,接下來我們以下面的偽代碼為脈絡逐步分析,但是不會每個原始碼細節都予以分析(并且如果小伙們只是想大概了解一下基本流程,那么下面的偽代碼就夠了!),而是挑出重點!
//發起端行程發起啟動Activity請求
Activity.startActivity(...)
Activity.startActivityForResult(...)
mInstrumentation.execStartActivity(...)
AMP.startActivity(...)//通過AMS代理端向AMS發起啟動Activity的Binder IPC請求
mInstrumentation.checkStartActivityResult(...)//檢測啟動是否成功
mMainThread.sendActivityResult(...)
2.1 Activity.startActivity
Intent intent = new Intent();
intent.setAction("xxx.xxx.xxx");
startActivity(intent);
??通常我們在Activity啟動Activity會直接呼叫startActivity方法,此時會執行Activity的startActivity方法
//Activity.java
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
此時可以看到會接著呼叫Activity的多載startActivity方法,我們接著繼續分析其多載方法
//Activity.java
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
startActivityForResult(intent, -1);//進入該分支,注意此時的引數requestCode取值為-1,表明發起端行程無需接收Activity的結果,詳見章節2.2
}
}
此時我們的入參options為null,所以會走入else的分支,即此時的startActivityForResult方法的引數requestCode被默認賦予了-1的值,
??分析到這里不知道小伙們注意到一個問題沒有,就是通常我們啟動Activity有兩個方法startActivity和startActivityForResult,這里我們可以看到Activity中呼叫startActivity的內部也是呼叫的startActivityForResult的,
??而我們知道通過startActivityForResult啟動目標Activity可以在Activity中回呼onActivityResult接收目標Acitiy啟動的情況,而呼叫startActivity則不可以呢?其最最主要的原因就是呼叫startActivity啟動目標Acitivity時,其內部呼叫startActivityForResult傳遞的引數requestCode被默認賦予為-1了在后續程序中會根據此值判斷是否需要傳遞回呼叫結果,這也意味著我們在Activity呼叫startActivityForResult的時候傳遞的requestCode值為-1(通過后續分析我們可知,只要小于0)的話,那么onActivityResult是不起作用的,所以當我們呼叫startActivityForResult的時候需要注意這一點,
2.2 Activity.startActivityForResult
//Activity.java
Activity mParent;
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
/*
* mToken: 資料型別為IBinder,這個Token貫穿AMS,Activity,WMS,并且可以跨行程傳遞
* mAppThread: 又是一個IBinder型別,此處它是Binder物體ApplicationThread
*/
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);//詳見2.3
if (ar != null) {
mMainThread.sendActivityResult(//發送執行結果
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
if (requestCode >= 0) {//注意此處
mStartedActivity = true;
}
cancelInputsAndStartExitTransition(options);
} else {//子視窗中會執行此分支
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
} else {
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}
??注意這里有一個判斷邏輯mParent是否為null,這里的mParent 根據檔案注釋和實測應該是用來判斷是否是在子視窗的,類似于在Dialog中啟動Activity中的那種,在當前情況下我們可知為null所以會走入ifi分支,
這里我們需要重點分析一下Instrumentation這個類,Instrumentation是android系統中啟動Activity的一個實際操作類,即實際執行者,在有些書中也被成為Activity的大管家,并且這里我們所說的Source端開始請求執行啟動Activity實際上就是Instrumentation進行實際操作執行的,那么為什么說是在應用行程端的啟動呢?實際上Activity的啟動分為應用行程端的啟動和system_server服務行程端的啟動,Activity的啟動不是獨立的,而是多個應用行程相互配合最終完成了Activity在系統中的啟動的,而在應用行程端的啟動實際的操作類就是Intrumentation來執行的,我們來簡單看看其提供了那些基本方法:
newActivity(…)
newApplication(…)
callApplicationOnCreate(…)
callActivityOnCreate(…)
callActivityOnNewIntent(…)
callActivityOnXXX(…)
execStartActivity(…)
從上面可以看到它的方法都是Application和Activity的創建以及生命周期的相關方法,
同時這里有一個知識點,我需要提前補充一下就是對于每一個Android App行程來說,它的總入口都是ActivityThread的main. 每一個應用的行程都有且僅有一個ActivityThread物件,而每一個ActivityThread物件有且僅有一個Instrumentation成員變數,即整個App行程中ActivityThread和Instrumentation實體物件是唯一的,
2.3 Instrumentation.execStartActivity
//Instrumentation.java
public ActivityResult execStartActivity(
Context who,
IBinder contextThread,
IBinder token,
Activity target,
Intent intent,
int requestCode,
Bundle options)
??在正式開始分析該方法前,我得對該方法的引數予以隆重的介紹:
-
who
引數型別為Context實體,標明發起端背景關系的資訊 -
contextThread
引數型別為IBinder實體,該物件繼承于ApplicationThreadNative(Binder服務端),這個ApplicationThread物件很重要,因為正是通過它串聯其了AMS對發起端行程的ActivityThread的互動(如果把ApplicationThread當作服務端,那么此時AMS相關于ApplicationThread而言就是客戶端),其兩者之間的關系建立詳見下述的示意圖,即AMS持有ApplicationThread的代理端,而應用端行程持有AMS的代理端AMP,二者相互持有各自Binder服務端的代理端進而完成了二者之間的RPC呼叫,在目標Activiy啟動后發起端Activity的onPause的執行是由其代理端ATP在AMS中來通過Binder IPC透傳過來,然后發起端Activity執行onPause流程
-
token
引數型別也為IBinder實體,指向發起端Activity的ActivityRecord物件中的Token,其Binder物體在AMS中,這里暫且不表 -
target
引數型別為Activity實體,標明發起端Activity,如果發起端不為Activity此時為null -
intent
引數型別為Intent實體,用來表明要啟動的Activity資訊,此時的intent可能是顯示Intent,也可能是隱式Intent,我們此處的是一個隱式Intent,顯式intent通常用在包內啟動組件,如果是啟動其他APP的組件,則通常用隱式intent,顯式intent里面包含了一個ComponentName,ComponentName由包名 + 類名組成,可以唯一標識一個組件,系統通過ComponentName就可以找到要啟動的組件,隱式intent通常通過Action來過濾出要啟動的組件 -
requestCode
引數型別為int,啟動Activity的請求碼,此請求碼表明發起端是否需要接收目標Activity啟動的結果 -
options
引數型別為Bundle ,可以理解我啟動目標Activity的附件引數,譬如附件傳輸的一些額外資訊
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
..
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
/* public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags,
ProfilerInfo profilerInfo, Bundle options) throws RemoteException;
caller:當前應用的ApplicationThread物件mAppThread
callingPackage: 呼叫當前ContextImpl.getBasePackageName(),獲取當前Activity所在包名
intent: 這便是啟動Activity時,傳遞過來的引數
*/
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);//詳見章節2.4
checkStartActivityResult(result, intent);//檢查Activity啟動是否成功
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
2.4 AMN.getDefault
??繼續回到章節2.3,我們可以看到最后其呼叫了AMN.getDefault().startActivity,這里牽涉到一個重要的方法AMN.getDefault(),其實它在我們的博客中 Android Binder框架實作之Java層獲取Binder服務原始碼分析已經有詳細的介紹和分析了,但是為了博客的連貫性還是簡單過下(主要是為了不太熟悉的小伙伴們),
//ActivityManagerNative.java
static public IActivityManager getDefault() {
return gDefault.get();
}
這里的gDefault是Singleton物件實體,而Singleton我們可以看到是一個模板類物件,并且提供了一個單例方法,其定義如下:
//Singleton.java
public abstract class Singleton<T> {
private T mInstance;
protected abstract T create();
public final T get() {
synchronized (this) {
if (mInstance == null) {//采用單例模式
mInstance = create();
}
return mInstance;
}
}
}
我們將IActivityManager帶入Singleton,得到如下的create方法程序:
//ActivityManagerNative.java
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
//此處等價于IBinder b = new BinderProxy(new BpBinder(handle));
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
//此處等價于IActivityManager am = new ActivityManagerProxy(new BinderProxy(new BpBinder(handle)))
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
//注意此處我們的入參是BinderProxy型別,所以會走代理端
static public IActivityManager asInterface(IBinder obj) {
if (obj == null) {
return null;
}
IActivityManager in =
(IActivityManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
//即會走到此處
return new ActivityManagerProxy(obj);
}
這里即最終經過層層轉換得到了AMS服務的代理端ActivityManagerProxy,進而借助它完成對AMS服務的RPC請求,
2.4.1 AMN.getDefault()小結
AMN.getDefault()的呼叫流程基本分析結束了,我們對其小結一下:
- AMN.getDefault()最侄訓取了AMS的遠程Binder代理端AMP
- AMS的Binder通信程序中提供了一個IActivityManager服務業務層介面,AMP類與AMS類都實作了IActivityManager介面方法,區別不同給的是AMS端顯示了真正的具體服務,而AMP端是封裝了相關的通信傳輸邏輯,AMP作為Binder通信的服務代理端,而AMS作為Binder通信的服務端物體,根據Android Binder框架實作之Java層Binder服務跨行程呼叫原始碼分析,AMP.bindService()最終呼叫AMS.startActivity(),整個流程圖如下:

關于上述整個Binder IPC呼叫流程,可以使用如下偽代碼來簡述
AMP.startActivity(...)--->
BinderProxy.transact(...) --->
BpBinder.transact(...)--->
binder驅動傳輸--->
JavaBBinder.onTransact(...)--->
AMN.onTransact(..)--->
AMN.startActivity(...)
2.5 AMP.startActivity(…)
//ActivityManagerNative.java
public int startActivity(IApplicationThread caller,
String callingPackage,
Intent intent,
String resolvedType,
IBinder resultTo,
String resultWho,
int requestCode,
int startFlags,
ProfilerInfo profilerInfo,
Bundle options) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
//寫入AMS Binder服務描述資訊即android.app.IActivityManager
data.writeInterfaceToken(IActivityManager.descriptor);
//寫入IApplicationThread 匿名Binder服務物體(這個在attachApplication時寫入過)
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(callingPackage);
intent.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeStrongBinder(resultTo);
data.writeString(resultWho);
data.writeInt(requestCode);
data.writeInt(startFlags);
if (profilerInfo != null) {
data.writeInt(1);
profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
data.writeInt(0);
}
if (options != null) {
data.writeInt(1);
options.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
//BinderProxy
//mRemote指向BinderProxy,而BinderProxy持有C++端的BpBinder,進而借助Binder驅動和AMS通信
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
reply.readException();
int result = reply.readInt();
reply.recycle();
data.recycle();
return result;
}
這里如果對Binder框架熟悉的小伙們應該對上述的呼叫程序是見怪不怪了,但是有幾個點我們需要注意:
- 此處startActivity()的共有10個引數, 下面說說每個引數傳遞AMP.startActivity()每一項的對應值
| 引數型別 | 引數名稱 | 引數含義以及取值 |
|---|---|---|
| IApplicationThread | caller | 當前應用的ActivityThread物件ApplicationThread實體mAppThread |
| String | callingPackage | 呼叫當前ContextImpl.getBasePackageName(),獲取當前Activity所在包名 |
| Intent | intent | 啟動目的端Activity傳遞過來的引數,其中攜帶目的端Acitivity隱式或者顯示啟動需要的引數 |
| String | resolvedType | 呼叫intent.resolveTypeIfNeeded而獲取 |
| IBinder | resultTo | 引數型別也為IBinder實體,指向發起端Activity的ActivityRecord物件中的Token,其Binder物體在AMS中 |
| String | resultWho | 來自于當前發起端Activity.mEmbeddedID,可能為null |
| int | requestCode | 啟動目的端Activity的請求碼,此時的取值為-1 |
| int | startFlags | 此時取值為0,代指Activity的啟動模式 |
| ProfilerInfo | profilerInfo | 此時取值null,這個引數暫時沒有搞懂是干啥的 |
| Bundle | options | 啟動目的端Activity附加引數,此時取值為null |
- startActivity中呼叫了二次Parcel類的方法writeStrongBinder(),這里我們需要注意writeStrongBinder()這二次寫入的是Binder物體代理端還是代理端,是實名Binder還是匿名Binder,
- 這里的mRemote指向BinderProxy,而BinderProxy持有C++端的BpBinder,而BpBinder作為遠程Binder物體的通信代理端,最后借助Binder驅動和AMS通信,最后呼叫到ActivityManagerNative的onTransact()方法中
三. System_server行程接收啟動Activity的請求
??通過上面的層層沖關,打怪我們跳出了發起端行程,來到了system_server行程,讓我們接著分析看看system_server是怎么處理startActivity的RPC請求的,
3.1 AMN.onTransact
//ActivityManagerNative.java
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
case START_ACTIVITY_TRANSACTION:
{
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
//轉換成ApplicationThread Binder物體代理端ApplicationThreadProxy
IApplicationThread app = ApplicationThreadNative.asInterface(b);
String callingPackage = data.readString();
Intent intent = Intent.CREATOR.createFromParcel(data);
String resolvedType = data.readString();
IBinder resultTo = data.readStrongBinder();
String resultWho = data.readString();
int requestCode = data.readInt();
int startFlags = data.readInt();
ProfilerInfo profilerInfo = data.readInt() != 0
? ProfilerInfo.CREATOR.createFromParcel(data) : null;
Bundle options = data.readInt() != 0
? Bundle.CREATOR.createFromParcel(data) : null;
//呼叫AMN的子類AMS,詳見章節3.2
int result = startActivity(app, callingPackage, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
reply.writeNoException();
reply.writeInt(result);
return true;
}
在正式開始上述的原始碼分析前,我們先來闡述一個重要的知識點,即在這個呼叫程序中涉及到兩個行程,不妨令startActivity的發起行程記為行程Process_A,AMS Service所屬行程記為行程Process_B;那么行程Process_A通過Binder機制(采用IActivityManager介面)向行程Process_B發起請求服務,行程Process_B則通過Binder機制(采用IApplicationThread介面)向行程Process_A發起請求服務,也就是說行程Process_A與行程Process_B能相互間主動發起請求,進而完成行程通信,但是這里有一點需要注意IApplicationThread的Binder物體端并沒有注冊到servicemanager行程中,它是一個依賴于實名Binder的匿名Binder,
這里涉及IApplicationThread很重要,它串聯起了AMS對App行程的生命周期及其其它的控制,那么下面直接把其相關的類圖展示如下:

這里的IApplicationThread與IActivityManager的Binder通信原理一樣,ATP作為Binder通信的客戶端,ATN作為Binder通信的服務端,其中ApplicationThread繼承ATN類,覆寫其中的部分方法,
接著繼續分析onTransact方法,其根據AMP傳遞過來的code值進入START_ACTIVITY_TRANSACTION分支,然后解讀取通過Binder驅動傳遞過來的資料,決議完成之后呼叫AMN的方法startActivity繼續未完成之作業(這里的startActivity在AMS服務中具體實作),這里從驅動中獲取到資料然后決議這里就不重點關注了,
3.2 AMS.startActivity
@Override
//AMS.java
public final int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
}
final ActivityStackSupervisor mStackSupervisor;
final ActivityStarter mActivityStarter;
final ActiveServices mServices;
@Override
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
enforceNotIsolatedCaller("startActivity");
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, "startActivity", null);
//這里的mActivityStarter是ActivityStarter的實體物件
return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
profilerInfo, null, null, bOptions, false, userId, null, null);//詳見章節3.3
}
這里需要重點強調如下幾點:
-
AMS是Android提供負責系統中四大組件的啟動、切換、調度及應用行程的管理和調度等作業的Java層Binder服務,其身上的擔子很重,為了減輕負擔和代碼邏輯的精簡其會將重任委托給幾個非常重要的類來執行ActivityStarter,ActivityStackSupervisor,ActiveServices,AMS的類圖關系如下所示,并且關于每個類的作用詳見博客Activity啟動流程原始碼實作詳解概要章節2.5這里就不重復了,

-
這里的mActivityStarter是ActivityStarter的實體物件,其是在AMS的構造方法中被創建的,如下所示可以看到其持有對AMS和ASS的參考,
//AMS.java
final ActivityStackSupervisor mStackSupervisor;
final ActivityStarter mActivityStarter;
final ActiveServices mServices;
public ActivityManagerService(Context systemContext) {
...
mServices = new ActiveServices(this);
mStackSupervisor = new ActivityStackSupervisor(this);
mActivityStarter = new ActivityStarter(this, mStackSupervisor);
...
}
3.3 AS.startActivityMayWait
//ActivityStarter.java
final int startActivityMayWait(IApplicationThread caller,
int callingUid,
String callingPackage,
Intent intent,
String resolvedType,
IVoiceInteractionSession voiceSession,
IVoiceInteractor voiceInteractor,
IBinder resultTo,
String resultWho,
int requestCode,
int startFlags,
ProfilerInfo profilerInfo,
IActivityManager.WaitResult outResult,
Configuration config,
Bundle bOptions,
boolean ignoreTargetSecurity,
int userId,
IActivityContainer iContainer,
TaskRecord inTask) {
??在正式開始分析該方法前,我們先對該方法的引數和入參整理一下,該方法的引數不少啊,總共有19個至多(不知道數對了沒有啊),其引數型別和取值如下:
| 引數型別 | 引數名稱 | 引數含義及取值 |
|---|---|---|
| IApplicationThread | caller | 和發起端行程匿名Binder物件ActivityThread進行通信的代理端ATP |
| int | callingUid | 取值為-1,看引數命名應該是表示發起端的行程的uid |
| String | callingPackage | 發起端行程所在包名 |
| Intent | intent | 啟動目的端Activity傳遞過來的引數,其中攜帶目的端Acitivity隱式或者顯示啟動需要的引數 |
| String | resolvedType | 發起端行程通過呼叫intent.resolveTypeIfNeeded而獲取 |
| IVoiceInteractionSession | voiceSession | 意義不明,取值為null |
| IVoiceInteractor | voiceInteractor | 意義不明,取值為null |
| IBinder | resultTo | 引數型別也為IBinder實體,指向發起端Activity的ActivityRecord物件中的Token,其Binder物體在AMS中 |
| String | resultWho | 來自于當前發起端Activity.mEmbeddedID,可能為null |
| int | requestCode | 啟動目的端Activity的請求碼,此時的取值為-1 |
| int | startFlags | 此時取值為0,代指Activity的啟動模式 |
| ProfilerInfo | profilerInfo | 此時取值null,這個引數暫時沒有搞懂是干啥的 |
| WaitResult | outResult | 此時取值為null,這個引數暫時沒有搞懂是干啥的 |
| Configuration | config | 應該是表示啟動Activity的Configuration配置資訊(不太確定),此時取值為null |
| Bundle | options | 啟動目的端Activity附加引數,此時取值為null |
| boolean | ignoreTargetSecurity | 是否忽略檢查發起端行程的安全,此時取值為false |
| int | userId | 通過mUserController.handleIncomingUser,當呼叫者userId跟當前處于同一個userId,則直接回傳該userId;當不相等時則根據呼叫者userId來決定是否需要將callingUserId轉換為mCurrentUserId |
| IActivityContainer | iContainer | 此時取值為null |
| TaskRecord | inTask | 此時取值為null |
??入參分析完了,我們接著分析原始碼:
//ActivityStarter.java
final int startActivityMayWait(IApplicationThread caller, int callingUid,
String callingPackage, Intent intent, String resolvedType,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, IActivityManager.WaitResult outResult, Configuration config,
Bundle bOptions, boolean ignoreTargetSecurity, int userId,
IActivityContainer iContainer, TaskRecord inTask) {
...
final Intent ephemeralIntent = new Intent(intent);
//以傳遞進來的intent為引數重新創建新的Intent物件,即便intent被修改也不受影響
intent = new Intent(intent);
//收集Intent所指向的Activity資訊, 當存在多個可供選擇的Activity,則直接向用戶彈出resolveActivity
ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);//重點分析該方法,詳見章節3.4
if (rInfo == null) {//不會進入該分支
...
}
//根據獲取的rInfo資訊重新組裝intent和設定啟動的引數資訊
ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);//詳見3.5
...
final ActivityStack stack;
if (container == null || container.mStack.isOnHomeDisplay()) {//傳入的引數container為null
stack = mSupervisor.mFocusedStack;//進入該分支
} else {
stack = container.mStack;
}
//此時傳入的config為null
stack.mConfigWillChange = config != null && mService.mConfiguration.diff(config) != 0;
...
if (aInfo != null &&
(aInfo.applicationInfo.privateFlags
& ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
//hwavy-weight行程,貌似木有見過這個東東,暫時不管
...
}
...
final ActivityRecord[] outRecord = new ActivityRecord[1];
//繼續跟進
int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
aInfo, rInfo, voiceSession, voiceInteractor,
resultTo, resultWho, requestCode, callingPid,
callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
options, ignoreTargetSecurity, componentSpecified, outRecord, container,
inTask);//詳見章節3.6
Binder.restoreCallingIdentity(origId);
...
return res;
}
該方法的主要功能如下:
- 借助ASS的resolveIntent和resolveActivity方法,通過傳遞進來的引數(主要是intent)查找合適的目標Actitiy,并將保存到ActivityInfo中
- 繼續呼叫startActivityLocked方法,繼續未完成啟動作業
此時整個上述整個流程的偽代碼如下:
AMS.startActivity(...)
ActivityStarter.startActivityMayWait(...)
ResolveInfo rInfo = ASS.resolveIntent(...)//收集Intent所指向的Activity資訊, 當存在多個可供選擇的Activity,則直接向用戶彈出resolveActivity
IPackageManager.Stub.resolveIntent(...)//通過PKMS物體查詢
ActivityInfo aInfo = ASS.resolveActivity(...)根據獲取的rInfo資訊重新組裝intent和設定啟動的引數資訊
ActivityStarter.startActivityLocked(...)
3.4 通過intent查詢獲取目的端Activity資訊
??在正式開始該流程分析前,我們先來看看ResolveInfo,它是一個容器類,里面包含了ActivityInfo,ServiceInfo,ProviderInfo等成員來表示四大組件的資訊,activity和broadcast資訊都是用ActivityInfo來表示的,這三個成員只有一個不為空,這里我們啟動的是activity,所以ActivityInfo是不為空的,ActivityInfo包含了各種各樣的activity資訊,都是宣告在AndroidManifest.xml檔案中的,比較重要的包括launchMode、theme、screenOrientation等,其中還包含了ApplicationInfo,提供packageName、targetSdkVersion等重要資訊,關于這兩者之間的關系,可以使用如下類圖表示:

3.4.1 ASS.resolveIntent
//[ActivityStackSupervisor.java]
ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId) {
return resolveIntent(intent, resolvedType, userId, 0);
}
ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId, int flags) {
try {
//呼叫到同行程PKMS服務的resolveIntent
return AppGlobals.getPackageManager().resolveIntent(intent, resolvedType,
PackageManager.MATCH_DEFAULT_ONLY | flags
| ActivityManagerService.STOCK_PM_FLAGS, userId);//詳見章節3.4.2
} catch (RemoteException e) {
}
return null;
}
??由于該流程牽涉到PKMS服務的呼叫,在開始原始碼前我們先看看PKMS的類圖關系如下:

//[AppGlobals.java]
public static IPackageManager getPackageManager() {
return ActivityThread.getPackageManager();
}
//[ActivityThread.java]
static volatile IPackageManager sPackageManager;
public static IPackageManager getPackageManager() {
if (sPackageManager != null) {
return sPackageManager;
}
//等同于IBinder b = new JavaBBinder()//此時AMS和PKMS在同一個行程,所以獲取的是PKMS的Binder服務的物體端,不需要通過Binder IPC跨行程呼叫
IBinder b = ServiceManager.getService("package");
//等同于sPackageManager = new IPackageManager.Stub(JavaBBinder)
sPackageManager = IPackageManager.Stub.asInterface(b);
return sPackageManager;
}
??AppGlobals.getPackageManager()經過函式層層呼叫,獲取的是IPackageManager.Stub,注意獲取的是PKMS的物體端,所以無需經過Binder IPC呼叫,此處一定要特別注意!最侄訓像是用普通的類一樣直接呼叫到PKMS物件.故此時呼叫方法為PMS.resolveIntent(),至于其中涉及的具體轉換可以詳見博客Android Binder框架實作之Java層Binder服務跨行程呼叫原始碼分析!
3.4.2 PKMS.resolveIntent
??通過上述的分析,我們看到AMS決議Intent主要是通過PKMS來決議的,因為我們四大組件都是必須宣告在AndroidManifest.xml檔案中的(廣播接收器允許動態注冊),Android這么做的原因主要是為了屏蔽行程間通訊細節,應用之間通過組件就可以互動,系統會在必要的時候拉起對方行程,但是這里會存在一個問題,即在應用沒起來之前,只有PMS知道應用都有哪些組件,所以AMS必須借助PKMS來完成相關intent的查詢,應用四大組件的資訊在應用安裝的時候,就已經被PMS決議保存起來了,如果沒有宣告在AndroidManifest.xml檔案中,那么AMS就無法獲取目標組件的資訊,對于顯式intent,會拋出錯誤;對于隱式intent,也會啟動失敗,關于PKSMS服務對App安裝的處理不是本文的重點,這里不與過多分析,
//[PackageManagerService.java]
@Override
public ResolveInfo resolveIntent(Intent intent, String resolvedType,
int flags, int userId) {
enforceCrossUserPermission(Binder.getCallingUid(), userId,false /*requireFullPermission*/, false /*checkShell*/, "resolve intent");
//queryIntentActivitiesInternal方法回傳的結果就是符合intent的ActivityInfo串列
final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType,
flags, userId);//詳見章節3.4.3
//根據priority,preferred選擇最佳的Activity,當有多個合適的Actitiy的時候,會彈出選擇框提供給用戶進行選擇
final ResolveInfo bestChoice =
chooseBestActivity(intent, resolvedType, flags, query, userId);
return bestChoice;
}
3.4.3 PKMS.queryIntentActivitiesInternal
//[PackageManagerService.java]
/*
1.查看當前Intent是否是顯式Intent,是則取出其中的class物件和AndroidManifest的進行匹配,匹配成功回傳,
2.如果沒有指定包名則全系統的查找匹配intent
3.如果指定包名,則從當前的包名尋找匹配規則相符合的intent的Activity
*/
private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
flags = updateFlagsForResolve(flags, userId, intent);
enforceCrossUserPermission(Binder.getCallingUid(), userId,
false /* requireFullPermission */, false /* checkShell */,
"query intent activities");
//獲取Intent的ComponentName
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
intent = intent.getSelector();
comp = intent.getComponent();
}
}
//不為空,則是通過顯示Intent啟動,直接獲取到ActivityInfo回傳
if (comp != null) {
final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
//獲取Activity資訊
final ActivityInfo ai = getActivityInfo(comp, flags, userId);
if (ai != null) {
final ResolveInfo ri = new ResolveInfo();
ri.activityInfo = ai;
list.add(ri);
}
return list;
}
//comp為空,則是隱式啟動
synchronized (mPackages) {
final String pkgName = intent.getPackage();
if (pkgName == null) {//如果包名為空,則會通過ActivityIntentResolver等進行模糊匹配,比如根據Action、Category等
...
return result;
}
// 通過包名獲取到Package物件
final PackageParser.Package pkg = mPackages.get(pkgName);
if (pkg != null) {
return filterIfNotSystemUser(
mActivities.queryIntentForPackage(
intent, resolvedType, flags, pkg.activities, userId),
userId);
}
return new ArrayList<ResolveInfo>();
}
}
??上面的流程就是通過intent獲取目的Activity的ResolveInfo核心代碼,這里不過多展開了(因為牽涉到PKMS對App的安裝決議流程),它的大致程序如下:
- 首先獲取Intent的Component物件,如果不為空,說明指定了Componet,那么就直接通過Componet找到ActivityInfo串列,并且這個串列size為1,所以這個ActivityInfo就是指定需要跳轉的組件,
- 如果沒有指定Component,那就是隱式Intent呼叫,接著獲取Intent傳遞的需要跳轉的包名,
- 如果包名為空,則會通過ActivityIntentResolver等進行模糊匹配,比如根據Action、Category等,
- 如果包名不為空,則直接根據包名來獲取到對應的ActivityInfo物件,而mActivities就是PMS存盤的activity資訊表,
3.4.4 通過intent查詢獲取目的端Activity資訊小結
??至此通過intent查詢獲取目的端Activity資訊就告一段落了,此時我們借助PKMS服務決議intent獲取到了合適的ResolveInfo(啟動包含了ActivityInfo資訊),那么接下來就可以繼續余下的作業了,我們還是用相關的偽代碼來總結一下上述的流程:
ResolveInfo rInfo = ASS.resolveIntent(...)//收集Intent所指向的Activity資訊, 當存在多個可供選擇的Activity,則直接向用戶彈出resolveActivity
IPackageManager.Stub.resolveIntent(...)//通過PKMS物體查詢
PKMS.resolveIntent(...)
PKMS.queryIntentActivitiesInternal(...)
PKMS.chooseBestActivity(...)
3.5 ASS.resolveActivity
讓我們整理下思路,回到章節3.3繼續分析resolveActivity方法
//[ActivityStackSupervisor.java]
/*根據獲取的rInfo資訊重新組裝intent和設定啟動的引數資訊
startFlags = 0;
profilerInfo = null;
rInfo 指向通過PKMS決議intent資訊獲取到的ResolveInfo實體物件,其中包含ActivityInfo的資訊
*/
ActivityInfo resolveActivity(Intent intent, ResolveInfo rInfo, int startFlags,
ProfilerInfo profilerInfo) {
final ActivityInfo aInfo = rInfo != null ? rInfo.activityInfo : null;
if (aInfo != null) {
intent.setComponent(new ComponentName(
aInfo.applicationInfo.packageName, aInfo.name));
if (!aInfo.processName.equals("system")) {//對于非system行程,根據flags來設定相應的debug資訊
if ((startFlags & ActivityManager.START_FLAG_DEBUG) != 0) {//用于除錯debug app
mService.setDebugApp(aInfo.processName, true, false);
}
if ((startFlags & ActivityManager.START_FLAG_NATIVE_DEBUGGING) != 0) {//除錯native
mService.setNativeDebuggingAppLocked(aInfo.applicationInfo, aInfo.processName);
}
if ((startFlags & ActivityManager.START_FLAG_TRACK_ALLOCATION) != 0) {//用于除錯allocation tracking
mService.setTrackAllocationApp(aInfo.applicationInfo, aInfo.processName);
}
if (profilerInfo != null) {
mService.setProfileApp(aInfo.applicationInfo, aInfo.processName, profilerInfo);
}
}
}
return aInfo;
}
resolveActivity方法的處理邏輯比較簡單,主要是根據前面獲取的rInfo資訊重新組裝intent和設定Activity啟動的引數資訊,ActivityManager類提供了如下3個flags用于除錯,如下:
- START_FLAG_DEBUG:用于除錯debug app
- START_FLAG_NATIVE_DEBUGGING:用于除錯native
- START_FLAG_TRACK_ALLOCATION: 用于除錯allocation tracking
3.6 AS.startActivityLocked
??讓我們整理下思路,回到章節3.3繼續分析startActivityLocked方法,在繼續分析之前,我們還是整理整理system_server行程從接收到啟動Activity至此startActivityLocked的呼叫流程!
AMS.startActivity(...)
ActivityStarter.startActivityMayWait(...)
ResolveInfo rInfo = ASS.resolveIntent(...)//收集Intent所指向的Activity資訊, 當存在多個可供選擇的Activity,則直接向用戶彈出resolveActivity
IPackageManager.Stub.resolveIntent(...)//通過PKMS物體查詢
PKMS.resolveIntent(...)
PKMS.queryIntentActivitiesInternal(...)
PKMS.chooseBestActivity(...)
ActivityInfo aInfo = ASS.resolveActivity(...)根據獲取的rInfo資訊重新組裝intent和設定啟動的引數資訊
ActivityStarter.startActivityLocked(...)
??不知道小伙們,我這個節奏是否還跟得上!如果小伙們感覺有點吃力了,不要退縮堅持就好了,因為當初的我也是這么過來的!大伙可以先上上廁所,喝杯茶,我們接著繼續!
//[ActivityStarter.java]
final int startActivityLocked(IApplicationThread caller, //caller是請求啟動當前Activity的發起方,IApplicationThread類是AMS呼叫ActivityThread的IBinder介面,在啟動者的ActivityThread中定義
Intent intent, //啟動當前Activity的intent
Intent ephemeralIntent,//啟動當前Activity的intent復本
String resolvedType, //啟動當前Activity的resolvedType
ActivityInfo aInfo, //當前啟動的Activity的ActivityInfo(PackageManger決議獲得,具體獲取見前面的操作步驟
ResolveInfo rInfo,//目標Activity的ResolveInfo資訊
IVoiceInteractionSession voiceSession, //暫時忽略
IVoiceInteractor voiceInteractor,//暫時忽略
IBinder resultTo, // 呼叫方Activity的ActivityRecord,每個Activity在啟動之后,AMS均會將這個Activity的ActivityRecord的IBinder再傳遞給Activity,作為其在AMS中的標識,
String resultWho,
int requestCode,
int callingPid, int callingUid,//用于權限檢查,檢查請求放是否有權限啟動這個Activity
String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
TaskRecord inTask) {
int err = ActivityManager.START_SUCCESS;
//用來存盤呼叫者的行程記錄物件
ProcessRecord callerApp = null;
if (caller != null) {
callerApp = mService.getRecordForAppLocked(caller);//獲取呼叫者的行程資訊
if (callerApp != null) {
callingPid = callerApp.pid;
callingUid = callerApp.info.uid;
} else {
...
err = ActivityManager.START_PERMISSION_DENIED;
}
}
final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
//記錄發起端Activity資訊記錄物件
ActivityRecord sourceRecord = null;//表示請求啟動當前Activity的Activity
ActivityRecord resultRecord = null;//表示當前activity啟動之后需要得到回傳結果的activity
/**若當前啟動方式是以startActivityForResult啟動的,
*則保存在呼叫者Activity在sourceRecord中,
*如果啟動時候設定了requestCode并且大于是0,那么將接收
*startActivityForResult回傳值的Activity保存在resultRecord中,
*在此種情況下,呼叫者和接識訓傳者的Activity是相同的
*是不是還是很抽象,我們來舉個例子:
*假如Activity A通過startActivityForResult啟動B,并且requestCode>0
*那么此時sourceRecord和resultRecord都為A
*/
if (resultTo != null) {
//獲取呼叫者所在的Activity
sourceRecord = mSupervisor.isInAnyStackLocked(resultTo);
if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
"Will send result to " + resultTo + " " + sourceRecord);
if (sourceRecord != null) { //一般情況下,sourceRecord的activity使用startActivityForResult()啟動當前activity且requestCode>=0,那么resultRecord = sourceRecord
if (requestCode >= 0 && !sourceRecord.finishing) {
resultRecord = sourceRecord;
}
}
}
final int launchFlags = intent.getFlags();
// Activity執行結果的回傳由源Activity轉換到新Activity, 不需要回傳結果則不會進入該分支
// 特殊情況,若sourceRecord啟動當前activity時設定了標記Intent.FLAG_ACTIVITY_FORWARD_RESULT,且requestCode<0, 那么當前activity的resultRecord等于sourceRecord.resultTo,也就是sourceRecord的resultRecord
/**
*FLAG_ACTIVITY_FORWARD_RESULT這個FLAG作用,舉個例子:
* 當一個應用中存在有ActivityA,B,C,A以startActivityForResult方式啟動了B,
* 此時B設定了FLAG_ACTIVITY_FORWARD_RESULT啟動了C,注意此時B啟動C
* 時requestCode不設定或者設定值要小于0,不然會報錯,
* 那么原來在A中接識訓傳值從B回傳的,但這時A接收的回傳值變成從C回傳,
*/
if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
// Transfer the result target from the source activity to the new
// one being started, including any failures.
// 將sourceRecord的resultRecord轉移給當前新啟動的activity
if (requestCode >= 0) {
ActivityOptions.abort(options);
return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
}
resultRecord = sourceRecord.resultTo;
if (resultRecord != null && !resultRecord.isInStackLocked()) {
resultRecord = null;
}
resultWho = sourceRecord.resultWho;
requestCode = sourceRecord.requestCode;
sourceRecord.resultTo = null;
if (resultRecord != null) {
resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
}
if (sourceRecord.launchedFromUid == callingUid) {
...
callingPackage = sourceRecord.launchedFromPackage;
}
}
if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
//從Intent中無法找到相應的Component
err = ActivityManager.START_INTENT_NOT_RESOLVED;
}
if (err == ActivityManager.START_SUCCESS && aInfo == null) {
//從Intent中無法找到相應的ActivityInfo
err = ActivityManager.START_CLASS_NOT_FOUND;
}
執行后resultStack = null
final ActivityStack resultStack = resultRecord == null ? null : resultRecord.task.stack;
if (err != START_SUCCESS) {
if (resultRecord != null) {
resultStack.sendActivityResultLocked(
-1, resultRecord, resultWho, requestCode, RESULT_CANCELED, null);
}
ActivityOptions.abort(options);
return err;
}
//權限檢測
boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity, callerApp,
resultRecord, resultStack, options);
abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
callingPid, resolvedType, aInfo.applicationInfo);
if (mService.mController != null) {
try {
Intent watchIntent = intent.cloneFilter();
abort |= !mService.mController.activityStarting(watchIntent,
aInfo.applicationInfo.packageName);
} catch (RemoteException e) {
mService.mController = null;
}
}
...
if (abort) {//權限檢查不滿足,才進入該分支則直接回傳
if (resultRecord != null) {
resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
RESULT_CANCELED, null);
}
ActivityOptions.abort(options);
return START_SUCCESS;
}
...
//創建Activity記錄物件
ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
requestCode, componentSpecified, voiceSession != null, mSupervisor, container,
options, sourceRecord);//詳見章節3.7
if (outActivity != null) {
outActivity[0] = r;// 將創建的ActivityRecord回傳
}
if (r.appTimeTracker == null && sourceRecord != null) {
// If the caller didn't specify an explicit time tracker, we want to continue
// tracking under any it has.
r.appTimeTracker = sourceRecord.appTimeTracker;
}
// 將mFocusedStack賦予當前stack,這里的mFocusedStack表示當前活動的
final ActivityStack stack = mSupervisor.mFocusedStack;
if (voiceSession == null && (stack.mResumedActivity == null
|| stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {
// 前臺stack還沒有resume狀態的Activity時, 則檢查app切換是否允許
if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
realCallingPid, realCallingUid, "Activity start")) {
PendingActivityLaunch pal = new PendingActivityLaunch(r,
sourceRecord, startFlags, stack, callerApp);
// 當不允許切換,則把要啟動的Activity添加到mPendingActivityLaunches物件, 并且直接回傳
mPendingActivityLaunches.add(pal);
ActivityOptions.abort(options);
return ActivityManager.START_SWITCHES_CANCELED;
}
}
if (mService.mDidAppSwitch) {
//從上次禁止app切換以來,這是第二次允許app切換,因此將允許切換時間設定為0,則表示可以任意切換app
mService.mAppSwitchesAllowedTime = 0;
} else {
mService.mDidAppSwitch = true;
}
//處理 pendind Activity的啟動, 這些Activity是由于app switch禁用從而被hold的等待啟動activity
doPendingActivityLaunchesLocked(false);
try {
//這個方法很長,很長,很長
err = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
true, options, inTask);
} finally {
mService.mWindowManager.continueSurfaceLayout();
}
postStartActivityUncheckedProcessing(r, err, stack.mStackId, mSourceRecord, mTargetStack);
return err;
}
startActivityLocked方法看著代碼一大堆,是有蠻唬人的,其實主要邏輯就是:
- 進一步對發起端的行程做一些權限檢查,然后接著確定sourceRecord和resultRecord的取值
- 接著通過上述確認的引數構建ActivityRecord,這個是重點會在后面章節分析
- 接著繼續呼叫startActivityUnchecked方法開始后續的Activity啟動,這個方法牽涉的邏輯很長,很長
3.7 ActivityRecord
??ActivityRecord是AMS中保存activity資訊的資料結構,AMS就是通過著這樣一個結構來管理Activity的,注意和ActivityInfo的區別!我個人認為二者最大的區別在與ActivityInfo是死的,它是對AndroidManifest.xml的完全決議的呈現,而ActivityRecord是根據發起端行程創建目標Activiyt傳入的引數等情況確定的,
ActivityRecord類的定義如下:
//ActivityRecord
final class ActivityRecord {
/*表示AMS在創建ActivityRecord時候指定*/
final ActivityManagerService service;
/*這個是和WindomMangerService通信的,該值會賦值給Activity中*/
final IApplicationToken.Stub appToken;
/*這個描述是AndroidManifest.xml中定義activity相關資訊*/
final ActivityInfo info;
/*這個描述是AndroidManifest.xml中定義application相關資訊*/
final ApplicationInfo appInfo;
...
/*應用的包名*/
final String packageName;
final String processName;
/**Activity親和性,這上簡單的描述就是該Activity應屬于是哪個Task*/
final String taskAffinity;
...
/**以下三個表示該Activity型別*/
static final int APPLICATION_ACTIVITY_TYPE= 0;
static final int HOME_ACTIVITY_TYPE = 1;
static final int RECENTS_ACTIVITY_TYPE = 2;
int mActivityType;
...
/**Activity屬于哪個Task*/
TaskRecord task;
/**通過startActivityForResult啟動時,接識訓傳值的Activity*/
ActivityRecord resultTo;
/**通過startActivityForResult啟動時設定的requestCode*/
final int requestCode;
...
/*Activity所屬的行程*/
ProcessRecord app;
/*表示Activity的當前狀態, INITIALIZING,RESUMED,PAUSING,PAUSED,STOPPING,STOPPED,FINISHING,DESTROYING,DESTROYED
有這幾種狀態*/
ActivityState state;
/*標記是否為Task的root Activity,比如每個應用有一個mainActivity,一般
*情況下該main Activity即為對應Task的rootActivity*/
boolean frontOfTask;
/*標記該ActivityRecord是否已經stoped*/
boolean stopped;
/*標記ActivityRecord是否已經finishing,這在activity finish時置為true*/
boolean finishing;
boolean deferRelaunchUntilPaused;
boolean visible;
boolean sleeping;
boolean nowVisible;
/*ActivityStack管理類*/
final ActivityStackSupervisormStackSupervisor;
ActivityRecord(ActivityManagerService _service, ProcessRecord _caller,
int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,
ActivityInfo aInfo, Configuration _configuration,
ActivityRecord _resultTo, String _resultWho, int _reqCode,
boolean _componentSpecified, boolean _rootVoiceInteraction,
ActivityStackSupervisor supervisor,
ActivityContainer container, ActivityOptions options, ActivityRecord sourceRecord) {
...
appToken = new Token(this, service);//注意此處的Token是一個匿名Binder,既然是Binder就可以跨行程傳輸了
state = ActivityState.INITIALIZING;
...
}
我還得在2.3章節中對execStartActivity中傳入的引數token嗎,它的Binder物體就是在啟動程序中經由此處創建的(當然它的Binder物體不是這里的Token,這里只是表達告訴各位小伙們這個token會隨著Activity的創建會在AMS,WMS,Activity之間進行傳遞的)YOU
??有了以上知識的鋪墊,那么此處的構造方法就很好理解了在AMS中為目標Activity構建了一個ActivityRecord資料結構,并且在其構造方法中實體化了一個Token,這個Token很重要它是Activity的唯一標識,并且會隨著目標Activity的啟動在AMS和WMS以及目標行程中傳輸!至此目標Ativity相關資訊已經在AMS中建立了!
??這里補充一個小的知識點,我們可以借助dumpsys命令查看AMS中相關的ActivityRecord的資料結構資訊,如下!特別是當我們想查看當前與用戶互動的前臺Activity時Android通過adb shell命令查看當前與用戶互動的前臺Activity,
130|XXX:/ # dumpsys activity | grep ActivityRecord
Hist #0: ActivityRecord{4c7a084 u0 com.android.launcher3/.Launcher t73}
Run #0: ActivityRecord{4c7a084 u0 com.android.launcher3/.Launcher t73}
Hist #0: ActivityRecord{68a76e3 u0 com.android.calculator2/.Calculator t77}
Hist #0: ActivityRecord{697cb49 u0 com.cyanogenmod.filemanager/.activities.NavigationActivity t76}
Hist #0: ActivityRecord{4c3e469 u0 org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity t75}
Hist #0: ActivityRecord{8a53d39 u0 com.pax.printtest/com.example.api.aidl.AidlActivity t74}
Run #3: ActivityRecord{68a76e3 u0 com.android.calculator2/.Calculator t77}
Run #2: ActivityRecord{697cb49 u0 com.cyanogenmod.filemanager/.activities.NavigationActivity t76}
Run #1: ActivityRecord{4c3e469 u0 org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity t75}
Run #0: ActivityRecord{8a53d39 u0 com.pax.printtest/com.example.api.aidl.AidlActivity t74}
mFocusedActivity: ActivityRecord{4c7a084 u0 com.android.launcher3/.Launcher t73}
小結
閱讀原始碼是很操蛋的事情,同樣的如果將太多的邏輯放在一篇中我想小伙們也會閱讀起來也會操蛋,失去耐心的的,所以本篇章就先到這里了,分析至此我們應該有了如下的知識圖譜:
- 發起端行程是怎么通過Instrumentation管理類,并且借助AMP完成啟動Activity請求的發送
- system_server行程中的AMS初步處理啟動Activiyt的請求,并借助PKMS服務決議intent獲取目標Activity的ActivityInfo資訊,然后通過上述決議得到的資料為目標Activiyt構建ActivityRecord資料結構
關于上述整個的程序可以使用下述的偽代碼來簡單描述:
發起端行程發起啟動Activity請求
Activity.startActivity(...)
Activity.startActivityForResult(...)
mInstrumentation.execStartActivity(...)
AMP.startActivity(...)//通過AMS代理端向AMS發起啟動Activity的Binder IPC請求
mInstrumentation.checkStartActivityResult(...)//檢測啟動是否成功
mMainThread.sendActivityResult(...)
system_server行程端
AMS決議Intent
AMS.startActivity(...)
ActivityStarter.startActivityMayWait(...)
ResolveInfo rInfo = ASS.resolveIntent(...)//收集Intent所指向的Activity資訊, 當存在多個可供選擇的Activity,則直接向用戶彈出resolveActivity
IPackageManager.Stub.resolveIntent(...)//通過PKMS物體查詢
PKMS.resolveIntent(...)
PKMS.queryIntentActivitiesInternal(...)
PKMS.chooseBestActivity(...)
ActivityInfo aInfo = ASS.resolveActivity(...)根據獲取的rInfo資訊重新組裝intent和設定啟動的引數資訊
ActivityStarter.startActivityLocked(...)
ActivityRecord r = new ActivityRecord(callerApp,intent,aInfo,mSupervisor,...)
appToken = new Token(this, _intent);
設定state為INITIALIZING
ActivityStarter.startActivityUnchecked(...)
創建目的端Activity的ActivityRecord
ActivityStarter.startActivityLocked(...)
ActivityRecord r = new ActivityRecord(callerApp,intent,aInfo,mSupervisor,...)
appToken = new Token(this, _intent);
設定state為INITIALIZING
好了,今天的博客就到這里了!閱讀原始碼小伙們一定要做好心理準備,千萬不能半途而廢!在接下來的篇章中我們將繼續分析system_server行程對Activity啟動的請求處理,希望小伙們能繼續關注,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/114939.html
標籤:其他
