binder通信机制是Android系统最重要的一种通信机制,也是一种C/S架构的通信机制,客户端和服务器端通过binder驱动进行通信。其架构如下图所示。
在binder通信机制中,客户端使用的是一个代理类BpBinder,而服务器端使用的是BBinder类,这两个类都是继承了抽象类IBinder。而BpBiner类中的成员函数transact用来向服务器端发送请求(实际上是往binder驱动发的),而binder驱动在收到请求后会通知相应的服务端,该服务端的BBinder的成员函数OnTransact函数会被调用来处理客户端发送过来的数据。这两个成员函数一般都会被具体的代理类和本地类重载。这是业务层的事情了。
在binder通信机制中有一个抽象类非常重要,且要自己实现。这个类一般使用Ixxx来表示如(IServiceManager),个人认为这个抽象类最重要的有两点,第一定义业务层需要用的纯虚函数(如IServiceManager里的addService和getService)。第二定义和实现两个宏。DECLEAR_META_INTERFACE和IMPLEMENT_META_INTERFACE.在获取代理类的时候需要用到asinterface这个函数。
#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(); \
#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; \
}
一、ServiceManager
ServiceManager是一个管理者的角色,服务器端用它来注册服务,而客户端用它来获取服务,通过获取服务可以得到一个IBinder类,从而在客户端可以获取代理类。服务器端注册服务和客户端获取服务时,无论时客户端还是服务器端均可看成是客户端,而ServiceManager则是对应的服务器端。ServiceManager和普通的服务器端不一样,不是用Bnxxx类来处理数据的。
(1)、获取ServiceManager的代理类
defaultServiceManager函数中调用模板函数interface_cast获取ServiceManager的代理类BpServiceManager,而interface_cast函数就是调用了IMPLEMENT_META_INTERFACE宏中实现的asinterface函数来获取的,而BpServiceManager的mRemoter成员则是使用ProcessSate类的成员函数getContextObject来获得的。
sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
{
AutoMutex _l(gDefaultServiceManagerLock);
while (gDefaultServiceManager == NULL) {
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(NULL));
if (gDefaultServiceManager == NULL)
sleep(1);
}
}
return gDefaultServiceManager;
}
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
return INTERFACE::asInterface(obj);
}
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
return getStrongProxyForHandle(0);
}
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
// We need to create a new BpBinder if there isn't currently one, OR we
// are unable to acquire a weak reference on this current one. See comment
// in getWeakProxyForHandle() for more info about this.
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
if (handle == 0) {
// Special case for context manager...
// The context manager is the only object for which we create
// a BpBinder proxy without already holding a reference.
// Perform a dummy transaction to ensure the context manager
// is registered before we create the first local reference
// to it (which will occur when creating the BpBinder).
// If a local reference is created for the BpBinder when the
// context manager is not present, the driver will fail to
// provide a reference to the context manager, but the
// driver API does not return status.
//
// Note that this is not race-free if the context manager
// dies while this code runs.
//
// TODO: add a driver API to wait for context manager, or
// stop special casing handle 0 for context manager and add
// a driver API to get a handle to the context manager with
// proper reference counting.
Parcel data;
status_t status = IPCThreadState::self()->transact(
0, IBinder::PING_TRANSACTION, data, NULL, 0);
if (status == DEAD_OBJECT)
return NULL;
}
b = new BpBinder(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
// This little bit of nastyness is to allow us to add a primary
// reference to the remote proxy when this team doesn't have one
// but another team is sending the handle to us.
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
需要注意handle的值,在binder驱动中根据该值来查找相应的本地类。
(2)、ServiceManager本地端
ServiceManager本地端没有对应的本地类BnServiceManager,而且其本地端是用C语言而非C++来写的。他是通过循环读取binder驱动的数据然后解析来获得代理类发过来的消息的。具体的可以通过/framework/native/cmds/servicemanager/service_manager.c来查看它的源码。
(3)、添加Service服务
服务端通过IserviceManager的成员函数addService来通知ServiceManager来注册对应的服务。
virtual status_t addService(const String16& name, const sp<IBinder>& service,
bool allowIsolated)
{
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
data.writeStrongBinder(service);
data.writeInt32(allowIsolated ? 1 : 0);
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
(4)、获取Service服务
客户端通过IServiceManager抽象类的成员函数getService来通知ServiceManager来获取服务(其实就是获取BpBinder)。
template<typename INTERFACE>
status_t getService(const String16& name, sp<INTERFACE>* outService)
{
const sp<IServiceManager> sm = defaultServiceManager();
if (sm != NULL) {
*outService = interface_cast<INTERFACE>(sm->getService(name));
if ((*outService) != NULL) return NO_ERROR;
}
return NAME_NOT_FOUND;
}
特别需要关注的addService函数和getService函数的name参数必须是一致的才能把本地类和代理类对应起来。
二、client
客户端通过代理类来发送数据给服务端,最终是通过BpBinder类的成员函数transact向服务端发送数据。BpBinder的获取是向ServiceManager获得的,然后通过函数asInterface函数来获取其自身的代理类。其过程如下。
第一步,使用defaultServiceManager获得ServiceManager的代理类BpServiceManager。
第二步,使用BpServiceManager的getService获取其自己的BpBinder。BpServiceManager是继承IServiceManager,所以IServiceManager的成员函数getService也是BpServiceManager的成员函数。
第三步,通过其自己的抽象类中定义的asInterface函数获取自己的代理类,而后可以通过代理类进行通信。
代理类的继承关系如下图所示:
三、服务端
服务端的service继承了他的本地类,而其对应的代理类发送数据过来通信的时候本地类的成员函数OnTransact被调用,可以通过这个函数真正操作一些设备。另外服务端还要想ServiceManager注册服务,才能让其对应的客户端找到相应的代理类。另外service类要实现函数OnTransact,addService函数里第二个参数不用Bnxxx而使用service类xxx。
本地类的继承关系如下图所示:
总结:这是个人对binder机制的理解,可能有些地方写的不是很好,有错误的地方也希望各位能够指正。另外binder机制里面代理类和本地类的继承关系,相当重要,只有搞懂了这些继承关系才能真正的运用好这些类。