本故事純屬虛構,若有不通順的邏輯請輕噴。❤️html
犬夜叉和奈落大決戰以後,四魂之玉、食骨之井消失,誰也不知道去了哪,而犬夜叉和阿籬再次被分割到兩個世界。java
因而犬夜叉拜託一位研究世界宇宙的法師——積木,來幫助他找到阿籬。android
時間轉眼來到了2021年,積木終於發現了這個世界的祕密。。面試
其實咱們所在的整個宇宙叫作Android宇宙,犬夜叉和阿籬所處的兩個世界實際上是兩個進程,兩個世界能夠經過食骨之井相鏈接。服務器
因此想讓犬夜叉從新聯繫到阿籬,必須再找到當年的食骨之井。架構
「犬夜叉,我終於找到了」ide
「找到什麼了?是阿籬嗎?阿籬找到了????」工具
「沒有,不過我找到了關鍵的東西——食骨之井」學習
「在哪,快帶我去」ui
因而,積木法師帶着犬夜叉來到一間屋子裏:
這間屋子門面上寫着《內核屋》
三個大字,犬夜叉一個箭步飛了進去,在裏面果真找到了當年那個食骨之井
,可是又有點不同,由於它被改了名,旁邊一個破碎的板子上寫着——Binder井
。板子上還同時刻有使用說明:
Binder井
這口井聯繫這兩個世界,你看到的也許不是真實的,請慎用!
如需使用,請找到當年遺落的四魂之玉,如今它叫SM之玉(ServiceManager)
。
找到SM之玉,內心默唸你想聯繫的那個世界那我的,若是她在那個世界的SM之玉碎片中留下了地址,那麼你就能找到她。
「積木法師,你知道SM之玉嗎,哪裏能夠找到它」,犬夜叉問到。
「說到SM之玉,還要從宇宙的起源提及,Android宇宙建立初期,誕生了第一個有人的世界(用戶進程),叫作Init世界
,而SM之玉就是由這個世界建立的。
SM之玉建立後,啓動了Binder井
,成爲了他的守護神。
可是它的真身存在於單獨的世界中,沒法得到。爲了讓人們可以使用到它,它特地在每一個世界都留下了本身的碎片(代理)。」
「在哪在哪,快告訴我」。
「第0街道(句柄值固定爲0)」,積木法師指了一個方向說到。
犬夜叉急忙去第0街道找到了SM之玉的碎片,而後回到Binder井
旁邊,內心默唸道:
「
SM之玉,
求求你幫我找到阿籬吧。
」
突然,Binder
井刮出一陣狂風,一個虛影出如今了犬夜叉的面前。
是阿籬~
「阿籬,你能聽到我說話嗎?」
「犬夜叉,我能聽到,沒想到還能看到你」,阿籬的虛影說到。
「我想你了,阿籬...」
故事結束了。
再幫你們理一下故事梗概,其實也就是Binder
的工做流程:
固然,故事畢竟是故事,並不能徹底說清楚。
因此下面就完整看看Binder
的工做流程和原理~
首先,咱們使用AIDL
來實現剛纔故事中的場景——讓犬夜叉和阿籬兩個不一樣進程的人說上話:
//IMsgManager.aidl interface IMsgManager { String getMsg(); void tell(in String msg); } //阿籬 public class AliWorldService extends Service { private static final String TAG = "lz1"; @Nullable @Override public IBinder onBind(Intent intent) { return mBinder; } private Binder mBinder = new IMsgManager.Stub() { @Override public String getMsg() throws RemoteException { String tellMsg="犬夜叉...是我"; Log.e(TAG, "阿籬:" + tellMsg); return tellMsg; } @Override public void tell(String msg) throws RemoteException { Log.e(TAG, "我是阿籬,我收到了你說的:" + msg); } }; } <service android:name=".binder.AliWorldService" android:process=":aliworld"> </service> //犬夜叉 public class QycWorldActivity extends Activity { private static final String TAG = "lz1"; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_qyc); Intent i = new Intent(this, AliWorldService.class); bindService(i, mConnection, Context.BIND_AUTO_CREATE); } private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { IMsgManager msgManager = IMsgManager.Stub.asInterface(service); try { String tellMsg="阿籬,是你嗎"; Log.e(TAG, "犬夜叉:" + tellMsg); msgManager.tell(tellMsg); String msg = msgManager.getMsg(); Log.e(TAG, "我是犬夜叉,我收到了你說的:" + msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }; @Override protected void onDestroy() { super.onDestroy(); unbindService(mConnection); } }
運行,打印結果:
E/lz1: 犬夜叉:阿籬,是你嗎 E/lz1: 我是阿籬,我收到了你說的:阿籬,是你嗎 E/lz1: 阿籬:犬夜叉...是我 E/lz1: 我是犬夜叉,我收到了你說的:犬夜叉...是我
代碼比較簡單,服務器端新建一個Binder
對象並傳到onBind
方法中,客戶端bindservice
以後,獲取到服務端的代理接口,就能夠進行方法的調用了。
AIDL
其實只是一個幫助咱們實現進程間通訊的工具,它會根據咱們寫的AIDL
文件代碼,生成相應的java
接口代碼,其內部也是經過Binder
實現的。
咱們能夠經過build——generated——aidl_source_output_dir——debug——out
文件路徑找到AIDL爲咱們生成的接口類。代碼以下:
public interface IMsgManager extends android.os.IInterface { public static abstract class Stub extends android.os.Binder implements com.example.studynote.binder.IMsgManager { //1 private static final java.lang.String DESCRIPTOR = "com.example.studynote.binder.IMsgManager"; public Stub() { this.attachInterface(this, DESCRIPTOR); } //2 public static com.example.studynote.binder.IMsgManager asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.example.studynote.binder.IMsgManager))) { return ((com.example.studynote.binder.IMsgManager) iin); } return new com.example.studynote.binder.IMsgManager.Stub.Proxy(obj); } @Override public android.os.IBinder asBinder() { return this; } //4 @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { java.lang.String descriptor = DESCRIPTOR; switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(descriptor); return true; } case TRANSACTION_getMsg: { data.enforceInterface(descriptor); java.lang.String _result = this.getMsg(); reply.writeNoException(); reply.writeString(_result); return true; } case TRANSACTION_tell: { data.enforceInterface(descriptor); java.lang.String _arg0; _arg0 = data.readString(); this.tell(_arg0); reply.writeNoException(); return true; } default: { return super.onTransact(code, data, reply, flags); } } } private static class Proxy implements com.example.studynote.binder.IMsgManager { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } @Override public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } //3 @Override public java.lang.String getMsg() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.lang.String _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getMsg, _data, _reply, 0); _reply.readException(); _result = _reply.readString(); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public void tell(java.lang.String msg) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeString(msg); mRemote.transact(Stub.TRANSACTION_tell, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } } static final int TRANSACTION_getMsg = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_tell = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); } public java.lang.String getMsg() throws android.os.RemoteException; public void tell(java.lang.String msg) throws android.os.RemoteException; }
代碼比較長,咱們依次來分析下:
DESCRIPTOR
。Binder的惟一標示。在Stub類的構造方法中,就是經過attachInterface
方法將當前的Binder和這個惟一標示進行了綁定。
asInterface()
。將服務端的Binder對象轉換成客戶端所需的接口類型對象。這個方法是客戶端調用的,在這個方法中,會經過queryLocalInterface(DESCRIPTOR)
方法,傳入惟一標示,來獲取對應的Binder。
若是是服務端和客戶端在同一個進程,那麼就會返回服務端的Binder對象,也就是Stub對象自己,而後就直接調用對象的方法了。
若是在不一樣進程,也就是咱們通常的跨進程狀況,就會返回封裝後的Stub.Proxy這個代理對象。
Proxy.getMsg/tell
接着就看看代理類裏面的方法,也就是咱們在客戶端(Activity)中實際調用的方法。
這其中有兩個比較重要的對象 :_data對象
和 _reply
對象,都是Parcel
類型的,這裏會對數據進行一個序列化操做,這樣才能進行跨進程傳輸。
若是方法傳有參數,就會把參數寫到_data對象
,而後調用transact方法
發起遠程調用請求(RPC),同時當前線程掛起,等待服務端執行完請求。
mRemote.transact(Stub.TRANSACTION_getMsg, _data, _reply, 0);
能夠看到,傳入了一個int類型的code——TRANSACTION_getMsg
,這個code其實就是爲了要肯定調用的是哪一個方法。
等請求結束後,當前線程繼續,會從_reply
對象中取出返回結果。
整個IPC流程就結束了。那服務器究竟是在哪裏進行任務執行的呢?繼續看onTransact方法。
onTransact
onTransact
方法就是服務端要作的事了,運行在服務端的Binder線程池
中。
當客戶端發起遠程調用請求後,會經過系統底層封裝,其實也就是內核層的Binder
驅動,而後交給服務端的onTransact
方法。
在該方法中,首先經過code
知曉是哪一個方法,而後就執行目標方法,並將序列化結果寫到reply
中,RPC過程結束,交給客戶端處理。
case TRANSACTION_getMsg: { data.enforceInterface(descriptor); java.lang.String _result = this.getMsg(); reply.writeNoException(); reply.writeString(_result); return true; }
最後畫張圖總結下AIDL整個流程:
通過了上述AIDL的例子,你們是否是對Binder又進一步瞭解了呢?
在java層面,其實Binder
就是一個實現了IBinder
接口的類。
真正跨進程的部分仍是在客戶端發起遠程調用請求以後,系統底層封裝好,交給服務端的時候。而這個系統底層封裝,其實就是發生在Linux內核
中。
而在內核中完成這個通訊關鍵功能的仍是Binder
,此次不是Binder
類了,而是Binder驅動
。
驅動你能夠理解爲一種硬件接口,能夠幫助操做系統來控制硬件設備。
Binder驅動
被添加運行到Linux內核空間
,這樣,兩個不一樣進程就能夠經過訪問內核空間來完成數據交換:把數據傳給Binder驅動
,而後處理好再交給對方進程,完成跨進程通訊。
而剛纔經過AIDL
的例子咱們能夠知道,客戶端在請求服務端通訊的時候,並非直接和服務端的某個對象聯繫,而是用到了服務端的一個代理對象,經過對這個代理對象操做,而後代理類會把方法對應的code、傳輸的序列化數據、須要返回的序列化數據
交給底層,也就是Binder驅動。(這也解釋了爲何犬夜叉看到的是阿籬的虛影,而不是真身😝)
而後Binder驅動把對應的數據交給服務器端,等結果計算好以後,再由Binder驅動
把數據返回給客戶端。
到這裏,可能就會有朋友會發現有點不對勁,剛纔不是說還有個ServiceManager
嗎?這裏AIDL通訊中咋沒有呢,漏了啊??
ServiceManager
實際上是爲了管理系統服務而設置的一種機制,每一個服務註冊在ServiceManager
中,由ServiceManager
統一管理,咱們能夠經過服務名在ServiceManager
中查詢對應的服務代理,從而完成調用系統服務的功能。因此ServiceManager有點相似於DNS,能夠把服務名稱和具體的服務記錄在案,供客戶端來查找。
在咱們這個AIDL的案例中,能直接獲取到服務端的Service
,也就直接能獲取到服務端的代理類IMsgManager
,因此就無需經過ServiceManager
這一層來尋找服務了。
並且ServiceManager
自己也運行在一個單獨的進程,因此它自己也是一個服務端,客戶端實際上是先經過跨進程獲取到ServiceManager
的代理對象,而後經過ServiceManager
代理對象再去找到對應的服務。
而ServiceManager
就像咱們剛纔AIDL中的Service同樣,是能夠直接找到的,他的句柄永遠是0
,是一個「衆所周知」的句柄,因此每一個APP程序均可以經過binder機制在本身的進程空間中建立一個ServiceManager
代理對象。
(這也解釋了爲何四魂之玉在另一個世界,其實就在另一個進程,咱們只能經過句柄值爲0找到四魂之玉的碎片,其實也就是代理😝)
因此經過ServiceManager
查找系統服務並調用方法的過程是進行了兩次跨進程通訊。
APP進程——>ServiceManager進程——>系統服務進程(好比AactivityManagerService)
下面咱們就拿ActivityManagerService
舉例看看怎麼經過ServeiceManager
獲取到系統服務。
熟悉APP啓動流程的朋友都知道,startActivityForResult
方法會轉到mInstrumentation.execStartActivity
方法中,而這裏獲取AMS服務的過程就用到了Binder機制:
//mInstrumentation.execStartActivity int result = ActivityManager.getService() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, requestCode, 0, null, options); checkStartActivityResult(result, intent); 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; } };
主要看這一句:ServiceManager.getService(Context.ACTIVITY_SERVICE)
這不就是ServiceManager
嗎,按照咱們以前理解的那樣,這裏傳入了一個name——Context.ACTIVITY_SERVICE
,而後就能獲取到對應服務的代理類,也就是IBinder對象,這裏也就是對應的AMS的代理對象——IActivityManager
。
而後就能夠對AMS進行一系列操做了。
這裏的AMS服務其實對應的服務端,而咱們調用的一方也就是APP自己的進程,就做爲客戶端。
剩下的問題就是,AMS是何時註冊到ServiceManager
的呢?答案在SystemServer
中,以前的文章中說過,AMS的啓動是在SystemServer
中完成的,其實啓動的同時也完成了在ServiceManager
中的註冊,這裏貼下AMS的啓動和註冊服務代碼,不熟悉的朋友能夠翻翻SystemServer
的源碼或者我以前的文章。
//SystemServer.java private void startBootstrapServices() { //... //啓動AMS mActivityManagerService = mSystemServiceManager.startService( ActivityManagerService.Lifecycle.class).getService(); mActivityManagerService.setSystemServiceManager(mSystemServiceManager); mActivityManagerService.setInstaller(installer); //爲系統進程設置應用程序實例並啓動。 mActivityManagerService.setSystemProcess(); } public void setSystemProcess() { try { ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ true, DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO); } }
到此,完整的Binder流程
也介紹完了,再補一張Binder機制
的流程圖:
因此Binder
究竟是什麼呢?我想你內心已經有了答案,這裏借用《Android開發藝術探索》書中的內容總結下,但願你們好好回味下~
直觀的說,Binder是一個類,實現了IBinder接口。 從IPC(進程間通訊)角度來講,Binder是Android中一種跨進程通訊方式。 還能夠理解爲一種虛擬的物理設備,它的設備驅動是/dev/binder。 從Android FrameWork角度來講,Binder是ServiceManager鏈接各類Manager(ActivityManager,WindowManager等等)和響應ManagerService的橋樑。 從Android應用層來講,Binder是客戶端和服務端進行通訊的媒介。
《Android開發藝術探索》
Binder學習指南
Android進程間通訊(IPC)機制Binder簡要介紹和學習計劃
Android系統的Binder機制之一——Service Manager
有一塊兒學習的小夥伴能夠關注下❤️ 個人公衆號——碼上積木,天天剖析一個知識點,咱們一塊兒積累知識,造成完總體系架構。公衆號回覆111可得到面試題《思考與解答》以往期刊。