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

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

生活随笔

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

Android

Android—Binder+AIDL

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

Binder?

Binder機(jī)制優(yōu)點(diǎn):

  • 只需要進(jìn)行一次數(shù)據(jù)拷貝,性能上僅次于共享內(nèi)存。
  • 基于C/S架構(gòu),職責(zé)明確,架構(gòu)清晰,穩(wěn)定性較好。
  • 安全性好,為每個(gè)App分配UID,UID是鑒別進(jìn)程身份的標(biāo)志。

內(nèi)存映射:(一次copy的原因)

Binder IPC 機(jī)制中涉及到的內(nèi)存映射通過(guò) mmap() 來(lái)實(shí)現(xiàn),mmap() 是操作系統(tǒng)中一種內(nèi)存映射的方法。內(nèi)存映射簡(jiǎn)單的講就是將用戶空間的一塊內(nèi)存區(qū)域映射到內(nèi)核空間。映射關(guān)系建立后,用戶對(duì)這塊內(nèi)存區(qū)域的修改可以直接反應(yīng)到內(nèi)核空間;反之內(nèi)核空間對(duì)這段區(qū)域的修改也能直接反應(yīng)到用戶空間。

Binder IPC 通信過(guò)程:

  • 首先 Binder 驅(qū)動(dòng)在內(nèi)核空間創(chuàng)建一個(gè)數(shù)據(jù)接收緩存區(qū);
  • 接著在內(nèi)核空間開(kāi)辟一塊內(nèi)核緩存區(qū),建立內(nèi)核緩存區(qū)和內(nèi)核中數(shù)據(jù)接收緩存區(qū)之間的映射關(guān)系,以及內(nèi)核中數(shù)據(jù)接收緩存區(qū)和接收進(jìn)程用戶空間地址的映射關(guān)系;
  • 發(fā)送方進(jìn)程通過(guò)系統(tǒng)調(diào)用 copy_from_user() 將數(shù)據(jù) copy 到內(nèi)核中的內(nèi)核緩存區(qū),內(nèi)核緩存區(qū)映射到接收區(qū),接收區(qū)又映射到用戶空間地址,因此也就相當(dāng)于把數(shù)據(jù)發(fā)送到了接收進(jìn)程的用戶空間,這樣便完成了一次進(jìn)程間的通信。

Binder通訊模型:
Binder是基于C/S架構(gòu)的,包含4個(gè)角色:Client、Server、Binder驅(qū)動(dòng)和ServiceManager。

  • Binder驅(qū)動(dòng):類似網(wǎng)絡(luò)通信中的路由器,負(fù)責(zé)將Client的請(qǐng)求轉(zhuǎn)發(fā)到具體的Server中執(zhí)行,并將Server返回的數(shù)據(jù)傳回給Client。
  • ServiceManager:類似網(wǎng)絡(luò)通信中的DNS服務(wù)器,負(fù)責(zé)將Client請(qǐng)求的Binder描述符轉(zhuǎn)化為具體的Server地址,以便Binder驅(qū)動(dòng)能夠轉(zhuǎn)發(fā)給具體的Server。Server如需提供Binder服務(wù),需要向ServiceManager注冊(cè)。

通信過(guò)程:

  • Server向ServiceManager注冊(cè)。Server通過(guò)Binder驅(qū)動(dòng)向ServiceManager注冊(cè),聲明可以對(duì)外提供服務(wù)。ServiceManager中會(huì)保留一份映射表。
  • Client向ServiceManager請(qǐng)求Server的Binder引用。Client想要請(qǐng)求Server的數(shù)據(jù)時(shí),需要先通過(guò)Binder驅(qū)動(dòng)向ServiceManager請(qǐng)求Server的Binder引用(代理對(duì)象),ServiceManager根據(jù)Server服務(wù)名找到對(duì)應(yīng)的Server,然后向具體的Server發(fā)送請(qǐng)求。
  • 創(chuàng)建遠(yuǎn)程代理對(duì)象。Server響應(yīng)請(qǐng)求后,通過(guò)Binder驅(qū)動(dòng)將結(jié)果返回給Client。Client在收到該Server的Binder引用信息之后,就根據(jù)該Binder引用信息創(chuàng)建一個(gè)Server對(duì)應(yīng)的遠(yuǎn)程代理對(duì)象,Client通過(guò)調(diào)用該遠(yuǎn)程服務(wù)的接口,就相當(dāng)于在調(diào)用Server的服務(wù)接口一樣。
  • Client和Server通信:

    Client要和Server通信,它就是通過(guò)保存一個(gè)Server對(duì)象的Binder引用,再通過(guò)該Binder引用在內(nèi)核中找到對(duì)應(yīng)的Binder實(shí)體,進(jìn)而找到Server對(duì)象,然后將通信內(nèi)容發(fā)送給Server對(duì)象。

    Client進(jìn)程將需要傳送的數(shù)據(jù)寫入到Parcel對(duì)象中調(diào)用BinderProxy的transact()將上述數(shù)據(jù)發(fā)送到Binder驅(qū)動(dòng)(通過(guò)BpBinder)Binder驅(qū)動(dòng)找到Binder引用對(duì)應(yīng)的Binder實(shí)體,通過(guò)Binder實(shí)體找到用戶空間的Server對(duì)象,Server收到Binder驅(qū)動(dòng)通知后,Server 進(jìn)程通過(guò)回調(diào)Binder對(duì)象onTransact()進(jìn)行數(shù)據(jù)解包和調(diào)用目標(biāo)方法,Binder驅(qū)動(dòng)根據(jù)代理對(duì)象沿原路將結(jié)果返回并通知Client進(jìn)程獲取返回結(jié)果,喚醒Client線程,接收結(jié)果。

    AIDL? Android Interface Definition Language(Android接口定義語(yǔ)言)

    AIDL是基于Binder的,作用是實(shí)現(xiàn)進(jìn)程間的通信。如果需要操作非基礎(chǔ)類型的數(shù)據(jù),需要序列化。

    首先是定義一個(gè)Person類繼承Parcelable。

    package com.example.mylibraryimport android.os.Parcel import android.os.Parcelableclass Person():Parcelable {var name:String = ""var age:Int = 0constructor(parcel: Parcel):this(){name = parcel.readString().toString()age = parcel.readInt()}constructor(name: String,age: Int):this(){this.name = namethis.age = age}override fun writeToParcel(dest: Parcel?, flags: Int) {dest?.writeString(name)dest?.writeInt(age)}fun readFromParcel(parcel: Parcel): Person? {name = parcel.readString().toString()age = parcel.readInt()return this}override fun describeContents(): Int {return 0}companion object CREATOR : Parcelable.Creator<Person> {override fun createFromParcel(parcel: Parcel): Person {return Person(parcel)}override fun newArray(size: Int): Array<Person?> {return arrayOfNulls(size)}} }

    要能操作Person類還需要定義一個(gè)AIDL文件

    // Person.aidl package com.example.mylibrary;// Declare any non-default types here with import statementsparcelable Person;

    接下來(lái)創(chuàng)建自己的AIDL文件,然后聲明自己需要的方法。?

    // IMyAidlInterface.aidl package com.example.mylibrary; import com.example.mylibrary.Person;// Declare any non-default types here with import statementsinterface IMyAidlInterface {/*** Demonstrates some basic types that you can use as parameters* and return values in AIDL.*/List<Person> getPeople();void addPerson(in Person person);Person updatePerson(inout Person person);Person updatePerson2(inout Person person); }

    關(guān)于參數(shù)前的in、out和inout,跨進(jìn)程時(shí),in參數(shù)會(huì)把參數(shù)的內(nèi)容傳給aidl,但其改動(dòng)不會(huì)同步到調(diào)用進(jìn)程;out參數(shù)不會(huì)把參數(shù)的屬性傳給aidl(aidl獲取的參數(shù)對(duì)象屬性為空),但其改動(dòng)會(huì)同步到調(diào)用進(jìn)程;inout參數(shù)則是in和out的綜合。不跨進(jìn)程時(shí),三者則是擺設(shè)。

    上面一定要導(dǎo)入Person類的正確地址,不然aidl生成對(duì)應(yīng)的java找不到。同步一下。

    3、有了接口文件,我們需要定義一個(gè)服務(wù)類,實(shí)現(xiàn)接口方法,在onBind返回實(shí)例。

    package com.example.mylibraryimport android.app.Service import android.content.Intent import android.os.IBinder import android.util.Log import kotlin.random.Randomclass PersonService: Service() {var personList:ArrayList<Person> = ArrayList()var random = Random(1)init {val p = Person("AAAA",20)personList.add(p)}private var personManager = object : IMyAidlInterface.Stub(){override fun addPerson(person: Person?) {val isNull = person == null // 參數(shù)為inLog.e("aaa","in person is null--$isNull")if (person != null) {personList.add(person)}}override fun updatePerson(person: Person): Person {personList.set(0,person)return person}override fun getPeople(): MutableList<Person> {return personList}override fun updatePerson2(person: Person): Person {val p1 = Person()p1.age = random.nextInt() % 40p1.name = "mike"personList[1] = p1return p1}}override fun onBind(intent: Intent?): IBinder? {Log.e("bbbbb","有連接請(qǐng)求");Log.e("cccc",intent.toString());return personManager;} }

    4、在manifest中聲明

    <service android:name="com.example.mylibrary.PersonService"android:exported="false"android:process=":remote"><intent-filter><action android:name="com.example.text" /><category android:name="android.intent.category.DEFAULT"/></intent-filter></service>

    android:exported 該屬性用來(lái)標(biāo)示,其它應(yīng)用的組件是否可以喚醒service或者和這個(gè)service進(jìn)行交互:true可以,false不可以。如果為false,只有同一個(gè)應(yīng)用的組件或者有著同樣user ID的應(yīng)用可以啟動(dòng)這個(gè)service或者綁定這個(gè)service。

    android:process=":remote"? 讓服務(wù)在指定進(jìn)程名中啟動(dòng),這里選擇”remote”這個(gè)名字是隨意主觀的,你能用其他名字來(lái)讓這個(gè)服務(wù)在另外的進(jìn)程中運(yùn)行。冒號(hào)’:’這個(gè)前綴將把這個(gè)名字附加到你的包所運(yùn)行的標(biāo)準(zhǔn)進(jìn)程名字的后面作為新的進(jìn)程名稱。

    現(xiàn)在的結(jié)構(gòu)是這樣的。?

    ?5、在主app中使用這個(gè)服務(wù)

    前提:app已經(jīng)依賴了mylibrary這個(gè)module

    package com.example.textimport android.content.ComponentName import android.content.Context import android.content.Intent import android.content.ServiceConnection import android.os.Bundle import android.os.IBinder import android.util.Log import androidx.appcompat.app.AppCompatActivity import com.example.mylibrary.IMyAidlInterface import com.example.mylibrary.Person import com.example.mylibrary.PersonServiceclass MainActivity : AppCompatActivity() {private var isConnected = falselateinit var peopleManager:IMyAidlInterfaceprivate val p = Person("Dustin", 27)override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)}private val connection: ServiceConnection = object : ServiceConnection {override fun onServiceConnected(name: ComponentName, service: IBinder) {peopleManager = IMyAidlInterface.Stub.asInterface(service) // 此處的service,就是Service的onBind()方法返回的Stub,必須經(jīng)過(guò)這個(gè)方法才能還原成Stub類對(duì)象isConnected = trueshow()logger("before add")logger(p.name+"aaaaaaaaaaaaaaaaa")logger("=================")peopleManager.addPerson(p)show()logger("=================")peopleManager.updatePerson(p)logger(p.name+"aaaaaaaaaaaaaaaaa")show()logger("=================") peopleManager.updatePerson2(p)show()}override fun onServiceDisconnected(name: ComponentName) {logger(name.toString() + "已經(jīng)斷開(kāi)連接")isConnected = false}}fun show(){for (i:Int in 0 until peopleManager.people.size){logger(peopleManager.people[i].name)logger(peopleManager.people[i].age.toString())}}private fun logger(info: String) {Log.e("FragmentActivity.TAG", info)}override fun onStop() {super.onStop()tryDisconnectService()}override fun onStart() {super.onStart()tryConnectService()}private fun tryConnectService() {logger("try to connect service")if (!isConnected) {val intent = Intent(this, PersonService::class.java)bindService(intent, connection, Context.BIND_AUTO_CREATE)}}private fun tryDisconnectService() {logger("try to disconnect service")if (isConnected) {unbindService(connection)isConnected = false}}}

    結(jié)果:

    服務(wù)進(jìn)程:

    app進(jìn)程:

    我們還沒(méi)測(cè)試過(guò)out,我們把AIDL文件的

    Person updatePerson(inout Person person); 改為Person updatePerson(out Person person);

    同步,再運(yùn)行。

    看到updatePerson(out Person person);改變不了服務(wù)類的數(shù)據(jù)了。

    但是傳到服務(wù)進(jìn)程的值并不為空。

    分析一下? mAidlInterface = IMyAidlInterface.Stub.asInterface(service)

    public static IMyAidlInterface asInterface(IBinder obj){if ((obj==null)) {return null;}IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof IMyAidlInterface))) {return ((IMyAidlInterface)iin);}return new Stub.Proxy(obj); } private static class Proxy implements IMyAidlInterface{private IBinder mRemote;Proxy(IBinder remote){mRemote = remote;}@Override public IBinder asBinder(){return mRemote;}public String getInterfaceDescriptor(){return DESCRIPTOR;}@Override public void myMethod() throws RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();try {_data.writeInterfaceToken(DESCRIPTOR);mRemote.transact(Stub.TRANSACTION_myMethod, _data, _reply, 0);_reply.readException();}finally {_reply.recycle();_data.recycle();}} }

    Stub.Proxy同樣實(shí)現(xiàn)了我們定義的功能接口,而且包含一個(gè)BinderProxy對(duì)象,當(dāng)我們?cè)贑lient進(jìn)程中調(diào)用我們所定義的功能方法時(shí),其實(shí)就是調(diào)用Stub.Proxy中實(shí)現(xiàn)的方法。?在實(shí)現(xiàn)該功能方法時(shí),它首先將參數(shù)序列化,然后調(diào)用BinderProxy的transact()方法,調(diào)用該方法以后,Binder驅(qū)動(dòng)會(huì)喚醒Server進(jìn)程中的本地Binder對(duì)象, 并調(diào)用它的onTransact()方法。

    @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException{switch (code){case INTERFACE_TRANSACTION:{reply.writeString(DESCRIPTOR);return true;}case TRANSACTION_myMethod:{data.enforceInterface(DESCRIPTOR);this.myMethod();reply.writeNoException();return true;}} return super.onTransact(code, data, reply, flags);}

    TRANSACTION_myMethod,是一個(gè)整型,也就是說(shuō)在Binder中對(duì)每一個(gè)方法都進(jìn)行了編號(hào),在transact()方法中傳入編號(hào),然后在onTransact()方法中,根據(jù)請(qǐng)求的變化調(diào)用相應(yīng)的方法。這里我們看到data接收參數(shù),然后調(diào)用本地Binder中定義的功能方法,這里是抽象方法,留有子類實(shí)現(xiàn),最后將結(jié)果寫入到_reply中,由Binder驅(qū)動(dòng)負(fù)責(zé)將返回值傳遞到BinderProxy的transact()方法中的_reply。

    Service接口方法調(diào)用流程小結(jié)

  • 客戶端調(diào)用bindService綁定服務(wù)時(shí),將觸發(fā)Service的onBind監(jiān)聽(tīng)方法。該方法將調(diào)用asBinder方法,返回一個(gè)Binder對(duì)象。
  • 客戶端將通過(guò)onServiceConnected回調(diào)函數(shù),獲取到該Binder對(duì)象(以傳參的形式傳入)。
  • 客戶端獲取到Binder對(duì)象后,可調(diào)用stub.asInterface方法,將其轉(zhuǎn)換為service實(shí)現(xiàn)類的對(duì)象。
  • 在asInterface方法中,將判斷service與當(dāng)前進(jìn)程,是否在同一進(jìn)程中。若是,則返回stub本身,否則返回stub.proxy。返回結(jié)果將作為Service實(shí)現(xiàn)類的實(shí)例。
  • 在通過(guò)Service實(shí)現(xiàn)類的實(shí)例調(diào)用接口方法時(shí),若為同一進(jìn)程,則直接調(diào)用方法本身。若為跨進(jìn)程,則調(diào)用stub.proxy的對(duì)應(yīng)接口方法,通過(guò)Transact方法將信息傳送到服務(wù)端。此時(shí),客戶端將掛起,等待結(jié)果返回。
  • 服務(wù)端接收到信息,通過(guò)onTransact()方法,根據(jù)方法的唯一標(biāo)識(shí),將信息轉(zhuǎn)發(fā)至各對(duì)應(yīng)方法。
  • 信息處理完成后,再由服務(wù)端onTransact返回結(jié)果。
  • 文章推薦:

    https://blog.csdn.net/weixin_44339238/article/details/110942282

    總結(jié)

    以上是生活随笔為你收集整理的Android—Binder+AIDL的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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