在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,请看以下代码。
package dw.test; import java.util.HashMap; import android.os.Binder; import android.os.IBinder; import android.os.IInterface; import android.os.Parcel; import android.os.RemoteException; import android.util.Log; /** * 负责接收指令({@link CmdCode}),并将指令派发到相应的处理器({@link CmdDispatcher.Callback}) */ public final class CmdDispatcher extends Binder implements IInterface{ private static final String LOG_TAG = CmdDispatcher.class.getSimpleName(); public static final String DESCRIPTOR = CmdDispatcher.class.getName(); /** * 存储所有指令处理器 * map.key = {@link CmdCode} */ private HashMap<Integer,Callback> mCallbacks = new HashMap<Integer, Callback>(); /** * 针对某个指令的处理 * @see #addCallback * @see #removeCallback */ public interface Callback { /** * @param code 请求指令集{@link CmdCode.Request},响应 指令集{@link CmdCode.Response} * @param data 数据 {@link Parcel} * @param reply 处理data的结果 {@link Parcel} * @return */ public boolean onTransact(int code, Parcel data, Parcel reply); } /** * 当client端调用 {@link IBinder#transact(int, Parcel, Parcel, int)}时,将会回调本方法。 */ @Override protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { dispatch(code,data,reply); return true; } /** * 得到某个指令处理器并调用 */ private void dispatch(int code, Parcel data, Parcel reply) { Log.i(LOG_TAG, "dispatch reply enter"); Callback callback = mCallbacks.get(code); if(callback!=null){ callback.onTransact(code, data, reply); } Log.i(LOG_TAG, "dispatch reply exit"); } @Override public IBinder asBinder() { return this; } @Override public String getInterfaceDescriptor() { return DESCRIPTOR; } @Override public IInterface queryLocalInterface(String descriptor) { return this; } /** * 针对某一个指令,如:请求指令集{@link CmdCode.Request},响应 指令集{@link CmdCode.Response} * 添加回调处理 * @param code 指令编码 * @param callback 针对某一个指定的处理 {@link Callback} */ public void addCallback(int code,Callback callback) { mCallbacks.put(code, callback); } public void removeCallback(int code) { mCallbacks.remove(code); } }
package dw.test; /** * 定义指令集 */ public interface CmdCode { public interface BaseCode { /** * 每个parcel的头 */ public static final int PARCEL_HEAD = 0xffff; public static final int RESULT_SUCCESS = 0x0001; public static final int RESULT_ERROR = 0x0002; } /** * 请求指令集 */ public interface Request extends BaseCode{ public static final int REQUEST = 0x0001; } /** * 响应指令集 */ public interface Response extends BaseCode { public static final int RESPONSE = 0x0001; } }
package dw.test; import dw.test.CmdDispatcher.Callback; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.Parcel; import android.util.Log; /** * RemoteService作为一个独立进程存在. */ public class RemoteCmdService extends Service implements Callback,CmdCode.Request{ private static final String LOG_TAG = RemoteCmdService.class.getSimpleName(); private final CmdDispatcher mCmdDispatcher = new CmdDispatcher(); @Override public IBinder onBind(Intent intent) { mCmdDispatcher.addCallback(REQUEST, this); return mCmdDispatcher; } @Override public void onCreate() { super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(LOG_TAG, "onStartCommand enter"); return super.onStartCommand(intent, flags, startId); } @Override public boolean onTransact(int code, Parcel data, Parcel reply) { Log.i(LOG_TAG, "remove service handle Reply enter"); data.enforceInterface(CmdDispatcher.DESCRIPTOR); //读取包头 int head = data.readInt(); if(head==PARCEL_HEAD) { String handeResult = data.readString(); reply.writeInt(RESULT_SUCCESS); Log.i(LOG_TAG, handeResult); } else { reply.writeInt(RESULT_ERROR); } Log.i(LOG_TAG, "remove service handle Reply exit"); return true; } }
package dw.test.activity; import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.Parcel; import android.os.RemoteException; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import dw.test.CmdCode; import dw.test.CmdDispatcher; import dw.test.R; import dw.test.RemoteCmdService; public class MainActivity extends Activity implements OnClickListener , CmdCode.Request,CmdCode.Response{ private static final String LOG_TAG = MainActivity.class.getSimpleName(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); this.findViewById(R.id.test_remote_binder_btn).setOnClickListener(this); } /** * 连接并调用远程服务 */ private void testRemote(){ Intent intent = new Intent(MainActivity.this,RemoteCmdService.class); //绑定远程服务 bindService(intent, new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { } @Override public void onServiceConnected(ComponentName name, IBinder service) { replyTo(service); } }, BIND_AUTO_CREATE); } private void replyTo(IBinder service) { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(CmdDispatcher.DESCRIPTOR); //写入包头 data.writeInt(PARCEL_HEAD); //写入要发送的字符数据 data.writeString("serviceConnected"); //当然你也可以传递一个binder对象过去作为callback,这样两个进程间就可以交互了。 // data.writeStrongBinder(IBinder binder); try { //调用远程MESSAGE_REQUEST服务 service.transact(REQUEST, data, reply,0); } catch (RemoteException e) { //ignore } //MESSAGE_REQUEST服务所返回的结果 int result = reply.readInt(); if(RESULT_SUCCESS==result) { Log.i(LOG_TAG, "ok"); } data.recycle(); reply.recycle(); } @Override public void onClick(View v) { int id = v.getId(); if(R.id.test_remote_binder_btn==id){ testRemote(); } } }
代码工程:http://download.csdn.net/detail/hacker686ok/5810399
Android中非aidl实现进程间通信(编写顺序的parcel写入与读出)
原文地址:http://xwteacher.blog.51cto.com/9653444/1584549