Android Binder机制分析

I. Android系统Binder机制之一(Service Manager篇)

本文转载整理自: http://my.unix-center.net/~Simon_fu/?p=875 


 

一、前言

Android虽然构建在Linux上面,但是在IPC(进程间)机制方面,没有利用Linux提供IPC机制,而是自己实现了一套轻量级的IPC机制——binder机制。并且Android Binder机制之上,Android框架提供了一套封装,可以实现对象代理(在本地进程中代理远程进程的对象)。本文简单分析一下Android Binder机制。

二、Binder情景分析

    一个IPC通讯我们可以理解成客户端-服务器模式,因此我们先在这里分析一下典型的Binder应用模式:

 

1、客户端通过某种方式(后文会详细介绍)得到服务器端的代理对象。从客户端角度看来代理对象和他的本地对象没有什么差别。它可以像其他本地对象一样调用其方法,访问其变量。 

2、客户端通过调用服务器代理对象的方法向服务器端发送请求。 

3、代理对象把用户请求通过Android内核(Linux内核)的Binder驱动发送到服务器进程。 

4、服务器进程处理用户请求,并通过Android内核(Linux内核)的Binder驱动返回处理结果给客户端的服务器代理对象。 

5、客户端收到服务器端的返回结果。

 

    如果你对COM或者Corba熟悉的话,以上的情景是否会让你联想到什么呢?没错!都是对象代理。以上的情景,在Android中经常会被用到。如果你还没有注意到这点儿,那么本文非常适合你。

三、Binder机制的组成

1、Binder驱动

    binder是内核中的一个字符驱动设备位于:/dev/binder。这个设备是Android系统IPC的核心部分,客户端的服务代理用来通过它向服务器(server)发送请求,服务器也是通过它把处理结果返回给客户端的服务代理对象。我们只需要知道它的功能就可以了,本文我们的重点不在这里,所以后面不会专门介绍这部分。如果想深入了解的话,请研究内核源码中的binder.c。

2、Service Manager

    负责管理服务。对应于第一步中,客户端需要向Service Manager来查询和获得所需要服务。服务器也需要向Service Manager注册自己提供的服务。可以看出Service Manager是服务的大管家。

3、服务(Server)

    需要强调的是这里服务是指的是System Server,而不是SDK server,请参考《(转)高焕堂——Android框架底层结构知多少?》关于两种Server的介绍(其实应该是三种,丢掉了init调用的server,在init.rc中配置)。

4、客户端

    一般是指Android系统上面的应用程序。它可以请求Server中的服务。

5、对象代理

    是指在客户端应用程序中生成的Server代理(proxy)。从应用程序角度看代理对象和本地对象没有差别,都可以调用其方法,方法都是同步的,并且返回相应的结果。

 

四、大内总管——Service Manager

    Android系统Binder机制的总管是Service Manager,所有的Server(System Server)都需要向他注册,应用程序需要向其查询相应的服务。可见其作用是多么的重要,所以本文首先介绍Service Manager。

    通过上面介绍我们知道Service Manager非常重要,责任重大。那么怎样才能成为Service Manager呢?是不是谁都可以成为Service Manager呢?怎样处理server的注册和应用程序的查询和获取服务呢?为了回答这些问题先查看,Android中Service Manager的源码,其源码位于:

frameworks\base\cmds\servicemanager\service_manager.c

我们发现了main函数,说明他自己就是一个进程,在init.rc中我们发现:

 

service servicemanager /system/bin/servicemanager

user system

critical

onrestart restart zygote

onrestart restart media


 

说明其是Android核心程序,开机就会自动运行。

    下面我们在研究一下它的代码,main函数很简单:

 

int main(int argc, char **argv)

{

    struct binder_state *bs;

    void *svcmgr = BINDER_SERVICE_MANAGER;

    bs = binder_open(128*1024);

    if (binder_become_context_manager(bs)) {

        LOGE("cannot become context manager (%s)\n", strerror(errno));

        return -1;

    }

    svcmgr_handle = svcmgr;

    binder_loop(bs, svcmgr_handler);

    return 0;

}


 

我们看到它先调用binder_open打开binder设备(/dev/binder),其次它调用了binder_become_context_manager函数,这个函数使他自己变为了“Server大总管”,其代码如下:

 

int binder_become_context_manager(struct binder_state *bs)

{

    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);

}


 

也就是通过ioctl向binder设备声明“我就是server大总管”。

    Service Manager作为一个Server大总管,本身也是一个server。既然是一个server就要时刻准备为客户端提供服务。最后Service Manager调用binder_loop进入到循环状态,并提供了一个回调函数,等待用户的请求。注意他的Service Manager的客户端既包括应用程序(查询和获取服务),也包括Server(注册服务)。

    Service Manager的客户怎样才能请求其服务呢?答案是上文我们提到的情景一样。客户需要在自己进程中创建一个服务器代理。现在没有地方去查询服务,那么它的客户怎样生成他的服务代理对象呢?答案是binder设备(/dev/binder)为每一个服务维护一个句柄,调用binder_become_context_manager函数变为“Server大总管”的服务,他的句柄永远是0,是一个“众所周知”的句柄,这样每个程序都可以通过binder机制在自己的进程空间中创建一个Service Manager代理对象了。其他的服务在binder设备在设备中的句柄是不定的,需要向“Server大总管”查询才能知道。

    现在我们需要研究Server怎样注册服务了,还是在其源码中,我们可以看到在其服务处理函数中(上文提到binder_loop函数注册给binder设备的回调函数svcmgr_handler)有如下代码:

 

    

case SVC_MGR_ADD_SERVICE:

        s = bio_get_string16(msg, &len);

        ptr = bio_get_ref(msg);

        if (do_add_service(bs, s, len, ptr, txn->sender_euid))

            return -1;

        break;


有server向binder设备写入请求注册Service时,Service Manager的服务处理回调函数将会被调用。我们在仔细看看do_add_service函数的实现:

 

int do_add_service(struct binder_state *bs,

                   uint16_t *s, unsigned len,

                   void *ptr, unsigned uid)

{

    struct svcinfo *si;

//    LOGI("add_service('%s',%p) uid=%d\n", str8(s), ptr, uid);




    if (!ptr || (len == 0) || (len > 127))

        return -1;

    if (!svc_can_register(uid, s)) {

        LOGE("add_service('%s',%p) uid=%d - PERMISSION DENIED\n",

             str8(s), ptr, uid);

        return -1;

    }

    si = find_svc(s, len);

    if (si) {

        if (si->ptr) {

            LOGE("add_service('%s',%p) uid=%d - ALREADY REGISTERED\n",

                 str8(s), ptr, uid);

            return -1;

        }

        si->ptr = ptr;

    } else {

        si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));

        if (!si) {

            LOGE("add_service('%s',%p) uid=%d - OUT OF MEMORY\n",

                 str8(s), ptr, uid);

            return -1;

        }

        si->ptr = ptr;

        si->len = len;

        memcpy(si->name, s, (len + 1) * sizeof(uint16_t));

        si->name[len] = '\0';

        si->death.func = svcinfo_death;

        si->death.ptr = si;

        si->next = svclist;

        svclist = si;

    }

    binder_acquire(bs, ptr);

    binder_link_to_death(bs, ptr, &si->death);

    return 0;

}


 

我们看到首先检查是否有权限注册service,没权限就对不起了,出错返回;然后检查是否已经注册过,注册过的service将不能再次注册。然后构造一个svcinfo对象,并加入一个全局链表中svclist中。最后通知binder设备:有一个service注册进来。  si->ptr = ptr;这里的ptr应该就是注册的service的句柄。

    我们再来看看客户端怎样通过Service Manager获得Service,还是在服务处理函数中(上文提到binder_loop函数注册给binder设备的回调函数)有如下代码:

 

   

 case SVC_MGR_GET_SERVICE:

    case SVC_MGR_CHECK_SERVICE:

        s = bio_get_string16(msg, &len);

        ptr = do_find_service(bs, s, len);

        if (!ptr)

            break;

        bio_put_ref(reply, ptr);

        return 0;


 

    我们可以看到通过do_find_service查找Service如果查找到的话,写入reply中返回给客户端。

do_find_service函数也在service_manager.c文件中,其源码如下:

 

void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len)

{

    struct svcinfo *si;

    si = find_svc(s, len);

//    LOGI("check_service('%s') ptr = %p\n", str8(s), si ? si->ptr : 0);

    if (si && si->ptr) {

        return si->ptr;

    } else {

        return 0;

    }

}


do_find_service又调用了find_svc函数,其源码如下:

struct svcinfo *svclist = 0;

struct svcinfo *find_svc(uint16_t *s16, unsigned len)

{

    struct svcinfo *si;

    for (si = svclist; si; si = si->next) {

        if ((len == si->len) &&

            !memcmp(s16, si->name, len * sizeof(uint16_t))) {

            return si;

        }

    }

    return 0;

}

 

II. Android系统Binder机制之二(服务代理对象 上篇)

    上文《Android系统Binder机制之一(Service Manager篇)》我们学习了Service Manager在Android Binder中的作用——服务(Service)注册,服务(Service)查询的功能。本文我们一起学习服务(Service)在客户端中的代理机制。重点介绍其核心对象BpBinder。 

一、服务代理的基本原理

    如下是客户端请求service服务的场景:

 

1、首先客户端向Service manager查找相应的Service。关于此,上文《Android系统Binder机制之一(Service Manager篇)》已有比较详细的介绍。注意客户端和Service可能在两个不同的进程中。 

2、Android系统将会为客户端进程中创建一个Service代理。关于此,下文将详细介绍。 

3、客户端视角只有Service代理,他所有对Service的请求都发往Service代理,然后有Service代理把用户请求转发给Service本身。Service处理完成之后,把结果返回给Service代理,Service代理负责把处理结果返回给客户端。注意客户端对Service代理的调用都是同步调用(调用挂住,直到调用返回为止),这样客户端视角来看调用远端Service的服务和调用本地的函数没有任何区别。这也是Binder机制的一个特点。

二、Android进程环境——ProcessState类型和对象

    在Android系统中任进程何,要想使用Binder机制,必须要创建一个ProcessState对象和IPCThreadState对象。当然如果Android进程不使用Binder机制,那么这两个对象是不用创建的。这种情况很少见,因为Binder机制是整个Android框架的基础,可以说影响到Android方方面面。所以说了解这两个对象的作用非常重要。

    台湾的高焕堂先生一片文章《认识ProcessState类型和对象》,可以在我的博文《(转)高焕堂——Android框架底层结构知多少?》中找到。可以先通过这篇文章对ProcessState进行一个大概了解。

    ProcessState是一个singleton类型,一个进程只能创建一个他的对象。他的作用是维护当前进程中所有Service代理(BpBinder对象)。一个客户端进程可能需要多个Service的服务,这样可能会创建多个Service代理(BpBinder对象),客户端进程中的ProcessState对象将会负责维护这些Service代理。

我们研究一下创建一个Service代理的代码:

frameworks\base\libs\binder\ProcessState.cpp中



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);

}





sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)

{

    sp<IBinder> result;

    AutoMutex _l(mLock);

    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)) {

            b = new BpBinder(handle); 

            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;

}


 

 getWeakProxyForHandle函数的作用是根据一个binder句柄(上文《Android系统的Binder机制之一——Service Manager》提到Binder驱动为每个Service维护一个Binder句柄,客户端可以通过句柄来和Service通讯)创建对应的Service代理对象。

    当前进程首先调用lookupHandleLocked函数去查看当前进程维护的Service代理对象的列表,该待创建Service代理对象是否已经在当前进程中创建,如果已经创建过了,则直接返回其引用就可以了。否则将会在Service代理对象的列表增加相应的位置(注意系统为了减少分配开销,可能会多分配一些空间,策略是“以空间换时间”),保存将要创建的代理对象。具体代码请参考lookupHandleLocked的源码。

    后面代码就好理解了,如果Service代理对象已经创建过了且当前弱引用数大于0(该值是通过attemptIncWeak返回),直接引用就行了。否则,则需要创建一个新的Service代理对象。

 

三、Android进程环境——IPCThreadState类型和对象

    Android进程中可以创建一个ProcessState对象,该对象创建过程中会打开/dev/binder设备,并保存其句柄。并初始化该设备。代码如下:

 

static int open_driver()

{

    int fd = open("/dev/binder", O_RDWR);

    if (fd >= 0) {

        fcntl(fd, F_SETFD, FD_CLOEXEC);

        int vers;

        status_t result = ioctl(fd, BINDER_VERSION, &vers);

        if (result == -1) {

            LOGE("Binder ioctl to obtain version failed: %s", strerror(errno));

            close(fd);

            fd = -1;

        }

        if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {

            LOGE("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) {

            LOGE("Binder ioctl to set max threads failed: %s", strerror(errno));

        }

    } else {

        LOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));

    }

    return fd;

}

ProcessState::ProcessState()

    : mDriverFD(open_driver())

    , mVMStart(MAP_FAILED)

    , mManagesContexts(false)

    , mBinderContextCheckFunc(NULL)

    , mBinderContextUserData(NULL)

    , mThreadPoolStarted(false)

    , mThreadPoolSeq(1)

{

    if (mDriverFD >= 0) {

        // 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 the binder, providing a chunk of virtual address space to receive transactions.

        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);

        if (mVMStart == MAP_FAILED) {

            // *sigh*

            LOGE("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.");

}


 

mDriverFD保存了/dev/binder设备的句柄,如果仔细查看ProcessState的源码会发现这个句柄不会被ProcessState对象使用。那么保存这个句柄做什么用呢?被谁使用呢?非常奇怪。经过查看ProcessState的头文件,发现如下代码:

 friend class IPCThreadState;


    发现IPCThreadState是ProcessState的友元类,那么就可以怀疑这个句柄是被IPCThreadState的对象使用的,然后查看代码发现确实如此。

    IPCThreadState也是一个singleton的类型,一个进程中也只能有一个这样的对象。它的源码也位于frameworks\base\libs\binder目录下。我们查看一下它的talkWithDriver函数:        

if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)

            err = NO_ERROR;

        else

            err = -errno;


 IPCThreadState通过ioctl系统调用对ProcessState打开的句柄进行读写。这样我们也可以看出IPCThreadState对象的作用:

 

1、维护当前进程中所有对/dev/binder的读写。换句话说当前进程通过binder机制进行跨进程调用都是通过IPCThreadState对象来完成的。

2、IPCThreadState也可以理解成/dev/binder设备的封装,用户可以不直接通过ioctl来操作binder设备,都通过IPCThreadState对象来代理即可。

不管是客户端进程和Service进程都是需要用IPCThreadState来和binder设备通讯的。

如果是客户端进程则通过服务代理BpBinder(IBinder的一个子类)对象的transact函数调用IPCThreadState的transact函数,该函数作用就是把客户端的请求写入binder设备另一端的Service进程,具体请参阅IPCThreadState类的transact方法。

如果是Service进程,当他完成初始化工作之后,他需要他们需要进入循环状态等待客户端的请求,Service进程调用它的IPCThreadState对象的joinThreadPool方法,开始轮询binder设备,等待客户端请求的到来,后面我们讨论Service时候会进一步讨论joinThreadPool方法。有兴趣的朋友可以先通过查看代码来了解joinThreadPool方法。

 

四、Service代理对象BpBinder

    上文关于ProcessState的介绍提到了,客户端进程创建的Service代理对象其实就是BpBinder对象。BpBinde其实是IBinder的一个子类。我们首先了解怎样创建BpBinder对象。

BpBinder::BpBinder(int32_t handle)

    : mHandle(handle)

    , mAlive(1)

    , mObitsSent(0)

    , mObituaries(NULL)

{

    LOGV("Creating BpBinder %p handle %d\n", this, mHandle);




    extendObjectLifetime(OBJECT_LIFETIME_WEAK);

    IPCThreadState::self()->incWeakHandle(handle);

}


我们可以看出首先是通过IPCThreadState读写binder设备增加中相应binder句柄上的Service的引用计数。然后本地保存代理Service的binder句柄mHandle。

    客户进程对Service的请求都通过调用BpBinder的transact方法来完成:

IBinder的transact函数源码如下

 

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);

        if (status == DEAD_OBJECT) mAlive = 0;

        return status;

    }

    return DEAD_OBJECT;

}


 

五、Android系统对Binder机制的抽象——IBinder

    上面我们讲解了Binder机制比较底层的机制,这些机制直接用还是比较麻烦的,比如使用binder设备的ioctl,需要记住很多ioctl的代码。

    Android为了是Binder机制容易使用,对Binder机制进行了抽象,定义了IBinder接口,该接口在C/C++和Java层都有定义。IBinder定义了一套使用Binder机制使用和实现客户程序和服务器的通讯协议。可以理解如下定义:

 

1、向Android注册的Service也必须是IBinder(继承扩展IBinder接口)对象。后续文章中我们讨论Service的时候我们会介绍到这方面的内容。

2、客户端得到Service代理对象也必须定义成IBinder(继承扩展IBinder接口)对象。这也是为什么BpBinder就是继承自IBinder。

3、客户端发送请求给服务器端,将Service代理对象IBinder接口的transact方法。

4、Android系统Binder机制将负责把用户的请求,调用Service对象IBinder接口的onTransact方法。具体实现我们将在以后介绍Service的时候讨论。

 

六、Service Manager代理对象

    我们知道Service Manager是Android Binder机制的大管家。所有需要通过Binder通讯的进程都需要先获得Service Manager的代理对象才能进行Binder通讯。Service Manager即在C/C++层面提供服务代理,又在Java层面提供服务代理,本文先介绍一下C/C++层面的服务代理,Java层面的服务代理将在后续文章中介绍。

    进程在C/C++层面上面,Android在Android命名空间中定义了一个全局的函数defaultServiceManager(定义在framework/base/libs/binder/IServiceManager.cpp),通过这个函数可以使进程在C/C++层面获得Service Manager的代理。我们先看一下该函数的定义:

 

sp<IServiceManager> defaultServiceManager()

{

    if (gDefaultServiceManager != NULL) return gDefaultServiceManager;

    {

        AutoMutex _l(gDefaultServiceManagerLock);

        if (gDefaultServiceManager == NULL) {

            gDefaultServiceManager = interface_cast<IServiceManager>(

                ProcessState::self()->getContextObject(NULL));

        }

    }

    return gDefaultServiceManager;

}


我们可以看到defaultServiceManager是调用ProcessState对象的getContextObject方法获得Service Manager的getContextObject方法获得Service Manager代理对象。我们再看一下getContextObject函数的定义:

sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller)

{

    return getStrongProxyForHandle(0);

}


    我们可以看出其实是调用我们上面描述过的getStrongProxyForHandle方法,并以句柄0为参数来获得Service Manager的代理对象。

    ProcessState::self()->getContextObject(NULL)返回一个IBinder对象,怎样把它转化成一个IServiceManager的对象呢?这就是模板函数interface_cast<IServiceManager>的作用了。调用的是IServiceManager.asInterface方法。IServiceManager的asInterface方法通过DECLARE_META_INTERFACE和IMPLEMENT_META_INTERFACE宏来定义,详细情况请查看IServiceManager类的定义。IMPLEMENT_META_INTERFACE宏关于asInterface的定义如下:

#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;                                                    \

    }                                                                   \

    I##INTERFACE::I##INTERFACE() { }                                    \

    I##INTERFACE::~I##INTERFACE() { }                                   \  


    最终asInterface将会用一个IBinder对象创建一个BpServiceManager对象,并且BpServiceManager继承自IServiceManager,这样我们就把IBinder对象转换成了IServiceManager对象。如果你仔细查看BpServiceManager的定义,你会发现查询Service,增加Service等方法其实都是调用底层的IBinder对象来完成的。

    当我们在C/C++层面编写程序使用Binder机制的时候将会调用defaultServiceManager函数来获得Service Manager,比如:很多Android系统Service都是在C/C++层面实现的,他们就需要向Service Manager注册其服务,那么这些服务将调用defaultServiceManager获得Service Manager代理对象。我们在后续介绍Android系统Service的时候将会详细介绍。

另注:IPCThreadState虽然也是Singleton模式(构造函数私有,通过IPCThreadState::self获取对象实例),但是IPCThreadState可不是一个进程只有一个哦!

    IPCThreadState对象是放到线程私有存储(Thread Local Storage)中的,一个进程可能有多个线程,因此IPCThreadState是每个线程都可能拥有一个。TLS通过全局的key获取。TLS相当于线程中的“线程全局”变量,线程中的函数是可以直接获取的(你不能在线程函数栈中new一个IPCThreadState对象,但你能获得该线程唯一的IPCThreadState对象)。

    参考多线程编程模型,再看看IPCThreadState::self为什么那样实现,就知道我所言非虚。

 

III. Android系统Binder机制之三(服务代理对象 下篇)

   上文《Android系统的Binder机制之二——服务代理对象(1)》我们学习了进程的C/C++层面的服务代理对象BpBinder,和Binder底层处理方式。本文我们将深入分析一下在进程的Java层面服务代理对象的创建和使用。

一、Android进程的C/C++层面和Java层

    Android中程序大部分都是java开发,底层通过JNI调用C/C++的代码。这样一个程序就分为了两个层面C/C++层面和Java层面。运行状态下,我们说它们都在一个进程之中,拥有相同的进程属性(UID,GID等等)。

    Binder客户程序的C/C++层面的对象和原理我们在上文《Android系统的Binder机制之二——服务代理对象(1)》已经学习。下面我们将介绍客户程序怎样在Java层面通过JNI调用底层C/C++代码的创建服务代理。

ServiceManager类型和对象

    我在《Android系统的Binder机制之一——Service Manager》中介绍过,客户端要想获得服务代理,首先要向ServiceManager查询Service。在Java层面也是这样,所以我们首先分析Java层面ServiceManager类。

    我们通过查看android.os.ServiceManager的源码我们发现,ServiceManager类型也是一个Singleton类型。所有的方法都是静态方法,所有静态方法都是访问它的IServiceManager类型的静态变量sServiceManager,定义如下:

private static IServiceManager sServiceManager;

所以可以理解ServiceManager就是IServiceManager对象的一个代理。为创建和访问这个变量都是通过ServiceManager的getIServiceManager方法,定义如下:

 

    private static IServiceManager getIServiceManager() {
        if (sServiceManager != null) {

            return sServiceManager;

        }

        // Find the service manager

        sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());

        return sServiceManager;

    }


   通过上面的代码,非常清晰的告诉我们ServiceManager类型是一个Singleton类型。现在我们主要研究sServiceManager对象怎样创建的。如下代码创建IServiceManager对象:

sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());

 

我们首先查看BinderInternal类的getContextObject方法的代码,发现是Native代码(哈哈!有终于到达C/C++层面了,我们已经熟悉了),对应的代码为android_util_binder.cpp中的android_os_BinderInternal_getContextObject函数,代码如下:

static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{

    sp<IBinder> b = ProcessState::self()->getContextObject(NULL);

    return javaObjectForIBinder(env, b);

}


 

    终于看到我们上文《Android系统的Binder机制之二——服务代理对象(1)》介绍过的ProcessState对象了,我们再去查看ProcessState对象的getContextObject方法,代码如下:

 

C语言的sprintf函数跟printf在用法上几乎一样,只是两者打印的目的地不同而已,前者打印到字符串中,后者则直接在命令行上输出

sprintf是个变参函数,定义如下:

sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller)
{

    return getStrongProxyForHandle(0);

}


 

    我们看到在当前进程的ProcessState对象其实是调用getStrongProxyForHandle方法来创建binder句柄为0的服务代理对象——BpBinder对象,我们在《Android系统的Binder机制之一——Service Manager》提到过ServiceManager的binder句柄是一个闻名句柄0。上文《Android系统的Binder机制之二——服务代理对象(1)》已经介绍过ProcessState对象的getStrongProxyForHandle方法,这里就不多说了。

    我们可以看出Java调用C/C++,创建一个服务代理对象BpBinder,在查看BpBinder的定义我们发现继承自IBinder接口,然后在android_util_binder.cpp中的方法android_os_BinderInternal_getContextObject中,把C/C++层面的IBinder对象封装成Java层面的IBinder对象。具体实现可以查看上文的android_os_BinderInternal_getContextObject方法。

    至此我们已经清楚BinderInternal.getContextObject(),返回的是ServiceManager的服务代理对象——BpBinder对象。那么ServiceManagerNative类的静态方法asInterface做什么用呢?我们还是通过代码来分析,在ServiceManagerNative.java中,asInterface的代码如下:

     
static public IServiceManager asInterface(IBinder obj)
    {

        if (obj == null) {

            return null;

        }

        IServiceManager in =

            (IServiceManager)obj.queryLocalInterface(descriptor);

        if (in != null) {

            return in;

        }

        

        return new ServiceManagerProxy(obj);

    }


    将会用IBinder对象创建一个ServiceManagerProxy对象,ServiceManagerProxy类型实现了IServiceManager接口,所以asInterface方法最终目的是用一个IBinder对象创建一个IServiceManager对象。

    为什么要用IBinder对象创建一个IServiceManager对象呢?通过ServiceManager的代理对象——IBinder对象(BpBinder对象)应该可以直接请求ServiceManager中的服务了啊?我们在前文《Android系统的Binder机制之二(服务代理对象 上篇)》简单介绍了一下IBinder类型,客户端通过transact方法向Service发送请求,且请求通过请求代码来区分。具体请参考Android手册,也可以参照后面将介绍的ServiceManagerProxy的getService()方法。如果客户端直接用调用ServiceManager的代理对象的IBinder接口,那么客户端必须要记住所有请求的请求代码,对客户端来说不太友好。所以在ServiceManagerNative类中就把ServiceManager的代理对象——IBinder对象(BpBinder对象)封装成ServiceManagerProxy对象,暴露给客户程序一个IServiceManager接口,这样IServiceManager对象(其实是ServiceManagerProxy对象)将会代理客户程通过IBinder把请求发往服务器。客服程序只是简单的调用IServiceManager接口的方法来给ServiceManager发送请求,这样对客户程序来讲和本地的函数调用是一致的,接口非常友好。比如我们客户程序需要调用IServiceManager的getService方法来查询一个Service,ServiceManagerProxy实现代码如下:

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);

        mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);

        IBinder binder = reply.readStrongBinder();

        reply.recycle();

        data.recycle();

        return binder;

    }

}


 

    我们可以非常清晰的看到ServiceManagerProxy对象将客户程序的请求转换成对ServiceManager代理对象——IBinder对象(BpBinder对象)的调用。后文我们将会详细介绍怎样通过IServiceManager查询和获得一个系统Service代理对象。

    到这里我们已经分析完了,ServiceManager的Singleton对象——sServiceManager的创建。如果有不清楚的地方请查看代码。

二、查询和获得Service代理对象

    客户程序通过调用ServiceManagerNative的静态方法asInterface获得了IServiceManager对象,但是最终目的一般都是要查询和获得其他的Service,一般都是要调用IServiceManager的getService方法,向ServiceManager获得其他的Service。比如:

 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);

    上面的代码中就是调用ServiceManager的静态方法获得网络管理服务代理对象。我们顺藤摸瓜,看看系统是怎样生成这个Service代理对象的。这里只是简单说明一下调用顺序,详细过程请查看源码。

1、调用ServiceManager.java中的ServiceManager静态方法getService。

2、调用ServiceManagerNative.java中的ServiceManagerProxy方法getService。代码如下:

    
public IBinder getService(String name) throws RemoteException {
        Parcel data = Parcel.obtain();

        Parcel reply = Parcel.obtain();

        data.writeInterfaceToken(IServiceManager.descriptor);

        data.writeString(name);

        mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);

        IBinder binder = reply.readStrongBinder();

        reply.recycle();

        data.recycle();

        return binder;

    }


    请注意IBinder的transact方法是同步方法(本例中ServiceManager处理完成请求之后才会返回),我们可以看出调用transact之后,调用reply.readStrongBinder()来读取IBinder对象。

3、查看Parcel.java中的readStrongBinder方法,发现是Native方法,将会调用到C/C++的代码。

4、查看android_util_binder.cpp中的android_os_Parcel_readStrongBinder函数。代码如下:

static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jobject clazz)
{

    Parcel* parcel = parcelForJavaObject(env, clazz);

    if (parcel != NULL) {

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

    }

    return NULL;

}


 

parcel->readStrongBinder()将会产生一个IBinder对象。

5、查看Parcel.cpp中,Parcel的方法readStrongBinder。代码如下:

sp<IBinder> Parcel::readStrongBinder() const
{

    sp<IBinder> val;

    unflatten_binder(ProcessState::self(), *this, &val);

    return val;

}


 

6、查看Parcel.cpp中,Parcel的方法unflatten_binder。代码如下:

status_t unflatten_binder(const sp<ProcessState>& proc,
    const Parcel& in, sp<IBinder>* out)

{

    const flat_binder_object* flat = in.readObject(false);

    if (flat) {

        switch (flat->type) {

            case BINDER_TYPE_BINDER:

                *out = static_cast<IBinder*>(flat->cookie);

                return finish_unflatten_binder(NULL, *flat, in);

            case BINDER_TYPE_HANDLE:

                *out = proc->getStrongProxyForHandle(flat->handle);

                return finish_unflatten_binder(static_cast<BpBinder*>(out->get()), *flat, in);

        }        

    }

    return BAD_TYPE;

}



 

终于看到调用我们的老朋友ProcessState对象的getStrongProxyForHandle方法了,这样将会创建一个BpBinder对象,然后该BpBinder对象将会被转换成IBinder对象返回给Java层。

7、Java层为了用使用Service方便,可以把Service代理对象——BpBinder对象(IBinder对象)封装成一个对客户程序友好的代理对象,就如前面ServiceManagerProxy所示那样。

8、用户程序就可以通过该代理对象访问相应Service了。

    通过所述,我们了解了Service代理对象在Java层的创建和使用。Android系统的Binder机制博大精深,我在本文中很多方面都是蜻蜓点水,如果想深入学习请参阅Android的源码。

参考资料:

IPC框架分析 Binder,Service,Service manager

IV. Android系统的Binder机制之四(系统Service篇)

前面我们已经介绍了Android Binder机制的Service ManagerService对象代理(上)Service对象代理(下)。本文将介绍一下Android机制的另外一个重要部分——系统Service。

一、系统Service实例——Media server

    首先我们先看一下Android一个实例Media Service,代码位于framework/base/media/mediaserver/main_mediaserver.cpp文件:

#include <sys/types.h>
#include <unistd.h>

#include <grp.h>




#include <binder/IPCThreadState.h>

#include <binder/ProcessState.h>

#include <binder/IServiceManager.h>

#include <utils/Log.h>




#include <AudioFlinger.h>

#include <CameraService.h>

#include <MediaPlayerService.h>

#include <AudioPolicyService.h>

#include <private/android_filesystem_config.h>




using namespace android;




int main(int argc, char** argv)

{

    sp<ProcessState> proc(ProcessState::self());

    sp<IServiceManager> sm = defaultServiceManager();

    LOGI("ServiceManager: %p", sm.get());

    AudioFlinger::instantiate();

    MediaPlayerService::instantiate();

    CameraService::instantiate();

    AudioPolicyService::instantiate();

    ProcessState::self()->startThreadPool();

    IPCThreadState::self()->joinThreadPool();

}


 

 我们发现Media Server是一个进程,并且该程序的实现表面上也挺简单,其实并不简单,让我们慢慢分析一下Media Server。

1、第一句创建创建一个ProcessState的引用,但是这个对象后面并没有被调用到,那么为什么创建呢?回想一下《

Android系统的Binder机制之二(服务代理对象 上篇)》中介绍ProcessState对象时提到:如果一个进程要使用Binder机制,

那么他的进程中必须要创建一个ProcessState对象来负责管理Service的代理对象。

2、第二句调用defaultServiceManager获得一个Service Manager代理对象,

我在《Android系统的Binder机制之二(服务代理对象 上篇)》已经对此有了详细的介绍这里就不赘述了。


 

3、后面几行都是创建具体的Service,我们展开之后发现都是一些调用Service Manager的addService进行注册的函数,以AudioFlinger为例,instantiate代码如下:

   void AudioFlinger::instantiate() {

       defaultServiceManager()->addService(

               String16("media.audio_flinger"), new AudioFlinger());

   }

 

4、最后调用ProcessState的startThreadPool方法和IPCThreadState的joinThreadPool使Media Server进入等待请求的循环当中。

    我们可以看出一个进程中可以有多个Service,Media Server这个进程中就存在AudioFlinger,MediaPlayerService,CameraService,AudioPolicyService四个Service。

二、系统Service的基础——BBinder

    我们仔细查看一下Media Server中定义的四个Service我们将会发现他们都是继承自BBinder,而BBinder又继承自IBinder接口,详细情况请自行查看他们的代码。每个Service都改写了BBinder的onTransact虚函数,当用户发送请求到达Service时,框架将会调用Service的onTransact函数,后面我们将会详细的介绍这个机制。

三、Service注册

    每个Service都需要向“大管家”Service Manager进行注册,调用Service Manager的addService方法注册。这样Service Manager将会运行客户端查询和获取该Service(代理对象),然后客户端就可以通过该Service的代理对象请求该Service的服务。

四、Service进入等待请求的循环

    每个Service必须要进入死循环,等待客户端请求的到达,本例中最后两句就是使Service进行等待请求的循环之中。

ProcessState的startThreadPool方法的代码如下

void ProcessState::startThreadPool()
{

    AutoMutex _l(mLock);

    if (!mThreadPoolStarted) {

        mThreadPoolStarted = true;

        spawnPooledThread(true);

    }

}

void ProcessState::spawnPooledThread(bool isMain)
{

    if (mThreadPoolStarted) {

        int32_t s = android_atomic_add(1, &mThreadPoolSeq);

        char buf[32];

        sprintf(buf, "Binder Thread #%d", s);

        LOGV("Spawning new pooled thread, name=%s\n", buf);

        sp<Thread> t = new PoolThread(isMain);

        t->run(buf);

    }

}

IPCThreadState的joinThreadPool方法的代码如下:




void IPCThreadState::joinThreadPool(bool isMain)
{

    LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());

    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);

    // This thread may have been spawned by a thread that was in the background

    // scheduling group, so first we will make sure it is in the default/foreground

    // one to avoid performing an initial transaction in the background.

    androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);

    status_t result;

    do {

        int32_t cmd;

        // When we've cleared the incoming command queue, process any pending derefs

        if (mIn.dataPosition() >= mIn.dataSize()) {

            size_t numPending = mPendingWeakDerefs.size();

            if (numPending > 0) {

                for (size_t i = 0; i < numPending; i++) {

                    RefBase::weakref_type* refs = mPendingWeakDerefs[i];

                    refs->decWeak(mProcess.get());

                }

                mPendingWeakDerefs.clear();

            }




            numPending = mPendingStrongDerefs.size();

            if (numPending > 0) {

                for (size_t i = 0; i < numPending; i++) {

                    BBinder* obj = mPendingStrongDerefs[i];

                    obj->decStrong(mProcess.get());

                }

                mPendingStrongDerefs.clear();

            }

        }

        // now get the next command to be processed, waiting if necessary

        result = talkWithDriver();

        if (result >= NO_ERROR) {

            size_t IN = mIn.dataAvail();

            if (IN < sizeof(int32_t)) continue;

            cmd = mIn.readInt32();

            IF_LOG_COMMANDS() {

                alog << "Processing top-level Command: "

                    << getReturnString(cmd) << endl;

            }

            result = executeCommand(cmd);

        }

        // After executing the command, ensure that the thread is returned to the

        // default cgroup before rejoining the pool.  The driver takes care of

        // restoring the priority, but doesn't do anything with cgroups so we

        // need to take care of that here in userspace.  Note that we do make

        // sure to go in the foreground after executing a transaction, but

        // there are other callbacks into user code that could have changed

        // our group so we want to make absolutely sure it is put back.

        androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);

        // Let this thread exit the thread pool if it is no longer

        // needed and it is not the main process thread.

        if(result == TIMED_OUT && !isMain) {

            break;

        }

    } while (result != -ECONNREFUSED && result != -EBADF);




    LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n",

        (void*)pthread_self(), getpid(), (void*)result);

    

    mOut.writeInt32(BC_EXIT_LOOPER);

    talkWithDriver(false);

}

 

    Service在IPCThreadState的joinThreadPool方法中,调用talkWithDriver方法和Binder驱动进行交互,读取客户端的请求。当客户端请求到达之后调用executeCommand方法进行处理。

    我们再看一下Service怎样处理客户端的请求?我们们查看一下executeCommand方法的源码:


 

   

status_t IPCThreadState::executeCommand(int32_t cmd)

   {

       BBinder* obj;

       RefBase::weakref_type* refs;

       status_t result = NO_ERROR;

       

       switch (cmd) {

           ...... 

            case BR_TRANSACTION:

           {

               ......

               if (tr.target.ptr) {

                   sp<BBinder> b((BBinder*)tr.cookie);

                   const status_t error = b->transact(tr.code, buffer, &reply, 0);

                   if (error < NO_ERROR) reply.setError(error);

                   

               } 

               ......            

           }

           break;

      

       ......

       }

    

       if (result != NO_ERROR) {

           mLastError = result;

       }

       

       return result;

   }


可以看到IPCThreadState将会直接调用BBinder的transact方法来处理客户端请求,我们再看一下BBinder的transact方法:

status_t BBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{

    data.setDataPosition(0);

    status_t err = NO_ERROR;

    switch (code) {

        case PING_TRANSACTION:

            reply->writeInt32(pingBinder());

            break;

        default:

            err = onTransact(code, data, reply, flags);

            break;

    }

    if (reply != NULL) {

        reply->setDataPosition(0);

    }

    return err;

}


我们发现他将会叫用自己的虚函数onTransact。我们前面提到所有的Service都集成自BBinder,并且都改写了onTransact虚函数。那么IPCThreadState将会调用Service定义onTransact方法来响应客户请求。

五、结论

    本文简单介绍了一下系统Service的原理,台湾的高焕堂先生有一篇文章,手把手教怎样实现一个系统Service,你可以在我的博文《(转)高焕堂——Android框架底层结构知多少?》中找到。

 

 

Alfred整理发布,本篇博文的著作权信息如下:

 

 

你可能感兴趣的:(Android Binder机制分析)