Ipc

IPC:

进行进程间的通信,对象数据是需要进行序列化的。序列化方法有:

  1. Serializable接口(java提供的):使用简单,但是序列化的开销大,序列化和反序列化需要大量的I/O操作。
  2. 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
// IBookManager.aidl
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 {
/**
* Local-side IPC implementation stub class.
*/
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";

/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}

/**
* Cast an IBinder object into an com.example.android.findme.IBookManager interface,
* generating a proxy if needed.
*/
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里面还有两个重要方法:

  1. linkToDeath
  2. unlinkToDeath

在Binder发生断裂的时候死亡的时候,linkToDeth方法会收到回调。让客户端知道服务端是否死亡了。

IPC

使用Bundle

优点:简单易用

缺点:只能传输Bundle支持的数据类型

使用场景:四大组件进行进程间的通信

使用文件共享

缺点:不适合高并发场景,并且无法做到进程间的即时通信

场景:无并发访问情景,交换简单的数据,实时性不高的场景

使用Messenger

优点:功能一般,支持一对多串行通信,支持实时通信

缺点:不能很好的处理高并发,不支持rpc,数据通过message进行传输

是对AIDL的封装,主要用来传递Message。不能直接在服务端调用客户端的方法。Messenger是通过Handler来传递消息的。

使用AIDL

功能强大,支持一对多并发通信,支持实时性

缺点:使用复杂,需要处理好线程同步

  1. Messenger对消息的处理是串行的,不支持并行。这里使用还有个知识点就是使用RemoteCallbackList用于删除进程listener的接口。
  2. 权限验证功能:我们的远程服务并不希望任何人都可以连接。
    实现方式:

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
// ICompute.aidl
interface ICompute {
int add(int a,int b);
}
1
2
3
4
5
//ISecurityCenter.aidl
interface ISecurityCenter {
String encrypt(String content);
String decrypy(String password);
}
1
2
3
4
//IBinderPool.aidl
interface IBinderPool {
IBinder queryBinder(int binderCode);
}
1
2
3
4
5
6
7
//ComputeImpl.java
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
//SecurityCenterImpl.java
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
// BinderPoolImpl.java
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
//BinderPoolService.java
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
//BinderPool.java
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)}")
}