原文网址(转载请注明出处): (http://blog.csdn.net/newchenxf/article/details/49425079)
虽然已经写了一个【android binder 基础实例及解析(一)】,但是觉得还是不够,为啥?因为那个例子太基础了,就一个client,一个server,调用是单向的,也就是,只有client能主动调用server,但server没法主动调用client。怎么办?
这时候,就需要匿名binder了。
匿名binder就是不需要向servicemanager注册的binder。
思路就是,再写一个binder,比如接口名字为ICallback,然后BpCallback放在server端,而BnCallback放在client端,那就可以做到server也能主动调用client了。
我们就基于前文的XXXXService修改吧。
首先,我们要在interface目录添加ICallback.h和ICallback.cpp。
然后在client目录实现Callback,继承BnCallback。然后IXXXXService添加Callback的使用。
目录结果如下
Android.mk
client->Android.mk, main_client.cpp, Callback.h, Callback.cpp
interface->IXXXXService.cpp, IXXXXService.h, ICallback.h, ICallback.cpp
server->Android.mk, XXXXService.cpp, XXXXService.h, main_XXXXService.cpp
该头文件干2件事,一个是定义接口ICallback,接口函数是notifyCallback。一个是声明BnCallback。
千万别忘了DECLARE_META_INTERFACE。
#ifndef Icallback_H
#define Icallback_H
#include <binder/IInterface.h>
namespace android {
class ICallback : public IInterface {
public:
DECLARE_META_INTERFACE(Callback);
virtual int notifyCallback(int a) = 0;
};
class BnCallback : public BnInterface<ICallback> {
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
};
}
#endif
#include "IXXXXService.h"
#include <binder/Parcel.h>
#include <binder/IInterface.h>
#include <utils/Log.h>
#define LOG_NDEBUG 0
#define LOG_TAG "chenxf: ICallback"
namespace android {
enum {
NOTIFY_CALLBACK,
};
//////////////////client
class BpCallback : public BpInterface<ICallback> {
public:
BpCallback(const sp<IBinder>& impl) : BpInterface<ICallback>(impl) {
}
virtual int notifyCallback(int a) {
ALOGD(" BpCallback::notifyCallback, a = %d", a);
Parcel data,reply;
data.writeInt32(a);
remote()->transact(NOTIFY_CALLBACK,data,&reply);
return reply.readInt32();
}
};
IMPLEMENT_META_INTERFACE(Callback, "chenxf.binder.ICallback");
////////////////server
status_t BnCallback::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
switch (code) {
case NOTIFY_CALLBACK: {
ALOGD("BnCallback::onTransact>>NOTIFY_CALLBACK\n");
reply->writeInt32(notifyCallback((int) data.readInt32()) );
return NO_ERROR;
} break;
}
return BBinder::onTransact(code, data, reply, flags);
}
}
很简单,实现BpCallback的notifyCallback和BnCallback的onTransact。千万记得写IMPLEMENT_META_INTERFACE。
现在callback的服务端是在client进程了,因此其继承BnCallback的Callbac类l就该放在client目录。
#include "../interface/IXXXXService.h"
#include "../interface/ICallback.h"
#include <binder/BinderService.h>
namespace android {
class Callback: public BnCallback {
public:
virtual int notifyCallback(int a);
};
}
#include <binder/Parcel.h>
#include <binder/IPCThreadState.h>
#include <utils/String16.h>
#include <utils/threads.h>
#include <utils/Atomic.h>
//#include <cutils/bitops.h>
#include <cutils/properties.h>
#include <cutils/compiler.h>
#include "Callback.h"
#include <utils/Log.h>
#define LOG_NDEBUG 0
#define LOG_TAG "chenxf: client-Callback"
namespace android {
int Callback::notifyCallback(int a) {
ALOGD("Callback::notifyCallback, Actually, come from XXXXService.., the callback value: %d", a);
return 1;
}
}
实现真正的notifyCallback。本例做很简单的事情,把callback的返回参数打印出来。
添加一个接口函数。
virtual int setCallback(const sp& callback) = 0;
client进程可以通过setCallback函数,告诉server进程,有这么一个回调可以用,这样server有啥事,就可以通过callback告诉client进程。
#ifndef IXXXXService_H
#define IXXXXService_H
#include <binder/IInterface.h>
#include "ICallback.h"
namespace android {
class IXXXXService : public IInterface {
public:
DECLARE_META_INTERFACE(XXXXService);
virtual int setSomething(int a) = 0;
virtual int getSomething() = 0;
virtual int setCallback(const sp<ICallback>& callback) = 0;
};
class BnXXXXService : public BnInterface<IXXXXService> {
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
};
}
#endif
实现BpXXXXService的setCallback函数。
并在BnXXXXService的onTransact添加对setCallback的处理。
这是最关键的一步,后文讲详细分析。这里先给出代码。
#include "IXXXXService.h"
#include <binder/Parcel.h>
#include <binder/IInterface.h>
#include "ICallback.h"
#include <utils/Log.h>
#define LOG_NDEBUG 0
#define LOG_TAG "chenxf: IXXXXService"
namespace android {
enum {
SET_SOMETHING = IBinder::FIRST_CALL_TRANSACTION,
GET_SOMETHING,
SET_CALLBACK
};
//------------------------------------proxy side--------------------------------
class BpXXXXService : public BpInterface<IXXXXService> {
public:
BpXXXXService(const sp<IBinder>& impl)
: BpInterface<IXXXXService>(impl) {
}
virtual int setSomething(int a) {
ALOGD(" BpXXXXService::setSomething a = %d ", a);
Parcel data,reply;
data.writeInt32(a);
remote()->transact(SET_SOMETHING,data,&reply);
return reply.readInt32();
}
virtual int getSomething() {
ALOGD(" BpXXXXService::getSomething ");
Parcel data,reply;
data.writeInterfaceToken(IXXXXService::getInterfaceDescriptor());
remote()->transact(GET_SOMETHING,data,&reply);
return reply.readInt32();
}
virtual int setCallback(const sp<ICallback>& callback) {
ALOGD("BpXXXXService::setCallback");
Parcel data, reply;
data.writeStrongBinder(callback->asBinder());// TODO: important
remote()->transact(SET_CALLBACK, data, &reply);
return reply.readInt32();
}
};
IMPLEMENT_META_INTERFACE(XXXXService, "chenxf.binder.IXXXXService");
//------------------------------------server side--------------------------------
status_t BnXXXXService::onTransact (
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){
switch (code) {
case SET_SOMETHING: {
ALOGD("BnXXXXService::onTransact SET_SOMETHING ");
reply->writeInt32(setSomething((int) data.readInt32()));
return NO_ERROR;
} break;
case GET_SOMETHING: {
ALOGD("BnXXXXService::onTransact GET_SOMETHING ");
reply->writeInt32(getSomething());
return NO_ERROR;
} break;
case SET_CALLBACK: {
ALOGD("BnXXXXService::onTransact SET_CALLBACK ");
sp<ICallback> callback = interface_cast<ICallback>(data.readStrongBinder());// TODO: important!
reply->writeInt32(setCallback(callback));
return NO_ERROR;
}
}
return BBinder::onTransact(code, data, reply, flags);
}
}
server进程得实现setCallback,在头文件声明一下,并添加一个本地变量mCallback。
#include "../interface/IXXXXService.h"
#include <binder/BinderService.h>
#include "../interface/ICallback.h"
namespace android {
class XXXXService : public BinderService<XXXXService>, public BnXXXXService {
public:
XXXXService();
static const char* getServiceName() { return "XXXXService"; }//will be the service name
virtual int setSomething(int a);
virtual int getSomething();
virtual int setCallback(const sp<ICallback>& callback);
protected:
int myParam;
sp<ICallback> mCallback;
};
}
实现server进程的setCallback函数。
这里就是让本地的mCallback等于setCallback的参数。
如此一来,我们server进程想主动发消息给client进程,只要执行mCallback->notifyCallback就行啦!有了callback,妥妥的全双工通信。
本例就简单点,发现客户端调用了setSomething,就notifyCallback一下,告诉客户端,收到事情了,给你办好了,你安心吧。^^
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include <binder/Parcel.h>
#include <binder/IPCThreadState.h>
#include <utils/threads.h>
#include <cutils/properties.h>
#include "XXXXService.h"
#define LOG_NDEBUG 0
#define LOG_TAG "chenxf: XXXXService"
namespace android {
XXXXService::XXXXService() {
myParam = 0;
}
int XXXXService::setSomething(int a) {
ALOGD(" XXXXService::setSomething a = %d myParam %d", a, myParam);
myParam += a;
//Let's trigger callback
if(mCallback != NULL) {
ALOGD("will notify???");
mCallback->notifyCallback(myParam);
} else {
ALOGW("mCallback is NULL");
}
return 0;//OK
}
int XXXXService::getSomething() {
ALOGD("#XXXXService::getSomething myParam = %d", myParam);
return myParam;
}
int XXXXService::setCallback(const sp<ICallback>& callback) {
ALOGD(" XXXXService::setCallback");
mCallback = callback;
return 0;
}
}
好了,现在client进程可以先调用setCallback注册callback。
#include <stdio.h>
#include "Callback.h"
#include "../interface/IXXXXService.h"
#define LOG_NDEBUG 0
#define LOG_TAG "chenxf: Client-main"
using namespace android;
sp<IXXXXService> mXXXXService;
void initXXXXServiceClient() {
int count = 10;
if (mXXXXService == 0) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->getService(String16("XXXXService"));
if (binder != 0)
break;
ALOGW("XXXXService not published, waiting...");
sleep(1); // 1 s
count++;
} while (count < 20);
mXXXXService = interface_cast<IXXXXService>(binder);
}
}
int main(int argc, char* argv[]) {
initXXXXServiceClient();
if(mXXXXService ==NULL) {
ALOGW("cannot find XXXXService");
return 0;
}
sp<Callback> c = new Callback();
mXXXXService->setCallback(c);
while(1) {
mXXXXService->setSomething(1);
sleep(1);
ALOGD("getSomething %d", mXXXXService->getSomething());
}
return 0;
}
server进程啥也不用该,因为他就是启动了XXXXService,具体callback的事情,都在XXXXService完成了。不过为了代码的完整性,我还是把代码贴出来。
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include "XXXXService.h"
#define LOG_NDEBUG 0
#define LOG_TAG "chenxf: XXXXService-main"
#define EASY_START_BINDER_SERVICE 0
using namespace android;
int main(int argc, char** argv)
{
#if EASY_START_BINDER_SERVICE
XXXXService::publishAndJoinThreadPool();
#else
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm(defaultServiceManager());
sm->addService(String16(XXXXService::getServiceName()), new XXXXService());
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
#endif
return 0;
}
这个的例子,我们用了2个binder实例,第一个IXXXXService是公开的,向ServiceManager注册过的。而ICallback就没有,我们称为匿名binder。
那么,2个binder实例是否要打开2次binder设备呢?不用喔,再次强调一下,每个进程都只有一个ProcessState对象,它打开binder设备就行了,不管你写多少个binder实例,最终的数据传输都可以让他处理。
本例最重要的细节,是IXXXXServce的setCallback。
client进程已经new了Callback(继承BnCallback),所以setCallback的根本目的就是,让server端建立对应的BpCallback.
来看一下client如何注册callback到服务端。
1. client进程BpXXXXService的setCallback。
代码如下
virtual int setCallback(const sp<ICallback>& callback) {
ALOGD("BpXXXXService::setCallback");
Parcel data, reply;
data.writeStrongBinder(callback->asBinder());// TODO: important
remote()->transact(SET_CALLBACK, data, &reply);
return reply.readInt32();
}
参数callback是main_client.cpp初始化的Callback对象。
writeStrongBinder干了什么?
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
return flatten_binder(ProcessState::self(), val, this);
}
status_t flatten_binder(const sp<ProcessState>& /*proc*/,
const sp<IBinder>& binder, Parcel* out)
{
//输入的binder,有可能是BpBinder或BBinder,准备构造flat_binder_object
flat_binder_object obj;
obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
if (binder != NULL) {
//localBinder()被IBinder定义且实现(返回NULL),被BBinder重写(返回this),因此,为NULL说明是BpBinder,不是NULL则是BBinder。对本例来说,就是BBinder
IBinder *local = binder->localBinder();
if (!local) {//参数是BpBinder,传递服务代理信息,客户端A把它得到的服务对象的BpBinder告诉客户端B,客户端B不查询ServiceManager也能使用服务,实现服务信息共享
BpBinder *proxy = binder->remoteBinder();
//remoteBinder()被IBinder定义且实现(返回NULL),被BpBinder重写(返回this)
if (proxy == NULL) {
ALOGE("null proxy");
}
const int32_t handle = proxy ? proxy->handle() : 0;
obj.type = BINDER_TYPE_HANDLE;
obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
obj.handle = handle;//服务对象的handle
obj.cookie = 0;
ALOGD("chenxf binder->localBinder() is null, handle = %08x", handle);
} else {//参数是BBinder,传递服务对象信息,本例将进入这个判断
obj.type = BINDER_TYPE_BINDER;
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());//服务对象的引用记录的地址
obj.cookie = reinterpret_cast<uintptr_t>(local);//服务对象的地址
}
} else {
obj.type = BINDER_TYPE_BINDER;
obj.binder = 0;
obj.cookie = 0;
}
//把flat_binder_object写到Parcel
return finish_flatten_binder(binder, obj, out);
}
//finish_flatten_binder
inline static status_t finish_flatten_binder(
const sp<IBinder>& /*binder*/, const flat_binder_object& flat, Parcel* out)
{
return out->writeObject(flat, false);
}
函数的功能,请看注释。
本例,由于Callback继承BnCallback,而BnCallback继承BBinder,所以进入的判断是
obj.type = BINDER_TYPE_BINDER;
obj.binder = reinterpret_cast(local->getWeakRefs());
obj.cookie = reinterpret_cast(local);
接着,执行
remote()->transact(SET_CALLBACK, data, &reply);
看一下做什么。
如上一篇文章说的,remote()就是BpBinder,而BpBinder的transact将调用IPCThreadState::transact()。
IPCThreadState先调用writeTransactionData()把数据写入mOut,
再调用waitForResponse()写入数据并等待应答。
下面给出一个transact的主要工作内容
status_t IPCThreadState::transact(int32_t handle,....)
{
//1. 构造写入数据mOut
IPCThreadState::writeTransactionData(BC_TRANSACTION,...)
//2. 写入命令并等待应答
IPCThreadState::waitForResponse();
}
IPCThreadState::waitForResponse() {
//1. talkWithDriver,通过ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)把mOut写入driver,然后读取返回值,写到mIn
talkWithDriver();
//2. 处理返回值
cmd = mIn.readInt32();
switch(cmd){
case BR_TRANSACTION_COMPLETE:
......
}
}
client进程写数据到driver后,基本就完事了。
2. server进程BnXXXXService的onTransact 。
server进程,不断的从binder驱动读取数据,如果是给自己的,将在onTransact处理。来看一下对callback的处理。
status_t BnXXXXService::onTransact (
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){ switch (code) { case SET_CALLBACK: { ALOGD("BnXXXXService::onTransact SET_CALLBACK "); sp<ICallback> callback = interface_cast<ICallback>(data.readStrongBinder()); reply->writeInt32(setCallback(callback)); return NO_ERROR; }
}
}
显而易见,下面这句话最重要。
sp callback = interface_cast(data.readStrongBinder());
看一下readStrongBinder做什么。
sp<IBinder> Parcel::readStrongBinder() const
{
sp<IBinder> val;
unflatten_binder(ProcessState::self(), *this, &val);
return val;
}
status_t unflatten_binder(const sp<ProcessState>& proc,
const Parcel& in, sp<IBinder>* out)
{
//out可能是BpBinder或BBinder,会把handle转换成BpBinder
//从Parcel缓冲区读取flat_binder_object
const flat_binder_object* flat = in.readObject(false);
if (flat) {
switch (flat->type) {
case BINDER_TYPE_BINDER:
//客户端和服务在同一进程,返回BBinder???
*out = reinterpret_cast<IBinder*>(flat->cookie);
return finish_unflatten_binder(NULL, *flat, in);
case BINDER_TYPE_HANDLE:
//客户端和服务不在同一进程,返回BpBinder,本例将走到这里。ProcessState根据handle创建BpBinder对象
*out = proc->getStrongProxyForHandle(flat->handle);
return finish_unflatten_binder(
static_cast<BpBinder*>(out->get()), *flat, in);
}
}
return BAD_TYPE;
}
如注释所说,函数将走到getStrongProxyForHandle,获得一个BpBinder对象。如果你有疑问为啥client进程发的type明明是BINDER_TYPE_BINDER,为啥这里处理确实BINDER_TYPE_HANDLE?好像是因为,在kernel,做了转换。
linux/drivers/staging/android/binder.c
static void binder_transaction(......)
{
......
if (fp->type == BINDER_TYPE_BINDER)
fp->type = BINDER_TYPE_HANDLE;
else
fp->type = BINDER_TYPE_WEAK_HANDLE;
fp->handle = ref->desc;
}
先不在意这个细节,来看最关键的函数getStrongProxyForHandle。
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
//如果Service代理对象(BpBinder)未创建,将在列表中增加一个entry,以保存下面将要创建的代理对象,但初始化e->binder=null
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
if (handle == 0) {//servicemanager proxy的handle=0,其他正常的不会走到这
Parcel data;
status_t status = IPCThreadState::self()->transact(
0, IBinder::PING_TRANSACTION, data, NULL, 0);
if (status == DEAD_OBJECT)
return NULL;
}
//Callback的调用,handle不是0,走到这
b = new BpBinder(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
所以,
sp callback = interface_cast(data.readStrongBinder());
相当于,
sp callback = interface_cast(new BpBinder(handle));
而interface_cast将会new BpCallback
所以又相当于
sp callback = new BpCallback(new BpBinder(handle));
所以到最后,XXXXService的mCallback = new BpCallback(new BpBinder(handle))。
所以我们明白了,其实client进程的setCallback的参数是一个BnCallback对象,但传递到server进程后,变成一个BpCallback对象。
server进程想要发送消息给client进程,相当于是让ICallback的客户端(BpCallback)发给ICallback的服务端(BnCallback)。
经过这个例子,我们发现,A进程和B进程,既可以有binder的客户端,也可以有binder的服务端,如A进程有BpXXXXService和BnCallback。B进程有BnXXXXService和BpCallback。并且A和B都还含有ServiceManager的客户端,因为他们都要与ServiceManager服务端通信,如调用addService、getService。
所以我刚才的称呼client进程和server进程,也不是很严肃的,或者说,我是以XXXXService为标准来称呼的。
启动2个进程。
#test_bidner_server &
#test_bidner_client &
server的processID是1947
client的processID是2136
下面是log。
10-12 00:00:41.078 2136 2136 D chenxf: IXXXXService: BpXXXXService::setCallback
10-12 00:00:41.078 1947 1947 D chenxf: IXXXXService: BnXXXXService::onTransact SET_CALLBACK
10-12 00:00:41.078 1947 1947 D chenxf: XXXXService: XXXXService::setCallback
10-12 00:00:41.078 2136 2136 D chenxf: IXXXXService: BpXXXXService::setSomething a = 1
10-12 00:00:41.078 1947 1948 D chenxf: IXXXXService: BnXXXXService::onTransact SET_SOMETHING
10-12 00:00:41.078 1947 1948 D chenxf: XXXXService: XXXXService::setSomething a = 1 myParam 0
10-12 00:00:41.078 1947 1948 D chenxf: XXXXService: will notify???
10-12 00:00:41.078 1947 1948 D chenxf: ICallback: BpCallback::notifyCallback, a = 1
10-12 00:00:41.079 2136 2136 D chenxf: ICallback: BnCallback::onTransact>>NOTIFY_CALLBACK
10-12 00:00:41.079 2136 2136 D chenxf: client-Callback: Callback::notifyCallback, Actually, come from XXXXService.., the callback value: 1
10-12 00:00:42.079 2136 2136 D chenxf: IXXXXService: BpXXXXService::getSomething
10-12 00:00:42.079 1947 1947 D chenxf: IXXXXService: BnXXXXService::onTransact GET_SOMETHING
10-12 00:00:42.079 1947 1947 D chenxf: XXXXService: #XXXXService::getSomething myParam = 1
10-12 00:00:42.080 2136 2136 D chenxf: Client-main: getSomething 1
10-12 00:00:42.080 2136 2136 D chenxf: IXXXXService: BpXXXXService::setSomething a = 1
10-12 00:00:42.080 1947 1948 D chenxf: IXXXXService: BnXXXXService::onTransact SET_SOMETHING
10-12 00:00:42.080 1947 1948 D chenxf: XXXXService: XXXXService::setSomething a = 1 myParam 1
10-12 00:00:42.081 1947 1948 D chenxf: XXXXService: will notify???
10-12 00:00:42.081 1947 1948 D chenxf: ICallback: BpCallback::notifyCallback, a = 2
10-12 00:00:42.081 2136 2136 D chenxf: ICallback: BnCallback::onTransact>>NOTIFY_CALLBACK
10-12 00:00:42.081 2136 2136 D chenxf: client-Callback: Callback::notifyCallback, Actually, come from XXXXService.., the callback value: 2