Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

Android内核学习笔记—Binder分析

$
0
0

进程间通信——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目录中,如下所示:
image
要特别提醒的是,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

作者:gc_gongchao 发表于2017/8/7 23:31:29 原文链接
阅读:219 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles