作者:apigfly
如何使用 Binder
就开发语言而言,Binder服务
可以用Java
实现,也可以用C++
实现,通常,我们在Java
代码中调用Java
语言实现的服务,在C++
代码中调用C++
编写的服务。但是从原理上讲,Binder
并没有这种语言平台的限制,混合调用也是可以的。
应用可以在任意的进程和线程中使用Binder服务
的功能,非常方便、灵活。也不用关心同步、死锁等问题
使用Binder服务
C++
层和Java
层使用Binder服务
的方式基本一样,包括函数的接口类型都相同,这里以C++
为例:
-
使用
Binder服务
前要先得到它的引用对象,比如:sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService("serviceName");
-
defaultServiceManager()
用来获得ServiceManager
服务的Binder引用对象
。前面已经说过ServiceManager
的Binder引用对象
是直接用数值0
作为引用号构造出来的 -
sm->getService("media.camera")
是查找注册的Binder服务
,找到后会返回服务的IBinder对象
,否则返回NULL
-
-
返回的
IBinder对象
,其实是Binder引用对象
,但是应用需要使用的是Binder代理对象
,因此需要进行如下转化:ICameraService service = ICameraService.Stub.asInterface(binder)
-
话说这部分应该是Java的转换方式,换成
C++
的版本应该是sp<ICameraService> service = ICameraService::asInterface(binder)
-
-
Binder
中提供了asInterface
方法来完成Binder代理对象
的转换,asInterface
会检查参数中的IBinder对象
的服务类型是否相符,如果不符将返回NULL
。
正常情况下,ServiceManager
进程会在所有应用启动前启动,而且不会停止服务,因此使用defaultServiceManager()
不必检查返回为NULL
的情况,但是对于方法getService()
的返回值需要检查是否为NULL
,因为服务可能不存在或者未启动。
Binder
的混合调用
Binder
是可以混合调用的,在C++
中可以调用Java
实现的Binder服务
,在Java
中也可以调用C++
实现的Binder服务
。
以ActivityManagerService
服务为例,其中定义的方法为
public int checkPermission(String permission, int pid, int uid, int mode);
,我们看下C++
调用的大体流程(有注释哈):
//获取Binder引用对象
sp<Binder> binder = defaultServiceManager()->getService("activity");
//创建Parcel data 放置方法调用是的参数信息
Parcel data = Parcel.obtain();
//创建Parcel reply 接收返回信息
Parcel reply = Parcel.obtain();
//添加接口识别Token
data.writeInterfaceToken("android.app.IActivityManager");
//添加请求的权限、pid、uid、mode等方法调用信息
data.writeString16(permission);
data.writeInt32(pid);
data.writeInt32(uid);
data.writeInt32(mode);
//调用远程函数号为54的远程服务
binder->transact(54, data, &reply, 0);
示例代码中最重要的是54
这个参数,叫做远程函数号
。这个号码在服务端代码中定义,而且随着系统版本不同可能会有所改变,所以示例方法并不是一个很科学和常用的方法,不要学坏哈。只是想说明Binder
很强大。。。
Java层的Binder服务
我们先用组件Service
来回顾一下流程:
首先,编写一个AIDL
文件
interface ICommandService {
void setResult_bool(String cmdid, boolean result);
void setResult_byte(String cmdid, in byte[] resultMsg);
void setResult_string(String cmdid, String resultMsg);
void finishCommand(String cmdid, String param);
}
然后,我们创建一个自定义的Service,然后这样写:
public class CommandService extends Service{
protected final ICommandService.Stub mBinder = new ICommandService.Stub() {
@Override
public void setResult_bool(String cmdid, boolean result) throws RemoteException {
//do something
}
@Override
public void setResult_byte(String cmdid, byte[] resultMsg) throws RemoteException {
//do something
}
@Override
public void setResult_string(String cmdid, String resultMsg) throws RemoteException {
//do something
}
@Override
public void finishCommand(String cmdid, String param) throws RemoteException {
//do something
}
};
@Override
public IBinder onBind(Intent intent) {
//do something
return mBinder;
}
}
ICommandService.Stub
类就是真正的Binder服务类
,它是通过我们前面定义的AIDL
文件自动生成的,不过它是抽象
的,所以我们需要继承并重写自己的业务逻辑。
C++
层的Binder服务
C++
层实现Bidner服务
比较麻烦,主要是没有了AIDL
的辅助,需要我们手动完成中间层的代码。
书中的源码部分看的有些没太看懂,本人从9.0项目源码中找了一份,我们来看下:
温馨提示:下面代码中会出现继承
BnInterface
、IInterface
、BpInterface
的操作,以及DECLARE_META_INTERFACE
和IMPLEMENT_META_INTERFACE
两个宏,这里暂不做详细解释,后面会有Binder应用层的核心类详解。我们暂先理解为:继承BnInterface
为实现服务端功能、继承BpInterface
为实现客户端、继承IInterface
表示定义要提供的服务接口
首先,是一个IImagePlayerService.h
的头文件,定义了:
-
IImagePlayerService
:通过纯虚函数
函数定义计划提供的Binder服务接口 -
BnImagePlayerService
:根据IImagePlayerService
中提供的接口,定义对应的枚举对象;重载onTransact()
虚拟函数
网友评论