前言
最近自己在整理一些東西,總歸吧學(xué)到的記錄下來這樣才能更好的理解纸镊,方便以后查閱倍阐。如果文章哪里理解的有些偏差,還望大家指正逗威。
什么是Binder
- Binder是一種Android中實(shí)現(xiàn)跨進(jìn)城通信的方式峰搪,是Android為了跨進(jìn)程提出來的,是Android特有的凯旭。
- 從組成上來說概耻,Binder是一種虛擬的物理設(shè)備驅(qū)動(dòng)使套。
- 從Android 代碼來說,Binder是一個(gè)類鞠柄,實(shí)現(xiàn)IBinder接口侦高,是將Binder機(jī)制模型以代碼的形式實(shí)現(xiàn)在整個(gè)Android系統(tǒng)中。
為什么用Binder
我們都知道android是基于Linux開發(fā)的厌杜,那么為什么不用Linux的奉呛,而是要自己定義一套呢。那么Google沒用那肯定說明Linux下的消息通信機(jī)制是不適合android的夯尽,那Linux下有哪幾種瞧壮?為什么不能用?一般都是基于性能呐萌、穩(wěn)定性馁痴、安全性
Linux下的消息通信
主要有 socket、管道肺孤、消息隊(duì)列罗晕、共享內(nèi)存
性能:首先socket是基于文件和端口通信,傳輸效率低赠堵,開銷大小渊,一般用于跨網(wǎng)絡(luò)之間的進(jìn)程間通信,所以這個(gè)肯定pass掉了茫叭。而管道和消息隊(duì)列采用了存儲(chǔ)-轉(zhuǎn)發(fā)的方式:即先從發(fā)送方緩存區(qū)拷貝到內(nèi)核開辟的緩存區(qū)酬屉,再從內(nèi)核開辟的緩存區(qū)發(fā)送到接收方的緩存區(qū),整個(gè)過程至少有兩次拷貝揍愁,那肯定pass呐萨。而共享內(nèi)存雖然無需拷貝,但是控制復(fù)雜莽囤,難以使用谬擦。那Binder只需要一次拷貝,性能僅次于共享內(nèi)存朽缎。
穩(wěn)定性:Binder是基于C/S架構(gòu)惨远,客戶端又什么需求直接丟給服務(wù)端服務(wù)端區(qū)完成,架構(gòu)清晰话肖,職責(zé)明確北秽,那么肯定性能,雖然共享內(nèi)存無需拷貝最筒,但是控制負(fù)責(zé)贺氓,肯定沒有Binder穩(wěn)定。
安全性:那么Android作為一個(gè)開放性的平臺(tái)床蜘,有大量的應(yīng)用給用戶讓用戶使用掠归,因此安全性對(duì)于Android平臺(tái)來說很重要的缅叠,作為用戶來說肯定不希望你這些應(yīng)用把我手機(jī)上個(gè)人隱私信息全部偷走,在后臺(tái)各種亂來虏冻,而傳統(tǒng)的IPC是沒有任何安全措施的肤粱,完全依賴于上層。而Binder是由系統(tǒng)給每個(gè)應(yīng)用在內(nèi)核空間添加一個(gè)UIP/PID來添加身份標(biāo)示的厨相。所以Binder的安全性很高领曼。
而Binder可以建立私有管道,是Linux的通信機(jī)制所無法實(shí)現(xiàn)的蛮穿。
Binder實(shí)現(xiàn)原理
內(nèi)存映射:Binder的跨進(jìn)程通信和傳統(tǒng)的Linux跨進(jìn)程通信不一樣庶骄,它是利用了Linux下的一個(gè)內(nèi)存映射這個(gè)概念來實(shí)現(xiàn)的,也就是mmap()践磅。內(nèi)存映射就是將用戶空間中的一塊內(nèi)存區(qū)域映射到內(nèi)核空間单刁,映射關(guān)系建立后,用戶對(duì)這塊內(nèi)存的修改直接可以反應(yīng)到內(nèi)核空間,反之內(nèi)核空間對(duì)這段區(qū)域的修改也能直接反應(yīng)到用戶空間。而且內(nèi)存映射相對(duì)管道和消息隊(duì)列來說少了一次拷貝泌辫,實(shí)現(xiàn)了用戶空間和內(nèi)核空間兩個(gè)及時(shí)感知养筒。
一次通信過程:
1讲坎、首先Binder驅(qū)動(dòng)在內(nèi)核空間創(chuàng)建一個(gè)數(shù)據(jù)接收緩存區(qū)。
2、接著在內(nèi)核空間開辟一塊內(nèi)核緩存區(qū),建立內(nèi)核緩存區(qū)和內(nèi)核中數(shù)據(jù)接收緩存區(qū)之間的映射關(guān)系卡儒,以及內(nèi)核中數(shù)據(jù)接收緩存區(qū)和接收進(jìn)程用戶空間地址的映射關(guān)系。
3俐巴、發(fā)送方通過系統(tǒng)調(diào)用將數(shù)據(jù)copy到內(nèi)核中的內(nèi)核緩存區(qū)骨望,由于內(nèi)核緩存區(qū)和接收進(jìn)城的用戶空間有映射關(guān)系, 因此 相當(dāng)于吧數(shù)據(jù)發(fā)送到了接收進(jìn)城的用戶空間欣舵,這樣就完成了一次通信擎鸠。
從代碼角度看通信過程:
- 首先,一個(gè)進(jìn)程使用BINDER_SEZT_CONTEXT_MGR命令通過Binder驅(qū)動(dòng)將自己注冊(cè)成為了ServiceManager
- Server通過驅(qū)動(dòng)向ServiceManager中注冊(cè)Binder(Server中Binder實(shí)體)邻遏,驅(qū)動(dòng)為這個(gè)Binder創(chuàng)建位于內(nèi)核中實(shí)體節(jié)點(diǎn)以及ServerManager對(duì)實(shí)體的引用糠亩,將名字以及新建的引用包打包傳給ServiceManager虐骑,ServiceManager將起填入查找表
- Client通過名字准验,在Binder驅(qū)動(dòng)的幫助下蔥ServiceManager中獲取對(duì)Binder實(shí)體的引用,通過這個(gè)引用就能完成和Server的通信
Binde機(jī)制在Android中的具體實(shí)現(xiàn)原理
在我們Android中廷没,首先要定義一個(gè)IMyService的AIDL文件糊饱,然后會(huì)幫我生成一個(gè)java文件,內(nèi)部會(huì)有Stub和Proxy類颠黎,他們分別是Binder和BinderProxy的子類另锋,Stub和Proxy都是實(shí)現(xiàn)了這個(gè)接口滞项。
所以這個(gè)IInterface到底是什么,它呢就是一個(gè)用于表達(dá)Service提供的功能的一個(gè)契約夭坪,也就是說IInterface里有的方法文判,Service都能提供,調(diào)用者不用管BinderProxy是什么室梅,只要拿到Interface戏仓,就可以直接調(diào)用里面的方法。
Proxy實(shí)現(xiàn)了IMyService亡鼠,并且實(shí)現(xiàn)了里面的方法赏殃。為什么IMyservice要分Stub和Proxy,這是為了適用于本地調(diào)用和遠(yuǎn)程調(diào)用兩種情況间涵,如果Service運(yùn)行在同一個(gè)進(jìn)程仁热,那直接就用Stub,因?yàn)樗侵苯訉?shí)現(xiàn)了Serice提供的功能勾哩,不需要任何IPC過程抗蠢,如果Service運(yùn)行在其他進(jìn)程,哪么客戶端就使用的Proxy钳幅,就是吧參數(shù)封裝后發(fā)送給Binder物蝙,然后Binder轉(zhuǎn)發(fā)給ServiceManager從而讓對(duì)應(yīng)的Server段執(zhí)行 在將結(jié)果返回。
bindService源碼解析
那么如果我們客戶端要去連接Server敢艰,那么一般都是要bindService去綁定的我們的服務(wù)诬乞,我們會(huì)去傳一個(gè)ServiceConnection,下面分析下源碼看看bindService 這一步是如何通過Binder去完成跨進(jìn)程綁定我們的服務(wù)的钠导,并且返回的Binder對(duì)象的
先肯定是bindService了震嫉,這里調(diào)用的ContextWrapper,那么它的實(shí)現(xiàn)類是ContextImpl牡属,而且僅有這一個(gè)實(shí)現(xiàn)類
ContextImpl類
@Override
public boolean bindService(Intent service, ServiceConnection conn,int flags) {
// 如果是系統(tǒng)進(jìn)程會(huì)打印一個(gè)log
warnIfCallingFromSystemProcess();
// 又去調(diào)用bindServiceCommon 這個(gè)方法
return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
Process.myUserHandle());
}
/**
** 這里的conn 就是我們傳過來要接受IBinder的接口
*/
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
// mPackageInfo是loadApk的實(shí)例
// handler是ActivityThread的mH實(shí)例票堵,將它保存到ServiceDispatcher里面,得到了一個(gè)IServiceConnect接口
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
} else {
throw new RuntimeException("Not supported in system context");
}
...
int res = ActivityManager.getService().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
}
}
從上面得出逮栅,要執(zhí)行ActivityManager.getService() 得到的這個(gè)對(duì)象的bindService方法悴势,那么我們就看看ActivityManager的getService方法。
ActivityManager類
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;
}
};
從上面看出措伐,得到的一個(gè)IActivityManager而且是通過通過IBinder進(jìn)行轉(zhuǎn)換的
public interface IActivityManager extends IInterface {
}
那么這里是基于Android8.0 (26)26的源碼特纤,26以下是和這里不一樣的,26用AIDL通信侥加,(26以下其實(shí)是中間多了一層代理對(duì)象)捧存。 那么就是得到了遠(yuǎn)程ActivityManagerService這個(gè)對(duì)象,那么我們直接看它是怎么實(shí)現(xiàn)的
ActivityManagerService類
public int bindService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String callingPackage,int userId) throws TransactionTooLargeException {
enforceNotIsolatedCaller("bindService");
...
synchronized(this) {
//這里調(diào)用的ActivitySerivces這個(gè)的bindServiceLocked
return mServices.bindServiceLocked(caller, token, service,
resolvedType, connection, flags, callingPackage, userId);
}
}
ActivityServices類
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String callingPackage, final int userId) throws TransactionTooLargeException {
...
//從ServiceMap中查找ServiceRecord對(duì)象
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),
Binder.getCallingUid(), userId, true, callerFg, isBindExternal);
ServiceRecord s = res.record;
...
// 創(chuàng)建鏈接信息
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent);
//將創(chuàng)建好的連接信息存到集合中
ArrayList<ConnectionRecord> clist = s.connections.get(binder);
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
s.connections.put(binder, clist);
}
clist.add(c);
b.connections.add(c);
if (activity != null) {
if (activity.connections == null) {
activity.connections = new HashSet<ConnectionRecord>();
}
activity.connections.add(c);
}
b.client.connections.add(c);
if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
b.client.hasAboveClient = true;
}
if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
s.whitelistManager = true;
}
if (s.app != null) {
updateServiceClientActivitiesLocked(s.app, c, true);
}
clist = mServiceConnections.get(binder);
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
mServiceConnections.put(binder, clist);
}
clist.add(c);
//如果Flag中包含BIND_AUTO_CREATE就啟動(dòng)Service
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsReviewRequired) != null) {
return 0;
}
}
if (s.app != null && b.intent.received) {
//如果Service已經(jīng)啟動(dòng)或者這個(gè)intent沒有被連接過,立即連接昔穴,在會(huì)掉onServiceConnected
c.conn.connected(s.name, b.intent.binder, false);
} else if (!b.intent.requested) {
//Service啟動(dòng)了 但是沒有bind過镰官,先調(diào)用onBind,在會(huì)掉onServiceConnected
requestServiceBindingLocked(s, b.intent, callerFg, false);
}
}
源碼就分析到這里吧吗货,下面總結(jié)下
- 當(dāng)我們bindService的時(shí)候泳唠,會(huì)調(diào)用ContextImpl的bindService的方法,然后獲取一個(gè)ServiceDispath.InnerConnect的對(duì)象宙搬,可以跨進(jìn)程通信
- 然后通過Binder回去調(diào)用ActivityManagerService的bindService 的方法警检,然乎會(huì)判斷當(dāng)前服務(wù)有沒有啟動(dòng)和綁定。
- 如果沒有啟動(dòng)害淤,那就執(zhí)行realStartServiceLocked的方法扇雕,在去調(diào)用ActivityThread中的ApplicationThread中的scheduleCreateService方法,通過反射加載一個(gè)class窥摄,去執(zhí)行onCreate方法镶奉。
- 如果啟動(dòng)但是沒有bind,執(zhí)行requestServiceBiningsLocked方法崭放,在里面調(diào)用ActivityThread中的ApplicationThread中的scheduleBindService方法來執(zhí)行service的bind過程哨苛。
- 然后調(diào)用AMS的publishService,再去調(diào)用我們的ServiceDispatch.InnerConnection的connect方法
大概就寫完了币砂,算是自己的學(xué)習(xí)筆記吧建峭。