进程间通信——Binder
概述
Binder是Android中使用最广泛的IPC机制。如果统观Binder中的各个组成元素,就会惊奇地发现它和TCP/IP网络有很多相似之处:
.Binder驱动——路由器
.Service Manager——DNS
.Binder Client——客户端
.Binder Server——服务器
Service Manager在Binder通信过程中的唯一标志永远都是0.
Binder驱动与协议
Android系统是基于Linux内核的,因而它所依赖的Binder驱动也必须是一个标准的Linux驱动。具体而言,Binder Driver会将自己注册成
一个misc device,并向上提供一个/dev/binder节点——值得一提的是,Binder节点并不对应真实的硬件设备。Binder驱动运行于内核态,
可以提供open(),ioctl(),mmap()等常用的文件操作。
Binder驱动源码在Kernel工程的drivers/staging/android目录中。
Android系统为什么把Binder注册成misc device类型的驱动呢?
这种”杂项”驱动的主设备号统一为10,次设备号则是每种设备独有的。驱动程序也可以通过设置MISC_DYNAMIC_MINOR来由系统动态分配次设备号。Linux中的字符设备通常要经过alloc_chrdev_region(),cdev_init()等一系列操作才能在内核中注册自己。而misc类型驱动则相对简单,只需要调用misc_register()就可轻松解决。
Binder驱动总共为上层应用程序提供了6个接口:
(1)binder_poll(2)binder_ioctl(3)binder_mmap(4)binder_open(5)binder_flush(6)binder_release.其中使用最多的binder_ioctl,binder_mmap
和binder_open。而一般文件操作需要用到的read()和write()则没有出现,这是因为它们的功能完全可以用ioctl()和mmap()来代替;而且后两者还更加灵活。
binder_open:上层进程在访问Binder驱动时,首先就需要开/dev/binder节点,这个操作最终的实现是 在binder_open()中。在binder_open函数中,Binder驱动会为用户创建一个它自己的 binder_proc实体。即Binder驱动会在/proc系统目录下生成各种管理信息(比如/proc/binder/proc,
/proc/binder/state,/proc/binder/stats等),binder_proc就是管理数据的记录体(每个进程都有 独立记录),用户对Binder设备的操作就是以binder_proc对象为基础的。
binder_mmap:该函数主要是对内存的管理,主要是对某块物理内存的共享,以便实现两个进程间的数据交互。
binder_ioctl:这是Binder接口函数中工作量最大的一个,它承担了Binder驱动的大部分业务。Binder并不提供read() 和write()等常规文件操作,因为binder_ioctl就可以完全替代它们。
binder_ioctl支持的命令:
1.BINDER_WRITE_READ:读写操作,可以用此命令向Binder读取或写入数据.
2.BINDER_SET_MAX_THREADS:设置支持的最大线程数,因为客户端可以并发向服务器端发送请求,如果Binder驱动发现当 前的线程数量已经超过设定值,就会告知Binder Server停止启动新的线程。
3.BINDER_SET_CONTEXT_MGR:Service Manager专用,将自己设置为”Binder大管家”。系统中只能有一个SM存在。
4.BINDER_THREAD_EXIT:通知Binder线程退出。每个线程在退出时都应该告知Binder驱动,这样才能释放相关资源,否则可能会造成内存泄露。
5.BINDER_VERSION:获取Binder版本号。
Binder驱动并没有脱离Linux的典型驱动模型,提供了多个文件操作接口。其中binder_ioctl实现了应用进程与Binder驱动之间的命令交互,可以说承载了Binder驱动中的大部分业务。
ServiceManager(Binder Server)
ServiceManager(以下简称SM)的功能可以类比为互联网中的”DNS”服务器,”IP地址”为0.另外,和DNS本身也是服务器一样,SM也是一个标准的Binder Server,Binder驱动中提供了专门为SM服务的相关命令。
ServiceManager的启动
ServiceManager是在init程序解析init.rc时启动的,另外需要注意的是:一旦ServiceManager发生问题后重启,其他系统服务zygote,media,surfaceflinger和drm 也会被重新加载。这个servicemanager是用c/c++编写的,源码路径在工程的
/frameworks/native/cmds/servicemanager目录中,如下所示:
要特别提醒的是,servicemanager所对应的c文件是service_manager.c和binder.c。源码工程中还有其他诸如ServiceManager.cpp的文件存在,但并不属于SM程序。
ServiceManager的构建
在Android系统中,Binder Server的另一个常见称谓是”XXX Service”,如Media Service,ActivityService等。
我们看下SM启动后都做了哪些工作,找到main函数.
//http://androidxref.com/5.1.0_r1/xref/frameworks/native/cmds/servicemanager/service_manager.c
int main(int argc, char **argv)
{
struct binder_state *bs;
bs = binder_open(128*1024);//打开Binder设备
if (!bs) {
ALOGE("failed to open binder driver\n");
return -1;
}
//将自己设置为Binder“大管家”,整个Android系统只允许一个ServiceManager存在,因而如果后面还
//有人调用这个函数就会失败
if (binder_become_context_manager(bs)) {
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
.................................................//代码省略
svcmgr_handle = BINDER_SERVICE_MANAGER;
binder_loop(bs, svcmgr_handler);//进入循环,等待客户请求
return 0;
}
我们可以看到main函数里主要做了以下几件事:
1.打开Binder设备,做好初始化
2.将自己设置为Binder大管家
3.进入主循环
下面我们再深入一些看一下这几件事:
//http://androidxref.com/5.1.0_r1/xref/frameworks/native/cmds/servicemanager/binder.c
struct binder_state *binder_open(size_t mapsize)
{
struct binder_state *bs;//这个结构体记录了SM中关于Binder的所有信息,如fd,map的大小等
struct binder_version vers;
bs = malloc(sizeof(*bs));
if (!bs) {
errno = ENOMEM;
return NULL;
}
bs->fd = open("/dev/binder", O_RDWR);//打开Binder驱动节点
if (bs->fd < 0) {
fprintf(stderr,"binder: cannot open device (%s)\n",
strerror(errno));
goto fail_open;
}
if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
(vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
fprintf(stderr, "binder: driver version differs from user space\n");
goto fail_open;
}
bs->mapsize = mapsize;//mapsize是SM自己设的,为128*1024,即128k
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
if (bs->mapped == MAP_FAILED) {
fprintf(stderr,"binder: cannot map device (%s)\n",
strerror(errno));
goto fail_map;
}
return bs;
fail_map:
close(bs->fd);//关闭file
fail_open:
free(bs);
return NULL;
}
/*
关于open和mmap最终都是调用的驱动层的binder_open和binder_mmap。
根据上面代码段中的参数设置可知:
1.由Binder驱动决定被映射到进程空间中的内存起始地址。
2.映射区块大小为128k
3.映射区只读
4.映射区的改变是私有的,不需要保存文件。
5.从文件的起始地址开始映射。
*/
接着我们来看第二件事,即将servicemanager注册成Binder机制的”大管家”.
//http://androidxref.com/5.1.0_r1/xref/frameworks/native/cmds/servicemanager/binder.c
int binder_become_context_manager(struct binder_state *bs)
{
return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
/*正如前面驱动部分的命令描述所陈述的那样,只要向Binder Driver发送BINDER_SET_CONTEXT_MGR的ioctl命令即可
。因为servicemanager启动得很早,能保证它是系统中的第一个向Binder驱动注册成"管家"的程序*/
第三件事就是看看SM是如何处理请求的:
//http://androidxref.com/5.1.0_r1/xref/frameworks/native/cmds/servicemanager/binder.c
void binder_loop(struct binder_state *bs, binder_handler func)
{
int res;
struct binder_write_read bwr;//这是执行BINDER_WRITE_READ命令所需的数据格式
uint32_t readbuf[32];//一次读取容量
bwr.write_size = 0;
bwr.write_consumed = 0;
bwr.write_buffer = 0;
readbuf[0] = BC_ENTER_LOOPER;//命令
binder_write(bs, readbuf, sizeof(uint32_t));
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);//读取消息
if (res < 0) {
ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
break;
}
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);//处理读取到的消息
if (res == 0) {
ALOGE("binder_loop: unexpected reply?!\n");
break;
}
if (res < 0) {
ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));
break;
}
}
}
/*由此可见,SM遵循以下几个步骤:
1.从Binder驱动读取消息:通过发送BINDER_WRITE_READ命令实现——z这个命令既可读取也可写入,具体
要看bwr.write_size和bwr.read_size。因为这里write_size的初始化值为
0,而read_size为sizeof(readbuf),所以Binder驱动只执行读取操作。
2.处理消息:调用binder_parse来解析消息。
3.不断循环,而且永远不会主动退出(除非出现致命错误)
*/
在binder_parse的处理过程中,需要重点关注下BR_TRANSACTION。
BR_TRANSACTION
对BR_TRANSACTION命令的处理主要由func来完成,然后将结果返回给Binder驱动。因为ServiceManager是为了完成”Binder Server Name”(域名)和”Server Handle”(IP地址)间对应关系的查询而存在的,所以可推测出它提供的服务应该至少包括以下几种:(1)注册:当一个Binder Server创建后,它们要将自己的名称,Binder句柄对应的关系告知SM进行备案。(2)查询:即应用程序可以向SM发起查询请求,以获知某个Binder Server所对应的句柄(3)其他信息查询:比如SM版本号,当前的状态等。当然,这一部分不是必需的,可以不实现。
注意在这里func函数指向svcmgr_handler函数。所以我们这里需要来看一下svcmgr_handler的实现:
//http://androidxref.com/5.1.0_r1/xref/frameworks/native/cmds/servicemanager/service_manager.c
int svcmgr_handler(struct binder_state *bs,
struct binder_transaction_data *txn,
struct binder_io *msg,
struct binder_io *reply)
{
struct svcinfo *si;
uint16_t *s;
size_t len;
uint32_t handle;
uint32_t strict_policy;
int allow_isolated;
//ALOGI("target=%x code=%d pid=%d uid=%d\n",
// txn->target.handle, txn->code, txn->sender_pid, txn->sender_euid);
if (txn->target.handle != svcmgr_handle)
return -1;
if (txn->code == PING_TRANSACTION)
return 0;
// Equivalent to Parcel::enforceInterface(), reading the RPC
// header with the strict mode policy mask and the interface name.
// Note that we ignore the strict_policy and don't propagate it
// further (since we do no outbound RPCs anyway).
strict_policy = bio_get_uint32(msg);
s = bio_get_string16(msg, &len);//bio_XX系列函数为取出各种类型的数据提供了便利。
if (s == NULL) {
return -1;
}
if ((len != (sizeof(svcmgr_id) / 2)) ||
memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
fprintf(stderr,"invalid id %s\n", str8(s, len));
return -1;
}
if (sehandle && selinux_status_updated() > 0) {
struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle();
if (tmp_sehandle) {
selabel_close(sehandle);
sehandle = tmp_sehandle;
}
}
switch(txn->code) {
case SVC_MGR_GET_SERVICE:
case SVC_MGR_CHECK_SERVICE://根据server名称查找它的handle值。
s = bio_get_string16(msg, &len);
if (s == NULL) {
return -1;
}
//do_find_service这个函数执行查找操作。SM中维护有一个全局的svclist变量,用于保存所有server的注册信息。
handle = do_find_service(bs, s, len, txn->sender_euid, txn->sender_pid);
if (!handle)
break;
bio_put_ref(reply, handle);//保存查询结果,以返回给客户端
return 0;
case SVC_MGR_ADD_SERVICE://用于注册一个Binder Server
s = bio_get_string16(msg, &len);
if (s == NULL) {
return -1;
}
handle = bio_get_ref(msg);
allow_isolated = bio_get_uint32(msg) ? 1 : 0;
//这个函数具体执行添加操作
if (do_add_service(bs, s, len, handle, txn->sender_euid,
allow_isolated, txn->sender_pid))
return -1;
break;
case SVC_MGR_LIST_SERVICES: {//获取列表中对应Server
uint32_t n = bio_get_uint32(msg);
if (!svc_can_list(txn->sender_pid)) {
ALOGE("list_service() uid=%d - PERMISSION DENIED\n",
txn->sender_euid);
return -1;
}
si = svclist;//所有的Server信息都保存于此。
while ((n-- > 0) && si)
si = si->next;
if (si) {
bio_put_string16(reply, si->name);
return 0;
}
return -1;
}
default:
ALOGE("unknown code %d\n", txn->code);
return -1;
}
bio_put_uint32(reply, 0);
return 0;
}
ServiceManager的功能架构比较简洁——其内部维护着一个svclist列表,用于存储所有Server相关信息(以svcinfo为数据结构),查询和注册都是基于这个表展开的。函数svcmgr_handler处理完成后,binder_parse会进一步通过binder_send_reply来将执行结果回复给底层Binder驱动,进而传递给客户端。然后binder_parse会进入下一轮的while循环,知道ptr < end为False——此时说明Service Manager上一次从驱动层读取的消息都已处理完成,因而它还会继续向Binder Driver发送BINDER_WRITE_READ以查询有没有消息。如果有的话就处理,否则会进入休眠等待。
我们来回忆一下顺序:init—>init.rc—>ServiceManager start->service_manager.c/main->binder.c/binder_open
->binder.c/binder_become_context_manager->binder.c/binder_loop->binder.c/binder_parse.
获取ServiceManager服务
所有Binder Client或者Binder Server都是围绕Binder驱动展开的。每个进程只允许打开一次Binder设备,且只做一次内存映射,所有需要使用Binder驱动的线程共享这一资源。与Binder驱动进行实际命令通信的是IPCThreadState.
ServiceManagerProxy
在Java层ServiceManagerProxy的封装类是ServiceManager.java.该类的部分代码如下:
//http://androidxref.com/5.1.0_r1/xref/frameworks/base/core/java/android/os/ServiceManager.java
public final class ServiceManager {
private static final String TAG = "ServiceManager";
private static IServiceManager sServiceManager;
//用于记录getService的历史查询结果,以加快查询速度。
private static HashMap<String, IBinder> sCache = new HashMap<String, IBinder>();
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
return sServiceManager;
}
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().getService(name);
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
public static void addService(String name, IBinder service) {
try {
getIServiceManager().addService(name, service, false);
} catch (RemoteException e) {
Log.e(TAG, "error in addService", e);
}
}
/*
*/
.........................//代码省略
}
通过上面的这部分代码我们可以发现,getService与addService的最终实现依赖IServiceManager的 某个实现类,我们看到sServiceManager的创建是依赖于 ServiceManagerNative.asInterface这方法.
下面我们继续查看这个函数的代码
//http://androidxref.com/5.1.0_r1/xref/frameworks/base/core/java/android/os/ServiceManagerNative.java
// Cast a Binder object into a service manager interface, generating a proxy if needed.
static public IServiceManager asInterface(IBinder obj)
{
if (obj == null) {
return null;
}
IServiceManager in =
(IServiceManager)obj.queryLocalInterface(descriptor);//查询本地是否已经有IServiceManager存在
if (in != null) {
return in;
}
//如果没有查询到,则新建一个ServiceManagerProxy.
return new ServiceManagerProxy(obj);
}
哈哈,看SM的代理ServiceManagerProxy终于出现了,可想而知ServiceManagerProxy必定是要与Binder驱动通信的,因而它的构造函数中传入了IBinder对象。我们看一下这个代理类的代码:
//http://androidxref.com/5.1.0_r1/xref/frameworks/base/core/java/android/os/ServiceManagerNative.java
class ServiceManagerProxy implements IServiceManager {
public ServiceManagerProxy(IBinder remote) {
mRemote = remote;
}
public IBinder asBinder() {
return mRemote;
}
public IBinder getService(String name) throws RemoteException {
//准备打包数据
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();//保存通讯结果
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name)
//打包数据结束
//利用IBinder的transact将请求发送出去,而不用理会Binder驱动的open,mmap以及一大堆具体
//的Binder协议中的命令。所以这个IBinder一定会在内部使用ProcessState和IPCThreadState来
//与Binder驱动进行通信,
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
return binder;
}
public IBinder checkService(String name) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
mRemote.transact(CHECK_SERVICE_TRANSACTION, data, reply, 0);
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
return binder;
}
public void addService(String name, IBinder service, boolean allowIsolated)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
data.writeStrongBinder(service);
data.writeInt(allowIsolated ? 1 : 0);
mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
reply.recycle();
data.recycle();
}
..........................................................................//代码省略
private IBinder mRemote;
/*
以上代码中的getService,checkService,addService这些函数的函数体的重要区别点在于命令的不同。
*/
}
IBinder和BpBinder
在创建ServiceManagerProxy时,传入了一个IBinder对象,然后借助于它的transact方法,可以方便地与Binder驱动进行通信。
那么我们的这个IBinder对象怎么来的呢?
我们可以看到在ServiceManager类中有这么一句ServiceManagerNative.asInterface(BinderInternal.getContextObject());然后再根据asInterface的代码我们可以肯定的是,这个IBinder对象是由BinderInternal.getContextObject()产生的。
//http://androidxref.com/5.1.0_r1/xref/frameworks/base/core/java/com/android/internal/os/BinderInternal.java
/**
* Return the global "context object" of the system. This is usually
* an implementation of IServiceManager, which you can use to find
* other services.
*/
public static final native IBinder getContextObject();//这个方法是native,所以我们得找到对应的jni实现
//http://androidxref.com/5.1.0_r1/xref/frameworks/base/core/jni/android_util_Binder.cpp
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
sp<IBinder> b = ProcessState::self()->getContextObject(NULL);//这里我们引出了ProcessState
return javaObjectForIBinder(env, b);//将native层创建的对象转换为Java层的IBinder对象。即BpBinder->BinderProxy
/*
这里有人可能会有疑问为什么取名为ContextObject呢?
Context即"背景,上下文",这里可以理解为运行时态的上下文。换句话说,是因为IPC和整个Process或者
Thread都是有紧密关联的。更进一步,基本上每个Process都需要IPC通信。既然如此,IPC就可以作为进程
的基础配置存在。作为IPC中的基础元素之一,Binder就是这个Context中的重要一环,因为称为ContexObject。
*/
}
IBinder只是一个接口类,显然还会有具体的实现类继承于它。在Native层,这就是BpBinder(BpBinder.cpp);而在Java层,则是Binder.java中的BinderProxy。事实上,ProcessState::self()->getContextObject(NULL)返回的就是一个BpBinder对象。BinderProxy和BpBinder分别继承自Java和Native层的IBinder接口。其中BpBinder是由ProcessState创建的,而BinderProxy是由javaObjectForIBinder()函数通过JNI的NewObject()创建的。
ProcessState和IPCThreadState
实现ProcessState的关键点在于:
1.保证同一个进程中只有一个ProcessState实例存在,而且只有在ProcessState对象创建时才打开Binder设备以及做内存映射。
2.向上层提供IPC服务
3.与IPCThreadState分工合作,各司其职。
我们来看一下ProcessState的代码:
//http://androidxref.com/5.1.0_r1/xref/frameworks/native/libs/binder/ProcessState.cpp
//这个函数我们在之前的获取ContextObject的时候用到过,访问ProcessState需要使用ProcessStata::Self()。
//如果当前已经有实例(gProcess不为空)存在,就直接返回这个对象;否则,新建一个ProcessState。
sp<ProcessState> ProcessState::self()
{
Mutex::Autolock _l(gProcessMutex);
if (gProcess != NULL) {
return gProcess;
}
gProcess = new ProcessState;//创建对象
return gProcess;
}
ProcessState::ProcessState()
: mDriverFD(open_driver())//注意这里打开驱动
, mVMStart(MAP_FAILED)
, mManagesContexts(false)
, mBinderContextCheckFunc(NULL)
, mBinderContextUserData(NULL)
, mThreadPoolStarted(false)
, mThreadPoolSeq(1)
{
if (mDriverFD >= 0) {//成功打开/dev/binder
// XXX Ideally, there should be a specific define for whether we
// have mmap (or whether we could possibly have the kernel module
// availabla).
#if !defined(HAVE_WIN32_IPC)
// 开始执行mmap,内存块大小为:BINDER_VM_SIZE ((1*1024*1024) - (4096 *2)),即接近1M的空间
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
if (mVMStart == MAP_FAILED) {
// *sigh*
ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
close(mDriverFD);
mDriverFD = -1;
}
#else
mDriverFD = -1;
#endif
}
LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating.");
}
void ProcessState::setContextObject(const sp<IBinder>& object)
{
setContextObject(object, String16("default"));
}
<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
return getStrongProxyForHandle(0);//传入0,代表Service Manager
}
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;//需要返回的IBinder
AutoMutex _l(mLock);
/**查找一个Vector表mHandleToObject,这里保存了这个进程已经建立的Binder相关信息。
如果没有找到相应节点,会自动添加一个。所以返回值正常情况下为非空。
mHandleToObject记录所有与Binder对象相关的信息,而每个表项是一个handle_entry,包含了
如下数据:
struct handle_entry{IBinder * binder;RefBase::weakref_type * refs;};
其中的binder属性实际上是一个BpBinder,而且程序只有在以下两种情况下才会生成一个BpBinder:
1.在列表中没有找到对应的BpBinder。
2.虽然从列表中查找到了对应的节点,但是没有办法顺利对这个BpBinder增加weakreference.
**/
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) {
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);//BpBinder出现了。
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;
}
ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
{
const size_t N=mHandleToObject.size();
if (N <= (size_t)handle) {
handle_entry e;
e.binder = NULL;
e.refs = NULL;
status_t err = mHandleToObject.insertAt(e, N, handle+1-N);
if (err < NO_ERROR) return NULL;
}
return &mHandleToObject.editItemAt(handle);
}
static int open_driver()
{
int fd = open("/dev/binder", O_RDWR);
if (fd >= 0) {
fcntl(fd, F_SETFD, FD_CLOEXEC);
int vers = 0;
status_t result = ioctl(fd, BINDER_VERSION, &vers);
if (result == -1) {
ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
close(fd);
fd = -1;
}
if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
ALOGE("Binder driver protocol does not match user space protocol!");
close(fd);
fd = -1;
}
size_t maxThreads = 15;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
if (result == -1) {
ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
}
} else {
ALOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
}
return fd;
}
...........................................................//代码省略
上面的代码注释中讲到了什么情况下才会生成一个BpBinder,那我们看一下BpBinder的构造函数
//http://androidxref.com/5.1.0_r1/xref/frameworks/native/libs/binder/BpBinder.cpp
BpBinder::BpBinder(int32_t handle)
: mHandle(handle)//如果是SM,handle为0
, mAlive(1)
, mObitsSent(0)
, mObituaries(NULL)
{
ALOGV("Creating BpBinder %p handle %d\n", this, mHandle);
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
IPCThreadState::self()->incWeakHandle(handle);//IPCThreadState出现了
}
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// Once a binder has died, it will never come back to life.
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);//在ServiceManagerProxy中的mRemote.transact最终调用的是IPCThreadState:self()->transact
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
我们前面说过IPCThreadState负责与Binder驱动进行具体的命令交互(ProcessState只是负责打开了Binder节点并做mmap),下面我们看看IPCThreadState的代码:
//http://androidxref.com/5.1.0_r1/xref/frameworks/native/libs/binder/IPCThreadState.cpp
IPCThreadState* IPCThreadState::self()
{
/*当第一次被调用时,gHaveTLS为false,因而不会进入第一个if判断中,也不会创建IPCThreadState.但是随后
它就会进入第二个if判断并启动TLS,然后返回restart处新建一个IPCThreadState。当以后再被调用时,gHaveTLS
为true,如果本线程已经创建过IPCThreadState,那么pthread_getspecific就不为空;否则返回一个新建的IPCThreadState
*/
if (gHaveTLS) {//这个变量初始值是false
restart://当启用TLS后,重新回到这
const pthread_key_t k = gTLS;
IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
if (st) return st;
return new IPCThreadState;
}
if (gShutdown) return NULL;
pthread_mutex_lock(&gTLSMutex);
if (!gHaveTLS) {
if (pthread_key_create(&gTLS, threadDestructor) != 0) {
pthread_mutex_unlock(&gTLSMutex);
return NULL;
}
gHaveTLS = true;//以后都是TLS了
}
pthread_mutex_unlock(&gTLSMutex);
goto restart;//返回restart接着执行
}
IPCThreadState::IPCThreadState()
: mProcess(ProcessState::self()),//ProcessState整个进程只有一个
mMyThreadId(androidGetTid()),//当前的线程id
mStrictModePolicy(0),
mLastTransactionBinderFlags(0)
{
pthread_setspecific(gTLS, this);
clearCaller();
mIn.setDataCapacity(256);//mIn是一个Parcel,从名称可以看出来,它是用于接收Binder发过来的数据的,最大容量为256
mOut.setDataCapacity(256);//mOut也是一个Parcel,它是用于存储要发送给Binder的命令数据的,最大容量为256
}
void IPCThreadState::incWeakHandle(int32_t handle)
{
LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)\n", handle);
mOut.writeInt32(BC_INCREFS);
mOut.writeInt32(handle);
}
void IPCThreadState::decWeakHandle(int32_t handle)
{
LOG_REMOTEREFS("IPCThreadState::decWeakHandle(%d)\n", handle);
mOut.writeInt32(BC_DECREFS);
mOut.writeInt32(handle);
}
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
status_t err = data.errorCheck();
flags |= TF_ACCEPT_FDS;
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "
<< handle << " / code " << TypeCode(code) << ": "
<< indent << data << dedent << endl;
}
if (err == NO_ERROR) {
LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
(flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
/*将数据打包成Binder驱动协议规定的格式,这个过程由writeTransactionData来完成(注意:
这个函数只是整理数据,并把结果存入mOut中。而在talkWithDriver()方法中才会将命令真正发
送给Binder驱动)*/
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
}
if (err != NO_ERROR) {
if (reply) reply->setError(err);
return (mLastError = err);
}
if ((flags & TF_ONE_WAY) == 0) {
#if 0
if (code == 4) { // relayout
ALOGI(">>>>>> CALLING transaction 4");
} else {
ALOGI(">>>>>> CALLING transaction %d", code);
}
#endif
if (reply) {
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
#if 0
if (code == 4) { // relayout
ALOGI("<<<<<< RETURNING transaction 4");
} else {
ALOGI("<<<<<< RETURNING transaction %d", code);
}
#endif
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
<< handle << ": ";
if (reply) alog << indent << *reply << dedent << endl;
else alog << "(none requested)" << endl;
}
} else {
err = waitForResponse(NULL, NULL);
}
return err;
}
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
int32_t cmd;
int32_t err;
while (1) {
if ((err=talkWithDriver()) < NO_ERROR) break;//将已有数据进行必要的包装,然后发送给Binder驱动
err = mIn.errorCheck();//错误检查
if (err < NO_ERROR) break;//数据有错误
if (mIn.dataAvail() == 0) continue;//如果没有可用数据,进入下一轮循环
cmd = mIn.readInt32();//读取cmd
IF_LOG_COMMANDS() {
alog << "Processing waitForResponse Command: "
<< getReturnString(cmd) << endl;
}
switch (cmd) {
case BR_TRANSACTION_COMPLETE:
if (!reply && !acquireResult) goto finish;
break;
case BR_DEAD_REPLY:
err = DEAD_OBJECT;
goto finish;
case BR_FAILED_REPLY:
err = FAILED_TRANSACTION;
goto finish;
case BR_ACQUIRE_RESULT:
{
ALOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
const int32_t result = mIn.readInt32();
if (!acquireResult) continue;
*acquireResult = result ? NO_ERROR : INVALID_OPERATION;
}
goto finish;
case BR_REPLY:
{
binder_transaction_data tr;
err = mIn.read(&tr, sizeof(tr));
ALOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
if (err != NO_ERROR) goto finish;
if (reply) {
if ((tr.flags & TF_STATUS_CODE) == 0) {
reply->ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t),
freeBuffer, this);
} else {
err = *reinterpret_cast<const status_t*>(tr.data.ptr.buffer);
freeBuffer(NULL,
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), this);
}
} else {
freeBuffer(NULL,
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), this);
continue;
}
}
goto finish;
default:
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
}
finish:
if (err != NO_ERROR) {
if (acquireResult) *acquireResult = err;
if (reply) reply->setError(err);
mLastError = err;
}
return err;
}
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
if (mProcess->mDriverFD <= 0) {//Binder驱动设备还没打开
return -EBADF;
}
binder_write_read bwr;//读写都使用这个数据结构
// Is the read buffer empty?
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
// We don't want to write anything if we are still reading
// from data left in the input buffer and the caller
// has requested to read the next data.
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data();
// This is what we'll read.
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}
IF_LOG_COMMANDS() {
TextOutput::Bundle _b(alog);
if (outAvail != 0) {
alog << "Sending commands to driver: " << indent;
const void* cmds = (const void*)bwr.write_buffer;
const void* end = ((const uint8_t*)cmds)+bwr.write_size;
alog << HexDump(cmds, bwr.write_size) << endl;
while (cmds < end) cmds = printCommand(alog, cmds);
alog << dedent;
}
alog << "Size of receive buffer: " << bwr.read_size
<< ", needRead: " << needRead << ", doReceive: " << doReceive << endl;
}
// Return immediately if there is nothing to do.
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
bwr.write_consumed = 0;//>0说明Binder驱动消耗了mOut中的数据
bwr.read_consumed = 0;//>0说明Binder驱动已经成功帮我们读取到了数据,并写入了mIn.data().
status_t err;
do {
IF_LOG_COMMANDS() {
alog << "About to read/write, write size = " << mOut.dataSize() << endl;
}
#if defined(HAVE_ANDROID_OS)
/*执行完ioctl后,通过bwr.write_consumed和bwr.read_consumed可以知道Binder驱动对
我们请求的BINDER_WRITE_READ命令的处理情况,然后对mIn和mOut做善后处理*/
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
#else
err = INVALID_OPERATION;
#endif
if (mProcess->mDriverFD <= 0) {
err = -EBADF;
}
IF_LOG_COMMANDS() {
alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
}
} while (err == -EINTR);
IF_LOG_COMMANDS() {
alog << "Our err: " << (void*)(intptr_t)err << ", write consumed: "
<< bwr.write_consumed << " (of " << mOut.dataSize()
<< "), read consumed: " << bwr.read_consumed << endl;
}
if (err >= NO_ERROR) {
if (bwr.write_consumed > 0) {
if (bwr.write_consumed < mOut.dataSize())
mOut.remove(0, bwr.write_consumed);
else
mOut.setDataSize(0);
}
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
}
IF_LOG_COMMANDS() {
TextOutput::Bundle _b(alog);
alog << "Remaining data size: " << mOut.dataSize() << endl;
alog << "Received commands from driver: " << indent;
const void* cmds = mIn.data();
const void* end = mIn.data() + mIn.dataSize();
alog << HexDump(cmds, mIn.dataSize()) << endl;
while (cmds < end) cmds = printReturnCommand(alog, cmds);
alog << dedent;
}
return NO_ERROR;
}
return err;
}
注意不管是读取还是写入,Binder驱动只是发挥中间人的作用,真正处理请求的还是Binder Client和Binder Server通信双方。
下面我们简单的来总结一下:
1.ServiceManagerProxy
当某个Binder Server在启动时,会把自己的名称name与对应的Binder句柄值保存在ServiceManager中。调用者通常只知道Binder Server的名称,所以必须先向Service Manager发起查询请求,就是getService(name)。任何Binder Client都可以直接通过
0这个Binder句柄创建一个BpBinder,再通过Binder驱动去获取Service Manager的服务,具体而言,就是调用BinderInternal的 getContextObject()来获得Service Manager的BpBinder.Android系统同时支持Java与C/C++层的Binder机制,因而很多对象 都必须有”双重身份”,如BpBinder在Java层以IBinder来表示。对于Service Manager而言,IBinder的真正持有者与使用者是ServiceManagerProxy.
2.ProcessState和IPCThreadState
大多数程序都有IPC的需要,而进程间通信本身又是非常烦琐的,因而Android系统特别为程序进程使用Binder机制封装了两个实现类,即ProcessState和IPCThreadState。从名称上可以看出,前者是进程相关的,而后者是线程相关的。ProcessState负责打开Binder驱动设备,进行mmap()等准备工作,而如何与Binder驱动进行具体的命令通信则由IPCThreadState来完成。在getService()这个场景中,调用者是从Java层的IBinder.transact()开始,层层往下调用到IPCThreadState.transact(),然后通过waitForResponse进入主循环,直至收到Service Manager的回复后才跳出循环,并将结果再次层层回传到应用层。
注意:真正与Binder驱动打交道的地方是talkWithDriver中的ioctl(),整个流程中多次调用了这个函数。
3.Binder驱动
Binder驱动通过巧妙的机制来使数据的传递更加高效,即只需要一次复制就可以把数据从一个进程复制到另一个进程。Binder中还保存着大量的全局以及进程相关的变量,用于管理每个进程/线程的状态,内存申请和待办事项等一系列复杂的数据信息。正是这些变量的有效协作,才使得整个Binder通信真正”动”了起来。
4.Service Manager的实现
ServiceManager在Android系统启动之后就运行起来了,并通过BINDER_SET_CONTEXT_MGR把自己注册成Binder”“大管家”.它在做完一系列初始
化后,在最后一次ioctl的read操作中会进入等待,直到有Binder Client发起服务请求而被Binder驱动唤醒。Service Manager唤醒后,程序分为两条主线索。其一,Service Manager端将接着执行read操作,把调用者的具体请求读取出来,然后利用binder_parse解析,再根据实际情况填写transaction信息,最后把结果BR_REPLY命令(也是ioctl)返回Binder驱动。其二,发起getService请求的Binder Client在等待Service Manager回复的过程中会进入休眠,直到被Binder驱动再次唤醒——它和Service Manager一样也是在read中睡眠的,因而醒来后继续执行读取操作。这一次得到的就是Service Manager对请求的执行结果。程序先把结果填充到reply这个Parcel中,然后通过层层返回到ServiceManagerProxy,再利用Parcel.readStrongBinder生成一个BpBinder,最终经过类型转换为IBinder对象后传给调用者。
Binder客户端——Binder Client
Binder的最大”“消费者”是Java层的应用程序。关于Binder Client,我们只需要知道的是Binder的Client端和Server端需要继承同样的公共接口类。Binder Client提供了与Binder Sever一样的函数原型,使用户感觉不出Server是运行在本地还是远端。
Android接口描述语言——AIDL
AIDL是Android Interface Description Language 的简写。从名称上看它是一种语言,而且是专门用于描述接口的语言。准确地说,它是用于定义客户端/服务端通信接口的一种描述语言。
这里我们先看一下构建一个Binder Server所需的工作是怎样的,主要考虑的因素如下:
1.启动的时机:主要考虑什么时候启动,比如SM是开机的时候通过init.rc文件启动的,这就保证了它是系统中第一个注册成”“服务大管家”的Service。
2.提供一致的服务接口:显然,一个Binder Server应该向公众暴露它所能提供的服务;而且客户端使用的服务接口和服务端实现的服务接口必须是完全 一致的。注意这里有个不一样的地方,SM中的服务接口是IServiceManager。客户端本地进程中的ServiceManagerProxy及 ServiceManagerNative都继承自这个接口。而它的服务端是直接用C语言实现的(Service_mananger.c)。不过通过分析其内部 binder_parse函数可知,它还是保持了与客户端接口的一致。
3.与Binder驱动的交互方式:一个Binder Server需要与Binder Driver做哪些交互呢?除去一系列必要的初始化以外(open,mmap等),就是要通过不断地ioctl来循环读写数据。比如SM就是通过binder_loop函数中的一个for死循环来完成这一工作的。
4.外界如何能访问到这个Server的服务:访问Server主要有两种方法:
(1)Server在ServiceManager中注册:这种方法普遍存在于Android系统服务中,如ActivityManagerService,WindowManagerService等都在ServiceManager中做了注册。调用者只要通过ServiceManager.getService(SERVICE_NAME)就可以获取到Binder Server的本地代理,然后与之通信
(2)通过其他Server作为中介:这是一种”“匿名”的方法。换句话说,这种类型的Binder Server不需要在ServiceManager中注册,通过一个”“第三方”的”实名”Sever——因为是实名的,调用者可以通过ServiceManager来首先访问到
它,然后由它提供的接口获取”匿名”者的Binder句柄。
关于匿名Binder Server与实名Server的差异主要就在于后者是通过ServiceManager来获得对它的引用,而前者则是以其他实名Server为中介来传递这一引用信息。
注:关于Android系统的深入知识也是之前一年的主要学习内容,由于没有去记录,导致了看过的许多东西都忘记了,感觉就是没有学习一样,最近的一段时间会陆续的整理出一些东西,Android系统的深入知识,主要参考资料为博客与《深入理解Android内核设计思想》等,当然还有源码。另:需要说明一点的是,文章标题以说明为笔记,所以大部分内容为摘抄,主要来源书籍。
转载请注明出处:http://blog.csdn.net/android_jiangjun/article/details/76691860