欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android IPC---Binder连接池

程序员文章站 2024-03-23 23:29:16
...

工作原理

每个业务模块创建自己的AIDL接口并实现此接口,然后向服务端提供自己的唯一标识和其对应的Binder对象,对于服务端来说,只需要一个Service就可以了,服务端提供一个queryBinder接口,该接口根据业务模块的特征来返回相应的Binder对像,不同的业务模块拿到所需的Binder对象后就可以进行远程方法调用了。

主要作用

将每个业务模块的Binder请求统一转发到远程Service中去执行,从而避免重复创建Service的过程。

Android IPC---Binder连接池

这是不是很像我们在设计模式中见到过的一种的思路呢?

没错,就是我们工厂模式,BinderPool在这里充当工厂。

下面让我们写个demo去理解这个流程:

  • 首先是三个AIDL文件

ISecurityCenter.aidl

package com.example.mybinderpool.aidl;

interface ISecurityCenter{
String encrypt(String content);
String decrypt(String password);
}

ICompute.aidl

package com.example.mybinderpool.aidl;

interface ICompute{
int add(int a,int b);
}

IBinderPool.aidl

package com.example.mybinderpool.aidl;

interface IBinderPool{
IBinder queryBinder(int bindercode);
}

我准备做的事情有两件,跨进程的计算加法以及跨进程的加密字符串,接着用IBinderPool这个AIDL去管理它们。

  • 接下来是头两个AIDL的实现:

文件 ISecurityImpl.java

public class ISecurityImpl extends ISecurityCenter.Stub{
private static char SECRET_CODE= '^';

@Override
public String encrypt(String content) throws RemoteException {
char[] chars = content.toCharArray();
for(int i = 0;i < chars.length;i++){
chars[i] ^= SECRET_CODE;
}
return new String(chars);
}

@Override
public String decrypt(String password) throws RemoteException {
return password;
}

}

文件IComputeImpl.java

public class IComputeImpl extends ICompute.Stub{

@Override
public int add(int a, int b) throws RemoteException {
return a + b;
}

}

接下来是BinderPoolService.java的实现

public class BinderPoolService extends Service {

private static final String TAG = "BinderPoolService";

private Binder mBinderPool = new BinderPool.BinderPoolImpl();

@Override
public void onCreate(){
super.onCreate();
}

@Override
public void onDestroy(){
super.onDestroy();
}


@Override
public IBinder onBind(Intent arg0) {
return mBinderPool;
}

}

上面三段源码需要解释并不多,十分简单,要注意的是我们在Service中调用的Binder是指BinderPool中BinderPoolImpl,这个内部类实际上就是返回查询之后的Binder。

  • 接下来才是重点,BinderPool的实现:
public class BinderPool {
private static final String TAG = "BinderPool";
public static final int BINDER_NONE = -1;
public static final int BINDER_COMPUTE = 0;
public static final int BINDER_SECURITY = 1;

private Context context;
private IBinderPool mBinderPool;
private static volatile BinderPool sInstance;
private CountDownLatch mConnectBinderPoolCountDownLatch;

private BinderPool(Context context){
this.context = context.getApplicationContext();
connectBinderPoolService();
}
//这里是单例模式,保证只有一个BinderPool
public static BinderPool getInstance(Context context){
if(sInstance == null){
synchronized (BinderPool.class) {
if(sInstance == null){
sInstance = new BinderPool(context);
}
}
}
return sInstance;
}

//这里synchronized的关键字是因为,这个行为可能是并发,进程,防止共享资源出现冲突。
private synchronized void connectBinderPoolService() {
mConnectBinderPoolCountDownLatch = new CountDownLatch(1);
Intent service = new Intent(context,BinderPoolService.class);
context.bindService(service, mBinderConnection, Context.BIND_AUTO_CREATE);
try {
mConnectBinderPoolCountDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

//调用内部类里面查询Binder的方法
public IBinder queryBinder(int binderCode){
IBinder binder = null;
try {
if(mBinderPool == null){
binder = mBinderPool.queryBinder(binderCode);
}
} catch (RemoteException e) {
e.printStackTrace();
}
return binder;
}

//实现ServiceConnection来绑定Service
private ServiceConnection mBinderConnection = new ServiceConnection() {

@Override
public void onServiceDisconnected(ComponentName arg0) {

}

@Override
public void onServiceConnected(ComponentName classname, IBinder service) {
mBinderPool = IBinderPool.Stub.asInterface(service);
try{
//回调BinderDied方法,为的是给BinderPool设置死亡代理
mBinderPool.asBinder().linkToDeath(mBinderPoolDeath, 0);
}catch(RemoteException e){
e.printStackTrace();
}
mConnectBinderPoolCountDownLatch.countDown();

}
};

private IBinder.DeathRecipient mBinderPoolDeath = new IBinder.DeathRecipient() {

@Override
public void binderDied() {
//BinderPool断开后重新连接并且重新绑定
mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeath, 0);
mBinderPool = null;
connectBinderPoolService();
}
};

public static class BinderPoolImpl extends IBinderPool.Stub{

public BinderPoolImpl(){
super();
}


//实现了IBinderPool.Stub中查询功能
@Override
public IBinder queryBinder(int bindercode) throws RemoteException {
IBinder binder = null;
switch (bindercode) {
case BINDER_SECURITY:
binder = new ISecurityImpl();
break;

case BINDER_COMPUTE:
binder = new IComputeImpl();
break;
default:
break;
}

return binder;
}

}


}

Binder连接池的核心代码就在这里。

让我稍微的解析一下:

首先,我们必须保证BinderPool必须是单例,由于远程通信可能是并发的,如果声明两个BinderPool去同时访问同一个资源,这样整个过程不可控。为此我们使用了单例模式。

private synchronized void connectBinderPoolService(){
mConnectBinderPoolCountDownLatch = new CountDownLatch(1);
Intent service = new Intent(context,BinderPoolService.class);
context.bindService(service, mBinderConnection, Context.BIND_AUTO_CREATE);
try {
mConnectBinderPoolCountDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

private ServiceConnection mBinderConnection = new ServiceConnection() {

@Override
public void onServiceDisconnected(ComponentName arg0) {

}

@Override
public void onServiceConnected(ComponentName classname, IBinder service) {
mBinderPool = IBinderPool.Stub.asInterface(service);
try{
//回调BinderDied方法,为的是给BinderPool设置死亡代理
mBinderPool.asBinder().linkToDeath(mBinderPoolDeath, 0);
}catch(RemoteException e){
e.printStackTrace();
}
mConnectBinderPoolCountDownLatch.countDown();

}
};

private IBinder.DeathRecipient mBinderPoolDeath = new IBinder.DeathRecipient() {

@Override
public void binderDied() {
//BinderPool断开后重新连接并且重新绑定
mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeath, 0);
mBinderPool = null;
connectBinderPoolService();
}
};

上面这一段,是为了防止访问共享资源冲突做出的方案。首先使用synchronized将这个方法上锁,这个时候这个对象的其他synchronized方法只能等到前一个方法调用完毕并释放锁之后才能被调用。

而CountDownLatch这个构建是Java同步多个或一个任务,强制他们等待由其他任务执行的一组操作执行。

countdown的方法是每一次调用,声明在构造器里的计数减一,到0之后释放所有等待任务。

await方法则是,当调用counDown()的任务在产生这个调用时没有被阻塞,只有await的调用会被调用,直到计数变为0。

清楚这两个方法是怎么回事之后,就能明白其实就是为了每执行一个任务的时候,另一个任务暂停,当执行完当前任务,才继续执行。

接下来是MainActivity.java

public class MainActivity extends Activity {
private static final String TAG = "BinderPoolActivity";

private ISecurityCenter mSecurityCenter;
private ICompute mCompute;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new Runnable() {

@Override
public void run() {
dowork();
}
}).start();

}

private void dowork() {
BinderPool binderPool = BinderPool.getInstance(MainActivity.this);
IBinder securityBinder = binderPool.queryBinder(BinderPool.BINDER_SECURITY_CENTER);
mSecurityCenter = (ISecurityCenter) ISecurityCenterImpl.asInterface(securityBinder);
Log.e(TAG, "VISIT SECURITY");
String msg = "helloworld";
Log.e(TAG, msg);

try{
String password = mSecurityCenter.encrypt(msg);
Log.e("encrypt",password);
Log.e("decrypt", mSecurityCenter.decrypt(password));
}catch(RemoteException e){
e.printStackTrace();
}

IBinder computeBinder = binderPool.queryBinder(BinderPool.BINDER_COMPUTE);
mCompute = IComputeImpl.asInterface(computeBinder);
try{

Log.e("3+5=", Integer.toString(mCompute.add(3, 5)));
}catch(RemoteException e){
e.printStackTrace();
}
}


}

像这种耗时的工作最好放在子线程中完成更好,到这里Binder连接池就分析完成。