Binder 是一种 IPC 机制,使用共享内存实现进程间通讯,既可以传递消息,也可以传递创建在共享内存中的对象,而Binder本身就是用共享内存实现的,因此遵循Binder写法的类是可以实例化后在进程间传递的。
Binder在Android架构中有很重的地位,各个模块都在重度使用它,从代码可读性角度看,在为熟悉之前的可读性较差。从整体架构的角度看,在各个模块中通过IPC分离接口和实现有效地提高了扩展性。
这个接口需要 Client/Bp 和 Server/Bn 都要遵循,Client需要关注有哪些消息类型,即enum值,Server需要关注虚函数,主要任务是根据消息中的enum值判断不同的业务类型,然后调用相应的虚函数。
/*
* IDemo.h
*/
class IDemo : public IInterface {
public:
enum {
ALERT = IBinder::FIRST_CALL_TRANSACTION,
PUSH,
ADD
};
// Sends a user-provided value to the service
virtual void push(int32_t data) = 0;
// Sends a fixed alert string to the service
virtual void alert() = 0;
// Requests the service to perform an addition and return the result
virtual int32_t add(int32_t v1, int32_t v2) = 0;
DECLARE_META_INTERFACE(Demo);
};
// This implementation macro would normally go in a cpp file
IMPLEMENT_META_INTERFACE(Demo, "com.my.Demo");
服务端需要继承 BnInterface
/*
* BnDemo.hpp
*/
class BnDemo : public BnInterface {
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags = 0);
};
status_t BnDemo::onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags) {
data.checkInterface(this);
switch(code) {
case ALERT: {
alert();
return NO_ERROR;
} break;
case PUSH: {
int32_t inData = data.readInt32();
push(inData);
return NO_ERROR;
} break;
case ADD: {
int32_t inV1 = data.readInt32();
int32_t inV2 = data.readInt32();
int32_t sum = add(inV1, inV2);
reply->writeInt32(sum);
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
如果不希望把业务代码和Binder架构代码混到一起,那么就再定义一个类来实现业务层。
/*
* Demo.hpp
*/
class Demo : public BnDemo {
virtual void push(int32_t data) {
// Do something with the data the client pushed
}
virtual void alert() {
// Handle the alert
}
virtual int32_t add(int32_t v1, int32_t v2) {
return v1 + v2;
}
};
客户端需要继承BpInterface
/*
* BpDemo.hpp
*/
class BpDemo : public BpInterface {
public:
BpDemo(const sp& impl) : BpInterface(impl) { }
virtual void push(int32_t push_data) {
Parcel data, reply;
data.writeInterfaceToken(IDemo::getInterfaceDescriptor());
data.writeInt32(push_data);
remote()->transact(PUSH, data, &reply);
}
virtual void alert() {
Parcel data, reply;
data.writeInterfaceToken(IDemo::getInterfaceDescriptor());
remote()->transact(ALERT, data, &reply, IBinder::FLAG_ONEWAY);
}
virtual int32_t add(int32_t v1, int32_t v2) {
Parcel data, reply;
data.writeInterfaceToken(IDemo::getInterfaceDescriptor());
data.writeInt32(v1);
data.writeInt32(v2);
remote()->transact(ADD, data, &reply);
int32_t res;
status_t status = reply.readInt32(&res);
return res;
}
};
服务端注册服务给系统的服务管理器。
defaultServiceManager()->addService(String16("com.my.Demo"), new Demo());
客户端在系统的服务管理器中根据 标识字符串 查找相应的服务,把返回的值cast 为 INTERFACE 实例使用即可。
p sm = defaultServiceManager();
sp binder = sm->getService(String16("com.my.Demo"));
sp demo = interface_cast(binder);
demo->alert();
demo->push(65);
int32_t sum = demo->add(453, 827);
服务端如何查找service的标识字符串?
代码中搜索 addService
客户端如何查找连接了哪个Binder服务端?
代码中搜索 getService
记住上面两点,能够快速定位客户端和服务端的关联关系。
https://android.googlesource.com/platform/frameworks/native/+/jb-mr1-dev/include/binder/IInterface.h