Android binder 匿名服務(wù)實現(xiàn)雙向通信的解決方案
在binder 用戶空間通信模型中,涉及client,server和servicemanager進程。一般來說,都是server注冊服務(wù)到servicemanager中,client從servicemanager中獲取服務(wù),然后由client發(fā)起,使用服務(wù)中的方法。server都是被動的接收client發(fā)起的請求。那如果server想主動的發(fā)起請求調(diào)用client中的方法,應(yīng)該怎么做呢?
實現(xiàn)上面的需求,首先可以想到的是,client也向servicemanager注冊一個服務(wù),server中從servicemanager獲取服務(wù),這樣client就變成了服務(wù)端,server就變成了客戶端,不就可以實現(xiàn)嗎?
當(dāng)然,這種方案是可行的,只是需要client和server都向servicemanager注冊一個服務(wù),實現(xiàn)起來有點麻煩,不太建議這么做。完全可以使用匿名服務(wù)來實現(xiàn)雙向通信的需求
1,背景知識
在注冊服務(wù)時,通過調(diào)用Parcel的writeStrongBinder,會構(gòu)造一個flat_binder_obj結(jié)構(gòu)體,其中的type為BINDER_TYPE_BINDER,binder驅(qū)動對于type是BINDER_TYPE_BINDER,則會生成一個binder_node,并為servicemanager創(chuàng)建binder_ref,而且還會將這個flat_binder_obj的type改為BINDER_TYPE_HANDLE,將binder_ref中的desc存入flat_binder_obj的handle,傳給servicemanager,在servicemanager中記錄其信息。這個過程就是binder實名服務(wù)的注冊過程。
2,匿名服務(wù)是什么?
binder_node代表一個服務(wù)的實體。了解了上面的背景知識后知道writeStrongBinder會導(dǎo)致在驅(qū)動中創(chuàng)建一個binder_node,那么我們可不可以直接在client和server通信的過程中,調(diào)用writeStrongBinder,而不需要通過添加服務(wù)在servicemanager中記錄這個服務(wù)的信息呢?答案是可以的,這就是匿名服務(wù)。匿名服務(wù)需要依賴于server已經(jīng)注冊好的實名服務(wù)
3,匿名服務(wù)在系統(tǒng)源碼中的使用
應(yīng)用進程和wms進行通信,通常是借助于一個IWindowSession對象。我們來看一下其構(gòu)造過程
@UnsupportedAppUsage public static IWindowSession getWindowSession() { synchronized (WindowManagerGlobal.class) { if (sWindowSession == null) { try { // Emulate the legacy behavior. The global instance of InputMethodManager // was instantiated here. // TODO(b/116157766): Remove this hack after cleaning up @UnsupportedAppUsage InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary(); IWindowManager windowManager = getWindowManagerService();//1 sWindowSession = windowManager.openSession( //2 new IWindowSessionCallback.Stub() { @Override public void onAnimatorScaleChanged(float scale) { ValueAnimator.setDurationScale(scale); } }); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } return sWindowSession; } }
注釋1處獲取一個IWindowManager.Stub.Proxy對象,不在本分分析的重點。注釋2處通過調(diào)用openSession獲取一個IWindowSession對象。
@Override public android.view.IWindowSession openSession(android.view.IWindowSessionCallback callback, com.android.internal.view.IInputMethodClient client, com.android.internal.view.IInputContext inputContext) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); android.view.IWindowSession _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeStrongBinder((((callback!=null))?(callback.asBinder()):(null))); _data.writeStrongBinder((((client!=null))?(client.asBinder()):(null))); _data.writeStrongBinder((((inputContext!=null))?(inputContext.asBinder()):(null))); mRemote.transact(Stub.TRANSACTION_openSession, _data, _reply, 0);//1 _reply.readException(); _result = android.view.IWindowSession.Stub.asInterface(_reply.readStrongBinder());//2 } finally { _reply.recycle(); _data.recycle(); } return _result; }
可以看出,注釋1處發(fā)起遠程調(diào)用,然后注釋2處從_reply中取出數(shù)據(jù),轉(zhuǎn)化之后返回。那我們來看看服務(wù)端的處理
case TRANSACTION_openSession: { data.enforceInterface(DESCRIPTOR); android.view.IWindowSessionCallback _arg0; _arg0 = android.view.IWindowSessionCallback.Stub.asInterface(data.readStrongBinder()); com.android.internal.view.IInputMethodClient _arg1; _arg1 = com.android.internal.view.IInputMethodClient.Stub.asInterface(data.readStrongBinder()); com.android.internal.view.IInputContext _arg2; _arg2 = com.android.internal.view.IInputContext.Stub.asInterface(data.readStrongBinder()); android.view.IWindowSession _result = this.openSession(_arg0, _arg1, _arg2); reply.writeNoException(); reply.writeStrongBinder((((_result!=null))?(_result.asBinder()):(null)));//1 return true; }
注釋1處也是調(diào)用writeStrongBinder,直接寫給客戶端。結(jié)合前面的背景知識,就知道這是一個binder匿名服務(wù)(并沒有先向servicemanager獲取)。匿名服務(wù)的實現(xiàn)也是通過writeStrongBinder來實現(xiàn)的,客戶端通過readStrongBinder來取出binder驅(qū)動轉(zhuǎn)化過后的flat_binder_obj,取出handle并存入BpBinder中
4,匿名服務(wù)雙向通信實戰(zhàn)
在我們的日常開發(fā)中,通常有這樣的需求,服務(wù)端更新了某種狀態(tài)需要實時的通知給客戶端。那么我們就可以在客戶端通過writeStrongBinder創(chuàng)建一個binder匿名服務(wù)供服務(wù)端使用。
1,在客戶端和服務(wù)端新建一個用于服務(wù)端通知客戶端的aidl文件,如:ICallBack.aidl。注意包名需要一致
// ICallBack.aidl package com.test.testserver; // Declare any non-default types here with import statements interface ICallBack { void onSucess(int code); void onError(); }
2,在客戶端和服務(wù)端本來的通信文件中(客戶端發(fā)起和服務(wù)端通信的aidl文件),新增接口
// ITestInterface.aidl package com.test.testserver; import com.test.testserver.ICallBack; // Declare any non-default types here with import statements interface ITestInterface { void registerCallBack(ICallBack callback); }
3,客戶端調(diào)用 registerCallBack
binder.registerCallBack(new ICallBack.Stub() { @Override public void onSucess(int code) throws RemoteException { Log.d("test", "onSucess code: "+code); } @Override public void onError() throws RemoteException { Log.d("test", "onError: "); } });
4,服務(wù)端接收到之后,做自己的處理
@Override public void registerCallBack(ICallBack callback) throws RemoteException { this.callBack = callback; }
我這里只是將客戶端傳過來的ICallBack 賦值給自己的callBack 對象
5,服務(wù)端需要通知時,調(diào)用ICallBack 中的方法
callBack.onError(); 或者 callBack.onSucess(1);
最后我們來看看,內(nèi)部實現(xiàn)是不是通過writeStrongBinder和readStrongBinder來實現(xiàn)
客戶端發(fā)起調(diào)用:
@Override public void registerCallBack(com.test.testserver.ICallBack callback) 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.writeStrongBinder((((callback!=null))?(callback.asBinder()):(null)));//1 boolean _status = mRemote.transact(Stub.TRANSACTION_registerCallBack, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { getDefaultImpl().registerCallBack(callback); return; } _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } }
注釋1處可以看出是通過writeStrongBinder,構(gòu)建一個匿名服務(wù)
服務(wù)端:
case TRANSACTION_registerCallBack: { data.enforceInterface(descriptor); com.test.testserver.ICallBack _arg0; _arg0 = com.test.testserver.ICallBack.Stub.asInterface(data.readStrongBinder());//1 this.registerCallBack(_arg0); reply.writeNoException(); return true; }
注釋1處是通過readStrongBinder取出來并轉(zhuǎn)化為ICallBack.Stub.proxy對象,用于和客戶端通信
到此這篇關(guān)于Android binder 匿名服務(wù)實現(xiàn)雙向通信的文章就介紹到這了,更多相關(guān)Android binder 匿名服務(wù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用Android開發(fā)接入第三方原生SDK實現(xiàn)微信登錄
這篇文章主要介紹了使用Android開發(fā)接入第三方原生SDK實現(xiàn)微信登錄,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03android 上傳aar到私有maven服務(wù)器的示例
這篇文章主要介紹了android 上傳aar到私有maven服務(wù)器,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11基于android樣式與主題(style&theme)的詳解
本篇文章是對android中的樣式與主題(style&theme)進行了詳細的分析介紹,需要的朋友參考下2013-06-06