日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

从Android源码的角度分析Binder机制

發(fā)布時(shí)間:2023/12/19 Android 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从Android源码的角度分析Binder机制 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.




IPC

為了弄懂IPC的來(lái)龍去脈,我將從以下三個(gè)方面為大家來(lái)講解,希望對(duì)大家理解IPC會(huì)有幫助

什么是IPC

IPC是Inter Process Communication的縮寫(xiě),其意思就是進(jìn)程間的通信,也就是兩個(gè)進(jìn)程之間的通信過(guò)程。我們都知道在Android系統(tǒng)中,每個(gè)應(yīng)用都運(yùn)行在一個(gè)進(jìn)程上,具有自己的DVM實(shí)例,而且進(jìn)程之間是相互隔離的,也就是說(shuō)各個(gè)進(jìn)程之間的數(shù)據(jù)是互相獨(dú)立,互不影響的,而如果一個(gè)進(jìn)程崩潰了,也不會(huì)影響到另一個(gè)進(jìn)程。
采取這樣的設(shè)計(jì)是有一定道理的,例如這樣的前提下將互相不影響的系統(tǒng)功能分拆到不同的進(jìn)程里面去,有助于提升系統(tǒng)的穩(wěn)定性,畢竟我們都不想自己的應(yīng)用進(jìn)程崩潰會(huì)導(dǎo)致整個(gè)手機(jī)系統(tǒng)的崩潰。
進(jìn)程之間隔離是不錯(cuò)的選擇,可是如果進(jìn)程之間想要互相通信,進(jìn)行數(shù)據(jù)交互的時(shí)候那該怎么辦呢?例如我們?cè)谧约旱膽?yīng)用中想要訪問(wèn)手機(jī)通訊錄中的聯(lián)系人,很顯然這是兩個(gè)不同的進(jìn)程,如果Android沒(méi)有提供一種進(jìn)程之間交流的機(jī)制,那么這種功能將無(wú)法實(shí)現(xiàn)。
不過(guò)由于Android系統(tǒng)使用的是Linux內(nèi)核,而在Linux系統(tǒng)中進(jìn)程之間的交互是有一套機(jī)制的,所以Android也借鑒了其中的一些機(jī)制,從而形成了Android的IPC機(jī)制。
上面只是粗略的講解了IPC是啥,關(guān)于它的使用和原理我將一一為大家呈上。

為什么要用IPC

上一點(diǎn)中我舉了訪問(wèn)手機(jī)通訊錄的例子。但你可能覺(jué)得我不需要用到這種功能,那么我就不用管IPC啦!其實(shí)不然,IPC在我們的應(yīng)用開(kāi)發(fā)過(guò)程中隨處可見(jiàn),下面我將舉一個(gè)例子來(lái)說(shuō)明他的重要性。
我們?cè)贛ainActivity中修改一個(gè)靜態(tài)變量,接著在另一個(gè)進(jìn)程的SecondActivity中去訪問(wèn)該變量,看看能否讀取已經(jīng)修改過(guò)的變量。

1、新建一個(gè)Student類(lèi),并聲明一個(gè)靜態(tài)變量

public?class?Student?{????public?static?String?name="BOB"; }

2、在MainActivity的onCreate方法中修改name的值,并打印log

@Overrideprotected?void?onCreate(Bundle?savedInstanceState)?{????super.onCreate(savedInstanceState);????setContentView(R.layout.activity_main);Student.name?=?"JACK";Log.d("MainActivity:Sname=",?Student.name); }

3、將SecondActivity設(shè)置為新進(jìn)程,并在其onCreate方法中訪問(wèn)name

<!--?在清單文件中通過(guò)android:process屬性為SecondActivity指定特定的進(jìn)程:com.bob.aidltest:second?--><activity?????android:name=".SecondActivity"????android:process=":second"></activity> public?class?SecondActivity?extends?AppCompatActivity?{????@Overrideprotected?void?onCreate(@Nullable?Bundle?savedInstanceState)?{????????super.onCreate(savedInstanceState);????????setContentView(R.layout.second_activity);Log.d("SecondActivity:Sname="?,?Student.name);} }

4、通過(guò)log,可以看到在MainActivity中修改了name的值,但是在SecondActivity中卻無(wú)法讀取修改后的值

通過(guò)以上的實(shí)驗(yàn),大家應(yīng)該明白了一點(diǎn):在不同的進(jìn)程之間訪問(wèn)同一個(gè)靜態(tài)變量是行不通的。其原因是:每一個(gè)進(jìn)程都分配有一個(gè)獨(dú)立的虛擬機(jī),不同的虛擬機(jī)在內(nèi)存分配上有不同的地址空間,這就導(dǎo)致在不同的虛擬機(jī)上訪問(wèn)同一個(gè)對(duì)象會(huì)產(chǎn)生多個(gè)副本。例如我們?cè)贛ainActivity中訪問(wèn)的name的值只會(huì)影響當(dāng)前進(jìn)程,而對(duì)其他進(jìn)程不會(huì)造成影響,所以在SecondActivity中訪問(wèn)name時(shí)依舊只能訪問(wèn)自己進(jìn)程中的副本。

Android中解決IPC的方法

上面也講到,為了解決這些跨進(jìn)程的問(wèn)題,Android沿用了一些Linux的進(jìn)程管理機(jī)制,使得進(jìn)程之間能夠進(jìn)行交互,下面我將列出一些常見(jiàn)的IPC方式,需要指出的是本文主要講解Binder機(jī)制,所以會(huì)注重講解AIDL,其他方式請(qǐng)讀者自行查閱相關(guān)資料。

名稱(chēng)特點(diǎn)使用場(chǎng)景
Bundle只能傳輸實(shí)現(xiàn)了Serializable或者Parcelable接口或者一些Android支持的特殊對(duì)象適合用于四大組件之間的進(jìn)程交互
文件不能做到進(jìn)程間的即時(shí)通信,并且不適合用于高并發(fā)的場(chǎng)景適合用于SharedPreference以及IO操作
ContentProvider可以訪問(wèn)較多的數(shù)據(jù),支持一對(duì)多的高并發(fā)訪問(wèn),因?yàn)镃ontentProvider已經(jīng)自動(dòng)做好了關(guān)于并發(fā)的機(jī)制適合用于一對(duì)多的數(shù)據(jù)共享并且需要對(duì)數(shù)據(jù)進(jìn)行頻繁的CRUD操作
Socket通過(guò)網(wǎng)絡(luò)傳輸字節(jié)流,支持一對(duì)多的實(shí)時(shí)通信,但是實(shí)現(xiàn)起來(lái)比較復(fù)雜適合用于網(wǎng)絡(luò)數(shù)據(jù)共享
Messenger底層原理是AIDL,只是對(duì)其做了封裝,但是不能很好的處理高并發(fā)的場(chǎng)景,并且傳輸?shù)臄?shù)據(jù)只能支持Bundle類(lèi)型低并發(fā)的一對(duì)多的即時(shí)通信
AIDL功能強(qiáng)大,使用Binder機(jī)制(接下來(lái)會(huì)講解),支持一對(duì)多的高并發(fā)實(shí)時(shí)通信,但是需要處理好線程同步一對(duì)多并且有遠(yuǎn)程進(jìn)程通信的場(chǎng)景

Binder

終于來(lái)到這篇文章的重頭戲了,上面講到Android解決IPC的方法中有一種是AIDL,它使用的原理就是Binder,只有理解了Binder,我們才算是理解了Android跨進(jìn)程通信的原理。在這里我會(huì)帶大家看看Android中有哪一些重要的地方使用到了Binder,接著我們會(huì)通過(guò)一個(gè)實(shí)例來(lái)了解如何使用Binder,最后我們會(huì)分析Binder的源碼來(lái)理解他的工作流程。

Binder在Android中的運(yùn)用

說(shuō)起B(yǎng)inder在Android的使用場(chǎng)景,可以說(shuō)是無(wú)處不在,我列出一些最常見(jiàn)的場(chǎng)景:

  • 四大組件的生命周期都是使用Binder機(jī)制進(jìn)行管理的

  • View的工作原理也使用了Binder

  • WindowManager的工作機(jī)制同樣使用了Binder

以上三個(gè)方面只是最常見(jiàn)的場(chǎng)景,但是卻幾乎包括了我們開(kāi)發(fā)的整個(gè)流程。我們開(kāi)發(fā)的應(yīng)用都離不開(kāi)四大組件,而四大組件也正是依靠Binder機(jī)制運(yùn)行的;對(duì)于我們最常見(jiàn)的View,他是如何顯示的,View又是如何響應(yīng)我們的動(dòng)作的,這其中也用到了Binder(關(guān)于這些內(nèi)容我會(huì)在后續(xù)的文章中為大家分析)??梢哉f(shuō)了解Binder對(duì)于我們的開(kāi)發(fā)是很有幫助的,那接下來(lái)我們就來(lái)看看我們?cè)撊绾问褂肂inder進(jìn)行進(jìn)程間的通信吧!

如何使用Binder

現(xiàn)在我們需要實(shí)現(xiàn)這樣的功能:客戶端與服務(wù)端位于不同的進(jìn)程,客戶端需要向服務(wù)端添加學(xué)生,同時(shí)客戶端還可以向服務(wù)端發(fā)起查詢學(xué)生列表的請(qǐng)求。

1、創(chuàng)建Student.java,Student.aidl,IStudentManager.aidl

  • Student.java

package?com.bob.aidltest.aidl;import?android.os.Parcel;import?android.os.Parcelable;/**?*?Created?by?bob?on?17-7-3.?*?所有需要在Binder傳遞的數(shù)據(jù)類(lèi)型都需要實(shí)現(xiàn)Parcelable接口?*/public?class?Student?implements?Parcelable{????public?static?String?name="BOB";????public?int?s_id;????public?String?s_name;????public?String?s_gender;????public?Student(Parcel?in)?{s_id?=?in.readInt();s_name?=?in.readString();s_gender?=?in.readString();}????public?Student(int?s_id,?String?s_name,?String?s_gender)?{????????this.s_id?=?s_id;????????this.s_name?=?s_name;????????this.s_gender?=?s_gender;}????@Overridepublic?int?describeContents()?{????????return?0;}????@Overridepublic?void?writeToParcel(Parcel?dest,?int?flags)?{dest.writeInt(s_id);dest.writeString(s_name);dest.writeString(s_gender);}????public?static?final?Creator<Student>?CREATOR?=?new?Creator<Student>()?{????????@Overridepublic?Student?createFromParcel(Parcel?in)?{????????????return?new?Student(in);}????????@Overridepublic?Student[]?newArray(int?size)?{????????????return?new?Student[size];}};????@Overridepublic?String?toString()?{????????return?String.format("[StudentID:?%s?,?StudentName:?%s?,?StudentGender:?%s]",?s_id,?s_name,?s_gender);} }
  • Student.aidl

//?Student1.aidlpackage?com.bob.aidltest.aidl;parcelable?Student;
  • IStudentManager.aidl

//?IStudentManager.aidlpackage?com.bob.aidltest.aidl;import?com.bob.aidltest.aidl.Student;interface?IStudentManager?{????List<Student>?getStudentList();????void?addStudent(in?Student?student); }

創(chuàng)建完畢之后手動(dòng)編譯項(xiàng)目(Build-->ReBuild Project),接著就會(huì)在app/build/generated/source/aidl/debug/com/bob/aidltest/aidl/IStudentManager.java中看到自動(dòng)生成的IStudentManager接口,如下圖:

2、分析IStudentManager.java

先來(lái)看看自動(dòng)生成的代碼:

public?interface?IStudentManager?extends?android.os.IInterface{????/**?內(nèi)部類(lèi)Stub,繼承自Binder并且實(shí)現(xiàn)了IStudentManager接口,因此他也是一個(gè)Binder對(duì)象,這個(gè)內(nèi)部類(lèi)是需要在服務(wù)端手動(dòng)實(shí)現(xiàn)的,并且會(huì)通過(guò)onBind方法返回給客戶端?*/public?static?abstract?class?Stub?extends?android.os.Binder?implements?com.bob.aidltest.aidl.IStudentManager{????????private?static?final?java.lang.String?DESCRIPTOR?=?"com.bob.aidltest.aidl.IStudentManager";????????/**?構(gòu)造方法?*/public?Stub(){????????????this.attachInterface(this,?DESCRIPTOR);}????????/**?????????*?將服務(wù)端的Binder對(duì)象轉(zhuǎn)換為客戶端的所需的AIDL接口類(lèi)型的對(duì)象,客戶端拿到這個(gè)對(duì)象就可以通過(guò)這個(gè)對(duì)象遠(yuǎn)程訪問(wèn)服務(wù)端的方法?????????*/public?static?com.bob.aidltest.aidl.IStudentManager?asInterface(android.os.IBinder?obj){????????????if?((obj==null))?{????????????????return?null;}android.os.IInterface?iin?=?obj.queryLocalInterface(DESCRIPTOR);????????????if?(((iin!=null)&&(iin?instanceof?com.bob.aidltest.aidl.IStudentManager)))?{????????????????return?((com.bob.aidltest.aidl.IStudentManager)iin);}????????????return?new?com.bob.aidltest.aidl.IStudentManager.Stub.Proxy(obj);}????????@Override?public?android.os.IBinder?asBinder(){????????????return?this;}????????/**?????????*?運(yùn)行在服務(wù)端進(jìn)程的Binder線程池中;當(dāng)客戶端進(jìn)程發(fā)起遠(yuǎn)程請(qǐng)求時(shí),遠(yuǎn)程請(qǐng)求會(huì)要求系統(tǒng)底層執(zhí)行回調(diào)該方法?????????*?@param?code?客戶端進(jìn)程請(qǐng)求方法標(biāo)識(shí)符。服務(wù)端進(jìn)程會(huì)根據(jù)該標(biāo)識(shí)確定所請(qǐng)求的目標(biāo)方法?????????*?@param?data?目標(biāo)方法的參數(shù),他是客戶端進(jìn)程傳進(jìn)來(lái)的,當(dāng)我們調(diào)用addStudent(Student?student)方法時(shí),參數(shù)就是Student對(duì)象?????????*?@param?reply?目標(biāo)方法執(zhí)行后的結(jié)果,將會(huì)返回給客戶端,例如當(dāng)我們調(diào)用getStudentList,返回的就是一個(gè)Student的列表?????????*/@Override?public?boolean?onTransact(int?code,?android.os.Parcel?data,?android.os.Parcel?reply,?int?flags)?throws?android.os.RemoteException{????????????switch?(code){????????????????case?INTERFACE_TRANSACTION:{reply.writeString(DESCRIPTOR);????????????????????return?true;}????????????????case?TRANSACTION_getStudentList:{data.enforceInterface(DESCRIPTOR);java.util.List<com.bob.aidltest.aidl.Student>?_result?=?this.getStudentList();reply.writeNoException();reply.writeTypedList(_result);????????????????????return?true;}????????????????case?TRANSACTION_addStudent:{data.enforceInterface(DESCRIPTOR);com.bob.aidltest.aidl.Student?_arg0;????????????????????if?((0!=data.readInt()))?{_arg0?=?com.bob.aidltest.aidl.Student.CREATOR.createFromParcel(data);}????????????????????else?{_arg0?=?null;}????????????????????this.addStudent(_arg0);reply.writeNoException();????????????????????return?true;}}????????????return?super.onTransact(code,?data,?reply,?flags);}????????/**?????????*?代理的內(nèi)部類(lèi),他實(shí)現(xiàn)了IStudentManager接口,這個(gè)代理類(lèi)就是服務(wù)端返回給客戶端的AIDL接口對(duì)象,客戶端可以通過(guò)這個(gè)代理類(lèi)訪問(wèn)服務(wù)端的方法?????????*/private?static?class?Proxy?implements?com.bob.aidltest.aidl.IStudentManager{????????????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?java.util.List<com.bob.aidltest.aidl.Student>?getStudentList()?throws?android.os.RemoteException{android.os.Parcel?_data?=?android.os.Parcel.obtain();android.os.Parcel?_reply?=?android.os.Parcel.obtain();java.util.List<com.bob.aidltest.aidl.Student>?_result;????????????????try?{_data.writeInterfaceToken(DESCRIPTOR);mRemote.transact(Stub.TRANSACTION_getStudentList,?_data,?_reply,?0);_reply.readException();_result?=?_reply.createTypedArrayList(com.bob.aidltest.aidl.Student.CREATOR);}????????????????finally?{_reply.recycle();_data.recycle();}????????????????return?_result;}????????????@Override?public?void?addStudent(com.bob.aidltest.aidl.Student?student)?throws?android.os.RemoteException{android.os.Parcel?_data?=?android.os.Parcel.obtain();android.os.Parcel?_reply?=?android.os.Parcel.obtain();????????????????try?{_data.writeInterfaceToken(DESCRIPTOR);????????????????????if?((student!=null))?{_data.writeInt(1);student.writeToParcel(_data,?0);}????????????????????else?{_data.writeInt(0);}mRemote.transact(Stub.TRANSACTION_addStudent,?_data,?_reply,?0);_reply.readException();}????????????????finally?{_reply.recycle();_data.recycle();}}}????????static?final?int?TRANSACTION_getStudentList?=?(android.os.IBinder.FIRST_CALL_TRANSACTION?+?0);????????static?final?int?TRANSACTION_addStudent?=?(android.os.IBinder.FIRST_CALL_TRANSACTION?+?1);}????public?java.util.List<com.bob.aidltest.aidl.Student>?getStudentList()?throws?android.os.RemoteException;????public?void?addStudent(com.bob.aidltest.aidl.Student?student)?throws?android.os.RemoteException; }

可能看了上面的注釋大家還是一頭霧水,那就先看看這個(gè)類(lèi)的結(jié)構(gòu)圖吧:

有關(guān)這個(gè)類(lèi)的細(xì)節(jié)我們待會(huì)講,現(xiàn)在只需要知道我們需要在服務(wù)端手動(dòng)實(shí)現(xiàn)Proxy類(lèi)并實(shí)現(xiàn)其中的方法。

創(chuàng)建StudentManagerService.java,并為其指定進(jìn)程

/**?*?Created?by?bob?on?17-7-3.?*?服務(wù)端代碼?*/public?class?StudentManagerService?extends?Service?{????private?static?final?String?TAG?=?"StudentManagerService";????//判斷Service是否銷(xiāo)毀private?AtomicBoolean?mIsServiceDestroyed?=?new?AtomicBoolean(false);????//適合用于進(jìn)程間傳輸?shù)牧斜眍?lèi)private?CopyOnWriteArrayList<Student>?mStudentList?=?new?CopyOnWriteArrayList<Student>();????@Overridepublic?void?onCreate()?{????????super.onCreate();????????//在服務(wù)端手動(dòng)添加兩位默認(rèn)的學(xué)生mStudentList.add(new?Student(1,?"BOB",?"man"));mStudentList.add(new?Student(2,?"MAY",?"woman"));}????@Overridepublic?IBinder?onBind(Intent?intent)?{????????return?mBinder;}????@Overridepublic?void?onDestroy()?{mIsServiceDestroyed.set(false);????????super.onDestroy();}????private?Binder?mBinder?=?new?IStudentManager.Stub()?{????????@Overridepublic?List<Student>?getStudentList()?throws?RemoteException?{SystemClock.sleep(5000);//休眠5s模擬耗時(shí)操作return?mStudentList;}????????@Overridepublic?void?addStudent(Student?student)?throws?RemoteException?{mStudentList.add(student);}};}

在清單文件中指定服務(wù)的進(jìn)程

<service?????android:name=".StudentManagerService"????android:process=":remote"></service>

可以看到這個(gè)服務(wù)類(lèi)跟普通的服務(wù)類(lèi)相差并不大,唯一的區(qū)別在于它創(chuàng)建了一個(gè)IStudentManager.Stub的匿名內(nèi)部類(lèi)并且實(shí)現(xiàn)了其中的方法,在onBind方法中將這個(gè)IBinder對(duì)象返回給客戶端。這里需要說(shuō)明一下:Binder是實(shí)現(xiàn)了IBinder接口的,所以他同時(shí)也是一個(gè)IBinder對(duì)象。

在客戶端愉快的綁定Service吧!

public?class?MainActivity?extends?AppCompatActivity?{????private?static?final?String?TAG?=?"MainActivity_Client";????private?static?final?int?MESSAGE_QUERY_STUDENTLIST=1;????private?int?student_size?=?3;????private?IStudentManager?mRemoteStudentManager;????private?ServiceConnection?mConnection=new?ServiceConnection()?{????????//onServiceConnected與onServiceDisconnected都是在主線程中的,所以如果里面如果涉及到服務(wù)端的耗時(shí)操作那么需要在子線程中進(jìn)行@Overridepublic?void?onServiceConnected(ComponentName?name,?IBinder?service)?{????????????//獲取到IStudentManager對(duì)象final?IStudentManager?studentManager?=IStudentManager.Stub.asInterface(service);mRemoteStudentManager?=?studentManager;}????????@Overridepublic?void?onServiceDisconnected(ComponentName?name)?{mRemoteStudentManager?=?null;Log.d(TAG,?"onServiceDisconnected.threadname:"?+?Thread.currentThread().getName());}};????@Overrideprotected?void?onCreate(Bundle?savedInstanceState)?{????????super.onCreate(savedInstanceState);????????setContentView(R.layout.activity_main);Intent?intent?=?new?Intent(this,?StudentManagerService.class);????????bindService(intent,?mConnection,?BIND_AUTO_CREATE);}????@Overrideprotected?void?onDestroy()?{????????unbindService(mConnection);????????super.onDestroy();}????//將服務(wù)端返回的數(shù)據(jù)顯示在界面上private?Handler?mHandler=new?Handler(){????????@Overridepublic?void?handleMessage(Message?msg)?{????????????switch?(msg.what)?{????????????????case?MESSAGE_QUERY_STUDENTLIST:Toast.makeText(MainActivity.this,?msg.obj.toString(),Toast.LENGTH_SHORT).show();????????????????default:????????????????????super.handleMessage(msg);}}};????/**?????*?在客戶端向服務(wù)端添加一名學(xué)生?????*?@param?view?????*/public?void?addStudent(View?view)?{????????if?(mRemoteStudentManager?!=?null)?{????????????try{????????????????int?student_id?=?student_size+?1;Student?newStudent;????????????????if?(student_id?%?2?==?0)?{newStudent=?new?Student(student_id,?"新學(xué)生"?+?student_id,?"man");}?else?{newStudent=?new?Student(student_id,?"新學(xué)生"?+?student_id,?"woman");}mRemoteStudentManager.addStudent(newStudent);Log.d(TAG,?"添加一位學(xué)生:"?+?newStudent.toString());}catch(Exception?e){e.printStackTrace();}}}????/**?????*?在客戶端向服務(wù)端發(fā)起查詢學(xué)生的請(qǐng)求?????*?@param?view?????*/public?void?get_student_list(View?view)?{Toast.makeText(this,?"正在獲取學(xué)生列表",?Toast.LENGTH_SHORT).show();????????//由于服務(wù)端的查詢操作是耗時(shí)操作,所以客戶端需要開(kāi)啟子線程進(jìn)行工作new?Thread(new?Runnable()?{????????????@Overridepublic?void?run()?{????????????????if?(mRemoteStudentManager?!=?null)?{????????????????????try{????????????????????????final?List<Student>?students?=?mRemoteStudentManager.getStudentList();student_size?=?students.size();Log.d(TAG,?"從服務(wù)器成功獲取到學(xué)生列表:"?+?students.toString());mHandler.obtainMessage(MESSAGE_QUERY_STUDENTLIST,?students).sendToTarget();}catch(Exception?e){e.printStackTrace();}}}}).start();} }

可以看到我們?cè)诳蛻舳酥恍枰壎ㄟh(yuǎn)程的服務(wù)端,服務(wù)端就會(huì)返回一個(gè)IBinder對(duì)象,接著我們需要調(diào)用IStudentManager.Stub.asInterface()方法,將這個(gè)IBinder對(duì)象轉(zhuǎn)換為我們客戶端可用的AIDL接口對(duì)象,拿到這個(gè)對(duì)象之后我們就可以遠(yuǎn)程調(diào)用服務(wù)端的方法了。是不是很容易?
但是需要注意的一點(diǎn)是為了模擬耗時(shí)操作,我們?cè)诜?wù)端的getStudentList的方法中使用休眠以模擬耗時(shí)操作,所以客戶端在調(diào)用該方法時(shí)不能直接在主線程中調(diào)用,而是應(yīng)該開(kāi)啟一個(gè)子線程,在子線程中調(diào)用這個(gè)耗時(shí)的操作。

看看效果

首先我們獲取學(xué)生列表,接著連續(xù)添加4個(gè)學(xué)生,再次查看學(xué)生列表,最終的結(jié)果如下圖,可以看到我們已經(jīng)實(shí)現(xiàn)了兩個(gè)進(jìn)程之間的交互,接下來(lái)我們將分析Binder的原理。

Binder的原理

進(jìn)程的機(jī)制

首先我們需要了解進(jìn)程之間為什么不能直接進(jìn)行通信,以下是兩個(gè)進(jìn)程的示意圖:

從上面的圖我們可以得到以下幾點(diǎn):

  • 一個(gè)進(jìn)程空間分為:用戶態(tài)和內(nèi)核態(tài),即把進(jìn)程內(nèi)用戶和內(nèi)核隔離開(kāi)來(lái)

  • 進(jìn)程之間,由于Android系統(tǒng)為每個(gè)進(jìn)程分配了一個(gè)獨(dú)立的虛擬機(jī),用戶空間和內(nèi)核空間的數(shù)據(jù)不可交互

  • Binder作為進(jìn)程間的介質(zhì),充當(dāng)了中介,使得進(jìn)程間的內(nèi)核態(tài)可以通過(guò)Binder進(jìn)行數(shù)據(jù)交互

IPC交互示意圖


圖中總共有四個(gè)元素,分別是充當(dāng)客戶端的Activity,服務(wù)端的StudentManagerService,充當(dāng)服務(wù)管理者的IStudentManager以及充當(dāng)訪問(wèn)介質(zhì)的Binder驅(qū)動(dòng)。他們的職責(zé)如下:

  • StudentManagerService:?服務(wù)提供者,這里面會(huì)有許多我們常用的服務(wù),在本例中提供的服務(wù)就是添加學(xué)生以及獲取學(xué)生列表。而在系統(tǒng)中則包括有ActivityService 、 WindowMananger等服務(wù),這些系統(tǒng)服務(wù)提供的功能,對(duì)四大組件以及Window的工作提供的保障。

  • Activity:?服務(wù)調(diào)用者,一般就是我們的應(yīng)用,在這里我們通過(guò)調(diào)用StudentManagerService的服務(wù)來(lái)完成工作。

  • IStudentManager:?他是負(fù)責(zé)管理服務(wù)的,在其內(nèi)部通過(guò)map集合來(lái)存儲(chǔ)Service與Binder的映射關(guān)系,這樣客戶端在向其請(qǐng)求服務(wù)的時(shí)候就能夠返回特定的Binder。

  • Binder驅(qū)動(dòng):?他是IStudentManager連接各種Service的橋梁,同時(shí)也是客戶端與服務(wù)端交流的橋梁。

總結(jié)起來(lái)說(shuō),應(yīng)用程序(Activity)首先向IStudentManager發(fā)送請(qǐng)求StudentManagerService的服務(wù),IStudentManager查看已經(jīng)注冊(cè)在里面的服務(wù)的列表,找到相應(yīng)的服務(wù)后,通過(guò)Binder驅(qū)動(dòng)將其中的Binder對(duì)象返回給客戶端,從而完成對(duì)服務(wù)的請(qǐng)求。

源碼分析

我們主要分析的就是IStudentManager這個(gè)類(lèi),從上面得到講解我們已經(jīng)知道它包含了兩個(gè)類(lèi):Stub和Proxy。先來(lái)看看Proxy類(lèi)

//Proxy.javapublic?java.util.List<com.bob.aidltest.aidl.Student>?getStudentList()?throws?android.os.RemoteException{android.os.Parcel?_data?=?android.os.Parcel.obtain();android.os.Parcel?_reply?=?android.os.Parcel.obtain();java.util.List<com.bob.aidltest.aidl.Student>?_result;????try?{_data.writeInterfaceToken(DESCRIPTOR);mRemote.transact(Stub.TRANSACTION_getStudentList,?_data,?_reply,?0);_reply.readException();_result?=?_reply.createTypedArrayList(com.bob.aidltest.aidl.Student.CREATOR);}????finally?{_reply.recycle();_data.recycle();}????return?_result; }public?void?addStudent(com.bob.aidltest.aidl.Student?student)?throws?android.os.RemoteException{android.os.Parcel?_data?=?android.os.Parcel.obtain();android.os.Parcel?_reply?=?android.os.Parcel.obtain();????try?{_data.writeInterfaceToken(DESCRIPTOR);????????if?((student!=null))?{_data.writeInt(1);student.writeToParcel(_data,?0);}????????else?{_data.writeInt(0);}mRemote.transact(Stub.TRANSACTION_addStudent,?_data,?_reply,?0);_reply.readException();}????finally?{_reply.recycle();_data.recycle();} }

上面截取了Proxy的兩個(gè)方法,其中Proxy是運(yùn)行在客戶端的,他是用服務(wù)端返回來(lái)的Binder對(duì)象調(diào)用了public static IStudentManager asInterface(IBinder obj)方法返回來(lái)的。
既然Proxy運(yùn)行在客戶端,那么客戶端也是通過(guò)Proxy來(lái)調(diào)用遠(yuǎn)程服務(wù)端的方法的,也就是說(shuō)我們將調(diào)用方法需要用到的參數(shù)傳遞給Proxy,接著由Proxy來(lái)訪問(wèn)服務(wù)端,所以我們能夠看到,Proxy將我們的參數(shù)寫(xiě)進(jìn)了_data,而_reply則代表從服務(wù)端返回來(lái)的結(jié)果。
從代碼中我們還看到客戶端在將數(shù)據(jù)傳遞給服務(wù)端之后就處于阻塞狀態(tài),直到服務(wù)端返回結(jié)果,所以如果調(diào)用的服務(wù)端方法是一個(gè)耗時(shí)方法,那么我們就需要在子線程中進(jìn)行工作了。
數(shù)據(jù)準(zhǔn)備好之后當(dāng)然是需要傳遞了,可以看到Proxy通過(guò)transact方法講數(shù)據(jù)傳遞出去了,接下來(lái)就來(lái)看transact方法:

//Binder#transactpublic?final?boolean?transact(int?code,?Parcel?data,?Parcel?reply,????????????int?flags)?throws?RemoteException?{????????if?(false)?Log.v("Binder",?"Transact:?"?+?code?+?"?to?"?+?this);????????if?(data?!=?null)?{data.setDataPosition(0);}????????//調(diào)用了Binder的onTransactboolean?r?=?onTransact(code,?data,?reply,?flags);????????if?(reply?!=?null)?{reply.setDataPosition(0);}????????return?r;}

可以看到transact方法實(shí)際上調(diào)用了Binder的onTransact,而這里的Binder就是指Stub了,我們看一下Stub的定義:

public?static?abstract?class?Stub?extends?android.os.Binder?implements?com.bob.aidltest.aidl.IStudentManager

可以看到Stub確實(shí)繼承了Binder并且也實(shí)現(xiàn)了IStudentManager接口,接下來(lái)我們繼續(xù)看Stub中的onTransact方法:

public?boolean?onTransact(int?code,?android.os.Parcel?data,?android.os.Parcel?reply,?int?flags)?throws?android.os.RemoteException{????switch?(code){????????case?INTERFACE_TRANSACTION:{reply.writeString(DESCRIPTOR);????????????return?true;}????????case?TRANSACTION_getStudentList:{data.enforceInterface(DESCRIPTOR);java.util.List<com.bob.aidltest.aidl.Student>?_result?=?this.getStudentList();reply.writeNoException();reply.writeTypedList(_result);????????????return?true;}????????case?TRANSACTION_addStudent:{data.enforceInterface(DESCRIPTOR);com.bob.aidltest.aidl.Student?_arg0;????????????if?((0!=data.readInt()))?{_arg0?=?com.bob.aidltest.aidl.Student.CREATOR.createFromParcel(data);}????????????else?{_arg0?=?null;}????????????this.addStudent(_arg0);reply.writeNoException();????????????return?true;}}????return?super.onTransact(code,?data,?reply,?flags); }

可以看到,服務(wù)端通過(guò)客戶端傳遞過(guò)來(lái)的code常量來(lái)判斷客戶端需要調(diào)用的是哪個(gè)方法,接著就執(zhí)行該方法,執(zhí)行完之后如果有數(shù)據(jù)返回則將結(jié)果寫(xiě)入reply,接著Proxy就可以收到結(jié)果了。而整個(gè)通信過(guò)程也就結(jié)束了。
最后我借用Carson_Ho的一張流程圖來(lái)描述這個(gè)完整的流程:


本文轉(zhuǎn)自lzwxx 51CTO博客,原文鏈接:http://blog.51cto.com/13064681/1944339


總結(jié)

以上是生活随笔為你收集整理的从Android源码的角度分析Binder机制的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。