如何使用 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)
- 话说这部分应该是Java的转换方式,换成
-
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()
虚拟函数
我们看下代码:
class IImagePlayerService: public IInterface {
public:
DECLARE_META_INTERFACE(ImagePlayerService);
virtual int init() = 0;
virtual int start() = 0;
virtual int release() = 0;
virtual int setTranslate(float tx, float ty) = 0;
};
class BnImagePlayerService: public BnInterface<IImagePlayerService> {
public:
enum {
IMAGE_INIT = IBinder::FIRST_CALL_TRANSACTION,
IMAGE_START,
IMAGE_RELEASE,
IMAGE_SET_TRANSLATE,
};
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags = 0);
};
IImagePlayerService.h
这部分的意思大概是:我们自己的Binder服务要提供哪些功能,先把这部分定义出来。
我们再来看下IImagePlayerService.h
的实现IImagePlayerService.cpp
的内容:
class BpImagePlayerService : public BpInterface<IImagePlayerService> {
public:
BpImagePlayerService(const sp<IBinder>& impl)
: BpInterface<IImagePlayerService>(impl) {
}
virtual int init() {
Parcel data, reply;
data.writeInterfaceToken(IImagePlayerService::getInterfaceDescriptor());
remote()->transact(BnImagePlayerService::IMAGE_INIT, data, &reply);
return NO_ERROR;
}
virtual int start() {
Parcel data, reply;
data.writeInterfaceToken(IImagePlayerService::getInterfaceDescriptor());
remote()->transact(BnImagePlayerService::IMAGE_START, data, &reply);
return NO_ERROR;
}
virtual int release() {
Parcel data, reply;
data.writeInterfaceToken(IImagePlayerService::getInterfaceDescriptor());
remote()->transact(BnImagePlayerService::IMAGE_RELEASE, data, &reply);
return NO_ERROR;
}
virtual int setTranslate(float tx, float ty) {
Parcel data, reply;
data.writeInterfaceToken(IImagePlayerService::getInterfaceDescriptor());
data.writeFloat(tx);
data.writeFloat(ty);
remote()->transact(BnImagePlayerService::IMAGE_SET_TRANSLATE, data, &reply);
return NO_ERROR;
}
};
IMPLEMENT_META_INTERFACE(ImagePlayerService, "droidlogic.IImagePlayerService");
status_t BnImagePlayerService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
switch (code) {
case IMAGE_INIT: {
CHECK_INTERFACE(IImagePlayerService, data, reply);
int result = init();
reply->writeInt32(result);
return NO_ERROR;
}
case IMAGE_START: {
CHECK_INTERFACE(IImagePlayerService, data, reply);
int result = start();
reply->writeInt32(result);
return NO_ERROR;
}
case IMAGE_RELEASE: {
CHECK_INTERFACE(IImagePlayerService, data, reply);
int result = release();
reply->writeInt32(result);
return NO_ERROR;
}
case IMAGE_SET_TRANSLATE: {
CHECK_INTERFACE(IImagePlayerService, data, reply);
int result = setTranslate(data.readFloat(), data.readFloat());
reply->writeInt32(result);
return NO_ERROR;
}
default: {
return BBinder::onTransact(code, data, reply, flags);
}
}
// should be unreachable
return NO_ERROR;
}
IImagePlayerService.cpp
做了这几件事情:
- 实现
BnImagePlayerService
类的onTransact
函数。BnImagePlayerService
类的对象实例会运行在服务进程中onTransact
函数在运行时会被底层的IPCThreadState类调用。- 函数实现比较公式化,根据参数中的函数号来调用对应的函数。
- 函数中的
CHECK_INTERFACE
用来检查Parcel
对象中的数据是否正确- 检查原理是先取出
Parcel
对象中客户端传来的类描述字符串 - 与当前类中定义的字符串比较,相同则正确
- 检查原理是先取出
- 然后按照函数参数的排列顺序取出参数,并使用这些参数调用服务端的函数
- 可以参考
case IMAGE_SET_TRANSLATE
- 可以参考
- 定义
BpImagePlayerService
类。Binder服务
在客户端的接口类BpImagePlayerService
类的对象实例会运行在客户端的进程中- 继承
BpInterface<IImagePlayerService>
- 实现
IImagePlayerService
中定义的纯虚函数
,把函数调用的信息发送给远端data.writeInterfaceToken
把类的描述字符串放到Parcel
中- 通过
remote()
函数得到Binder引用对象
的指针 - 调用
Binder引用对象
的transact()
函数把数据传给底层 IBinder
的transact()
函数其实有4个参数,由于第四个参数flags定义了默认值0,因此调用transact()
常常只使用3个参数。- 如果客户端调用
Binder服务
是不打算等待对方运行结束就继续执行,可以使用TF_ONE_WAY
作为第四个参数以异步的方式调用Binder服务
。这种方式也就意味着无法得到返回值了。
会不会有个疑惑IImagePlayerService.cpp
为什么把这两个类定义在一起来?
- 主要原因是两个类中都是用了相同的函数号码和类的描述字符串。如果分开,需要维护两份,容易失误
到这里和Binde服务
相关的定义就结束了,接下来就是最后一步了,实现我们Binder服务
的业务逻辑了,我们看下ImagePlayerService.h
的头文件定义
class ImagePlayerService : public BnImagePlayerService {
public:
ImagePlayerService();
virtual ~ImagePlayerService();
virtual int init();
virtual int start();
virtual int release();
virtual int setTranslate(float tx, float ty);
};
这里我们需要注意的是继承BnImagePlayerService
。具体函数的实现其实在ImagePlayerService.cpp
完成:
int ImagePlayerService::init() {
//.....
}
//.....省略部分方法
int ImagePlayerService::setTranslate(float tx, float ty) {
//.....
}
书中并没有定义头文件,直接做了服务类的实现。
到这里C++
版本的Binder服务
就完成了,我们看下整体代码结构:
Google的HIDL
不过,上面的这种操作已经过OUT
了,Android 从8.0开始做了架构调整(一个称为Treble
的模式),增加了HIDL
接口定义语言进行HAL层
和应用层的解耦合优化。
HAL 接口定义语言(简称 HIDL,发音为“hide-l”)是用于指定 HAL 和其用户之间的接口的一种接口描述语言 (IDL)。HIDL 允许指定类型和方法调用(会汇集到接口和软件包中)。从更广泛的意义上来说,HIDL 是用于在可以独立编译的代码库之间进行通信的系统。
HIDL 旨在用于进程间通信 (IPC)。进程之间的通信采用 Binder 机制。对于必须与进程相关联的代码库,还可以使用直通模式(在 Java 中不受支持)。
从介绍来看,HIDL
在Binder机制
的基础上增加了一个直通模式
,这部分暂不深入深究哈,当前紧要任务还是看完Binder的核心实现
,官方传送门:HIDL
暂且把它当成和AIDL
一样的接口定义语言就好,只是AIDL
用与Java层
的服务实现,而HIDL
用于C++层
的服务实现。
应用层的核心类
前面我们了解了Binder的使用,都是基于
libbinder
库来实现的,我们看下libbinder
库中的一些核心类,源码位置:frameworks/native/libs/binder
libbinder
库中的IInterface
类、BpInterface
类、BnInterface
类、BBinder
类、BpBinder
类、IBinder
类共同构成了Binder应用层的核心类。
IInterface
类中的两个宏
在
C++层Binder服务实现
中,还有一些知识没有细说,包括IInterface
接口类、BpInterface
模板类、BnInterface
模板类,以及宏DECLARE_META_INTERFACE
和宏IMPLEMENT_META_INTERFACE
。
我们先来看下宏DECLARE_META_INTERFACE
的定义:
#define DECLARE_META_INTERFACE(INTERFACE) \
static const ::android::String16 descriptor; \
static ::android::sp<I##INTERFACE> asInterface( \
const ::android::sp<::android::IBinder>& obj); \
virtual const ::android::String16& getInterfaceDescriptor() const; \
I##INTERFACE(); \
virtual ~I##INTERFACE();
这个宏定义了一些成员变量和方法,在类中使用这个宏就意味着将这些成员变量和方法加入到了这个类中。转换逻辑也比较简单,把##INTERFACE
替换成传入的参数
即可,对于前面的例子,相当于添加了如下代码:
static const ::android::String16 descriptor;
static ::android::sp<IImagePlayerService> asInterface(
const ::android::sp<::android::IBinder>& obj);
virtual const ::android::String16& getInterfaceDescriptor() const;
IImagePlayerService();
virtual ~IImagePlayerService();
这里添加了静态成员变量descriptor
、静态函数asInterface
,以及类构造函数
和析构函数
。可能这些变量和函数是每个Binder服务
必须实现的,为了方便开发,Android把它们定义成了宏。
我们再来看下宏IMPLEMENT_META_INTERFACE
的定义:
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
const ::android::String16 I##INTERFACE::descriptor(NAME); \
const ::android::String16& \
I##INTERFACE::getInterfaceDescriptor() const { \
return I##INTERFACE::descriptor; \
} \
::android::sp<I##INTERFACE> I##INTERFACE::asInterface( \
const ::android::sp<::android::IBinder>& obj) \
{ \
::android::sp<I##INTERFACE> intr; \
if (obj != NULL) { \
intr = static_cast<I##INTERFACE*>( \
obj->queryLocalInterface( \
I##INTERFACE::descriptor).get()); \
if (intr == NULL) { \
intr = new Bp##INTERFACE(obj); \
} \
} \
return intr; \
} \
I##INTERFACE::I##INTERFACE() { } \
I##INTERFACE::~I##INTERFACE() { } \
对于实例代码中的
IMPLEMENT_META_INTERFACE(ImagePlayerService, "droidlogic.IImagePlayerService");
则会转换为:
const ::android::String16 IImagePlayerService::descriptor("droidlogic.IImagePlayerService");
const ::android::String16&
IImagePlayerService::getInterfaceDescriptor() const {
return IImagePlayerService::descriptor;
}
::android::sp<IImagePlayerService> IImagePlayerService::asInterface(
const ::android::sp<::android::IBinder>& obj)
{
::android::sp<IImagePlayerService> intr;
if (obj != NULL) {
intr = static_cast<IImagePlayerService*>(
obj->queryLocalInterface(
IImagePlayerService::descriptor).get());
if (intr == NULL) {
intr = new BpImagePlayerService(obj);
}
}
return intr;
}
IImagePlayerService::IImagePlayerService() { }
IImagePlayerService::~IImagePlayerService() { }
- 变量
descriptor
是一个字符串,用来描述Bidner服务
。在检查客户端传来的参数是否合法时会用到。 - 函数
asInterface
主要用来把Binder引用对象
转换为Binder代理对象
。这个函数很关键,但我们目前还不能看明白,先记住这个方法,我们继续学习核心类。
Binder核心类的关系
我们先来看下核心类的继承关系图:
继承关系中虚线代表了什么?
上图中实线表示的继承关系可以从源码中找到,关键是虚线的继承部分,没有找到明显的继承关系,我们根据示例代码来分析下。
我们看下BnInterface
的定义先:
template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
{
public:
virtual sp<IInterface> queryLocalInterface(const String16& _descriptor);
virtual const String16& getInterfaceDescriptor() const;
protected:
typedef INTERFACE BaseInterface;
virtual IBinder* onAsBinder();
};
这是一个模板类,而在C++
版本Binder服务中,我们的类是这样定义的:
class IImagePlayerService: public IInterface{};
class BnImagePlayerService: public BnInterface<IImagePlayerService>{};
对于模板类BnInterface
,我们使用的时候要给一个INTERFACE
,也就是IImagePlayerService
。
其实很像Java的泛型不是?
我们看到,模板类BnInterface
的定义中,类继承部分是这样写的:
class BnInterface : public INTERFACE, public BBinder
而对于示例代码中的BnInterface<IImagePlayerService>
则意味BnInterface
会把IImagePlayerService
当做INTERFACE
继承,也就转化为
class BnInterface : public IImagePlayerService, public BBinder
而IImagePlayerService
又是继承自IInterface
。
所以模板类BnInterface
最后还是会继承IInterface
,可能这层关系有些隐晦,所以就用虚线表示了。同样BpInterface
也是如此。
一张更容易理解的核心类图
图解一:BpInterface
和 BpBinder
的聚合关系
这张图中,多了一个BpInterface
和BpBinder
的聚合关系,我们通过源码来认识下:
首先是BpInterface
模板类的定义:
template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
{
public:
explicit BpInterface(const sp<IBinder>& remote);
protected:
typedef INTERFACE BaseInterface;
virtual IBinder* onAsBinder();
};
我们这次重点关注的是:
- 显式构造函数
BpInterface(const sp<IBinder>& remote)
- 传入了一个
IBinder
类型的指针,其实就是BpBinder
- 这个指针会在父类
BpRefBase
的构造函数中做一系列的处理 - 很多远程方法调用都是使用这个
BpBinder
- 传入了一个
- 继承类
BpRefBase
- 真正关联
BpBinder
的操作 - 主要成员
mRemote
,一个指向IBinder
的指针 - 定义了
remote()
方法
- 真正关联
我们看下BpRefBase
类的部分信息:
class BpRefBase : public virtual RefBase
{
protected:
explicit BpRefBase(const sp<IBinder>& o);
virtual ~BpRefBase();
//......
inline IBinder* remote() { return mRemote; }
private:
//......
IBinder* const mRemote;
//......
};
图解二:服务端的调用逻辑
BnInterface
类是开发Binder服务必须继承的一个模板类,它继承BBinder
的同时也继承了IInterface
类(这部分的继承逻辑前面已经细讲了哈)。
BBinder
是服务端的核心,实际的函数实现都在BBinder
的继承类中。先看下BBinder
的部分函数定义:
class BBinder : public IBinder
{
public:
//......
virtual const String16& getInterfaceDescriptor() const;
virtual bool isBinderAlive() const;
virtual status_t pingBinder();
virtual status_t dump(int fd, const Vector<String16>& args);
// NOLINTNEXTLINE(google-default-arguments)
virtual status_t transact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0) final;
// NOLINTNEXTLINE(google-default-arguments)
virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
void* cookie = nullptr,
uint32_t flags = 0);
// NOLINTNEXTLINE(google-default-arguments)
virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
void* cookie = nullptr,
uint32_t flags = 0,
wp<DeathRecipient>* outRecipient = nullptr);
//......
};
BBinder
负责和更底层的IPCThread
打交道。但是,当Binder调用
从Binder驱
动传递过来时,IPCThread
会调用BBinder
的transact()
函数,然后transact()
函数会调用继承类的onTransact()
函数。
这部分其实要和IPCThread
结合起来看,先跟着书本走吧,等下返个场,哈哈
图解三:客户端的调用逻辑
BpBinder
类是客户端Binder的核心,也是继承自IBinder
类。我们在图解一
已经说过:BpInterface
类并不是从BpBinder
类继承来的,而是继承自BpRefBase
。BpBinder
和BpInterface
是聚合关系
这么做是主要是为了:
- 使得上层开发更加灵活
Binder
的内部实现和上层应用完全隔离开,用户类完全不知道BpBinder
的存在BpBinder
改动了,用户类不用重新编译也能运行
BpBinder
负责和更底层的IPCThread
打交道。客户端通过remote()->transact(...)
调用IBinder
的transact
虚函数,实际调用的是BpBinder
的transact
函数。transact
函数会调用IPCThread
类的函数来向驱动传递数据。
Binder类继承关系的总结
- 从继承关系上看
IBinder
是BBinder
和BpBinder
的基类。 - 在应用层看见的只是
IBinder
,BBinder
和BpBinder
都藏在后面- 这样在概念上就统一了
- 从
Binder
的使用角度,不用刻意地区分当前对象是实体对象
还是引用对象
- 只要获得
IBinder
对象,就可以使用服务
IBinder
中有两个接口,localBinder
和remoteBinder
,从返回值我们就可以知道他们代表的Binder服务对象
了:virtual BBinder* localBinder();
virtual BpBinder* remoteBinder();
- 对于服务端,
Binder服务
就在本进程中,可以用localBinder
获取IBinder对象,而remoteBinder
则会返回NULL
- 对于客户端,
Binder服务
在其他进程中,可以用remoteBinder
获取IBinder对象,而localBinder
则会返回NULL
- 如果想确定一个IBInder对象到底是
BpBinder
还是BBinder
对象时,通过这两个接口就可以判断
函数asInterface的奥秘
理解了
Binder
核心类关系后,我们再来看下asInterface()
函数
asInterface()
函数就是把Binder引用对象转换成代理对象的关键,asInterface()
函数的宏定义如下:
::android::sp<I##INTERFACE> I##INTERFACE::asInterface( \
const ::android::sp<::android::IBinder>& obj) \
{ \
::android::sp<I##INTERFACE> intr; \
if (obj != nullptr) { \
intr = static_cast<I##INTERFACE*>( \
obj->queryLocalInterface( \
I##INTERFACE::descriptor).get()); \
if (intr == nullptr) { \
intr = new Bp##INTERFACE(obj); \
} \
} \
return intr; \
}
上面代码中变量obj
的类型是IBinder
,但是obj
是参数,它既可能是BpBinder对象
,也可能是BBinder对象
,判断逻辑如下:
- 如果
obj
传入的是一个BpBinder对象
- 在
BpBinder类
中没有重载queryLocalInterface
函数,因此,调用的是其基类IBinder
的函数,直接返回sp<NULL>
- 通过
sp<NULL>.get
结果还是NULL
- 所以
intr
为NULL
- 这样接下来就会new一个Bp##INTERFACE对象
- 在
- 如果
obj
传入的是一个BBinder对象
,在这种情形下,因为继承关系,BBinder对象
同时也会是一个BnInterface对象
,在BnInterface类
中重载了queryLocalInterface
函数,代码如下:template<typename INTERFACE> inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface( const String16& _descriptor) { if (_descriptor == INTERFACE::descriptor) return this; return nullptr; }
- 如果参数传递的描述字符串和类的描述字符串相同,则返回
this
指针,也就是obj
本身 - 否则,返回
NULL
- 如果参数传递的描述字符串和类的描述字符串相同,则返回
asIntreface
函数的作用总结如下:
- 在客户端调用
asInterface
,会创建一个Binder代理对象
,代理对象中包含了Binder引用对象
。 - 在服务端调用
asInterface
,直接返回参数的指针。因为在服务进程中可以直接调用服务类,无需创建Binder代理对象
。
Binder的死亡通知
作为Binder服务
的提供者,Binder实体对象
也会死亡,可能是正常退出,也可能是意外崩溃。一旦实体对象死亡,Binder引用对象
需要有机制来得到通知。
注册接收Binde的死亡通知
IBinder中提供了一个纯虚函数linkToDeath
,定义如下:
virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
void* cookie = nullptr,
uint32_t flags = 0) = 0;
函数具体实现暂不深究,我们看下使用方式:
class HeapCache : public IBinder::DeathRecipient
{
public:
HeapCache(sp<IBinder> binder){
mService=binder
};
virtual void binderDied(const wp<IBinder>& who);
private:
wp<IBinder> mService;
};
void HeapCache::binderDied(const wp<IBinder>& binder)
{
//死亡会调用此方法
}
在继承DeathRecipient
类中需要重载binderDied
函数,当Binder服务死亡时,这个函数会被回调。
linkToDeath
函数会调用IPCThreadState的函数来告诉驱动需要接收某个Binder服务死亡的通知消息,我们看下BpBinder的相关代码:
status_t BpBinder::linkToDeath(
const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
{
//......
IPCThreadState* self = IPCThreadState::self();
self->requestDeathNotification(mHandle, this);
self->flushCommands();
//......
}
发送Binder死亡通知
一旦驱动检测到某个Binder服务
已经死亡,会根据设置向应用层发送消息,IPCThreadState
中检测到死亡消息后,利用保存在消息中的BpBinder
的指针,调用其sendObituary
函数,IPCThreadState.cpp
中代码定义如下:
case BR_DEAD_BINDER:
{
BpBinder *proxy = (BpBinder*)mIn.readPointer();
proxy->sendObituary();
mOut.writeInt32(BC_DEAD_BINDER_DONE);
mOut.writePointer((uintptr_t)proxy);
} break;
sendObituary
函数的主要工作是调用reportOneDeath
函数通知上次应用,代码定义如下:
void BpBinder::sendObituary()
{
//......
//这部的代码没看懂是干啥用的
Vector<Obituary>* obits = mObituaries;
if(obits != nullptr) {
ALOGV("Clearing sent death notification: %p handle %d\n", this, mHandle);
IPCThreadState* self = IPCThreadState::self();
self->clearDeathNotification(mHandle, this);
self->flushCommands();
mObituaries = nullptr;
}
//这部的代码没看懂是干啥用的
//......
const size_t N = obits->size();
for (size_t i=0; i<N; i++) {
reportOneDeath(obits->itemAt(i));
}
//......
}
void BpBinder::reportOneDeath(const Obituary& obit)
{
sp<DeathRecipient> recipient = obit.recipient.promote();
ALOGV("Reporting death to recipient: %p\n", recipient.get());
if (recipient == nullptr) return;
recipient->binderDied(this);
}
监听死亡通知对象都被保存在了Vector类型
的成员变量mObituaries
中,然后通过循环来调用reportOneDeath
通知所有对象。
而在reportOneDeath
函数中把弱引用转变成强引用后再调用binderDied
。
到这里就和注册接收Binde的死亡通知
的操作接上拉。
Java 层的 Binder 类
了解了C++层
的Binder
类体系后,我们再来看下Java层
提供的Binder
体系。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mfKoORTU-1599285250647)(http://cdn.hualee.top/Java%E5%B1%82Binder%E7%B1%BB%E5%9B%BE.png)]
Java层
的Binder
虽然设计了自己的框架,但最后还是通过native层
的BpBinder
和BBinder
。Java层
的Binder框架
和C++层
的原理是一样的,而且Java层
可以通过AIDL
来生成相关的细节代码,所以我们这次重点关注:Java框架
是通过什么方式和C++
中的BpBinder
和BBinder
关联起来的?
Java 层的 Binder 服务类
开发一个Java服务,必须继承android.os.Binder
类。Binder
类中最重要的成员变量如下:
public class Binder implements IBinder {
//......
private final long mObject;
private IInterface mOwner;
private String mDescriptor;
//......
public Binder(@Nullable String descriptor) {
//获取 JavaBBinderHolder 类的实例
mObject = getNativeBBinderHolder();
//registerNativeAllocation 是在 Android8.0(API27)引入的一种辅助回收native内存的机制,本身并不复杂,抽个时间好好看看它
NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mObject);
//......
mDescriptor = descriptor;
}
}
static jlong android_os_Binder_getNativeBBinderHolder(JNIEnv* env, jobject clazz)
{
JavaBBinderHolder* jbh = new JavaBBinderHolder();
return (jlong) jbh;
}
mObject
存放的是native层关联对象额指针mOwner
存放的是Binder继承类的引用,实际上就是 Java Binder对象本身mDescriptor
存放的是类的描述字符串
android.os.Binder
类在构造方法中会通过getNativeBBinderHolder()
本地方法获取JavaBBinderHolder
类的实例,并把指针保存在Java层
的mObject
变量中。我们看下JavaBBinderHolder
是干啥的:
class JavaBBinderHolder
{
public:
sp<JavaBBinder> get(JNIEnv* env, jobject obj)
{
AutoMutex _l(mLock);
sp<JavaBBinder> b = mBinder.promote();
if (b == NULL) {
b = new JavaBBinder(env, obj);
//......
mBinder = b;
//......
}
return b;
}
//......
private:
Mutex mLock;
wp<JavaBBinder> mBinder;
//......
};
JavaBBinderHolder
类在第一次调用get
函数时创建一个JavaBBinder
对象,并通过mBinder
保存JavaBBinder
对象的弱引用。而JavaBBinder
是从BBinder
类继承过来的,我们看下JavaBBinder
的核心定义:
class JavaBBinder : public BBinder
{
//......
status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) override
{
JNIEnv* env = javavm_to_jnienv(mVM);
IPCThreadState* thread_state = IPCThreadState::self();
const int32_t strict_policy_before = thread_state->getStrictModePolicy();
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
}
private:
JavaVM* const mVM;
jobject const mObject; // GlobalRef to Java Binder
//......
};
mVM
保存的是Java虚拟机的指针mObject
保存的是android.os.Binder
在native层
的JNI对象
,就是调用JavaBBinderHolder
的get
函数是参入的jobject obj
参数
到这里,我们就可以梳理出Java层
和native层
的Binder服务
关系:
- 首先,
Java层
的Binder
对象在构造方法中,通过JNI调用,是的mObject
属性,持有了native
层JavaBBinderHolder
对象的指针 - 而在
JavaBBinderHolder
中,mBinder
变量持有一个JavaBBinder
对象的弱引用 JavaBBinder
继承自BBinder
,并重写了onTransact
onTransact
方法中会通过JNI
调用Java层
的android.os.Binder
的execTransact
方法
Java层的Binder引用类
应用在Java层
调用Binder
的操作同样也是通过Binder代理对象
来完成的,和C++
中一样,代理对象
的生成也是通过接口类中的asIntreface
方法来完成。Java
中的接口类一般都可以通过AIDL
自动生成。格式如下:
public static com.example.factory.ICommandService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.fengmi.factory.ICommandService))) {
return ((com.example.factory.ICommandService)iin);
}
return new com.example.factory.ICommandService.Stub.Proxy(obj);
}
这个asIntreface
方法的逻辑其实和C++
中的asIntreface
一样:
- 先通过
queryLocalInterface
方法的返回值判断传入的参数是否是在服务端调用传入的Binder服务对象
,如果是直接返回该对象 - 否就就认为
obj
是Binder引用对象
,这时需要新创建一个Binder代理对象
,也就是return new com.example.factory.ICommandService.Stub.Proxy(obj);
com.example.factory.ICommandService.Stub.Proxy
就是AIDL
自动生成的代理对象。这个类实现了ICommandService
接口- 这样对于应用开发,只需要关系
ICommandService
接口包含了哪些方法即可,真正实现细节无需关心。- 只能说
Binder
设计的很是巧妙,整个体系在功能实现上基本形式化了
- 只能说
Java层
的Binder代理对象
实现的思路和C++层
如出一辙,可以阅读源码frameworks/base/core/java/android/os/*Binder*
来加深印象
我们再来看下asInterface
方法的参数android.os.IBinder obj
,通常情况我们都是通过ServiceManager
的getService
方法来得到这个IBinder对象
,我们看下getService
的部分代码(由于和Android 5.0不太一样,加注释了哟):
//Android 9 的这部分源码和书中有些不同,不过原理性的东西还是一样的
//file::ServiceManager.java
public static IBinder getService(String name) {
try {
// 查看缓存
IBinder service = sCache.get(name);
if (service != null) {
// 有缓存,直接返回缓存对象
return service;
} else {
// allowBlocking是在设置mWarnOnBlocking属性,看样子是将属性设置为可接受不受信任代码的调用
// 真正获取Binder对象的是rawGetService
// rawGetService 最后调用了 ServiceManagerNative的getService()
//真正触发binder通信并获取到binder对象的,就是在ServiceManagerNative中
return Binder.allowBlocking(rawGetService(name));
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
//file::Binder.java
//建议看看英文注释吧,木有完全理解。
public static IBinder allowBlocking(IBinder binder) {
try {
if (binder instanceof BinderProxy) {
//仅仅在binder对象是客户端时进行设置
((BinderProxy) binder).mWarnOnBlocking = false;
} else if (binder != null && binder.getInterfaceDescriptor() != null
&& binder.queryLocalInterface(binder.getInterfaceDescriptor()) == null) {
Log.w(TAG, "Unable to allow blocking on interface " + binder);
}
} catch (RemoteException ignored) {
}
return binder;
}
//file::ServiceManager.java
private static IBinder rawGetService(String name) throws RemoteException {
//......
final IBinder binder = getIServiceManager().getService(name);
//忽略很多代码
return binder;
}
//file::ServiceManager.java
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
// 最后执行到了ServiceManagerNative
sServiceManager = ServiceManagerNative
.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
return sServiceManager;
}
再看下ServiceManagerNative
的部分代码,已添加注释:
//file::ServiceManagerNative.java
public IBinder getService(String name) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
//设置要获取的Binder服务的描述符
data.writeInterfaceToken(IServiceManager.descriptor);
//设置要获取的Binder服务的名称
data.writeString(name);
//通过 transact 发送Binder请求,怎么发送的据说后面原理会讲到
// GET_SERVICE_TRANSACTION 就是获取特定binder服务请求号
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
//通过Parcel类的readStrongBinder来获得IBinder对象
//readStrongBinder是一个本地方法,它的实现是nativeReadStrongBinder
//然后调用到了android_os_Parcel_readStrongBinder
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
return binder;
}
//file::android_os_Parcel.cpp
//方法中的 parcel->readStrongBinder() 会返回一个C++层的IBinder对象
//这个C++层的IBinder对象怎么创建的据说后面原理部分会讲
//javaObjectForIBinder则根据C++层的IBinder对象创建一个Java层的BinderProxy对象
static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
return javaObjectForIBinder(env, parcel->readStrongBinder());
}
return NULL;
}
javaObjectForIBinder
实现了在native层
创建Java类
实例,我们仔细看下这个神奇的方法:
// android_util_binder.cpp
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
if (val == NULL) return NULL;
if (val->checkSubclass(&gBinderOffsets)) {
// 如果是JavaBBinder 说明在服务端,直接返回该对象
// It's a JavaBBinder created by ibinderForJavaObject. Already has Java object.
jobject object = static_cast<JavaBBinder*>(val.get())->object();
LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);
return object;
}
// For the rest of the function we will hold this lock, to serialize
// looking/creation/destruction of Java proxies for native Binder proxies.
//加锁
AutoMutex _l(gProxyLock);
// 查看缓存中是否存在 BinderProxyNativeData,没有就新建
// BinderProxyNativeData就是一结构体,存放了BpBinder的指针和对应注册Binder服务死亡通知的对象List的指针
BinderProxyNativeData* nativeData = gNativeDataCache;
if (nativeData == nullptr) {
nativeData = new BinderProxyNativeData();
}
// gNativeDataCache is now logically empty.
// 通过JNI调用CallStaticObjectMethod创建BinderProxy对象
// 这里的JNI调用其实就是在调用Java层BinderProxy类的getInstance方法
// getInstance 需要传入long nativeData, long iBinder两个指针
// 所以,在创建完Java层的BinderProxy对象后,它已经持有了BpBinder和BinderProxyNativeData的指针
jobject object = env->CallStaticObjectMethod(gBinderProxyOffsets.mClass,
gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get());
if (env->ExceptionCheck()) {
//异常检查
// In the exception case, getInstance still took ownership of nativeData.
gNativeDataCache = nullptr;
return NULL;
}
//通过 getBPNativeData 获取object对象中的mNativeData字段的数据
//并转化为BinderProxyNativeData指针
BinderProxyNativeData* actualNativeData = getBPNativeData(env, object);
if (actualNativeData == nativeData) {
// 两个指针相等
// New BinderProxy; we still have exclusive access.
// 新建死亡通知注册表
nativeData->mOrgue = new DeathRecipientList;
// 把 mObject 指针指向 传入的IBiner,也就是BpBinder
nativeData->mObject = val;
gNativeDataCache = nullptr;
//.....
} else {
// nativeData wasn't used. Reuse it the next time.
gNativeDataCache = nativeData;
}
return object;
}
经过这个方法的操作,Java层
获得了一个在native层
创建的BinderProxy
实例,同时也关联上了BpBinder
对象。
如果从Java调用Binder服务,会使用BinderProxy
类的transact
方法,这最后也是调用了一个本地方法,我们看下实现:
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
//......
//省略参数合法性判断
//......
// 获取 BpBinder 指针
IBinder* target = getBPNativeData(env, obj)->mObject.get();
//......
// 执行 BpBinder 的 transact
status_t err = target->transact(code, *data, reply, flags);
//......
}
中期总结
学习到这里,我们了解了如何使用Binder
以及Binder的一些基本知识
:
- 数据通信通过
Parcel
来传递 - 对于客户端
- 客户端可以通过
linkToDeath
来注册监听服务端的死亡通知 - 不管是从
C++
还是Java
的客户端调用,都会走到BpBinder
这里 - 客户端触发
Binder调用
的操作是BpBinder
的transact
BpBinder
的transact
调用的是IPCThreadState::self()->transact()
- 客户端可以通过
- 对于服务端
- 有
AIDL
支持的Java层
,在服务端的业务实现上很简单 - 支持
HIDL
的C++
,在实现上也变得比较容易 - 不管是
C++
还是Java
,最后都是通过继承BBinder
来实现 - 在
onTransact
中实现不同方法调用的case
- 有
但是,我还有这么几个疑问:
- 客户端
transact
后是怎么通知到服务端的? - 服务端
reply.write*
怎么把数据给到客户端的? onTransact
在什么时候被调用的?- 服务端何时启动运行的呢?
那我们就带着疑问,继续学习Binder的实现原理