Binder是Android中一种跨进程通信方式,还可以理解为一种虚拟的物理设备,它的设备驱动是/dev/binder。
从Framework角度来说,Binder又是ServiceManager连接各种Manager和相应ManagerService的桥梁,从应用层来说,它是客户端和服务端进行通信的媒介,绑定服务的时候服务端会返回一个包含服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据。
一、创建AIDL
//Book.java
package com.qijinfeng.jvm;
import android.os.Parcel;
import android.os.Parcelable;
class Book implements Parcelable {
public int bookId;
public String bookName;
protected Book(Parcel in) {
bookId = in.readInt();
bookName = in.readString();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(bookId);
dest.writeString(bookName);
}
public static final Creator<Book> CREATOR = new Creator<Book>() {
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
}
//Book.aidl
package com.qijinfeng.jvm;
parcelable Book;
//IBookManager.aidl
package com.qijinfeng.jvm;
import com.qijinfeng.jvm.Book;
interface IBookManager {
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,double aDouble, String aString);
List<Book> getBookList();
void adddBook();
}
二、内部方法解析
在build/generated/aidl_source_output_dir/debug/out
目录下会自动生成一个IBookManager.java文件,它继承了IInterface接口。
IBookManager.java里边声明了两个方法getBookList和addBook
public java.util.List<com.qijinfeng.jvm.Book> getBookList() throws android.os.RemoteException;
public void adddBook() throws android.os.RemoteException;
同时声明了两个整型的id,标识两个方法,用于在transact过程中判断客户端发送请求的到底是哪个方法。
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_adddBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
声明了一个内部类Stub,是一个Binder派生类,客户端和服务端都位于同一个进程时,方法不会走跨进程transact过程,而当连着处于不同的进程,就会走transact过程,这个邮它的内部类Proxy来完成。
public static abstract class Stub extends android.os.Binder implements com.qijinfeng.jvm.IBookManager
{
private static class Proxy implements com.qijinfeng.jvm.IBookManager
{
}
}
1.DESCRIPTOR
Binder的唯一标识,一般用单签Binder的类名标识。
private static final java.lang.String DESCRIPTOR = "com.qijinfeng.jvm.IBookManager";
2.asInterface(android.os.IBinder obj)
用户将服务端的Binder对象转换陈客户端所需的AIDL对象,这种转换是区分进程的,同一进程返回的是服务端的Stub对象本身,否则是系统封装后的Stub.proxy对象。
3.asBinder()
返回当前的Binder对象。
4.onTransact
这个方法运行于服务端的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由次方法来处理。参数code确定客户端的请求目标方法,参数data存放数据,请求完成后,reply中写入返回值,onTransact如果返回false,客户端会请求失败,可以用这个特性来做权限验证。
5.Proxy#getBookList和Proxy#addBook
这个方法运行在客户端,当客户端远程调用次方法时。
- 先创建方法需要的输入性Parcel对象_data,输出型Parcel对象_reply和返回对象
- 然后把该方法的参数信息写书_data
- 调用transact方法发起RPC请求,同时线程挂起
- 服务器会调用onTransact方法
- 直到RPC请求返回,当前线程继续执行
- 从_reply中取出RPC的返回结果,最后返回reply中的数据。
6.linkToDeath和unlinkToDeath
Binder运行于服务端,可能由于某种原因异常终止,这个时候我们到服务端的Binder连接已经断裂。会导致调用远程失败,客户端功能受到影响。
Binder中提供linkToDeath和unlinkToDeath方法,通过linkToDeath给Binder设置死亡代理,当Binder死亡时,我们会收到用纸,就可以重新发起连接请求,从而恢复连接。
class MainActivity2 : AppCompatActivity() {
var mIBookManager: IBookManager? = null
val mConn = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
mIBookManager = IBookManager.Stub.asInterface(service);
try {
service!!.linkToDeath(mDeathRecipient!!, 0);
} catch (e: RemoteException) {
e.printStackTrace()
}
}
override fun onServiceDisconnected(name: ComponentName?) {
}
}
var mDeathRecipient: IBinder.DeathRecipient? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
mDeathRecipient = IBinder.DeathRecipient {
if (mIBookManager == null)
return@DeathRecipient
mIBookManager!!.asBinder().unlinkToDeath(mDeathRecipient!!, 0);
mIBookManager = null
val intent = Intent(this, BookService::class.java)
bindService(intent, mConn, AppCompatActivity.BIND_AUTO_CREATE);
}
val intent = Intent(this, BookService::class.java)
bindService(intent, mConn, BIND_AUTO_CREATE);
}
override fun onDestroy() {
unbindService(mConn)
super.onDestroy()
}
三、Binder连接池
Binder连接池的主要作用是将每个业务模块请求统一发到远程Service中去执行,从而避免重复创建Service的过程。
image.png
1.创建两个或者多个AIDL接口
ISecurityCenter.aidl
interface ISecurityCenter {
String encrypt(String content);
String decrypt(String password);
}
IComputer .aidl
interface IComputer {
int add(int a,int b);
}
2.实现AIDL接口
SecurityCenterImpl.java
public class SecurityCenterImpl extends ISecurityCenter.Stub {
private static final 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 encrypt(password);
}
}
ComputerImpl.java
public class ComputerImpl extends IComputer.Stub {
@Override
public int add(int a, int b) throws RemoteException {
return a + b;
}
}
3.创建Binder连接池AIDL
interface IBinderPool {
IBinder queryBinder(int binderCode);
}
4.创建Service
class BinderPoolService : Service() {
private val mBinderPool = BinderPool.BinderPoolImpl()
override fun onBind(intent: Intent?): IBinder? {
return mBinderPool
}
}
Binder连接池实现
public class BinderPool {
public static final int BINDER_NONE = -1;
public static final int BINDER_COMPUTE = 0;
public static final int BINDER_SECURITY_CENTER = 1;
private Context mContext;
private IBinderPool mBinderPool;
private static volatile BinderPool mInstance;
private CountDownLatch mConnectBinderPoolCountDownLatch;
private BinderPool(Context context) {
mContext = context.getApplicationContext();
connectBinderPoolService();
}
public static BinderPool getInstance(Context context) {
if (mInstance == null) {
synchronized (BinderPool.class) {
if (mInstance == null) {
mInstance = new BinderPool(context);
}
}
}
return mInstance;
}
private synchronized void connectBinderPoolService() {
mConnectBinderPoolCountDownLatch = new CountDownLatch(1);
Intent intent = new Intent(mContext, BinderPoolService.class);
mContext.bindService(intent, mBindPoolConnection, Context.BIND_AUTO_CREATE);
try {
mConnectBinderPoolCountDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public IBinder queryBinder(int binderCode) {
IBinder binder = null;
if (mBinderPool != null) {
try {
binder = mBinderPool.queryBinder(binderCode);
} catch (RemoteException e) {
e.printStackTrace();
}
}
return binder;
}
private ServiceConnection mBindPoolConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBinderPool = IBinderPool.Stub.asInterface(service);
try {
mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
mConnectBinderPoolCountDownLatch.countDown();
}
@Override
public void onServiceDisconnected(ComponentName name) {
System.out.println("123456"+name);
}
};
private IBinder.DeathRecipient mBinderPoolDeathRecipient = () -> {
mBinderPool.asBinder().unlinkToDeath(mInstance.mBinderPoolDeathRecipient, 0);
mBinderPool = null;
connectBinderPoolService();
};
public static class BinderPoolImpl extends IBinderPool.Stub {
public BinderPoolImpl(){
super();
}
@Override
public IBinder queryBinder(int binderCode) {
IBinder binder = null;
switch (binderCode) {
case BINDER_SECURITY_CENTER:
binder = new SecurityCenterImpl();
break;
case BINDER_COMPUTE:
binder = new ComputerImpl();
break;
default:
break;
}
return binder;
}
}
}
首先去绑定服务,绑定服务后,客户端可以通过它的queryBinder方法区获取各自对应的Binder。
通过CountDownLatch将bindService这一异步的操作转换成同步操作。Binder的调用过程可能是耗时的,因此不建议在主线程执行。
BinderPool可以方便日常AIDL的开发,如果需要添加新的AIDL,只需要实现自己的AIDL之后,把BinderPoolImpl中的queeyBinder方法进行修改,添加一个新的binderCode并返回对应的Binder对象即可。
网友评论