<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                [TOC] 官方文檔:[https://developer.android.com/guide/components/bound-services?hl=zh-cn](https://developer.android.com/guide/components/bound-services?hl=zh-cn) [https://developer.android.com/guide/components/aidl?hl=zh-cn](https://developer.android.com/guide/components/aidl?hl=zh-cn) 本文部分轉載自:[Binder學習指南--weishu](http://weishu.me/2016/01/12/binder-index-for-newer/) Binder 是 Android 中非常重要的機制,本篇文章從 AIDL 入手分析 Binder 的原理,主要是進行宏觀上的理解,暫不糾結細節及底層源碼。 # 基礎知識 本文部分轉載自:[Binder學習指南--weishu](http://weishu.me/2016/01/12/binder-index-for-newer/) ## 進程隔離 > 進程隔離是為保護操作系統中進程互不干擾而設計的一組不同硬件和軟件的技術。這個技術是為了避免進程A寫入進程B的情況發生。 進程的隔離實現,使用了虛擬地址空間。進程A的虛擬地址和進程B的虛擬地址不同,這樣就防止進程A將數據信息寫入進程B。 > 操作系統的不同進程之間,數據不共享;對于每個進程來說,它都天真地以為自己獨享了整個系統,完全不知道其他進程的存在;(有關虛擬地址,請自行查閱)因此一個進程需要與另外一個進程通信,需要某種系統機制才能完成。 ## 用戶空間/內核空間 > Linux Kernel是操作系統的核心,獨立于普通的應用程序,可以訪問受保護的內存空間,也有訪問底層硬件設備的所有權限。 > 對于Kernel這么一個高安全級別的東西,顯然是不容許其它的應用程序隨便調用或訪問的,所以需要對Kernel提供一定的保護機制,這個保護機制用來告訴那些應用程序,你只可以訪問某些許可的資源,不許可的資源是拒絕被訪問的,于是就把Kernel和上層的應用程序抽像的隔離開,分別稱之為Kernel Space和User Space。 ## 系統調用/內核態/用戶態 > 雖然從邏輯上抽離出用戶空間和內核空間;但是不可避免的的是,總有那么一些用戶空間需要訪問內核的資源;比如應用程序訪問文件,網絡是很常見的事情,怎么辦呢? > 用戶空間訪問內核空間的唯一方式就是**系統調用**;通過這個統一入口接口,所有的資源訪問都是在內核的控制下執行,以免導致對用戶程序對系統資源的越權訪問,從而保障了系統的安全和穩定。用戶軟件良莠不齊,要是它們亂搞把系統玩壞了怎么辦?因此對于某些特權操作必須交給安全可靠的內核來執行。 > 當一個任務(進程)執行系統調用而陷入內核代碼中執行時,我們就稱進程處于內核運行態(或簡稱為內核態)此時處理器處于特權級最高的(0級)內核代碼中執行。當進程在執行用戶自己的代碼時,則稱其處于用戶運行態(用戶態)。即此時處理器在特權級最低的(3級)用戶代碼中運行。處理器在特權等級高的時候才能執行那些特權CPU指令。 ## 內核模塊/驅動 > 通過系統調用,用戶空間可以訪問內核空間,那么如果一個用戶空間想與另外一個用戶空間進行通信怎么辦呢?很自然想到的是讓操作系統內核添加支持;傳統的Linux通信機制,比如Socket,管道等都是內核支持的;但是Binder并不是Linux內核的一部分,它是怎么做到訪問內核空間的呢?Linux的動態可加載內核模塊(Loadable Kernel Module,LKM)機制解決了這個問題;模塊是具有獨立功能的程序,它可以被單獨編譯,但不能獨立運行。它在運行時被鏈接到內核作為內核的一部分在內核空間運行。這樣,Android系統可以通過添加一個內核模塊運行在內核空間,用戶進程之間的通過這個模塊作為橋梁,就可以完成通信了。 > 在Android系統中,這個運行在內核空間的,負責各個用戶進程通過Binder通信的內核模塊叫做**Binder驅動**。 > 驅動就是操作硬件的接口,為了支持Binder通信過程,Binder使用了一種“硬件”,因此這個模塊被稱之為驅動。 ## 為什么使用Binder? Android使用的Linux內核擁有著非常多的跨進程通信機制,比如管道,System V,Socket等;為什么還需要單獨搞一個Binder出來呢?主要有兩點,性能和安全。在移動設備上,廣泛地使用跨進程通信肯定對通信機制本身提出了嚴格的要求;Binder相對出傳統的Socket方式,更加高效;另外,傳統的進程通信方式對于通信雙方的身份并沒有做出嚴格的驗證,只有在上層協議上進行架設;比如Socket通信ip地址是客戶端手動填入的,都可以進行偽造;而Binder機制從協議本身就支持對通信雙方做身份校檢,因而大大提升了安全性。這個也是Android權限模型的基礎。 # Binder通信模型 > 對于跨進程通信的雙方,我們姑且叫做Server進程(簡稱Server),Client進程(簡稱Client);由于進程隔離的存在,它們之間沒辦法通過簡單的方式進行通信,那么Binder機制是如何進行的呢? > 回想一下日常生活中我們通信的過程:假設A和B要進行通信,通信的媒介是打電話(A是Client,B是Server);A要給B打電話,必須知道B的號碼,這個號碼怎么獲取呢? > 先查閱通信錄,拿到B的號碼;才能進行通信;否則,怎么知道應該撥什么號碼?回想一下古老的電話機,如果A要給B打電話,必須先連接通話中心,說明給我接通B的電話;這時候通話中心幫他呼叫B;連接建立,就完成了通信。 > 另外,光有電話和通信錄是不可能完成通信的,沒有基站支持;信息根本無法傳達。 > 我們看到,一次電話通信的過程除了通信的雙方還有兩個隱藏角色:通信錄和基站。Binder通信機制也是一樣:兩個運行在用戶空間的進程要完成通信,必須借助內核的幫助,這個運行在內核里面的程序叫做**Binder驅動**,它的功能類似于基站;通信錄呢,就是一個叫做**ServiceManager**的東西(簡稱SM) > OK,Binder的通信模型就是這么簡單,如下圖: [![](http://weishu.dimensionalzone.com/binder-model.png)](http://weishu.dimensionalzone.com/binder-model.png) > 整個通信步驟如下: > 1. SM建立(建立通信錄);首先有一個進程向驅動提出申請為SM;驅動同意之后,SM進程負責管理Service(注意這里是Service而不是Server,因為如果通信過程反過來的話,那么原來的客戶端Client也會成為服務端Server)不過這時候通信錄還是空的,一個號碼都沒有。 > 2. 各個Server向SM注冊(完善通信錄);每個Server端進程啟動之后,向SM報告,我是zhangsan, 要找我請返回0x1234(這個地址沒有實際意義,類比);其他Server進程依次如此;這樣SM就建立了一張表,對應著各個Server的名字和地址;就好比B與A見面了,說存個我的號碼吧,以后找我撥打10086; > 3. Client想要與Server通信,首先詢問SM;請告訴我如何聯系zhangsan,SM收到后給他一個號碼0x1234;Client收到之后,開心滴用這個號碼撥通了Server的電話,于是就開始通信了。 > 那么Binder驅動干什么去了呢?這里Client與SM的通信,以及Client與Server的通信,都會經過驅動,驅動在背后默默無聞,但是做著最重要的工作。驅動是整個通信過程的核心,因此完成跨進程通信的秘密全部隱藏在驅動里面;這個我們稍后討論。 > OK,上面就是整個Binder通信的基本模型;做了一個簡單的類比,當然也有一些不恰當的地方,(比如通信錄現實中每個人都有一個,但是SM整個系統只有一個;基站也有很多個,但是驅動只有一個);但是整體上就是這樣的;我們看到其實整個通信模型非常簡單。 # Binder機制跨進程原理 > 上文給出了Binder的通信模型,指出了通信過程的四個角色: Client, Server, SM, driver; 但是我們仍然不清楚**Client到底是如何與Server完成通信的**。 > 兩個運行在用戶空間的進程A和進程B如何完成通信呢?內核可以訪問A和B的所有數據;所以,最簡單的方式是通過內核做中轉;假設進程A要給進程B發送數據,那么就先把A的數據copy到內核空間,然后把內核空間對應的數據copy到B就完成了;用戶空間要操作內核空間,需要通過系統調用;剛好,這里就有兩個系統調用:`copy_from_user`,`copy_to_user`。 > 但是,Binder機制并不是這么干的。講這么一段,是說明進程間通信并不是什么神秘的東西。那么,Binder機制是如何實現跨進程通信的呢? > Binder驅動為我們做了一切。 > 假設Client進程想要調用Server進程的`object`對象的一個方法`add`;對于這個跨進程通信過程,我們來看看Binder機制是如何做的。 (通信是一個廣泛的概念,只要一個進程能調用另外一個進程里面某對象的方法,那么具體要完成什么通信內容就很容易了。) [![Alt text](http://weishu1.dimensionalzone.com/2016binder-procedure.png)](http://weishu1.dimensionalzone.com/2016binder-procedure.png "Alt text") > 首先,Server進程要向SM注冊;告訴自己是誰,自己有什么能力;在這個場景就是Server告訴SM,它叫`zhangsan`,它有一個`object`對象,可以執行`add`操作;于是SM建立了一張表:`zhangsan`這個名字對應進程Server; > 然后Client向SM查詢:我需要聯系一個名字叫做`zhangsan`的進程里面的`object`對象;這時候關鍵來了:進程之間通信的數據都會經過運行在內核空間里面的驅動,驅動在數據流過的時候做了一點手腳,它并不會給Client進程返回一個真正的`object`對象,而是返回一個看起來跟`object`一模一樣的代理對象`objectProxy`,這個`objectProxy`也有一個`add`方法,但是這個`add`方法沒有Server進程里面`object`對象的`add`方法那個能力;`objectProxy`的`add`只是一個傀儡,它唯一做的事情就是把參數包裝然后交給驅動。(這里我們簡化了SM的流程,見下文) > 但是Client進程并不知道驅動返回給它的對象動過手腳,畢竟偽裝的太像了,如假包換。Client開開心心地拿著`objectProxy`對象然后調用`add`方法;我們說過,這個`add`什么也不做,直接把參數做一些包裝然后直接轉發給Binder驅動。 > 驅動收到這個消息,發現是這個`objectProxy`;一查表就明白了:我之前用`objectProxy`替換了`object`發送給Client了,它真正應該要訪問的是`object`對象的`add`方法;于是Binder驅動通知Server進程,*調用你的object對象的`add`方法,然后把結果發給我*,Sever進程收到這個消息,照做之后將結果返回驅動,驅動然后把結果返回給`Client`進程;于是整個過程就完成了。 > 由于驅動返回的`objectProxy`與Server進程里面原始的`object`是如此相似,給人感覺好像是**直接把Server進程里面的對象object傳遞到了Client進程**;因此,我們可以說**Binder對象是可以進行跨進程傳遞的對象** > 但事實上我們知道,Binder跨進程傳輸并不是真的把一個對象傳輸到了另外一個進程;傳輸過程好像是Binder跨進程穿越的時候,它在一個進程留下了一個真身,在另外一個進程幻化出一個影子(這個影子可以很多個);Client進程的操作其實是對于影子的操作,影子利用Binder驅動最終讓真身完成操作。 > 理解這一點非常重要;務必仔細體會。另外,Android系統實現這種機制使用的是*代理模式*, 對于Binder的訪問,如果是在同一個進程(不需要跨進程),那么直接返回原始的Binder實體;如果在不同進程,那么就給他一個代理對象(影子);我們在系統源碼以及AIDL的生成代碼里面可以看到很多這種實現。 > 另外我們為了簡化整個流程,隱藏了SM這一部分驅動進行的操作;實際上,由于SM與Server通常不在一個進程,Server進程向SM注冊的過程也是跨進程通信,驅動也會對這個過程進行暗箱操作:SM中存在的Server端的對象實際上也是代理對象,后面Client向SM查詢的時候,驅動會給Client返回另外一個代理對象。Sever進程的本地對象僅有一個,其他進程所擁有的全部都是它的代理。 > 一句話總結就是:**Client進程只不過是持有了Server端的代理;代理對象協助驅動完成了跨進程通信。** 總結: * 一個進程向驅動申請為 ServiceManager,來管理 Service * 各個 Server 依次向 ServiceManager 進行注冊 * Client 想同 Server 通信,向 ServiceManager 請求 * ServiceManager 返回給 Client 的是 Server 的代理對象 * Client 調用代理對象的方法,傳給 ServiceManager * ServiceManager 通知 Server,拿到 Server 的返回值交給 Client # Binder到底是什么? > 我們經常提到Binder,那么Binder到底是什么呢? > Binder的設計采用了面向對象的思想,在Binder通信模型的四個角色里面;他們的代表都是“Binder”,這樣,對于Binder通信的使用者而言,Server里面的Binder和Client里面的Binder沒有什么不同,一個Binder對象就代表了所有,它不用關心實現的細節,甚至不用關心驅動以及SM的存在;這就是抽象。 > * 通常意義下,Binder指的是一種通信機制;我們說AIDL使用Binder進行通信,指的就是**Binder這種IPC機制**。 > * 對于Server進程來說,Binder指的是**Binder本地對象** > * 對于Client來說,Binder指的是**Binder代理對象**,它只是**Binder本地對象**的一個遠程代理;對這個Binder代理對象的操作,會通過驅動最終轉發到Binder本地對象上去完成;對于一個擁有Binder對象的使用者而言,它無須關心這是一個Binder代理對象還是Binder本地對象;對于代理對象的操作和對本地對象的操作對它來說沒有區別。 > * 對于傳輸過程而言,Binder是可以進行跨進程傳遞的對象;Binder驅動會對具有跨進程傳遞能力的對象做特殊處理:自動完成代理對象和本地對象的轉換。 > 面向對象思想的引入將進程間通信轉化為通過對某個Binder對象的引用調用該對象的方法,而其獨特之處在于Binder對象是一個可以跨進程引用的對象,它的實體(本地對象)位于一個進程中,而它的引用(代理對象)卻遍布于系統的各個進程之中。最誘人的是,這個引用和java里引用一樣既可以是強類型,也可以是弱類型,而且可以從一個進程傳給其它進程,讓大家都能訪問同一Server,就象將一個對象或引用賦值給另一個引用一樣。Binder模糊了進程邊界,淡化了進程間通信過程,整個系統仿佛運行于同一個面向對象的程序之中。形形色色的Binder對象以及星羅棋布的引用仿佛粘接各個應用程序的膠水,這也是Binder在英文里的原意。 > 我們現在知道,Server進程里面的Binder對象指的是Binder本地對象,Client里面的對象值得是Binder代理對象;在Binder對象進行跨進程傳遞的時候,Binder驅動會自動完成這兩種類型的轉換;因此Binder驅動必然保存了每一個跨越進程的Binder對象的相關信息;在驅動中,Binder本地對象的代表是一個叫做`binder_node`的數據結構,Binder代理對象是用`binder_ref`代表的;有的地方把Binder本地對象直接稱作Binder實體,把Binder代理對象直接稱作Binder引用(句柄),其實指的是Binder對象在驅動里面的表現形式;讀者明白意思即可。 > OK,現在大致了解Binder的通信模型,也了解了Binder這個對象在通信過程中各個組件里面到底表示的是什么。 # 理解Java層的Binder > 我們使用AIDL接口的時候,經常會接觸到這些類,那么這每個類代表的是什么呢? > * IBinder是一個接口,它代表了**一種跨進程傳輸的能力**;只要實現了這個接口,就能將這個對象進行跨進程傳遞;這是驅動底層支持的;在跨進程數據流經驅動的時候,驅動會識別IBinder類型的數據,從而自動完成不同進程Binder本地對象以及Binder代理對象的轉換。 > * IBinder負責數據傳輸,那么client與server端的調用契約(這里不用接口避免混淆)呢?這里的IInterface代表的就是遠程server對象具有什么能力。具體來說,就是aidl里面的接口。 > * Java層的Binder類,代表的其實就是**Binder本地對象**。BinderProxy類是Binder類的一個內部類,它代表遠程進程的Binder對象的本地代理;這兩個類都繼承自IBinder, 因而都具有跨進程傳輸的能力;實際上,在跨越進程的時候,Binder驅動會自動完成這兩個對象的轉換。 > * 在使用AIDL的時候,編譯工具會給我們生成一個Stub的靜態內部類;這個類繼承了Binder, 說明它是一個Binder本地對象,它實現了IInterface接口,表明它具有遠程Server承諾給Client的能力;Stub是一個抽象類,具體的IInterface的相關實現需要我們手動完成,這里使用了策略模式。 # AIDL 分析(Android 接口定義語言) ## IBinder IBinder 是一個接口,代表一種跨進程傳輸的能力,實現了這個接口的對象就可以擁有跨進程傳輸能力 ## IInterface 在定義 Server 所具有能力的接口(具體就是 aidl 里面的接口)時,需繼承自 IInterface,IInterface接口定義如下: ```java public interface IInterface { public IBinder asBinder(); } ``` ## demo **1、定義 AIDL 接口** ![](https://img.kancloud.cn/f8/8a/f88a3b7f9e271a5cc81a0de48fc6f5af_300x318.png) ```java // ICompute.aidl package com.markxu.aidltest; // Declare any non-default types here with import statements interface ICompute { int add(int a, int b); } ``` **2、系統自動生成ICompute類** 編譯后,在 app/build/generated/aidl_source_output_dir/ 目錄下,系統會自動為我們生成 ICompute.java 類,源碼如下: ```java // ICompute.java public interface ICompute extends android.os.IInterface { /** * Default implementation for ICompute. */ public static class Default implements com.markxu.aidltest.ICompute { @Override public int add(int a, int b) throws android.os.RemoteException { return 0; } @Override public android.os.IBinder asBinder() { return null; } } /** * Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.markxu.aidltest.ICompute { private static final java.lang.String DESCRIPTOR = "com.markxu.aidltest.ICompute"; /** * Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.markxu.aidltest.ICompute interface, * generating a proxy if needed. */ public static com.markxu.aidltest.ICompute asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.markxu.aidltest.ICompute))) { return ((com.markxu.aidltest.ICompute) iin); } return new com.markxu.aidltest.ICompute.Stub.Proxy(obj); } @Override public android.os.IBinder asBinder() { return this; } @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_add: { data.enforceInterface(descriptor); int _arg0; _arg0 = data.readInt(); int _arg1; _arg1 = data.readInt(); int _result = this.add(_arg0, _arg1); reply.writeNoException(); reply.writeInt(_result); return true; } default: { return super.onTransact(code, data, reply, flags); } } } private static class Proxy implements com.markxu.aidltest.ICompute { 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; } @Override public int add(int a, int b) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(a); _data.writeInt(b); boolean _status = mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().add(a, b); } _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } public static com.markxu.aidltest.ICompute sDefaultImpl; } static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); public static boolean setDefaultImpl(com.markxu.aidltest.ICompute impl) { if (Stub.Proxy.sDefaultImpl == null && impl != null) { Stub.Proxy.sDefaultImpl = impl; return true; } return false; } public static com.markxu.aidltest.ICompute getDefaultImpl() { return Stub.Proxy.sDefaultImpl; } } public int add(int a, int b) throws android.os.RemoteException; } ``` **3、Server端代碼:** ```java public class AIDLService extends Service { private ICompute.Stub mCompute = new ICompute.Stub() { @Override public int add(int a, int b) throws RemoteException { return a + b; } }; public AIDLService() { } @Override public IBinder onBind(Intent intent) { return mCompute; } } ``` **4、Client端代碼:** ```java findViewById(R.id.cl_main).setOnClickListener(new View.OnClickListener() { private ICompute mICompute; @Override public void onClick(View v) { Intent intent = new Intent(MainActivity.this, AIDLService.class); bindService(intent, new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mICompute = ICompute.Stub.asInterface(service); try { int value = mICompute.add(1, 99); Toast.makeText(MainActivity.this, String.valueOf(value), Toast.LENGTH_SHORT).show(); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { } }, BIND_AUTO_CREATE); } }); ``` **5、總結** * 在Server的onBind方法中,直接返回Stub對象即可 * Stub類繼承自Binder,說明Stub是一個Binder本地對象;Stub類實現ICompute接口,說明Stub攜帶某種Client需要的的能力(方法add) * 在Client的onServiceConnected回調中,調用Stub類的asInterface獲取到遠程Server ## 源碼分析 將ICompute的代碼精簡下: ```java public interface ICompute extends android.os.IInterface { /** * Default implementation for ICompute. */ public static class Default implements com.markxu.aidltest.ICompute { //... } /** * Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.markxu.aidltest.ICompute { //... } public int add(int a, int b) throws android.os.RemoteException; } ``` ICompute是一個接口,繼承自IInterface,描述了遠程Server所擁有的功能。ICompute內包含了 * Default類:一個內部靜態類,也就是ICompute的默認實現類 * Stub類:一個靜態抽象類,繼承自Binder,實現ICompute接口 * add方法:一個接口方法 可以理解為ICompute是一個接口,聲明了Server具有的能力add方法;Stub類和Default類都是靜態內部類,可以理解為恰巧聲明在了ICompute內部,和ICompute關系不大。 **1、Stub類** Stub類的代碼如下: ```java // ICompute.java public static abstract class Stub extends android.os.Binder implements com.markxu.aidltest.ICompute { private static final java.lang.String DESCRIPTOR = "com.markxu.aidltest.ICompute"; /** * Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.markxu.aidltest.ICompute interface, * generating a proxy if needed. */ public static com.markxu.aidltest.ICompute asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.markxu.aidltest.ICompute))) { return ((com.markxu.aidltest.ICompute) iin); } return new com.markxu.aidltest.ICompute.Stub.Proxy(obj); } @Override public android.os.IBinder asBinder() { return this; } @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_add: { data.enforceInterface(descriptor); int _arg0; _arg0 = data.readInt(); int _arg1; _arg1 = data.readInt(); int _result = this.add(_arg0, _arg1); reply.writeNoException(); reply.writeInt(_result); return true; } default: { return super.onTransact(code, data, reply, flags); } } } private static class Proxy implements com.markxu.aidltest.ICompute { //... } static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); public static boolean setDefaultImpl(com.markxu.aidltest.ICompute impl) { if (Stub.Proxy.sDefaultImpl == null && impl != null) { Stub.Proxy.sDefaultImpl = impl; return true; } return false; } public static com.markxu.aidltest.ICompute getDefaultImpl() { return Stub.Proxy.sDefaultImpl; } } ``` 首先將代碼精簡下: ```java public static abstract class Stub extends android.os.Binder implements com.markxu.aidltest.ICompute { // Binder 類的唯一標識 private static final java.lang.String DESCRIPTOR = "com.markxu.aidltest.ICompute"; public Stub() { this.attachInterface(this, DESCRIPTOR); } // 通過這個方法,Client 可以拿到遠程的 Server 對象 public static com.markxu.aidltest.ICompute asInterface(android.os.IBinder obj) { //... } // 返回當前 Binder 對象 @Override public android.os.IBinder asBinder() { return this; } // 處理 Client 傳遞來的方法,下面詳細分析 @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { //... } // Binder代理對象 private static class Proxy implements com.markxu.aidltest.ICompute { //... } static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); public static boolean setDefaultImpl(com.markxu.aidltest.ICompute impl) { //... } public static com.markxu.aidltest.ICompute getDefaultImpl() { return Stub.Proxy.sDefaultImpl; } } ``` 1、asInterface方法:通過此方法,Client可以拿到Server對象。 ```java // ICompute.java#Stub public static com.markxu.aidltest.ICompute asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } // 查找是否為本地對象 android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.markxu.aidltest.ICompute))) { // 說明 Client 和 Server 在一個進程 // 返回 Server 的 Binder 本地對象 Stub return ((com.markxu.aidltest.ICompute) iin); } // 不在一個進程,new 一個遠程代理對象 return new com.markxu.aidltest.ICompute.Stub.Proxy(obj); } ``` 參數obj對象是驅動給我們的,當obj 為 Binder 時,queryLocalInterface方法源碼如下: ```java // Binder.java public IInterface queryLocalInterface(String descriptor) { if (mDescriptor.equals(descriptor)) { return mOwner; } return null; } ``` 當obj 為 BinderProxy 時,queryLocalInterface方法源碼如下: ```java // BinderProxy.java public IInterface queryLocalInterface(String descriptor) { return null; } ``` 所以,asInterface方法會嘗試在obj中查找Binder本地對象,如果找到說明Client和Server在同一個進程,參數直接就是本地對象,直接類型轉換并返回;如果找不到說明obj是BinderProxy,也就是說Client和Server不在同一個進程。 2、Stub 的 onTransact 方法運行在 Server 的 Binder 線程池中,展開看下: * 通過 code 確定 Client 所請求的目標方法 * 然后從 data 中取出目標方法所需的參數 * 執行目標方法 * 向 reply 中寫入返回值 * 返回 false 時,客戶端請求失敗 ```java @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; // 通過 code 確定 Client 所請求的目標方法 switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(descriptor); return true; } case TRANSACTION_add: { data.enforceInterface(descriptor); // 從 data 中取出目標方法所需的參數 int _arg0; _arg0 = data.readInt(); int _arg1; _arg1 = data.readInt(); // 執行目標方法 int _result = this.add(_arg0, _arg1); reply.writeNoException(); // 向 reply 中寫入返回值 reply.writeInt(_result); return true; } default: { return super.onTransact(code, data, reply, flags); } } } ``` **2、Proxy類** 接下來看看 Binder 代理對象 Proxy 類,ServiceManager 和 Client 拿到的都是 Binder 代理對象,通過調用代理對象的方法,經過 Binder driver 的轉換后最終調用到 Binder 本地對象的方法。 ```java // ICompute.java#Proxy private static class Proxy implements com.markxu.aidltest.ICompute { 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; } @Override public int add(int a, int b) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(a); _data.writeInt(b); boolean _status = mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().add(a, b); } _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } public static com.markxu.aidltest.ICompute sDefaultImpl; } ``` 下面看看 Binder 代理對于方法的處理,以 add()方法為例: * 首先用 Parcel 把數據序列化 * 傳遞給 Binder driver,Binder driver 再傳遞給 Server * Server 執行方法并返回結果 ```java @Override public int add(int a, int b) throws android.os.RemoteException { // 用 Parcel 把數據序列化 android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(a); _data.writeInt(b); // 此處發起調用請求,當前線程掛起,Server 端的 onTransact 方法會被調用 // 傳遞給 Binder driver 處理 // 此處的 mRemote 為 Binder Proxy boolean _status = mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().add(a, b); } // 遠程調用結束,從 _reply 讀取返回結果 _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } // 返回結果 return _result; } ``` 看看 Binder Proxy 的 transact 方法: ```java // BinderProxy.java public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { Binder.checkParcel(this, code, data, "Unreasonably large binder buffer"); if (Binder.isTracingEnabled()) { Binder.getTransactionTracker().addTrace(); } return transactNative(code, data, reply, flags); } ``` 調用了 transactNative 方法,在此,Client 將方法傳遞給了 Binder driver。 ```java // BinderProxy.java public native boolean transactNative(int code, Parcel data, Parcel reply, int flags) throws RemoteException; ``` ## 總結 ### Binder總結 * 從IPC角度來說,Binder是Android中的一種跨進程通信方式;Binder還可以理解為一種虛擬的物理設備,它的設備驅動是/dev/binder,該通信方式在Linux中沒有 * 從Android Framework角度來說,Binder是ServiceManager連接各種Manager(ActivityManager、WindowManager等)和相應ManagerService的橋梁 * 從Android應用層來說,Binder是客戶端和服務端進行通信的媒介,當bindService時,**服務端會返回一個包含了服務端業務調用的Binder對象**,通過這個Binder對象,客戶端就可以獲取服務端提供的服務或數據,這里的服務包括普通服務和基于AIDL的服務。 ### AIDL總結 1、IBinder是一個接口,代表一種跨進程傳輸的能力,由系統驅動提供支持 2、IInterface也是一個接口,代表遠程Server可以轉化為Binder對象(asBinder方法)。ICompute繼承自IInterface,聲明了遠程Server新增的能力(add方法) 3、編寫AIDL文件聲明遠程Server的接口后,系統會自動生成ICompute接口及Stub類和Proxy類。 4、Stub類繼承自Binder,因此具有跨進程傳輸的能力;實現了ICompute接口,因此擁有遠程Server的能力 5、在Server的onBind方法中,創建一個Stub對象并返回,可以跨進程傳輸,且擁有Server的能力。創建Stub對象時,將Binder的所有者mOwner設置為Stub對象 6、在Client的回調中,拿到IBinder對象。 * 當Client與Server在同一個進程時,IBinder是Binder對象,通過asInterface方法直接拿到mOwner強轉為遠程Server對象,接下來Client可以直接調用Server的方法。 * 當Client與Server不在同一個進程時,IBinder是BinderProxy對象,此時通過asInterface拿不到mOwner,需根據BinderProxy對象創建一個Proxy對象,并返回給Client。Proxy對象可以理解為遠程Server對象的代理。 * 當Client調用Proxy對象的方法(代表Server能力的方法)時,首先將參數Parcel序列化,再傳遞給底層Binder驅動層,Binder驅動層傳遞給Server,Server執行方法后返回結果給Client。 > 備注 在[【專題分析】Service](http://www.androidwiki.site/1657723)一文中,綁定Service使用的也是Binder機制,只不過是默認當前Activity和Service在同一個進程,不涉及進程間通信,所以在拿到IBinder對象后,直接強轉為遠程Server。 ## 實際應用 Android中Window的添加、移除、更新都有使用到AIDL。 在[Window的添加](http://www.androidwiki.site/1640753)源碼分析時,最終是通過ViewRootImplk更新界面,完成Window的添加: ```java // ViewRootImpl.java public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { // ... mView = view; requestLayout(); res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame, mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel, mTempInsets); // ... } ``` 其中mWindowSession的類型是IWindowSession,mWindowSession是一個Binder代理對象,addToDisplay是一個跨進程調用: ```plain // IWindowSession.aidl interface IWindowSession { int add(IWindow window, int seq, in WindowManager.LayoutParams attrs, in int viewVisibility, out Rect outContentInsets, out Rect outStableInsets, out InputChannel outInputChannel); int addToDisplay(IWindow window, int seq, in WindowManager.LayoutParams attrs, in int viewVisibility, in int layerStackId, out Rect outFrame, out Rect outContentInsets, out Rect outStableInsets, out Rect outOutsets, out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel); int addWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs, in int viewVisibility, out Rect outContentInsets, out Rect outStableInsets); int addToDisplayWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs, in int viewVisibility, in int layerStackId, out Rect outContentInsets, out Rect outStableInsets); void remove(IWindow window); } ``` ```java // Session.java // 文件所在目錄: frameworks/base/services/core/java/com/android/server/wm/Session.java public class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { //... @Override public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) { return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outContentInsets, outStableInsets, outOutsets, outInputChannel); } } ``` ```java // WindowManagerService.java public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs { //... public int addWindow(Session session, IWindow client, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) { //... } } ``` # 參考文檔 [Binder 學習指南 -- Weishu](http://weishu.me/2016/01/12/binder-index-for-newer/) [Android 開發藝術探索 -- 任玉剛](http://www.google.com) [可能是講解 Binder 機制最好的文章](https://juejin.im/entry/5786afbb8ac2470060665499)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看