起源
身為一名Android程式猿,我們每天都在呼叫StartActivity來啟動另一個頁面,可是在呼叫了成百上千次之後,我們往往會疑惑在執行這行程式碼的時候,背後到底隱藏著什麼原理。是的,我曾不止一次的懷疑過,可是卻始終鼓不起勇氣去揭開它背後那神祕的面紗。今天,我終於決定硬著頭皮走進這超長的呼叫鏈,正所謂不成功便成仁,男人就要對自己狠一點。好了,廢話不多說,直接開始。(下面有些圖來自網路,因為我們往往都是站在巨人得到肩膀上)
開始
Activity#startActivity
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
// Note we want to go through this call for compatibility with
// applications that may have overridden the method.
startActivityForResult(intent, -1);
}
}複製程式碼
我們都知道加入類中存在多個相同名字的函式時(java過載),最終肯定都會呼叫到引數最多的那個函式所以我們直接檢視startActivityForResult(intent, -1, options),,並且會省略掉許多無關的程式碼,下面同理,不再強調。
Activity#startActivityForResult
public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
if (mParent == null) {
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}else{
……
}
}
}複製程式碼
我們看到程式碼執行了mInstrumentation.execStartActivity,那mInstrumentation是在什麼時候被初始化得到呢?通過查詢我們發現以下程式碼
Activity#attach
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window) {
//注意這行程式碼 我們知道startActivity可以在任何Context中呼叫 下文會分析
attachBaseContext(context);
……
mUiThread = Thread.currentThread();
mMainThread = aThread;
//注意這個變數
mInstrumentation = instr;
mToken = token;
mIdent = ident;
mApplication = application;
mIntent = intent;
mReferrer = referrer;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstances = lastNonConfigurationInstances;
……複製程式碼
那這個instr到底是什麼呢,我們繼續查詢在ActivityThread中發現了一下程式碼
ActivityThread#performLaunchActivity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
……
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (activity != null) {
//注意這行程式碼,他其實就是ContextWrapper中的mBase,下面會分析
Context appContext = createBaseContextForActivity(r, activity);
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window);
……
}
return activity;
}
}複製程式碼
可以看到instr是由getInstrumentation()傳入的,而真正的Instrumentation是在ActivityThread中直接new出來的,看一下程式碼:
ActivityThread#attach
private void attach(boolean system) {
try {
mInstrumentation = new Instrumentation();
ContextImpl context = ContextImpl.createAppContext(
this, getSystemContext().mPackageInfo);
mInitialApplication = context.mPackageInfo.makeApplication(true, null);
mInitialApplication.onCreate();
} catch (Exception e) {
throw new RuntimeException(
"Unable to instantiate Application():" + e.toString(), e);
}
}複製程式碼
好了Instrumentation找到了,沒有繼承,也沒有子類什麼,那我們直接去看他的execStartActivity()方法
Instrumentation#execStartActivity
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
……
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
……
}複製程式碼
可以看到 我們找到了最終的呼叫點ActivityManagerNative.getDefault().startActivity,至於ActivityManagerNative是什麼,我們先放放等下再分析。還記得我在上面提到過,我們其實可以在任何的Contex中呼叫startActivity,那如果不是在activity中呼叫,那他的呼叫流程是什麼樣的呢?我們以Service為例看下。經過搜尋我們發現Service中並沒有StartActivity方法,那我們就在它的父類ContextWrapper中查詢,發現以下程式碼:
ContextWrapper#startActivity
@Override
public void startActivity(Intent intent) {
mBase.startActivity(intent);
}
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}複製程式碼
直接通過mBase呼叫,而mBase 是通過attachBaseContext直接賦值的,那這個mBase到底是個什麼鬼,還記得我在Activity中提到的attachBaseContext嗎,沒錯呼叫的就是這裡,然後 Activity#attach的呼叫鏈已經分析過了,在ActivityThread#performLaunchActivity中被呼叫,大家可以去看上面的程式碼。
ActivityThread#createBaseContextForActivity
private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
……
ContextImpl appContext = ContextImpl.createActivityContext(
this, r.packageInfo, r.token, displayId, r.overrideConfig);
appContext.setOuterContext(activity);
Context baseContext = appContext;
……
return baseContext;
}複製程式碼
原來是通過ContextImpl#createActivityContext得到的,廢話不多說進去看看
ContextImpl#createActivityContext
static ContextImpl createActivityContext(ActivityThread mainThread,
LoadedApk packageInfo, IBinder activityToken, int displayId,
Configuration overrideConfiguration) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
return new ContextImpl(null, mainThread, packageInfo, activityToken, null, 0,
null, overrideConfiguration, displayId);
}複製程式碼
直接new了他自己,真實簡單粗暴,不過我喜歡,哈哈。所以我們直接去看他的StartActivity
ContextImpl#startActivity
@Override
public void startActivity(Intent intent, Bundle options) {
warnIfCallingFromSystemProcess();
// Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is
// generally not allowed, except if the caller specifies the task id the activity should
// be launched in.
if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0
&& options != null && ActivityOptions.fromBundle(options).getLaunchTaskId() == -1) {
throw new AndroidRuntimeException(
"Calling startActivity() from outside of an Activity "
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."
+ " Is this really what you want?");
}
mMainThread.getInstrumentation().execStartActivity(
getOuterContext(), mMainThread.getApplicationThread(), null,
(Activity) null, intent, -1, options);
……
}複製程式碼
看到了嗎 看到了嗎 看到了嗎,重要的話說三遍,跟上面連起來了,mMainThread其實就是ActivityThread,原來哪怕你的呼叫棧再深,最終返回的還是同一個Instrumentation,真實666啊。還有一點,我們記得如果是在除Activity中啟動另一個Activity是需要動態設定啟動模式為FLAG_ACTIVITY_NEW_TASK的,其實就是在這裡做了判斷。
好了想到這,我們來簡單的總結下:
我們先來看看Context家族,放一張網上的圖片,方便大家記憶:
從名字我們可以看出ContextWrapper是Context的包裝類,而ContexImpl才是Context的實現類,只要跟Context有關的呼叫,最終肯定會進到ContexImpl中。
----------------------------------------我的是分割線-----------------------------------------------------
OK,我們繼續我們的分析,上面我們們呼叫到了ActivityManagerNative.getDefault().startActivity。所以我們們首先得了解ActivityManagerNative是什麼,其實這裡已經開始涉及到Bindle了,還有一丟丟的小興奮呢,廢話不多說,先上圖,大致瞭解一下Bindle相關類。
這是關於framework層的Binder架構圖
這是我自己整理的關於應用層Activity模組的的Binder架構圖
從上面2張圖我們可以看出架構是一一對應的,建議大家對照著看,從圖中我們可以看到ActivityManagerNative是Binder的子類,那Binder到底是什麼,其實要說明白這個問題,其實很困難,因為它太複雜了,在這裡我給介紹網上一個叫gityuan的大神,他分析的很透徹,強烈建議大家先看完他的博文在回來繼續閱讀,下面放上鍊接:徹底理解Android Binder通訊架構
好了,我們繼續我們的博文
Binder家族
相信大家已經看過大神的博文,但是我還是想把相關的概念再理一遍,對於這麼複雜的框架,重複一遍加深記憶應該是沒錯的,另一方面也是為了自己博文的連貫性,方便那些不想跳轉連結的朋友,請大家見諒,還有一點,大神分析的呼叫棧是startService(),而我是故意選擇startActivity()的,因為只有自己跟一遍程式碼,才能真正掌握一個知識點,好的我們開始。
以下的概念和圖直接摘錄大神博文,就當做增加了一個推廣渠道吧
我們先對比下TCP/IP的五層通訊體系結構和Binder的架構:
怎麼樣,是不是很像,每一層負責自己的業務邏輯程式碼,然後層與層之間定義好介面,方便上一層呼叫。 這裡盜用一下大神的圖
大家把startService()換成startActivity()其實是一樣的(請大家原諒我的厚臉皮)。
其中AMP作為Binder的客戶端,執行在各個app所在程式, AMN(或AMS)執行在系統程式system_server。
Binder IPC原理
上面這張圖是Binder程式間呼叫架構圖
可以看出無論是註冊服務和獲取服務的過程都需要ServiceManager,需要注意的是此處的Service Manager是指Native層的ServiceManager(C++),並非指framework層的ServiceManager(Java)。ServiceManager是整個Binder通訊機制的大管家,是Android程式間通訊機制Binder的守護程式,Client端和Server端通訊時都需要先獲取Service Manager介面,才能開始通訊服務, 當然查詢到目標資訊可以快取起來則不需要每次都向ServiceManager請求。
圖中Client/Server/ServiceManage之間的相互通訊都是基於Binder機制。既然基於Binder機制通訊,那麼同樣也是C/S架構,則圖中的3大步驟都有相應的Client端與Server端。
- 註冊服務:首先AMS註冊到ServiceManager。該過程:AMS所在程式(system_server)是客戶端,ServiceManager是服務端。
- 獲取服務:Client程式使用AMS前,須先向ServiceManager中獲取AMS的代理類AMP。該過程:AMP所在程式(app process)是客戶端,ServiceManager是服務端。
- 使用服務: app程式根據得到的代理類AMP,便可以直接與AMS所在程式互動。該過程:AMP所在程式(app process)是客戶端,AMS所在程式(system_server)是服務端。
圖中的Client,Server,Service Manager之間互動都是虛線表示,是由於它們彼此之間不是直接互動的,而是都通過與Binder Driver進行互動的,從而實現IPC通訊方式。其中Binder驅動位於核心空間,Client,Server,Service Manager位於使用者空間。Binder驅動和Service Manager可以看做是Android平臺的基礎架構,而Client和Server是Android的應用層.
好了,概念的東西講完了,繼續我們的程式碼跟蹤(以下博文為原創):
ActivityManagerNative#getDefault()
static public IActivityManager getDefault() {
return gDefault.get();
}
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
}複製程式碼
ServiceManager#getService
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().getService(name);
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}複製程式碼
注意看面的程式碼ServiceManager.getService("activity")得到的是IBinder的子類,但是具體是什麼呢?這裡好像看不太出來,想猜一下吧,是ActivityService嗎?經過查詢並沒有這個類,好吧我們先把這個放一放,看來遇到了點麻煩。沒事,既然不知道是什麼,那我就直接除錯,請看下圖
很明顯ActivityManagerNative#getDefault()返回的是ActivityManagerProxy,同時我們還知道了mRemote是BinderProxy。這裡推薦大家看下gityuan的另一篇文章:
Binder系列7—framework層分析,裡面有解釋。這裡我總結一下getIServiceManager().getService(name)其實呼叫的是ServiceManagerProxy#getService
public IBinder getService(String name) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
//mRemote為BinderProxy
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
//從reply裡面解析出獲取的IBinder物件
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
return binder;
}複製程式碼
BinderProxy#transact
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
return transactNative(code, data, reply, flags);
}
public native boolean transactNative(int code, Parcel data, Parcel reply,
int flags) throws RemoteException;複製程式碼
到掉到C++程式碼了,我們就繼續往下分析了,大家該興趣的話可以去看Binder系列7—framework層分析,這裡我直接說結論吧:
通過getService()最終獲取到的指向目標Binder服務端的代理物件BinderProxy。
getService的核心過程:
public static IBinder getService(String name) {
...
Parcel reply = Parcel.obtain(); //此處還需要將java層的Parcel轉為Native層的Parcel
BpBinder::transact(GET_SERVICE_TRANSACTION, *data, reply, 0); //與Binder驅動互動
IBinder binder = javaObjectForIBinder(env, new BpBinder(handle));
...
}複製程式碼
好了,我們繼續分析AMP(ActivityManagerProxy)的建立
ActivityManagerNative#asInterface
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);
}複製程式碼
此時obj為BinderProxy物件,queryLocalInterface的實現在BinderProxy中,我們可以看下程式碼
public class Binder implements IBinder {
//對於Binder物件的呼叫,則返回值不為空
public IInterface queryLocalInterface(String descriptor) {
//mDescriptor的初始化在attachInterface()過程中賦值
if (mDescriptor.equals(descriptor)) {
return mOwner;
}
return null;
}
}
final class BinderProxy implements IBinder {
//BinderProxy物件的呼叫, 則返回值為空
public IInterface queryLocalInterface(String descriptor) {
return null;
}
}複製程式碼
可以看到這裡返回的是null,好了,我們先總結一下:
對於Binder IPC的過程中, 同一個程式中Binder呼叫asInterface()方法返回的便是本地的Binder物件;對於不同程式的BinderProxy呼叫asInterface()則返回空。
繼續看程式碼
ActivityManagerProxy#ActivityManagerProxy
public ActivityManagerProxy(IBinder remote)
{
mRemote = remote;
}複製程式碼
可知mRemote便是指向AMS服務的BinderProxy物件,搞了半天,我們回到startActivity呼叫鏈,說實話真的有點累啊。
ActivityManagerNative.getDefault().startActivity就相當於是
ActivityManagerProxy#startActivity
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();
data.writeInterfaceToken(IActivityManager.descriptor);
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);
}
//其實重點是這行的程式碼
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
reply.readException();
int result = reply.readInt();
reply.recycle();
data.recycle();
return result;
}複製程式碼
BinderProxy#transact
final class BinderProxy implements IBinder {
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
//用於檢測Parcel大小是否大於800k
Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
return transactNative(code, data, reply, flags);
}
}複製程式碼
又是C++本地方法,直接上鍊接徹底理解Android Binder通訊架構2.5小節開始
我這裡自己說結論吧,其實在transactNative的本地方法呼叫棧中,經過一系列的呼叫最終會進入
Binder#execTransact
private boolean execTransact(int code, long dataObj, long replyObj,
int flags) {
Parcel data = Parcel.obtain(dataObj);
Parcel reply = Parcel.obtain(replyObj);
boolean res;
try {
// 呼叫子類AMN.onTransact方法
res = onTransact(code, data, reply, flags);
} catch (RemoteException e) {
if ((flags & FLAG_ONEWAY) != 0) {
...
} else {
//非oneway的方式,則會將異常寫回reply
reply.setDataPosition(0);
reply.writeException(e);
}
res = true;
} catch (RuntimeException e) {
if ((flags & FLAG_ONEWAY) != 0) {
...
} else {
reply.setDataPosition(0);
reply.writeException(e);
}
res = true;
} catch (OutOfMemoryError e) {
RuntimeException re = new RuntimeException("Out of memory", e);
reply.setDataPosition(0);
reply.writeException(re);
res = true;
}
reply.recycle();
data.recycle();
return res;
}複製程式碼
好了, 上面的程式碼呼叫到了之類的onTransact方法,即:
ActivityManagerNative#onTransact
@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();
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;
//呼叫ActivityManagerService的startActivity()方法
int result = startActivity(app, callingPackage, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
reply.writeNoException();
reply.writeInt(result);
return true;
}
}
}複製程式碼
上面說到mRemote是指向AMS服務的BinderProxy物件,所以此次的startActivity呼叫的就是ActivityManagerService#startActivity
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle options) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode, startFlags, profilerInfo, options,
UserHandle.getCallingUserId());
}
@Override
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
enforceNotIsolatedCaller("startActivity");
userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
false, ALLOW_FULL_ONLY, "startActivity", null);
// TODO: Switch to user app stacks here.
return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
profilerInfo, null, null, options, false, userId, null, null);
}複製程式碼
mStackSupervisor又是什麼鬼,我們直接進去看看吧
當程式執行到這裡時, ASS.startActivityMayWait的各個引數取值如下:
caller = ApplicationThreadProxy, 用於跟呼叫者程式ApplicationThread進行通訊的binder代理類.
callingUid = -1;
callingPackage = ContextImpl.getBasePackageName(),獲取呼叫者Activity所在包名
intent: 這是啟動Activity時傳遞過來的引數;
resolvedType = intent.resolveTypeIfNeeded
voiceSession = null;
voiceInteractor = null;
resultTo = Activity.mToken, 其中Activity是指呼叫者所在Activity, mToken物件儲存自己所處的ActivityRecord資訊
resultWho = Activity.mEmbeddedID, 其中Activity是指呼叫者所在Activity
requestCode = -1;
startFlags = 0;
profilerInfo = null;
outResult = null;
config = null;
options = null;
ignoreTargetSecurity = false;
userId = AMS.handleIncomingUser, 當呼叫者userId跟當前處於同一個userId,則直接返回該userId;當不相等時則根據呼叫者userId來決定是否需要將callingUserId轉換為mCurrentUserId.
iContainer = null;
inTask = null;
引數真是多啊,心好累,但是我不能放棄,直接看原始碼
由於下面的程式碼過長我只貼重要的方法,詳細請見startActivity啟動過程分析2.7小節開始
ActivityStackSupervisor#startActivityMayWait
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, WaitResult outResult, Configuration config,
Bundle options, boolean ignoreTargetSecurity, int userId,
IActivityContainer iContainer, TaskRecord inTask) {
...
boolean componentSpecified = intent.getComponent() != null;
//建立新的Intent物件,即便intent被修改也不受影響
intent = new Intent(intent);
//收集Intent所指向的Activity資訊, 當存在多個可供選擇的Activity,則直接向使用者彈出resolveActivity
ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags, profilerInfo, userId);
……
int res = startActivityLocked(caller, intent, resolvedType, aInfo,
voiceSession, voiceInteractor, resultTo, resultWho,
requestCode, callingPid, callingUid, callingPackage,
realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity,
componentSpecified, null, container, inTask);
return res;
}
}複製程式碼
ASS.resolveActivity()方法的核心功能是找到相應的Activity元件,並儲存到intent物件
ActivityStackSupervisor#startActivityLocked
final int startActivityLocked(IApplicationThread caller,
Intent intent, String resolvedType, ActivityInfo aInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode,
int callingPid, int callingUid, String callingPackage,
int realCallingPid, int realCallingUid, int startFlags, Bundle options,
boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
ActivityContainer container, TaskRecord inTask) {
……
final int launchFlags = intent.getFlags();
if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
... // activity執行結果的返回由源Activity轉換到新Activity, 不需要返回結果則不會進入該分支
}
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_INTENT_NOT_RESOLVED;
}
……
// 建立Activity記錄物件
ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
requestCode, componentSpecified, voiceSession != null, this, container, options);
……
if (voiceSession == null && (stack.mResumedActivity == null
|| stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {
// 前臺stack還沒有resume狀態的Activity時, 則檢查app切換是否允許 [見流程2.8.1]
if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
realCallingPid, realCallingUid, "Activity start")) {
PendingActivityLaunch pal =
new PendingActivityLaunch(r, sourceRecord, startFlags, stack);
// 當不允許切換,則把要啟動的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);
err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, true, options, inTask);
if (err < 0) {
notifyActivityDrawnForKeyguard();
}
return err;
}複製程式碼
其中有兩個返回值代表啟動Activity失敗:
- START_INTENT_NOT_RESOLVED: 從Intent中無法找到相應的Component或者ActivityInfo
- START_NOT_CURRENT_USER_ACTIVITY:該Activity對當前使用者不可見
AMS#doPendingActivityLaunchesLocked
startActivityUncheckedLocked方法的程式碼相當的長足足有差不多快700行,這裡就補貼程式碼,其實他的主要重要就是找到或建立新的Activit所屬於的Task物件,這中間有各種判斷條件,一行一行看會看暈掉,在檢查完成會後會呼叫targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);targetStack是ActivityStack物件,從名字就可以看出,這是一個Activity管理棧。final void doPendingActivityLaunchesLocked(boolean doResume) { while (!mPendingActivityLaunches.isEmpty()) { PendingActivityLaunch pal = mPendingActivityLaunches.remove(0); try { startActivityUncheckedLocked(pal.r, pal.sourceRecord, null, null, pal.startFlags, doResume && mPendingActivityLaunches.isEmpty(), null, null); } catch (Exception e) { ... } } }複製程式碼
再繼續下面的程式碼之前,我們先來看下activity的啟動模式
##Launch Mode(摘錄自部落格startActivity啟動過程分析)
先來說說在ActivityInfo.java中定義了4類Launch Mode:- LAUNCH_MULTIPLE(standard):最常見的情形,每次啟動Activity都是建立新的Activity;
- LAUNCH_SINGLE_TOP: 當Task頂部存在同一個Activity則不再重新建立;其餘情況同上;
- LAUNCH_SINGLE_TASK:當Task棧存在同一個Activity(不在task頂部),則不重新建立,而
移除該Activity上面其他的Activity;其餘情況同上; - LAUNCH_SINGLE_INSTANCE:每個Task只有一個Activity.
再來說說幾個常見的flag含義:
- FLAG_ACTIVITY_NEW_TASK:將Activity放入一個新啟動的Task;
- FLAG_ACTIVITY_CLEAR_TASK:啟動Activity時,將目標Activity關聯的Task清除,再啟動新Task,將該Activity放入該Task。該flags跟FLAG_ACTIVITY_NEW_TASK配合使用。
- FLAG_ACTIVITY_CLEAR_TOP:啟動非棧頂Activity時,先清除該Activity之上的Activity。例如Task已有A、B、C3個Activity,啟動A,則清除B,C。類似於SingleTop。
最後再說說:設定FLAG_ACTIVITY_NEW_TASK的幾個情況:
- 呼叫者並不是Activity context;
- 呼叫者activity帶有single instance;
- 目標activity帶有single instance或者single task;
- 呼叫者處於finishing狀態;
ActivityStack#startActivityLocked
final void startActivityLocked(ActivityRecord r, boolean newTask,
boolean doResume, boolean keepCurTransition, Bundle options) {
if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
//task中的上一個activity已被移除,或者ams重用該task,則將該task移到頂部
insertTaskAtTop(rTask, r);
mWindowManager.moveTaskToTop(taskId);
}
……
if (doResume) {
//重點關注這行程式碼
mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
}
}複製程式碼
mStackSupervisor是ActivityStackSupervisor的物件
ActivityStackSupervisor#resumeTopActivitiesLocked
boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,
Bundle targetOptions) {
if (targetStack == null) {
targetStack = mFocusedStack;
}
boolean result = false;
if (isFrontStack(targetStack)) {
//重點關注這行程式碼
result = targetStack.resumeTopActivityLocked(target, targetOptions);
}
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 (stack == targetStack) {
//上面剛已啟動
continue;
}
if (isFrontStack(stack)) {
stack.resumeTopActivityLocked(null);
}
}
}
return result;
}複製程式碼
又回到ActivityStack了
ActivityStack#resumeTopActivityLocked
final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
if (mStackSupervisor.inResumeTopActivity) {
return false; //防止遞迴啟動
}
boolean result = false;
try {
mStackSupervisor.inResumeTopActivity = true;
if (mService.mLockScreenShown == ActivityManagerService.LOCK_SCREEN_LEAVING) {
mService.mLockScreenShown = ActivityManagerService.LOCK_SCREEN_HIDDEN;
mService.updateSleepIfNeededLocked();
}
//重點關注這行程式碼
result = resumeTopActivityInnerLocked(prev, options);
} finally {
mStackSupervisor.inResumeTopActivity = false;
}
return result;
}複製程式碼
ActivityStack#resumeTopActivityInnerLocked
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
……
if (next == null) {
final String reason = "noMoreActivities";
if (!mFullscreen) {
//當該棧沒有全屏,則嘗試聚焦到下一個可見的stack
final ActivityStack stack = getNextVisibleStackLocked();
if (adjustFocusToNextVisibleStackLocked(stack, reason)) {
return mStackSupervisor.resumeTopActivitiesLocked(stack, prev, null);
}
}
ActivityOptions.abort(options);
final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?
HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
//啟動home桌面activity
return isOnHomeDisplay() &&
mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, reason);
}
……
//需要等待暫停當前activity完成,再resume top activity
boolean dontWaitForPause = (next.info.flags&ActivityInfo.FLAG_RESUME_WHILE_PAUSING) != 0;
//暫停其他Activity[見小節2.13.1]
boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);
if (mResumedActivity != null) {
//當前resumd狀態activity不為空,則需要先暫停該Activity 注意這行程式碼
pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
}
……
mStackSupervisor.startSpecificActivityLocked(next, true, true);
return true;
}複製程式碼
主要分支功能:
- 當找不到需要resume的Activity,則直接回到桌面;
- 否則,當mResumedActivity不為空,則執行startPausingLocked()暫停該activity;
- 然後再進入startSpecificActivityLocked環節,接下來從這裡繼續往下說。
ActivityStackSupervisor#pauseBackStacks
boolean pauseBackStacks(boolean userLeaving, boolean resuming, boolean dontWait) {
boolean someActivityPaused = false;
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
if (!isFrontStack(stack) && stack.mResumedActivity != null) {
//[見小節2.13.2]
someActivityPaused |= stack.startPausingLocked(userLeaving, false, resuming,
dontWait);
}
}
}
return someActivityPaused;
}複製程式碼
ActivityStack#startPausingLocked
final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,
boolean dontWait) {
if (mPausingActivity != null) {
if (!mService.isSleeping()) {
completePauseLocked(false);
}
}
ActivityRecord prev = mResumedActivity;
...
if (mActivityContainer.mParentActivity == null) {
//暫停所有子棧的Activity
mStackSupervisor.pauseChildStacks(prev, userLeaving, uiSleeping, resuming, dontWait);
}
...
final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();
if (prev.app != null && prev.app.thread != null) {
EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
prev.userId, System.identityHashCode(prev),
prev.shortComponentName);
mService.updateUsageStats(prev, false);
//暫停目標Activity
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
userLeaving, prev.configChangeFlags, dontWait);
}else {
...
}
if (!uiSleeping && !mService.isSleepingOrShuttingDown()) {
mStackSupervisor.acquireLaunchWakelock(); //申請wakelock
}
if (mPausingActivity != null) {
if (!uiSleeping) {
prev.pauseKeyDispatchingLocked();
}
if (dontWait) {
completePauseLocked(false);
return false;
} else {
Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
msg.obj = prev;
prev.pauseTime = SystemClock.uptimeMillis();
//500ms後,執行暫停超時的訊息
mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
return true;
}
} else {
if (!resuming) { //排程暫停失敗,則認為已暫停完成,開始執行resume操作
mStackSupervisor.getFocusedStack().resumeTopActivityLocked(null);
}
return false;
}複製程式碼
ActivityStackSupervisor#startSpecificActivityLocked
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
r.task.stack.setLaunchTime(r);
if (app != null && app.thread != null) {
try {
if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
|| !"android".equals(r.info.packageName)) {
app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
mService.mProcessStats);
}
//真正的啟動Activity 注意這行
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
}
//當程式不存在則建立程式
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
}複製程式碼
ActivityStackSupervisor#realStartActivityLocked
final boolean realStartActivityLocked(ActivityRecord r,
ProcessRecord app, boolean andResume, boolean checkConfig)
throws RemoteException {
//排程啟動ticks用以收集應用啟動慢的資訊
r.startLaunchTickingLocked();
//注意這行程式碼
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
new Configuration(stack.mOverrideConfig), r.compat, r.launchedFromPackage,
task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
//更新所有與該Activity具有繫結關係的Service連線
mService.mServices.updateServiceConnectionActivitiesLocked(r.app);
return true;複製程式碼
app.thread其實就是ApplicationThreadProxy物件
ApplicationThreadProxy#scheduleLaunchActivity
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
intent.writeToParcel(data, 0);
data.writeStrongBinder(token);
data.writeInt(ident);
info.writeToParcel(data, 0);
curConfig.writeToParcel(data, 0);
if (overrideConfig != null) {
data.writeInt(1);
overrideConfig.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
compatInfo.writeToParcel(data, 0);
data.writeString(referrer);
data.writeStrongBinder(voiceInteractor != null ? voiceInteractor.asBinder() : null);
data.writeInt(procState);
data.writeBundle(state);
data.writePersistableBundle(persistentState);
data.writeTypedList(pendingResults);
data.writeTypedList(pendingNewIntents);
data.writeInt(notResumed ? 1 : 0);
data.writeInt(isForward ? 1 : 0);
if (profilerInfo != null) {
data.writeInt(1);
profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
data.writeInt(0);
}
//注意這行程式碼
mRemote.transact(SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
}複製程式碼
按照我們上面的分析,這裡的mRemote應該的指向ApplicationThread的BinderProxy物件,所以 mRemote.transact(SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);會呼叫到
ApplicationThreadNative#onTransact
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
case SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION:
{
data.enforceInterface(IApplicationThread.descriptor);
Intent intent = Intent.CREATOR.createFromParcel(data);
IBinder b = data.readStrongBinder();
int ident = data.readInt();
ActivityInfo info = ActivityInfo.CREATOR.createFromParcel(data);
Configuration curConfig = Configuration.CREATOR.createFromParcel(data);
Configuration overrideConfig = null;
if (data.readInt() != 0) {
overrideConfig = Configuration.CREATOR.createFromParcel(data);
}
CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
String referrer = data.readString();
IVoiceInteractor voiceInteractor = IVoiceInteractor.Stub.asInterface(
data.readStrongBinder());
int procState = data.readInt();
Bundle state = data.readBundle();
PersistableBundle persistentState = data.readPersistableBundle();
List<ResultInfo> ri = data.createTypedArrayList(ResultInfo.CREATOR);
List<ReferrerIntent> pi = data.createTypedArrayList(ReferrerIntent.CREATOR);
boolean notResumed = data.readInt() != 0;
boolean isForward = data.readInt() != 0;
ProfilerInfo profilerInfo = data.readInt() != 0
? ProfilerInfo.CREATOR.createFromParcel(data) : null;
//注意這行程式碼
scheduleLaunchActivity(intent, b, ident, info, curConfig, overrideConfig, compatInfo,
referrer, voiceInteractor, procState, state, persistentState, ri, pi,
notResumed, isForward, profilerInfo);
return true;
}
}複製程式碼
ApplicationThread#scheduleLaunchActivity
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.referrer = referrer;
r.voiceInteractor = voiceInteractor;
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
r.persistentState = persistentState;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
r.profilerInfo = profilerInfo;
r.overrideConfig = overrideConfig;
updatePendingConfiguration(curConfig);
//注意這行程式碼
sendMessage(H.LAUNCH_ACTIVITY, r);
}複製程式碼
ActivityThread.java ::H#handleMessage
public void handleMessage(Message msg) {
switch (msg.what) {
case LAUNCH_ACTIVITY: {
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
//注意這行程式碼
handleLaunchActivity(r, null);
} break;
...
}
}複製程式碼
ActivityThread.java#handleLaunchActivity
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
unscheduleGcIdler();
mSomeActivitiesChanged = true;
//最終回撥目標Activity的onConfigurationChanged()
handleConfigurationChanged(null, null);
//初始化wms
WindowManagerGlobal.initialize();
//最終回撥目標Activity的onCreate 注意這行程式碼
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
//最終回撥目標Activity的onStart,onResume.
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed);
if (!r.activity.mFinished && r.startsNotResumed) {
r.activity.mCalled = false;
mInstrumentation.callActivityOnPause(r.activity);
r.paused = true;
}
} else {
//存在error則停止該Activity
ActivityManagerNative.getDefault()
.finishActivity(r.token, Activity.RESULT_CANCELED, null, false);
}
}複製程式碼
ActivityThread.java#performLaunchActivity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
ComponentName component = r.intent.getComponent();
if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
}
if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
...
}
try {
//建立Application物件
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (activity != null) {
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor);
if (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstances = null;
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
activity.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
...
r.activity = activity;
r.stopped = true;
if (!r.activity.mFinished) {
activity.performStart();
r.stopped = false;
}
if (!r.activity.mFinished) {
if (r.isPersistable()) {
if (r.state != null || r.persistentState != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
r.persistentState);
}
} else if (r.state != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
}
}
if (!r.activity.mFinished) {
activity.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnPostCreate(activity, r.state,
r.persistentState);
} else {
mInstrumentation.callActivityOnPostCreate(activity, r.state);
}
...
}
}
r.paused = true;
mActivities.put(r.token, r);
} catch (Exception e) {
...
}
return activity;
}複製程式碼
到此,正式進入了Activity的onCreate, onStart, onResume這些生命週期的過程啟動一個Activity的過程到此結束,我實話我已經暈了,大家一定要自己跟一遍程式碼。
總結
此圖來自gityuan部落格
啟動流程:
- 點選桌面App圖示,Launcher程式採用Binder IPC向system_server程式發起startActivity請求;
- system_server程式接收到請求後,向zygote程式傳送建立程式的請求;
- Zygote程式fork出新的子程式,即App程式;
- App程式,通過Binder IPC向sytem_server程式發起attachApplication請求;
- system_server程式在收到請求後,進行一系列準備工作後,再通過binder IPC向App程式傳送scheduleLaunchActivity請求;
- App程式的binder執行緒(ApplicationThread)在收到請求後,通過handler向主執行緒傳送LAUNCH_ACTIVITY訊息;
- 主執行緒在收到Message後,通過發射機制建立目標Activity,並回撥Activity.onCreate()等方法。
到此,App便正式啟動,開始進入Activity生命週期,執行完onCreate/onStart/onResume方法,UI渲染結束後便可以看到App的主介面