本文主要从进程间大致通信原理来讲,能力有限,本着对学术认真负责的态度,如有偏差,欢迎留言纠正。
在讲解Binder前先了解以下知识
(1)IBinder 接口: 实现了该接口表示具有跨进程通信能力。Binder就实现了IBinder。
(2)IInterface:通信的功能,就是AIDL中定义的接口。
(3)ServiceManager 存储服务。
(4)Binder驱动: 是通信的核心,负责进程间Binder的建立,通信,以及进程间数据的传递。
1:Binder是一种进程间通信机制( IPC)。Android系统是Linux内核,Linux 提供的 IPC通信方式有,Socket,管道、消息队列、共享内存。而Socket效率低,管道、消息队列则发送数据到接受数据需要拷贝2次。共享内存比较难以控制。所以采用了Binder。
2:Binder采用采用内存映射机制,在发送数据进程到接受数据进程,数据只需要拷贝一次,及copy_from_user到Binder驱动。
3:内存映射。将server进程内存映射到内核空间,对内核空间server的操作,相当于操作server进程。这样在单次通信,数据只需要从客户端进程将数据拷贝到共享内核空间一次。而server进程对客户端数据操作,则反映在内核空间,操作完数据,则将内核空间将数据拷贝到客户端进程。
下面使用AIDL实现跨进程间的简单通信
1:客户端与服务端需要建立相同的AIDL路径与名称。
interface IMyAidlInterface { void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString); int sum(int a,int b); }
2:AndroidStudio会自动生成IMyAidlInterface.java文件
以下是生成的Java代码:
public interface IMyAidlInterface extends android.os.IInterface { //Stub是IMyAidlInterface内部抽象类 public static abstract class Stub extends android.os.Binder implements comy.server.IMyAidlInterface { private static final java.lang.String DESCRIPTOR = "comy.server.IMyAidlInterface"; public Stub() { this.attachInterface(this, DESCRIPTOR); } //该方法表示如果是当前进程的Binder,则直接返回当前进程的IMyAidlInterface,否则创建Proxy代理返回 public static comy.server.IMyAidlInterface asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof comy.server.IMyAidlInterface))) { return ((comy.server.IMyAidlInterface) iin); } return new comy.server.IMyAidlInterface.Stub.Proxy(obj);//返回IMyAidlInterface代理 } @Override public android.os.IBinder asBinder() { return this; } /** * 该方法在客户端调用transact后,会回调该方法 * @param code 方法标识,对应IMyAidlInterface中的方法 * @param data * @param reply * @param flags * @return * @throws android.os.RemoteException */ @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { java.lang.String descriptor = DESCRIPTOR; switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(descriptor); return true; } case TRANSACTION_basicTypes: { data.enforceInterface(descriptor); int _arg0; _arg0 = data.readInt(); long _arg1; _arg1 = data.readLong(); boolean _arg2; _arg2 = (0 != data.readInt()); float _arg3; _arg3 = data.readFloat(); double _arg4; _arg4 = data.readDouble(); java.lang.String _arg5; _arg5 = data.readString(); this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5); reply.writeNoException(); return true; } case TRANSACTION_sum: { data.enforceInterface(descriptor); int _arg0; _arg0 = data.readInt(); int _arg1; _arg1 = data.readInt(); int _result = this.sum(_arg0, _arg1);//调用IMyAidlInterface实现类MyService中的sum方法 reply.writeNoException(); reply.writeInt(_result); //将计算接口写到到本地,内存映射到内核空间 return true; } default: { return super.onTransact(code, data, reply, flags); } } } //当走到该类,则说明不是当前进程Binder private static class Proxy implements comy.server.IMyAidlInterface { 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 void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) 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.writeInt(anInt); _data.writeLong(aLong); _data.writeInt(((aBoolean) ? (1) : (0))); _data.writeFloat(aFloat); _data.writeDouble(aDouble); _data.writeString(aString); mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } / @Override public int sum(int a, int b) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(a); _data.writeInt(b); //调用server进程,将数据拷贝到内核空间,此时Binder只是server进程的代理对象。 mRemote.transact(Stub.TRANSACTION_sum, _data, _reply, 0); _reply.readException(); //读取计算结果,从内核空间拷贝来的数据。 _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } //返回结果 return _result; } } static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_sum = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); } public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException; public int sum(int a, int b) throws android.os.RemoteException; }
3:以下是Client进程代码
public class MainActivity extends AppCompatActivity { String action = "comy.server.IMyAidlInterface"; IMyAidlInterface iMyAidlInterface; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(getApplicationContext(), IMyAidlInterface.class); intent.setAction(action); intent.setComponent(new ComponentName("comy.server", "comy.server.MyService")); bindService(intent, conn, BIND_AUTO_CREATE); } private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { iMyAidlInterface = IMyAidlInterface.Stub.asInterface(iBinder); try { int data = iMyAidlInterface.sum(5, 6); Log.e(":MainActivity:", ":onServiceConnected: = " + data); } catch (Exception e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName componentName) { } }; @Override protected void onDestroy() { super.onDestroy(); unbindService(conn); } }
4:以下是server进程代码
public class MainActivity extends AppCompatActivity { String action = "comy.server.IMyAidlInterface"; Intent intent; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); intent = new Intent(getApplicationContext(), MyService.class); intent.setAction(action); intent.setComponent(new ComponentName("comy.server", "comy.server.MyService")); startService(intent); } @Override protected void onDestroy() { super.onDestroy(); stopService(intent); } }
public class MyService extends Service { IMyAidlInterface.Stub binderStub = new IMyAidlInterface.Stub() { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } @Override public int sum(int a, int b) throws RemoteException { return a + b; } }; @Override public IBinder onBind(Intent intent) { Log.e(":MyService:",":onBind: [*********]="); return binderStub; } }
在AndroidManifest注册MyService
<service android:name="comy.server.MyService" android:enabled="true" android:exported="true"> </service>
此时就可以实现跨进程通信,当客户端调用 iMyAidlInterface.sum(5, 6);时,此时客户端进程被挂起,知道server进程处理结束后才被唤醒,也就是说,使用Binder实现跨进程通信则是进程间同步的。