Android中非aidl实现进程间通信(编写顺序的parcel写入与读出)
在android中进程间通信(IPC)的基石是Binder系统,Binder系统的核心Binder驱动是C来实现的,对于应用开发人员来说无疑晦涩难懂,而整个android框架是基于面向对象思想的,对于底层Binder驱动的操作细节全部隐藏,framework层提供了一个牛逼无比的Binder对象, 所以我们要实现进程间通信(IPC)只需玩转Binder对象即可。
在android源码中基于Binder对象的通信随处可见,几乎可以认定为以 I 打头的class,都具有进程间通信能力,如:IServiceManager,IContentProvider等。
在源码中实现的方式也可概括为两种:
1. 通过aidl来生成对Binder的操作。
2.手动调用IBinder.transact编写按照顺序写入与读出的parcel代码实现。
第一种方法网上案例较多,不多说。第二种方法实现源码参考:ActivityManagerNative,ActivityManagerProxy
关于第二种方法的实现本人做了一个demo,请看以下代码。
packagedw.test;importjava.util.HashMap;importandroid.os.Binder;importandroid.os.IBinder;importandroid.os.IInterface;importandroid.os.Parcel;importandroid.os.RemoteException;importandroid.util.Log;/***负责接收指令({@linkCmdCode}),并将指令派发到相应的处理器({@linkCmdDispatcher.Callback})*/publicfinalclassCmdDispatcherextendsBinderimplementsIInterface{privatestaticfinalStringLOG_TAG=CmdDispatcher.class.getSimpleName();publicstaticfinalStringDESCRIPTOR=CmdDispatcher.class.getName();/***存储所有指令处理器*map.key={@linkCmdCode}*/privateHashMap<Integer,Callback>mCallbacks=newHashMap<Integer,Callback>();/***针对某个指令的处理*@see#addCallback*@see#removeCallback*/publicinterfaceCallback{/***@paramcode请求指令集{@linkCmdCode.Request},响应指令集{@linkCmdCode.Response}*@paramdata数据{@linkParcel}*@paramreply处理data的结果{@linkParcel}*@return*/publicbooleanonTransact(intcode,Parceldata,Parcelreply);}/***当client端调用{@linkIBinder#transact(int,Parcel,Parcel,int)}时,将会回调本方法。*/@OverrideprotectedbooleanonTransact(intcode,Parceldata,Parcelreply,intflags)throwsRemoteException{dispatch(code,data,reply);returntrue;}/***得到某个指令处理器并调用*/privatevoiddispatch(intcode,Parceldata,Parcelreply){Log.i(LOG_TAG,"dispatchreplyenter");Callbackcallback=mCallbacks.get(code);if(callback!=null){callback.onTransact(code,data,reply);}Log.i(LOG_TAG,"dispatchreplyexit");}@OverridepublicIBinderasBinder(){returnthis;}@OverridepublicStringgetInterfaceDescriptor(){returnDESCRIPTOR;}@OverridepublicIInterfacequeryLocalInterface(Stringdescriptor){returnthis;}/***针对某一个指令,如:请求指令集{@linkCmdCode.Request},响应指令集{@linkCmdCode.Response}*添加回调处理*@paramcode指令编码*@paramcallback针对某一个指定的处理{@linkCallback}*/publicvoidaddCallback(intcode,Callbackcallback){mCallbacks.put(code,callback);}publicvoidremoveCallback(intcode){mCallbacks.remove(code);}}
packagedw.test;/***定义指令集*/publicinterfaceCmdCode{publicinterfaceBaseCode{/***每个parcel的头*/publicstaticfinalintPARCEL_HEAD=0xffff;publicstaticfinalintRESULT_SUCCESS=0x0001;publicstaticfinalintRESULT_ERROR=0x0002;}/***请求指令集*/publicinterfaceRequestextendsBaseCode{publicstaticfinalintREQUEST=0x0001;}/***响应指令集*/publicinterfaceResponseextendsBaseCode{publicstaticfinalintRESPONSE=0x0001;}}
packagedw.test;importdw.test.CmdDispatcher.Callback;importandroid.app.Service;importandroid.content.Intent;importandroid.os.IBinder;importandroid.os.Parcel;importandroid.util.Log;/***RemoteService作为一个独立进程存在.*/publicclassRemoteCmdServiceextendsServiceimplementsCallback,CmdCode.Request{privatestaticfinalStringLOG_TAG=RemoteCmdService.class.getSimpleName();privatefinalCmdDispatchermCmdDispatcher=newCmdDispatcher();@OverridepublicIBinderonBind(Intentintent){mCmdDispatcher.addCallback(REQUEST,this);returnmCmdDispatcher;}@OverridepublicvoidonCreate(){super.onCreate();}@OverridepublicintonStartCommand(Intentintent,intflags,intstartId){Log.i(LOG_TAG,"onStartCommandenter");returnsuper.onStartCommand(intent,flags,startId);}@OverridepublicbooleanonTransact(intcode,Parceldata,Parcelreply){Log.i(LOG_TAG,"removeservicehandleReplyenter");data.enforceInterface(CmdDispatcher.DESCRIPTOR);//读取包头inthead=data.readInt();if(head==PARCEL_HEAD){StringhandeResult=data.readString();reply.writeInt(RESULT_SUCCESS);Log.i(LOG_TAG,handeResult);}else{reply.writeInt(RESULT_ERROR);}Log.i(LOG_TAG,"removeservicehandleReplyexit");returntrue;}}
packagedw.test.activity;importandroid.app.Activity;importandroid.content.ComponentName;importandroid.content.Intent;importandroid.content.ServiceConnection;importandroid.os.Bundle;importandroid.os.IBinder;importandroid.os.Parcel;importandroid.os.RemoteException;importandroid.util.Log;importandroid.view.View;importandroid.view.View.OnClickListener;importdw.test.CmdCode;importdw.test.CmdDispatcher;importdw.test.R;importdw.test.RemoteCmdService;publicclassMainActivityextendsActivityimplementsOnClickListener,CmdCode.Request,CmdCode.Response{privatestaticfinalStringLOG_TAG=MainActivity.class.getSimpleName();@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);this.findViewById(R.id.test_remote_binder_btn).setOnClickListener(this);}/***连接并调用远程服务*/privatevoidtestRemote(){Intentintent=newIntent(MainActivity.this,RemoteCmdService.class);//绑定远程服务bindService(intent,newServiceConnection(){@OverridepublicvoidonServiceDisconnected(ComponentNamename){}@OverridepublicvoidonServiceConnected(ComponentNamename,IBinderservice){replyTo(service);}},BIND_AUTO_CREATE);}privatevoidreplyTo(IBinderservice){Parceldata=Parcel.obtain();Parcelreply=Parcel.obtain();data.writeInterfaceToken(CmdDispatcher.DESCRIPTOR);//写入包头data.writeInt(PARCEL_HEAD);//写入要发送的字符数据data.writeString("serviceConnected");//当然你也可以传递一个binder对象过去作为callback,这样两个进程间就可以交互了。//data.writeStrongBinder(IBinderbinder);try{//调用远程MESSAGE_REQUEST服务service.transact(REQUEST,data,reply,0);}catch(RemoteExceptione){//ignore}//MESSAGE_REQUEST服务所返回的结果intresult=reply.readInt();if(RESULT_SUCCESS==result){Log.i(LOG_TAG,"ok");}data.recycle();reply.recycle();}@OverridepublicvoidonClick(Viewv){intid=v.getId();if(R.id.test_remote_binder_btn==id){testRemote();}}}
代码工程:http://download.csdn.net/detail/hacker686ok/5810399
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。