IPC:
进行进程间的通信,对象数据是需要进行序列化的。序列化方法有:
Serializable接口(java提供的):使用简单,但是序列化的开销大,序列化和反序列化需要大量的I/O操作。
Parcelable接口(android提供的):使用麻烦点,但是效率高。
Binder
Binder就是一个类,一个实现接口IBinder接口的类。Binder是ServiceManager连接各种Manager(ActivityManager,WindowManager)和相应ManagerSerivce的桥梁。从Android应用层来说,Binder是客户端和服务端进行通信的媒介。
目前已知,在Android里面Binder主要用在Service中,包括AIDL和Messenger。
所有可以在Binder中传输的接口都需要继承接口IInterface接口。比如在使用AIDL的时候,我们新建如下:
1 2 3 4 5 interface IBookManager { List<String> getBookList () ; void addBook (String book) ; }
然后你再build一下,会在build文件里面生成类IBookManager.java类:乍一看很复杂其实很简单。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 public interface IBookManager extends android .os .IInterface { public static abstract class Stub extends android .os .Binder implements com .example .android .findme .IBookManager { private static final java.lang.String DESCRIPTOR = "com.example.android.findme.IBookManager" ; public Stub () { this .attachInterface(this , DESCRIPTOR); } public static com.example.android.findme.IBookManager asInterface (android.os.IBinder obj) { if ((obj == null )) { return null ; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null ) && (iin instanceof com.example.android.findme.IBookManager))) { return ((com.example.android.findme.IBookManager) iin); } return new com.example.android.findme.IBookManager.Stub.Proxy(obj); } @Override public android.os.IBinder asBinder () { return this ; } @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_getBookList: { data.enforceInterface(descriptor); java.util.List<java.lang.String> _result = this .getBookList(); reply.writeNoException(); reply.writeStringList(_result); return true ; } case TRANSACTION_addBook: { data.enforceInterface(descriptor); java.lang.String _arg0; _arg0 = data.readString(); this .addBook(_arg0); reply.writeNoException(); return true ; } default : { return super .onTransact(code, data, reply, flags); } } } private static class Proxy implements com .example .android .findme .IBookManager { 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 java.util.List<java.lang.String> getBookList() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.util.List<java.lang.String> _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0 ); _reply.readException(); _result = _reply.createStringArrayList(); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public void addBook (java.lang.String book) 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.writeString(book); mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0 ); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } } static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0 ); static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1 ); } public java.util.List<java.lang.String> getBookList() throws android.os.RemoteException; public void addBook (java.lang.String book) throws android.os.RemoteException ; }
首先他声明了两个方法,getBookList和addBook,很显然就是我们在IBookManager.aidl中声明的方法,然后还声明了两个id,分别对应这两个方法。然后就是申明了一个内部类Stub继承Binder。
从上面的分析看来。我们其实可以不用生命adil文件就可以实现Binder。之所以android提供这个aidl文件,其实是帮助我们生成代码。
**asInterface(IBinder obj)**: 用于将服务端的Binder对象转换成客户端所需要的aidl接口类的对象。如果客户端和服务端属于同一个进程,那么此方法返回的就是服务端的Stub对象本身,否则返回是系统封装后的Stub.proxy对象。
asBinder : 此方法返回当前Binder对象。
Binder里面还有两个重要方法:
linkToDeath
unlinkToDeath
在Binder发生断裂的时候死亡的时候,linkToDeth方法会收到回调。让客户端知道服务端是否死亡了。
IPC
使用Bundle
优点:简单易用
缺点:只能传输Bundle支持的数据类型
使用场景:四大组件进行进程间的通信
使用文件共享
缺点:不适合高并发场景,并且无法做到进程间的即时通信
场景:无并发访问情景,交换简单的数据,实时性不高的场景
使用Messenger
优点:功能一般,支持一对多串行通信,支持实时通信
缺点:不能很好的处理高并发,不支持rpc,数据通过message进行传输
是对AIDL的封装,主要用来传递Message。不能直接在服务端调用客户端的方法。Messenger是通过Handler来传递消息的。
使用AIDL
功能强大,支持一对多并发通信,支持实时性
缺点:使用复杂,需要处理好线程同步
Messenger对消息的处理是串行的,不支持并行。这里使用还有个知识点就是使用RemoteCallbackList用于删除进程listener的接口。
权限验证功能:我们的远程服务并不希望任何人都可以连接。 实现方式:
1.1 在onBind中进行验证: 首先在AndroidMenifest里面申明权限:
1 2 3 <permission android:name="com.tgf.ds.permission.ACCESS_BOOK_SERVICE" android:protectionLevel="normal"/>
然后在obBind里面进行验证:
1 2 3 4 5 6 7 public onBind(Intent intent){ int chek = checkCallingOrSelfPermission("com.tgf.ds.permission.ACCESS_BOOK_SERVICE"); if(chek == PackageManager.PERMISSION_DENIED){ return null; } return mBinder; }
1.2 在服务端的onTranscat方法进行验证。如果验证失败就直接返回false。
使用ContentProvider
优点:在数据访问方面功能强大,支持一对多并发数据共享,可通过call进行方法扩展操作
缺点:受约束的aidl
他是专门用于不用应用间数据共享的方式。
使用socket
Binder连接池
当有10个aidl需要进行进程间的通信,那应该怎么处理,总不能新建10个服务一次进行绑定吧。我们需要将所有的aidl放在一个service里面去处理。这是实现好的demo:
1 2 3 4 interface ICompute { int add (int a,int b) ; }
1 2 3 4 5 interface ISecurityCenter { String encrypt (String content) ; String decrypy (String password) ; }
1 2 3 4 interface IBinderPool { IBinder queryBinder (int binderCode) ; }
1 2 3 4 5 6 7 public class ComputeImpl extends ICompute .Stub { @Override public int add (int a, int b) throws RemoteException { return a+b; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class SecurityCenterImpl extends ISecurityCenter .Stub { private static final char SECREPT_CODE = '^' ; @Override public String encrypt (String content) throws RemoteException { char [] chars = content.toCharArray(); for (int i=0 ;i<chars.length;i++){ chars[i]^=SECREPT_CODE; } return new String(chars); } @Override public String decrypy (String password) throws RemoteException { return encrypt(password); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class BinderPoolImpl extends IBinderPool .Stub { @Override public IBinder queryBinder (int binderCode) throws RemoteException { IBinder binder = null ; switch (binderCode) { case BinderPool.BINDER_SECURITY_CENTER: binder = new SecurityCenterImpl(); break ; case BinderPool.BINDER_COMPUTER: binder = new ComputeImpl(); break ; default : break ; } return binder; } }
1 2 3 4 5 6 7 8 9 10 public class BinderPoolService extends Service { private static final String TAG = "BinderPoolService" ; private Binder mBinderPool = new BinderPoolImpl(); @Nullable @Override public IBinder onBind (Intent intent) { return mBinderPool; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 public class BinderPool { private static final String TAG = "BinderPool" ; public static final int BINDER_NONE = -1 ; public static final int BINDER_COMPUTER = 0 ; public static final int BINDER_SECURITY_CENTER = 1 ; private Context mContext; private IBinderPool mIBinderPool; private static volatile BinderPool sInstance; private CountDownLatch mConnectBinderPoolCountDownLatch; private BinderPool (Context context) { mContext = context.getApplicationContext(); connectBinderPoolService(); } public static BinderPool getInstance (Context context) { if (sInstance == null ) { synchronized (BinderPool.class) { if (sInstance == null ) { sInstance = new BinderPool(context); } } } return sInstance; } private synchronized void connectBinderPoolService () { mConnectBinderPoolCountDownLatch = new CountDownLatch(1 ); Intent service = new Intent(mContext, BinderPoolService.class); mContext.bindService(service, mBinderPoolConnection, Context.BIND_EXTERNAL_SERVICE); try { mConnectBinderPoolCountDownLatch.await(); } catch (Exception e) { } } public IBinder queryBinder (int binderCode) { IBinder iBinder = null ; if (mIBinderPool != null ) { try { iBinder = mIBinderPool.queryBinder(binderCode); } catch (RemoteException e) { e.printStackTrace(); } } return iBinder; } private ServiceConnection mBinderPoolConnection = new ServiceConnection() { @Override public void onServiceConnected (ComponentName name, IBinder service) { mIBinderPool = IBinderPool.Stub.asInterface(service); try { mIBinderPool.asBinder().linkToDeath(mBinderDeathRecipient, 0 ); } catch (RemoteException e) { e.printStackTrace(); } mConnectBinderPoolCountDownLatch.countDown(); } @Override public void onServiceDisconnected (ComponentName name) { } }; private IBinder.DeathRecipient mBinderDeathRecipient = new IBinder.DeathRecipient() { @Override public void binderDied () { mIBinderPool.asBinder().unlinkToDeath(mBinderDeathRecipient, 0 ); mIBinderPool = null ; connectBinderPoolService(); } }; }
在MainActivity.java进行使用:
1 2 3 4 5 6 7 8 9 10 11 fun dowork () { var binderPool = BinderPool.getInstance(this ) var securityBinder = binderPool.queryBinder(BinderPool.BINDER_SECURITY_CENTER) var mSecurityCenter = SecurityCenterImpl.asInterface(securityBinder) var password = mSecurityCenter.encrypt("Hellp=Android" ) println("encrty:${password} " ) println("dectypt:${mSecurityCenter.decrypy(password)} " ) var computeBinder = binderPool.queryBinder(BinderPool.BINDER_COMPUTER) var mComoute = ComputeImpl.asInterface(computeBinder) println("3+5=${mComoute.add(3 ,5 )} " ) }