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

1. Service是什么?

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

  1. 请求Service服务的代码(Client)  和 Service本身(Server) 不在一个线程,很多情况下不在一个进程内。跨进程的服务称为远端(Remote)服务,跨进程的调用称为IPC。通常应用程序通过代理(Proxy)对象来访问远端的Service。
  2. Service 可以运行在native 端(C/C++),也可以运行在Java 端。同样,Proxy 可以从native 端访问Java Service, 也可以从Java端访问native service, 也就是说,service的访问与语言无关。
  3. Android里大部分的跨进程的IPC都是基于Binder实现。
  4. Proxy 通过 Interface 类定义的接口访问Server端代码。
  5. Service可以分为匿名和具名Service. 前者没有注册到ServiceManager, 应用无法通过名字获取到访问该服务的Proxy对象。
  6. 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

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

接口 BBinder BpBinder
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是客户端,为什么这么说?

  1. pingBinder, BBinder直接返回OK,而BpBinder需要运行一个transact函数,这个函数具体做什么,我们后面会介绍。
  2. linkToDeath()是用来在服务挂的时候通知客户端的,那服务端当然不需要自己监视自己咯,所以BBinder直接返回非法,而Bpbinder需要通过requestDeathNotification()要求某人完成这个事情,究竟是谁提供这个服务?答案后面揭晓。
  3. 在Android中,remote一般代表某个远端对象的本地代理,想象一下航空公司和机票代理,BBinder是航空公司,当然没有remote的了,那BpBinder就是机票代理了,所以remote()自然返回自己了。
  4. 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() = ;
};

这也太简单了吧,只是定义了 从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 = );
}; class IMediaPlayer: public IInterface
{
public:
DECLARE_META_INTERFACE(MediaPlayer);
... }

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

归纳一下,

  1. BBinder 实现了大部分的IBinder 接口,除了onTransact() 和 queryLocalInterface(), getInterfaceDescriptor();
  2. BnInterface 实现了IBinder的queryLocalInterface()和getInterfaceDescriptor(), 但是其必须借助实际的接口类。
  3. BnMediaPlayer只是定义了onTransact(), 没有实现。
  4. onTransact()的具体实现在Client类。

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

  1. 定义一个接口文件, IXXXService, 继承IInterface
  2. 定义BnXXX(), 继承 BnInterface<IXXXService)
  3. 实现一个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()
{
...
}
//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

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

这里通过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:;
unsigned pending_strong_ref:;
unsigned has_weak_ref:;
unsigned pending_weak_ref:;
unsigned has_async_transaction:;
unsigned accept_fds:;
unsigned min_priority:;
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:;
/* 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 = ,
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端类似,我们用下面的表格和类图概括他们的关系

Native Java Note
IBinder IBinder  
IInterface IInterface  
IXXX IXXX aidl文件定义
BBinder Binder  通过JavaBBinder类作为桥梁
BpBinder BinderProxy  通过JNI访问Native的实现
BnInterface N/A  
BpInterface   N/A  
BnXXX Stub aidl工具自动生成   
BpXXX     Proxy aidl工具自动生成 
     

可见,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的接口函数。

图解Android - Binder 和 Service的更多相关文章

  1. 图解Android - System Service 概论 和 Android GUI 系统

    通过 图解Android - Binder 和 Service 一文中,我们已经分析了Binder 和 Service的工作原理.接下来,我们来简要分析Android 系统里面都有哪些重要的Servi ...

  2. 图解Android - 如何看Android的UML 图?

    如何看UML图? UML能给我们带来什么? 这是本文要寻找的答案.UML图有很多类型,我们这里只讨论最重要也最常用的两种 - 类图和时序图. 1. 类图 通过类图,我们可以很容易的了解代码架构,理清模 ...

  3. Android 核心分析 之六 IPC框架分析 Binder,Service,Service manager

    IPC框架分析 Binder,Service,Service manager 我首先从宏观的角度观察Binder,Service,Service Manager,并阐述各自的概念.从Linux的概念空 ...

  4. Android使用binder访问service的方式(一)

    binder机制是贯穿整个android系统的进程间访问机制,经常被用来访问service,我们结合代码看一下binder在访问service的情形下是怎么具体使用的. service 你可以理解成没 ...

  5. (转载)Android中的Service:Binder,Messenger,AIDL(2)

    前言 前面一篇博文介绍了关于Service的一些基本知识,包括service是什么,怎么创建一个service,创建了一个service之后如何启动它等等.在这一篇博文里有一些需要前一篇铺垫的东西,建 ...

  6. Android 使用binder访问service的方式

    binder机制是贯穿整个Android系统的进程间访问机制,经常被用来访问service,我们结合代码看一下binder在访问service的情形下是怎么具体使用的. service 你可以理解成没 ...

  7. 图解Android - Android GUI 系统 (5) - Android的Event Input System

    Android的用户输入处理 Android的用户输入系统获取用户按键(或模拟按键)输入,分发给特定的模块(Framework或应用程序)进行处理,它涉及到以下一些模块: Input Reader: ...

  8. Android Binder机制彻底梳理二

    根据AIDL了解整体调用流程[重点分析AIDL流程]: 在上一次https://www.cnblogs.com/webor2006/p/11741743.html中我们已经对Android Binde ...

  9. Android探索之Service全面回顾及总结

    什么是Service? Service(服务)是Android提供的四大组件之一,是一个没有用户界面的在后台运行执行耗时操作的应用组件.其他应用组件能够启动Service,并且当用户切换到另外的应用场 ...

随机推荐

  1. java 空指针异常(java.lang.NullPointerException)

    在Java中对值为null的指针调用任何方法,就会引发空指针异常(java.lang.NullPointerException).空指针异常绝对 是Java中最难查找和调试的一种异常,你永远无法得到任 ...

  2. 边工作边刷题:70天一遍leetcode: day 71-1

    Longest Substring with At Most K Distinct Characters 要点:要搞清楚At Most Two Distinct和Longest Substring W ...

  3. HDU 3333 Turing Tree --树状数组+离线处理

    题意:统计一段序列[L,R]的和,重复元素只算一次. 解法:容易看出在线做很难处理重复的情况,干脆全部讲查询读进来,然后将查询根据右端点排个序,然后离散化数据以后就可以操作了. 每次读入一个数,如果这 ...

  4. CSU 1060 Nearest Sequence

    题意:求三个序列的最长公共子序列. 思路:一开始以为只要求出前两个的LCS,然后和第三个再求一遍LCS就是答案了.但是样例就对我进行啪啪啪打脸了.实际上就跟两个序列的差不多,换成三维的就行了. 代码: ...

  5. 在Android Studio中使用shareSDK进行社会化分享(图文教程)

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...

  6. eclipse android 不会自动生成R.java文件和包的解决办法

    eclipse下编写android程序突然不会自动生成R.java文件和包的解决办法   我的eclipse原来是好好的,什么问题都没有的,结果今天一打开新建一个android程序,发现工程里不会自动 ...

  7. 使用clone( )和Cloneable接口

    由Object类定义的绝大部分方法在本书其他部分讨论.而一个特别值得关注的方法是clone( ).clone( )方法创建调用它的对象的一个复制副本.只有那些实现Cloneable接口的类能被复制. ...

  8. Lambda表达式关于like问题(未解决)

    参考文章: http://stackoverflow.com/questions/3616215/like-in-lambda-expression-and-linq 1. c=>c.name. ...

  9. Android 开发环境下载地址 -- 百度网盘 adt-bundle android-studio sdk adt 下载

    最近 Google 被墙了, 上传一下自己收集的 Android 开发环境, 下面给出的官网链接也可以下载; http://www.androiddevtools.cn/ 1. 百度网盘下载地址 An ...

  10. SilverIight数据绑定实例

    前台Code <DataGrid Name="DataGrid1" AutoGenerateColumns="False" IsReadOnly=&quo ...