您的位置:首页 > 移动开发 > Android开发

图解Android - Binder 和 Service

2013-10-25 00:08 309 查看
Zygote启动过程 一文中我们说道,Zygote一生中最重要的一件事就是生下了 System Server 这个大儿子,System Server 担负着提供系统 Service的重任,在深入了解这些Service 之前,我们首先要了解 什么是Service?它的工作原理是什么?

1. Service是什么?

简单来说,Service就是提供服务的代码,这些代码最终体现为一个个的接口函数,所以,Service就是实现一组函数的对象,通常也称为组件。Android 的Service 有以下一些特点:

请求Service服务的代码(Client) 和 Service本身(Server) 不在一个线程,很多情况下不在一个进程内。跨进程的服务称为远端(Remote)服务,跨进程的调用称为IPC。通常应用程序通过代理(Proxy)对象来访问远端的Service。

Service 可以运行在native 端(C/C++),也可以运行在Java 端。同样,Proxy 可以从native 端访问Java Service, 也可以从Java端访问native service, 也就是说,service的访问与语言无关。

Android里大部分的跨进程的IPC都是基于Binder实现。

Proxy 通过 Interface 类定义的接口访问Server端代码。

Service可以分为匿名和具名Service. 前者没有注册到ServiceManager, 应用无法通过名字获取到访问该服务的Proxy对象。

Service通常在后台线程执行(相对于前台的Activity), 但Service不等同于Thread,Service可以运行在多个Thread上,一般这些Thread称为 Binder Thread.

要了解Service,我们得先从 Binder 入手。

2. Binder





先给一张Binder相关的类图一瞰Binder全貌,从上面的类图(点击看大图)跟Binder大致有这么几部分:

Native 实现: IBinder, BBinder, BpBinder, IPCThread, ProcessState, IInterface, etc

Java 实现: IBinder, Binder, BinderProxy, Stub, Proxy.

Binder Driver: binder_proc, binder_thread, binder_node, etc.

我们将分别对这三部分进行详细的分析,首先从中间的Native实现开始。

通常来说,接口是分析代码的入口,Android中'I' 打头的类统统是接口类(C++里就是抽象类), 自然,分析Binder就得先从IBinder下手。先看看他的定义。

class IBinder : public virtual RefBase
{
public:
...
virtual sp<IInterface>  queryLocalInterface(const String16& descriptor); //返回一个IInterface对象
...
virtual const String16& getInterfaceDescriptor() const = 0;
virtual bool            isBinderAlive() const = 0;
virtual status_t        pingBinder() = 0;
virtual status_t        dump(int fd, const Vector<String16>& args) = 0;
virtual status_t        transact(   uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0) = 0;
virtual status_t        linkToDeath(const sp<DeathRecipient>& recipient,
void* cookie = NULL,
uint32_t flags = 0) = 0;
virtual status_t        unlinkToDeath(  const wp<DeathRecipient>& recipient,
void* cookie = NULL,
uint32_t flags = 0,
wp<DeathRecipient>* outRecipient = NULL) = 0;
...
virtual BBinder*        localBinder();  //返回一个BBinder对象
virtual BpBinder*       remoteBinder(); //返回一个BpBinder对象
};


有接口必然有实现,从图中可以看出,BBinder和BpBinder都是IBinder的实现类,它们干啥用的,有啥区别?有兴趣同学可以去分别去读读他们的代码,分别在

Bpinder: frameworks/native/lib/binder/BpBinder.cpp

BBinder: frameworks/native/lib/binder/Binder.cpp

这里我们简单总结一下他们的区别:

接口BBinderBpBinder
queryLocalInterface()没有实现, 默认实现 IBinder 默认{reutrn NULL};  没有实现 IBinder 默认实现 {return NULL}
getInterfaceDescriptor()  {return sEmptyDescriptor;}  (this)->transact(INTERFACE_TRANSACTION, send, &reply);
...
mDescriptorCache = res;
isBinderAlive()  {return true;}{return mAlive != 0;}
pingBinder(){return NoError;}{transact(PING_TRANSACTION, send, &reply);
linkToDeath(){return INVALID_OPERATION;}  {self->requestDeathNotification(mHandle, this);}
unlinkToDeath()  {return INVALID_OPERATION;}{self->clearDeathNotification(mHandle, this);}
localBinder(){return this;}没有实现, IBinder默认实现 {return NULL};
remoteBinder()没有实现,IBinder默认实现 {return NULL;}{return this};
transact(){err = onTransact(code, data, reply, flags);}IPCThreadState::self()->transact(mHandle, code, data, reply, flags);
onTransact()switch (code) {
case INTERFACE_TRANSACTION:
reply->writeString16(getInterfaceDescriptor());
return NO_ERROR; ...

没有实现
看出来了吧,它们的差异在于它们是通信两端的不同实现,BBinder是服务端,而BpBinder是客户端,为什么这么说?

pingBinder, BBinder直接返回OK,而BpBinder需要运行一个transact函数,这个函数具体做什么,我们后面会介绍。

linkToDeath()是用来在服务挂的时候通知客户端的,那服务端当然不需要自己监视自己咯,所以BBinder直接返回非法,而Bpbinder需要通过requestDeathNotification()要求某人完成这个事情,究竟是谁提供这个服务?答案后面揭晓。

在Android中,remote一般代表某个远端对象的本地代理,想象一下航空公司和机票代理,BBinder是航空公司,当然没有remote的了,那BpBinder就是机票代理了,所以remote()自然返回自己了。

Transact的英文意思是交易,就是买卖嘛,那自然transact()就是买的操作,而onTransact()就是卖的操作,BBinder的transact()的实现就是onTransact(), 航空公司的买票当然不用通过机票代理了,直接找自己人就好了。

所以结论是,BBinder代表着服务端,而BpBinder则是它在客户端的代理,客户程序通过BpBinder的transact()发起请求,而服务器端的BBinder在onTranscat()里响应请求,并将结果返回。

可是交易肯定有目标的吧,回到航空公司和机票代理的例子,如果要订去某个地方的机票,我们怎么也得先查询一下都有那些航班,然后才能告诉机票代理订具体的航班号吧。这里的查询和预订可以看成服务的接口函数,而航班号就是我们传递给机票代理的参数。客户程序通过queryLocalInterface() 可以知道航空公司都提供哪些服务。

可是奇怪的是BBinder和BpBinder都没有实现这个接口啊,那肯定另有他人实现这个类了,这个人就是IInterface.h, 看看代码

template<typename INTERFACE>
inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface(
const String16& _descriptor)
{
if (_descriptor == INTERFACE::descriptor) return this;
return NULL;
}


BnInterface<INTERFACE> 对象将自己强制转换成 IInterface对象返回,看看BnInterface的定义:

template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
{
public:
virtual sp<IInterface>      queryLocalInterface(const String16& _descriptor);
virtual const String16&     getInterfaceDescriptor() const;

protected:
virtual IBinder*            onAsBinder();
};


是一个模板类,继承了BBinder, 还有模板 INTERFACE。我们刚才已经看过,BBinder没有实现queryLocalInterface(), 而BnInterface 返回自己,可以他并没有继承IInterface, 怎么可以强制转换呢,唯一的解释就是 INTERFACE模板必须继承和实现IInterface.

class IInterface : public virtual RefBase
{
public:
IInterface();
sp<IBinder>         asBinder();
sp<const IBinder>   asBinder() const;
protected:
virtual                     ~IInterface();
virtual IBinder*            onAsBinder() = 0;
};


这也太简单了吧,只是定义了 从Interface 到 IBinder的转换接口 asBinder, 而刚才我们研究的queryLocalInterface() 正好反过来,说明IBinder 和 IInterface 之间是可以互转的,一个人怎么可以变成另外一个人呢?唯一的解释就是这个人有双重性格,要么他同时继承 IInterface 和 IBinder, 要么他体内有这两个对象同时存在,不卖关子了,在服务端,这个双重性格的人就是BnXXX, XXX 代表某个具体的服务,我们以图中的BnMediaPlayer为例,看看他的定义

class BnMediaPlayer: public BnInterface<IMediaPlayer>
{
public:
virtual status_t    onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
};

class IMediaPlayer: public IInterface
{
public:
DECLARE_META_INTERFACE(MediaPlayer);
...

}


这下本性都露出来了,IBinder 和 IInterface 的影子都露出来了,让我们用图梳理一下 (箭头代表继承关系)



归纳一下,

BBinder 实现了大部分的IBinder 接口,除了onTransact() 和 queryLocalInterface(), getInterfaceDescriptor();

BnInterface 实现了IBinder的queryLocalInterface()和getInterfaceDescriptor(), 但是其必须借助实际的接口类。

BnMediaPlayer只是定义了onTransact(), 没有实现。

onTransact()的具体实现在Client类。

为什么搞得那么复杂?Google 是希望通过这些封装尽可能减少开发者的工作量,开发一个native的service 开发者只需要做这么几件事(上图中深色部分):

定义一个接口文件, IXXXService, 继承IInterface

定义BnXXX(), 继承 BnInterface<IXXXService)

实现一个XXXService类,继承BnXXX(), 并具体实现onTransact() 函数。

那客户端呢? 我们的目标是找到一个类,它必须同时拥有IBinder 和 IIterface的特性, 先看看BpBinder 吧

class BpBinder : public IBinder


跟IInterface 没有关系,那一定是别人,看看BpInterface 吧,

template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
{
public:
BpInterface(const sp<IBinder>& remote);
protected:
virtual IBinder*            onAsBinder();
};


我们刚才已经知道了,INTERFACE 是 IMediaPlayer, 它继承了IInterface, IInterface 的对象找到了, 但跟IBinder 没关系?只剩下BpRefBase 了,

class BpRefBase : public virtual RefBase
{
protected:
...
inline  IBinder*        remote()                { return mRemote; }
...
private:
...
IBinder* const          mRemote;
RefBase::weakref_type*  mRefs;
volatile int32_t        mState;
};


有了,BpRefBase 里有IBinder 成员变量,看来在客户端,没有一个类同时继承IBinder 和 IInterface, 但是有一个类继承了其一,但包含了另外一个,这种在设计模式里成为组合(Composition).

还是不太明白?还是用图解释吧,



看明白了?从BpInterface开始,通过BpRefBase 我们可以找到IBinder, 这个转换就在 asBinder() 的实现里,看看代码

sp<IBinder> IInterface::asBinder(){
return this ? onAsBinder() : NULL;
}

sp<const IBinder> IInterface::asBinder() const{
return this ? const_cast<IInterface*>(this)->onAsBinder() : NULL;
}

template<typename INTERFACE>
inline IBinder* BpInterface<INTERFACE>::onAsBinder()
{
return remote();
}

template<typename INTERFACE>
IBinder* BnInterface<INTERFACE>::onAsBinder()
{
return this;
}


这里印证我们上面两张图的正确性,onAsBinder是转换的发生的地方,服务端(BnInterface)的实现直接返回了自己,因为它继承了两者,而客户端(BpInterface)则需要通过remote()(返回mRemote 成员变量)获取,因为他自己本身不是IBinder,

那个BpRefbase的mRemote是如何被赋值的?看看以下代码

//frameworks/native/libs/binder/binder.cpp
BpRefBase::BpRefBase(const sp<IBinder>& o)
: mRemote(o.get()), mRefs(NULL), mState(0)
{
...
}


//frameworks/native/include/binder/iinterface.h
template<typename INTERFACE>
inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
: BpRefBase(remote)
{
}


//frameworks/av/media/libmedia/IMediaPlayer.cpp
class BpMediaPlayer: public BpInterface<IMediaPlayer>
{
public:
BpMediaPlayer(const sp<IBinder>& impl)
: BpInterface<IMediaPlayer>(impl)
{
}
...
}


原来是从子类一级一级注入的,那唯一的问题就是在哪里完成这个注入操作, 马上搜索"new BpMediaPlayer", 奇怪,竟然没有,试试搜索"IMediaPlayer“,发现了一点线索

//av/media/libmedia/IMediaPlayerService.cpp

70:     virtual sp<IMediaPlayer> create(
71:             const sp<IMediaPlayerClient>& client, int audioSessionId) {
72          Parcel data, reply;
73:         ...
77          remote()->transact(CREATE, data, &reply);
78:         return interface_cast<IMediaPlayer>(reply.readStrongBinder()); //reply里读出IBinder,然后转成IMediaPlayer接口对象
79      }


这里通过interface_cast 直接把IBinder 转换成了 IMediaPlayer, interface_cast 到底有什么魔力?

template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
return INTERFACE::asInterface(obj);
}


继续跟进 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;                                                    \
}                                                                   \


恍然大悟,原来在DECLARE_META_INTERFACE 这个宏里定义了asInterface, 在IMPLEMENT_META_INTERFACE 里实现了它,这里果然有一个new BpMediaPlayer! 然后把它转换成父父类 IMediaPlayer。

一切都清楚了,用一张图来表示



客户端从远端获取一个IBinder对象,接着生成BpMediaPlayer, 将其转成 IMediaPlayer 接口对象,这是用户程序看到的对象,并通过其调用接口方法,最终调到BpBinder的transact()。

问题又来了,这个transact() 怎么传递到服务端,并最终调到 onTransact()?

回想一下,onTransact() 是IBinder的接口函数吧,而且Server的IBinder实现是BBinder, 那一定有人通过某种方式得到了BBinder对象。

这个人就是Binder Driver. 为了找到真相,必须用源头开始,那就是transact()

status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
...
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
...
return DEAD_OBJECT;
}


IPCThreadState的transact()函数相比IBinder 多了一个mHandle, 啥来历?

BpBinder::BpBinder(int32_t handle)
: mHandle(handle)


构造带进来的,赶紧找“new BpBinder", 结果在ProcessState.cpp 看到了

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
...
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
b = new BpBinder(handle);


找谁call了getStrongProxyForHandle?为了快速找到调用栈,我们在BpBinder的构造函数里加了这么几句话:

#include <utils/CallStack.h>
...
CallStack cs;
cs.update();
cs.dump("BpBinder")


然后得到了下面的打印

09-29 07:11:14.363  1624  1700 D BpBinder: #00  pc 0001eb34  /system/lib/libbinder.so (android::BpBinder::BpBinder(int)+260)
09-29 07:11:14.363  1624  1700 D BpBinder: #01  pc 0003b9a2  /system/lib/libbinder.so (android::ProcessState::getStrongProxyForHandle(int)+226)
09-29 07:11:14.363  1624  1700 D BpBinder: #02  pc 00032b8c  /system/lib/libbinder.so (android::Parcel::readStrongBinder() const+316) //frameworks/native/libs/binder/Parcel.cpp:247
09-29 07:11:14.363  1624  1700 D BpBinder: #03  pc 000ad9d2  /system/lib/libandroid_runtime.so //frameworks/base/core/jni/android_os_Parcel.cpp:355
09-29 07:11:14.363  1624  1700 D BpBinder: #04  pc 00029c5b  /system/lib/libdvm.so (dvmPlatformInvoke+79) //dalvik/vm/arch/x86/Call386ABI.S:128


#04 dvmPlatformInvork 说明这是一个Jni调用,#03 对应的代码是

return javaObjectForIBinder(env, parcel->readStrongBinder());


应该是Java传下来一个Parcel对象,然后由本地代码进行解析,从中读出IBinder对象,并最终返回。也就是说,远端有人将这个IBinder对象封在Parcel里。还是没有头绪?继续顺着调用栈往前看,

#02 对应于下面的代码

status_t unflatten_binder(const sp<ProcessState>& proc,
const Parcel& in, sp<IBinder>* out)
{
const flat_binder_object* flat = in.readObject(false);
...case BINDER_TYPE_HANDLE:
*out = proc->getStrongProxyForHandle(flat->handle);
return finish_unflatten_binder(
static_cast<BpBinder*>(out->get()), *flat, in);
}
}
return BAD_TYPE;
}


#bionic/libc/kernel/common/linux/binder.h
struct flat_binder_object {
unsigned long type;
unsigned long flags;
union {
void *binder;
signed long handle;
};
void *cookie;
};


原来mHandle就是flat_binder_object里面的handle, 它只是一个数字!这个数据结构定义在Kernel里,是经过Kernel转手的。越来越乱了,赶紧整理一下思路:

1. Kernel 封装了一个数据结构(flat_binder_object),里面带有一个数字(mHandle)。

2. 客户端获取这个数字后,生成一个BpBinder的对象。

3. 然后当客户端需要访问远端服务的时候,将这个数字附上。

回到现实生活,机票代理需要向航空公司查询或订票的话,一定要知道是哪个航空公司,莫非这个号就是航空公司的编号?

恭喜你,就是那么简单,这个号就对应了服务器端的提供的某一个服务,Android 中每个Service都有一个号码(根据创建时间递增,0号Service 是ServiceManager,让我用下面的图来描述整个过程吧,



1. 在已知服务名的情况下,App 通过getService() 从ServiceManager 获取该服务的信息,该信息封装在Parcel里。

2. 应用程序收到返回的这个Parcel对象(通过Kernel), 从中读取出flat_binder_object 对象,最终从对象中得到服务对应的服务号,mHandle.

3. 以该号码作为参数输入生成一个IBinder对象(实际是BpBinder)。

4. 应用获取该对象后,通过asInterface(IBinder*) 生成服务对应的Proxy对象(BpXXX),并将其强转为接口对象(IXXX),然后直接调用接口函数。

5. 所有的接口对象调用最终会走到BpBinder->transact()函数,这个函数调用IPCThreadState->transact()并以Service号作为参数之一。

6. 最终通过系统调用ioctrl() 进入内核空间,Binder驱动根据传进来的Service 号寻找该Service正处于等待状态的Binder Thread, 唤醒它并在该线程内执行相应的函数,并返回结果给APP。

强调一下:

1. 从应用程序的角度来看,他只认识IBinder 和 IMediaPlayer 这两个类,但真正的实现在BpBinder 和 BpMediaPlayer, 这正是设计模式所推崇的“ Programs to interface, not implementations", 可以说Android 是一个严格遵循设计模式思想精心设计的系统,我们将来会就这个话题进行深入的探讨。

2. 客户端应该层层的封装,最终的目的就是获取和传递这个mHandle 值,从图中,我们看到,这个mHandle至来自与IServiceManager, 他是一个管理其他服务的服务,通过服务的名字我们可以拿到这个服务对应的Handle号,类似网络域名服务系统。但是我们说了,IServiceManager也是服务啊,要访问他我们也需要一个Handle号啊,对了,就如同你必须为你的机器设置DNS 服务器地址,你才能获得DNS 服务。在Android系统里, 默认的将ServiceManger的Handler号设为0,0就是DNS服务器的地址,这样,我们通过调用 getStrongProxyForHandle(0) 就可以拿到ServiceManager 的IBinder 对象,当然,系统提供一个 getService(char *)函数来帮助完成这个过程。

3. Android Binder 的设计目标就是让访问远端服务就像调用本地函数一样简单,但是远端的对象不在本地控制之内,我们必须保证调用过程中远端的对象不能被析构,否则本地应用程序将很有可能崩溃。同时,万一远端服务异常退出,如Crash, 本地对象必须知晓从而避免后续的错误。Android 通过 智能指针 和 DeathNotification 来支持这两个要求,我们会有专门的章节介绍智能指针,这里我们会在后面简单介绍 DeathNotifycation的实现原理。

Binder的上层设计逻辑简单介绍完毕。我们接下来看看Binder的底层设计。

3. Binder Driver

我们知道,Linux的进程空间相互独立,两个进程只能通过Kernel space 进行互访,所有的IPC 机制,最底层的实现都是在Kernel space. Binder 也是如此,通过系统调用切入内核态,内核寻找到提供服务的进程,唤醒他并进入用户空间,然后在某个线程里调用onTransact(), 完成特定操作,并将结果返回到应用程序。那Binder Driver是如何搭起连接服务端和客户端的这座桥梁呢?

先看看binder driver 内部的数据结构吧:



下面一一进行解释:

1. Binder node:

我们前面说过Service 其实是一个存在于某个进程里的对象,因此,进程PID 和 对象地址可以唯一的标识一个Service 对象,除此之外,因为这个对象可能被很多应用所使用,必须有引用计数来管理他的生命周期。这些工作都必须在内核里完成,Binder node 就是这样一个结构体来管理每个Service 对象。

struct binder_node {
int debug_id;              //kernel内部标识node的id
struct binder_work work;
union {
struct rb_node rb_node;
struct hlist_node dead_node;
};
struct binder_proc *proc;  //Service所在进程的结构体
struct hlist_head refs;    //双向链表头,链表里存放一系列指针,指向引用该Service的binder_ref对象,
int internal_strong_refs;  //内部强引用计数
int local_weak_refs;       //弱引用计数
int local_strong_refs;     //强引用计数
binder_ptr __user ptr;     //Service对象地址
binder_ptr __user cookie;
unsigned has_strong_ref:1;
unsigned pending_strong_ref:1;
unsigned has_weak_ref:1;
unsigned pending_weak_ref:1;
unsigned has_async_transaction:1;
unsigned accept_fds:1;
unsigned min_priority:8;
struct list_head async_todo;
};


2. binder_ref

binder_ref 描述了每个对服务对象的引用,对应与Client端。如上图所示,每个Ref通过node指向binder_node. 一个进程所有的binder_ref通过两个红黑树(RbTree)进行管理,通过binder_get_ref() 和 binder_get_ref_for_node快速查找。

struct binder_ref {
/* Lookups needed: */
/*   node + proc => ref (transaction) */
/*   desc + proc => ref (transaction, inc/dec ref) */
/*   node => refs + procs (proc exit) */
int debug_id;
struct rb_node rb_node_desc;
struct rb_node rb_node_node;
struct hlist_node node_entry;
struct binder_proc *proc;           //应用进程
struct binder_node *node;
uint32_t desc;
int strong;
int weak;
struct binder_ref_death *death;  //如果不为空,则client想获知binder的死亡
};


3. binder_proc

一个进程既包含的Service对象,也可能包含对其他Service对象的引用. 如果作为Service对象进程,它可能会存在多个Binder_Thread。这些信息都在binder_proc结构体进行管理。

struct binder_proc {
struct hlist_node proc_node; //全局链表 binder_procs 的node之一
struct rb_root threads; //binder_thread红黑树,存放指针,指向进程所有的binder_thread, 用于Server端
struct rb_root nodes;   //binder_node红黑树,存放指针,指向进程所有的binder 对象
struct rb_root refs_by_desc; //binder_ref 红黑树,根据desc(service No) 查找对应的引用
struct rb_root refs_by_node; //binder_ref 红黑树,根据binder_node 指针查找对应的引用
int pid;
struct vm_area_struct *vma;
struct mm_struct *vma_vm_mm;
struct task_struct *tsk;
struct files_struct *files;
struct hlist_node deferred_work_node;
int deferred_work;
void *buffer;
ptrdiff_t user_buffer_offset;

struct list_head buffers;
struct rb_root free_buffers;
struct rb_root allocated_buffers;
size_t free_async_space;

struct page **pages;
size_t buffer_size;
uint32_t buffer_free;
struct list_head todo; //task_list, binder_work链表,存放指针最终指向某个binder_transaction对象
wait_queue_head_t wait;
struct binder_stats stats;
struct list_head delivered_death;
int max_threads;
int requested_threads;
int requested_threads_started;
int ready_threads;
long default_priority;
struct dentry *debugfs_entry;
};


为了实现快速的查找,binder_proc内部维护了若干个数据结构,如图中黄色高亮所示,

4. binder_transaction

每个transact() 调用在内核里都会生产一个binder_transaction 对象,这个对象会最终送到Service进程或线程的todo队列里,然后唤醒他们来最终完成onTransact()调用。

struct binder_transaction {
int debug_id;             //一个全局唯一的ID
struct binder_work work; // 用于存放在todo链表里
struct binder_thread *from; //transaction 发起的线程。如果BC_TRANSACTION, 则为客户端线程,如果是BC_REPLY, 则为服务端线程。
struct binder_transaction *from_parent; //上一个binder_transaction. 用于client端
struct binder_proc *to_proc; //目标进程
struct binder_thread *to_thread; //目标线程
struct binder_transaction *to_parent; //上一个binder_transaction, 用于server端
unsigned need_reply:1;
/* unsigned is_dead:1; */    /* not used at the moment */

struct binder_buffer *buffer;
unsigned int    code;
unsigned int    flags;
long    priority;
long    saved_priority;
kuid_t    sender_euid;
};


5. binder_thread

binder_proc里的threads 红黑树存放着指向binder_thread对象的指针。这里的binder_thread 不仅仅包括service的binder thread, 也包括访问其他service的调用thread. 也就是说所有与binder相关的线程都会在binder_proc的threads红黑树里留下记录。binder_thread里最重要的两个成员变量是 transaction_stack 和 wait.

struct binder_thread {
struct binder_proc *proc;
struct rb_node rb_node; //红黑树节点
int pid;
int looper;  //
struct binder_transaction *transaction_stack; //transaction栈
struct list_head todo;
uint32_t return_error;
uint32_t return_error2;
wait_queue_head_t wait; //等待队列,用于阻塞等待
struct binder_stats stats;
};


在binder_proc里面我们也能看到一个wait 队列,是不是意味着线程既可以在proc->wait上等待,也可以在thread->wait上等待?binder driver 对此有明确的用法,所有的binder threads (server 端)都等待在proc->wait上。因为对于服务端来说,用哪个thread来响应远程调用请求都是一样的。然而所有的ref thread(client端)的返回等待都发生在调用thread的wait 队列,因为,当某个binder thread 完成服务请求后,他必须唤醒特定的等待返回的线程。但是有一个例外,在双向调用的情况下,某个Server端的thread将会挂在thread->wait上等待,而不是proc->wait. 举个例子,假设两个进程P1 和 P2,各自运行了一个Service, S1,S2, P1 在 thread T1 里调用S2提供的服务,然后在T1->wait里等待返回。S2的服务在P2的binder thread(T2)里执行,执行过程中,S2又调到S1里的某个接口,按理S1 将在P1的binder thread T3里执行, 如果P1接下来又调到了P2,那又会产生新的进程 T4, 如果这个反复调用栈很深,需要耗费大量的线程,显然这是非常不高效的设计。所以,binder driver 里做了特殊的处理。当T2 调用 S1的接口函数时,binder driver 会遍历T2的transaction_stack, 如果发现这是一个双向调用(binder_transaction->from->proc 等于P1), 便会唤醒正在等待reply的T1,T1 完成这个请求后,继续等待S2的回复。这样,只需要最多两个Thread就可以完成多层的双向调用。

binder_thread里的transaction_stack 是用链表实现的堆栈, 调用线程和服务线程的transaction有着不同的堆栈。下图是上面这个例子的堆栈情形:



6. binder_ref_death

binder_ref 记录了从client进程到server进程某个service的引用,binder_ref_death 是binder_ref的一个成员变量,它的不为空说明了client进程想得到这个service的死亡通知(严格意义上讲,是service所在进程的死亡通知,因为一个进程一个/dev/binder的fd, 只有进程死亡了,driver才会知晓,通过 file_operations->release 接口)。

struct binder_ref_death {
struct binder_work work;
binder_ptr __user cookie;
};


我们可以下面一张时序图来了解binder death notifycation 的全过程。



7. binder_work

从应用程序角度来看,所有的binder调用都是同步的。但在binder driver 内部,两个进程间的交互都是异步的,一个进程产生的请求会变成一个binder_work, 并送入目标进程或线程的todo 队列里,然后唤醒目标进程和线程来完成这个请求,并阻塞等待结果。binder_work的定义如下:

struct binder_work {
struct list_head entry;
enum {
BINDER_WORK_TRANSACTION = 1,
BINDER_WORK_TRANSACTION_COMPLETE,
BINDER_WORK_NODE,
BINDER_WORK_DEAD_BINDER,
BINDER_WORK_DEAD_BINDER_AND_CLEAR,
BINDER_WORK_CLEAR_DEATH_NOTIFICATION,
} type;
};


很简单,其实只定义了一个链表的节点和work的类型。

8. binder_buffer

进程间通信除了命令,还有参数和返回值的交换,要将数据从一个进程的地址空间,传到另外一个进程的地址空间,通常需要两次拷贝,进程A -> 内核 -> 进程B。binder_buffer 就是内核里存放交换数据的空间(这些数据是以Parcel的形式存在)。为了提高效率,Android 的 binder 只需要一次拷贝,因为binder 进程通过mmap将内核空间地址映射到用户空间,从而可以直接访问binder_buffer的内容而无需一次额外拷贝。binder_buffer由内核在每次发起的binder调用创建,并赋给binder_transaction->buffer. binder driver 根据binder_transaction 生产 transaction_data(包含buffer的指针而非内容), 并将其复制到用户空间。

9. flat_binder_obj

前面我们说过,<proc, handle> 可以标识一个BpBinder 对象,而<proc, ptr> 可以标识一个BBinder对象。Binder Driver 会收到来自与BpBinder 和 BBinder的系统调用,它是如何判别它们的身份呢?答案就在flat_binder_obj里,先看看它的定义,

struct flat_binder_object {
unsigned long type;  //见下面定义
unsigned long flags;
union {
void *binder;            //BBinder,通过它driver可以找到对应的node
signed long handle; //BpBinder,根据它driver可以找到对应的ref
};
void *cookie;
};

enum {
BINDER_TYPE_BINDER = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),
BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE),
BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE),
BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),
BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE),
};


union表明了在Server端和Client端它有着不同的解读。type则表明了它的身份。binder driver 根据它可以找到BpBinder 和 BBinder 在内核中相对应的对象 (ref 或 node). flat_binder_obj 封装在parcel里,详见Parcel.cpp.

至此,binder driver里面重要的数据结构都介绍完了,大家对binder driver的工作原理也有了大致的了解,这里再稍作总结:

1. 当一个service向binder driver 注册时(通过flat_binder_object), driver 会创建一个binder_node, 并挂载到该service所在进程的nodes红黑树。

2. 这个service的binder线程在proc->wait 队列上进入睡眠等待。等待一个binder_work的到来。

3. 客户端的BpBinder 创建的时候,它在driver内部也产生了一个binder_ref对象,并指向某个binder_node, 在driver内部,将client和server关联起来。如果它需要或者Service的死亡状态,则会生成相应的binfer_ref_death.

4. 客户端通过transact() (对应内核命令BC_TRANSACTION)请求远端服务,driver通过ref->node的映射,找到service所在进程,生产一个binder_buffer, binder_transactionbinder_work 并插入proc->todo队列,接着唤醒某个睡在proc->wait队列上的Binder_thread. 与此同时,该客户端线程在其线程的wait队列上进入睡眠,等待返回值。

5. 这个binder thread 从proc->todo 队列中读出一个binder_transaction, 封装成transaction_data (命令为 BR_TRANSACTION) 并送到用户空间。Binder用户线程唤醒并最终执行对应的on_transact() 函数。

6. Binder用户线程通过transact() 向内核发送 BC_REPLY命令,driver收到后从其thread->transaction_stack中找到对应的binder_transaction, 从而知道是哪个客户端线程正在等待这个返回。

7. Driver 生产新的binder_transaction (命令 BR_REPLY), binder_buffer, binder_work, 将其插入应用线程的todo对立,并将该线程唤醒。

8. 客户端的用户线程收到回复数据,该Transaction完成。

9. 当service所在进程发生异常退出,driver 的 release函数被调到,在某位内核work_queue 线程里完成该service在内核态的清理工作(thread,buffer,node,work...), 并找到所有引用它的binder_ref, 如果某个binder_ref 有不为空的binder_ref_death, 生成新的binder_work, 送人其线程的todo 对立,唤醒它来执行剩余工作,用户端的DeathRecipient 会最终被调用来完成client端的清理工作。

下面这张时序图描述了上述一个transaction完成的过程。不同的颜色代表不同的线程。注意的是,虽然Kernel和User space 线程的颜色是不一样的,但所有的系统调用都发生在用户进程的上下文里(所谓上下文,就是Kernel能通过某种方式找到关联的进程(通过Kernel的current 宏),并完成进程相关的操作,比如说唤醒某个睡眠的线程,或跟用户空间交换数据,copy_from, copy_to, 与之相对应的是中断上下文,其完全异步触发,因此无法做任何与进程相关的操作,比如说睡眠,锁等)。



4. Java Binder

Binder 的学习已经接近尾声了,我们已经研究了Binder Driver, C/C++的实现,就差最后一个部分了,Binder在Java端的实现了。Java端的实现与Native端类似,我们用下面的表格和类图概括他们的关系

NativeJavaNote
IBinderIBinder
IInterfaceIInterface
IXXXIXXXaidl文件定义
BBinderBinder通过JavaBBinder类作为桥梁
BpBinderBinderProxy通过JNI访问Native的实现
BnInterfaceN/A
BpInterface  N/A
BnXXXStubaidl工具自动生成   
BpXXX    Proxyaidl工具自动生成 



可见,Java较Native端实现简单很多,通过Aidl工具来实现类似功能。所以,要实现一个Java端的service,只需要做以下几件事情:

1. 写一个.aidl文件,里面用AIDL语言定义一个接口类IXXX。

2.在Android.mk里加入该文件,这样编译系统会自动生成一个IXXX.java, 放在out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core 下面。

3. 在服务端,写一个类,扩展IXXX.Stub,具体实现IXXX的接口函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: