簡(jiǎn)述
關(guān)于Activity啟動(dòng)流程和Binder的文章很多椭微,大多數(shù)是分開來講的洞坑,本文將二者結(jié)合起來,著重分析啟動(dòng)流程中跨進(jìn)程方面的細(xì)節(jié)蝇率,其實(shí)迟杂,啟動(dòng)流程看似調(diào)用繁多,主要是復(fù)雜在Activity棧管理等方面本慕,如果將其看作一個(gè)整體排拷,整個(gè)啟動(dòng)流程就簡(jiǎn)單很多。在啟動(dòng)流程中锅尘,App和AMS的跨進(jìn)程調(diào)用是其中的重點(diǎn)监氢,理解了這個(gè),會(huì)加深對(duì)Binder和啟動(dòng)流程的理解認(rèn)知藤违,也能窺到Framework層的冰山一角浪腐。另外我也發(fā)現(xiàn),很多文章在講啟動(dòng)流程的時(shí)候顿乒,關(guān)于ActivityMangagerService進(jìn)程如何調(diào)用App進(jìn)程的細(xì)節(jié)都沒有講清楚议街,這個(gè)問題也是我寫這篇文章的初衷。閱讀本文前建議了解一下AIDL璧榄,對(duì)Binder,Stub,Proxy等有一些印象特漩。建議讀一下這篇文章寫給 Android 應(yīng)用工程師的 Binder 原理剖析
Binder簡(jiǎn)介
對(duì)于Binder吧雹,初學(xué)的人會(huì)對(duì)里面的概念比較模糊,因?yàn)榭雌饋泶_實(shí)有些繞拾稳,我在這兒寫幾點(diǎn)幫助理解吮炕。
- 所謂的“跨進(jìn)程”能力指的是兩個(gè)方面:一個(gè)是能夠作為客戶端調(diào)用遠(yuǎn)程服務(wù)的能力,一個(gè)是能夠作為服務(wù)端接收客戶端進(jìn)程消息的能力访得,二者都是跨進(jìn)程的一部分,分別對(duì)應(yīng)transact和onTransact方法陕凹,而這兩個(gè)方法的實(shí)現(xiàn)悍抑,分別位于BinderProxy和Binder兩個(gè)類中,這兩個(gè)類都在Binder.java這個(gè)文件中杜耙,讀者可以自行閱讀搜骡。
- BinderProxy具有發(fā)送消息的能力,通過transact方法佑女,調(diào)用底層binder驅(qū)動(dòng)记靡,服務(wù)端的Binder具有接收底層binder驅(qū)動(dòng)傳過來的消息的能力,當(dāng)接收到消息會(huì)調(diào)用onTransact方法团驱。
- 剛開始看AIDL的時(shí)候需要反復(fù)記憶理解一下摸吠,否則看別的代碼容易混淆。這里說幾個(gè)比較容易記憶的點(diǎn):一個(gè)類繼承了Stub類嚎花,表示這個(gè)類是遠(yuǎn)程服務(wù)端寸痢,Stub類有個(gè)asInterface的靜態(tài)方法,這個(gè)方法用在拿到binder驅(qū)動(dòng)傳過來的BinderProxy對(duì)象時(shí)紊选,將該對(duì)象轉(zhuǎn)化成client端使用的本地代理xxxProxy啼止,客戶端用它調(diào)用遠(yuǎn)程service的方法。該代理跟service實(shí)現(xiàn)了同樣的接口兵罢,只不過一個(gè)是真實(shí)現(xiàn)献烦,一個(gè)是假實(shí)現(xiàn),這里假實(shí)現(xiàn)指的是它通過Binder驅(qū)動(dòng)調(diào)用S端方法卖词,真正做工作的在Service端巩那。簡(jiǎn)言之,Stub代表service端坏平,Proxy代表service在客戶端的代理拢操。
- 以AMS為例,看代碼
public class ActivityManagerService extends IActivityManager.Stub
AMS繼承了Stub類舶替,而Stub類一共實(shí)現(xiàn)了三個(gè)接口:IActivityManger令境,IInterface和IBinder,分別對(duì)應(yīng)了三種能力顾瞪,管理activity舔庶、跨進(jìn)程抛蚁、asBinder,前兩者好理解惕橙,那么這里的asBinder能力是干嘛的呢瞧甩?這里先賣個(gè)關(guān)子,等下講啟動(dòng)流程的時(shí)候會(huì)說明弥鹦。
- AMS和APP跨進(jìn)程的過程簡(jiǎn)單說就是C端和S端分別通過二者在對(duì)方的代理去互相調(diào)用對(duì)方的方法
啟動(dòng)流程
我們先從宏觀角度理解這個(gè)過程肚逸,首先,為什么要跨進(jìn)程呢彬坏?我自己在客戶端new一個(gè)Activity不行嗎朦促?顯然是不可以的,Android的安全機(jī)制以及為了統(tǒng)一管理Activity(比如activity棧)栓始,需要有個(gè)大管家去進(jìn)行所有Activity的管理和控制,而這個(gè)管家是運(yùn)行在一個(gè)單獨(dú)進(jìn)程的务冕,因此App端如果想發(fā)起一個(gè)Activity的請(qǐng)求,需要先把“申請(qǐng)”提交給大管家幻赚,也就是AMS禀忆。AMS處理完這個(gè)請(qǐng)求之后,需要再次通過跨進(jìn)程通知App端落恼,去執(zhí)行剩下的相應(yīng)的工作箩退。因此這里的核心就在于兩者如何互相調(diào)用對(duì)方了。好多文章對(duì)AMS如何通知App這塊講的不夠清楚领跛,甚至忽略乏德,本文著重會(huì)說明。
App端如何調(diào)用AMS方法
下面看代碼:用戶啟動(dòng)一個(gè)頁(yè)面時(shí)吠昭,會(huì)依次調(diào)用activity的startActivity-->Instrumentation的executestartActivity-->execStartActivitiesAsUser喊括,這幾個(gè)調(diào)用很容易找到,就簡(jiǎn)單帶過矢棚,在最后這個(gè)方法里郑什,執(zhí)行了遠(yuǎn)程調(diào)用,即:
int result = ActivityManager.getService()
.startActivities(whoThread, who.getBasePackageName(), intents, resolvedTypes,
token, options, userId);
ActivityManager.getService獲取的是什么蒲肋?看ActivityMangaer.getService()這個(gè)代碼里面:
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
如果對(duì)Binder有所了解蘑拯,應(yīng)該很容易知道,這里取得的是AMS在客戶端的代理兜粘,也就是代碼中的最后一行返回的am申窘。因?yàn)锳pp要頻繁的調(diào)用AMS的方法,因此用單例模式緩存在本地了一個(gè)AMS的本地代理孔轴,從單例的第一次獲取可以看到剃法,AMS的Binder是通過ServiceManager.getService()獲取到的,那么ServiceMangaer是個(gè)什么東西,其實(shí)這個(gè)就是Android系統(tǒng)統(tǒng)一管理所有遠(yuǎn)程服務(wù)的“大管家”路鹰,比如AMS贷洲,WMS等系統(tǒng)服務(wù)都在這里注冊(cè)了收厨,客戶端想調(diào)用任意一個(gè)服務(wù),只需要知道名字就可以通過SM獲取到相應(yīng)的Server的Binder优构。拿到Binder之后便可以通過asInterface靜態(tài)方法轉(zhuǎn)化成本地代理诵叁,從而調(diào)用server的方法了。因此第一次獲取AMS的Binder的過程實(shí)際上是客戶端跟ServiceManager的一次跨進(jìn)程通信钦椭。
AMS如何通知App進(jìn)程
(1)AMS如何獲取到App進(jìn)程的Binder的
從上面的分析知道拧额,App獲取AMS的Binder實(shí)際上是通過ServiceManager這個(gè)大管家間接獲取的,那反過來AMS處理完activity的管理任務(wù)(棧操作等)之后又如何通知App的呢玉凯?
一個(gè)App總不可能像AMS那樣在ServiceManger中注冊(cè)吧势腮,而且也沒這個(gè)必要。那么到底是怎么通知的呢漫仆?
答案就是:App跨進(jìn)程調(diào)用AMS的方法時(shí),還順便把App進(jìn)程(這個(gè)時(shí)候App可以看作是服務(wù)端了)的Binder作為參數(shù)傳給了AMS泪幌,AMS拿到這個(gè)APP的Binder之后盲厌,通過asInterface方法轉(zhuǎn)化成在server端可以使用的代理,然后在需要回調(diào)App進(jìn)程的時(shí)候通過這個(gè)代理來通知客戶端祸泪。其實(shí)跟App端邏輯是一致的吗浩,只不過C/S調(diào)了一下順序,C變成了S没隘,S變成了C懂扼。下面我們從代碼里驗(yàn)證:
我們以6.0之前版本的源碼為例,新版本改成事務(wù)了右蒲,有些源碼不容易看到阀湿,不如直接看老版本的,便于理解瑰妄。
首先看APP調(diào)用startActivity時(shí)是如何把App進(jìn)程的Binder參數(shù)傳過去的陷嘴,剛才說了,startActivity實(shí)際上調(diào)用的是AMS本地代理的startActivity间坐,而AMS本地代理是ActivityMangerProxy灾挨,這里AMP是AIDL自動(dòng)生成的
class ActivityManagerProxy implements IActivityManager
{
public ActivityManagerProxy(IBinder remote)
{
mRemote = remote;
}
public IBinder asBinder()
{
return mRemote;
}
public int startActivity(IApplicationThread caller, Intent intent,
String resolvedType, Uri[] grantedUriPermissions, int grantedMode,
IBinder resultTo, String resultWho,
int requestCode, boolean onlyIfNeeded,
boolean debug, String profileFile, ParcelFileDescriptor profileFd,
boolean autoStopProfiler) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
intent.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeTypedArray(grantedUriPermissions, 0);
data.writeInt(grantedMode);
data.writeStrongBinder(resultTo);
data.writeString(resultWho);
data.writeInt(requestCode);
data.writeInt(onlyIfNeeded ? 1 : 0);
data.writeInt(debug ? 1 : 0);
data.writeString(profileFile);
if (profileFd != null) {
data.writeInt(1);
profileFd.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
data.writeInt(0);
}
data.writeInt(autoStopProfiler ? 1 : 0);
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
reply.readException();
int result = reply.readInt();
reply.recycle();
data.recycle();
return result;
}
startActivity方法的第一個(gè)參數(shù)caller,這個(gè)東西是IApplicationThread,這個(gè)IApplicationThread就是AMS去通知App做相應(yīng)處理的接口竹宋,它跟IActivityManger配合組成了App和AMS交互的“協(xié)議”劳澄。那么這個(gè)傳過來的IApplicationThread的是誰(shuí)呢,看代碼:
Instrumentation:
int result = ActivityManager.getService()
.startActivityAsUser(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, resultWho,
requestCode, 0, null, options, user.getIdentifier());
ContextImpl:
mMainThread.getInstrumentation().execStartActivities(
getOuterContext(), mMainThread.getApplicationThread(), null,
(Activity) null, intents, options);
ActivityThread:
public ApplicationThread getApplicationThread()
{
return mAppThread;
}
通過函數(shù)調(diào)用可以查到蜈七,首先是instrumentation類里傳入的whoThread秒拔,whoThread是ContextImpl傳進(jìn)來的mMainThread.getApplicationThread(),而最后這個(gè)是mAppThread,這個(gè)東西就是ActivityThread這個(gè)類的內(nèi)部類ApplicationThread,我們看代碼:
private class ApplicationThread extends IApplicationThread.Stub {
繼承自Stub宪潮,因此從AIDL語(yǔ)法看出溯警,是一個(gè)服務(wù)端趣苏,對(duì)應(yīng)的客戶端是誰(shuí)呢?當(dāng)然是AMS了梯轻,所以ApplicationThread這個(gè)類就是AMS向App進(jìn)程發(fā)消息時(shí)的服務(wù)端食磕,因此客戶端和服務(wù)端都是相對(duì)的,A要調(diào)B的服務(wù)喳挑,A就是客戶端彬伦,B就是服務(wù)端,反之亦然伊诵。
思路回到主線上单绑,上面已經(jīng)說明了,在客戶端調(diào)用Binder的時(shí)候把ApplicationThread傳給了AMS曹宴,怎么傳的呢搂橙?這里回到剛才的ActivityMangerProxy這個(gè)類里面來,參數(shù)已經(jīng)傳給了startActivity方法笛坦,接下來會(huì)執(zhí)行到這一行:
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
caller.asBinder,這里asBinder方法就涉及到之前遺留的那個(gè)問題区转,服務(wù)端為什么要實(shí)現(xiàn)IInterface這個(gè)接口,就是在這個(gè)時(shí)候用的版扩,即把S端(相對(duì)的)轉(zhuǎn)成一個(gè)binder废离,之后binder寫入到Parcel里,然后通過transact方法調(diào)用底層Binder驅(qū)動(dòng)傳給其他進(jìn)程礁芦,這里也要注意蜻韭,transact方法調(diào)用的是mRemote的transact,而mRemote本質(zhì)上是一個(gè)BinderProxy,千萬不要理解成Binder了柿扣,因?yàn)檫@兩個(gè)類都實(shí)現(xiàn)了IBinder接口肖方,我們看代碼的時(shí)候很可能會(huì)誤認(rèn)為調(diào)用的Binder的transact。binderProxy的transact會(huì)調(diào)用transactNative函數(shù)窄刘,傳給jni層窥妇,將之前保存在Parcel里的數(shù)據(jù)data傳給Binder驅(qū)動(dòng),之后在傳給AMS娩践』铘妫可以這樣理解,對(duì)于Binder驅(qū)動(dòng)來說翻伺,它可以看成跨進(jìn)程的一個(gè)“傳送帶”材泄,從A進(jìn)程傳遞給B進(jìn)程,只要你實(shí)現(xiàn)了IInterface吨岭,就可以放到這個(gè)傳送帶上傳送(writeStrongBinder方法)拉宗。總結(jié)一下就是IInterface接口表明了這個(gè)類可以轉(zhuǎn)成一個(gè)binder從而在binder驅(qū)動(dòng)中跨進(jìn)程運(yùn)輸,IBinder接口表明了類具有跨進(jìn)程的能力旦事,即可以通過調(diào)用transact方法“使用”Binder驅(qū)動(dòng)魁巩。
(2)獲取到了Binder之后
上面的討論已經(jīng)知道,AMS其實(shí)在App跨進(jìn)程調(diào)用AMS的時(shí)候就把ApplicationThread的Binder傳過來了姐浮,傳過來以后谷遂,AMS如果要用,必須得拿到ApplicationThread的代理卖鲤,怎么拿到的呢肾扰?
剛才說了,客戶端startActivity蛋逾,通過AMS的代理發(fā)起transact方法集晚,AMS的onTransact方法會(huì)監(jiān)聽,我們看onTransact的代碼:AMS繼承自IActivityManager.Stub区匣,在源碼中叫ActivityManagerNative:
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);
可以看到:
IBinder b = data.readStrongBinder();客戶端將binder write到Parcel中偷拔,服務(wù)端從data中讀了出來,然后通過asInterface轉(zhuǎn)換成ApplicationThread的代理ApplicationThreadProxy這個(gè)類亏钩。注意:前面也講了条摸,Binder驅(qū)動(dòng)過來的IBinder不是Binder,而是BinderProxy铸屉,但是為什么我們之前傳的參數(shù)是ApplicationThread,這個(gè)類是一個(gè)binder切端,為什么讀出來以后變成了BinderProxy了呢彻坛?答案就在這個(gè)readStrongBinder里,看jni層的源碼可以知道踏枣,系統(tǒng)在客戶端收到(readStrongBinder)IBinder以后昌屉,會(huì)保存下來,通過Binder驅(qū)動(dòng)傳給Service時(shí)茵瀑,會(huì)通過之前保存的Binder在底層創(chuàng)建BinderProxy间驮,然后傳給上層,其實(shí)看framework的源碼马昨,BinderProxy沒有看到在java層的new方法竞帽,原來都在底層創(chuàng)建好了。
有了代理對(duì)象后接下來既可以直接用了:
int result = startActivity(app, intent, resolvedType,
grantedUriPermissions, grantedMode, resultTo, resultWho,
requestCode, onlyIfNeeded, debug, profileFile, profileFd, autoStopProfiler);
即進(jìn)入到AMS對(duì)Activity啟動(dòng)管理流程中了鸿捧,經(jīng)過復(fù)雜的跳轉(zhuǎn)屹篓,最后跑到ActivityStackSupervisor這個(gè)類的realStartActivityLocked方法中,里面最終會(huì)執(zhí)行到這行代碼:
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
r.compat, r.task.voiceInteractor, app.repProcState, r.icicle, r.persistentState,
results, newIntents, !andResume, mService.isNextTransitionForward(),
profilerInfo);
這里的app.thread就是前面ApplicationThread在AMS中的代理匙奴,到了這里大家應(yīng)該理清楚了堆巧,接下來通過代理調(diào)起App進(jìn)程的ApplicationThread里的相應(yīng)方法,即:scheduleLaunchActivity方法,這個(gè)方法會(huì)發(fā)送一個(gè)Message給主線程的handler :H,然后在handleMessage里通過類加載器創(chuàng)建出一個(gè)Activity對(duì)象谍肤,并執(zhí)行onCreate方法.balabala....
最后用圖片總結(jié)一下:
最后推薦一篇文章啦租,目前發(fā)現(xiàn)的講的binder最詳細(xì)的,聽說你 Binder 機(jī)制學(xué)的不錯(cuò)荒揣,來解決下這幾個(gè)問題