Android深入浅出之Binder机制

 

Android 深入浅出之Binder 机制

说明

 Android 系统最常见也是初学者最难搞明白的就是 Binder 了,很多很多的 Service 就是通过 Binder 机制来和客户端通讯交互的。所以搞明白 Binder 的话,在很大程度上就能理解程序运行的流程。

我们这里将以 MediaService 的例子来分析 Binder 的使用:

l         ServiceManager ,这是 Android OS 的整个服务的管理程序

l         MediaService ,这个程序里边注册了提供媒体播放的服务程序 MediaPlayerService ,我们最后只分析这个

l         MediaPlayerClient ,这个是与 MediaPlayerService 交互的客户端程序

下面先讲讲 MediaService 应用程序。

MediaService 的诞生

MediaService 是一个应用程序,虽然 Android 搞了七七八八的 JAVA 之类的东西,但是在本质上,它还是一个完整的 Linux 操作系统,也还没有牛到什么应用程序都是 JAVA 写。所以, MS(MediaService) 就是一个和普通的 C++ 应用程序一样的东西。

MediaService 的源码文件在: framework/base/Media/MediaServer/Main_mediaserver.cpp 中。让我们看看到底是个什么玩意儿!

int main(int argc, char** argv)

{

//FT ,就这么简单??

// 获得一个ProcessState 实例

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

// 得到一个ServiceManager 对象

    sp<IServiceManager> sm = defaultServiceManager();

    MediaPlayerService::instantiate();// 初始化MediaPlayerService 服务

    ProcessState::self()->startThreadPool();// 看名字,启动Process 的线程池?

    IPCThreadState::self()->joinThreadPool();// 将自己加入到刚才的线程池?

}

其中,我们只分析 MediaPlayerService

这么多疑问,看来我们只有一个个函数深入分析了。不过,这里先简单介绍下 sp 这个东西。

sp ,究竟是 smart pointer 还是 strong pointer 呢?其实我后来发现不用太关注这个,就把它当做一个普通的指针看待,即 sp<IServiceManager>====== IServiceManager* 吧。 sp google 搞出来的为了方便 C/C++ 程序员管理指针的分配和释放的一套方法,类似 JAVA 的什么 WeakReference 之类的。我个人觉得,要是自己写程序的话,不用这个东西也成。

好了,以后的分析中, sp<XXX> 就看成是 XXX* 就可以了。

2.1 ProcessState

第一个调用的函数是 ProcessState::self() ,然后赋值给了 proc 变量,程序运行完, proc 会自动 delete 内部的内容,所以就自动释放了先前分配的资源。

ProcessState 位置在 framework/base/libs/binder/ProcessState.cpp

sp<ProcessState> ProcessState::self()

{

    if (gProcess != NULL) return gProcess;----> 第一次进来肯定不走这儿

    AutoMutex _l(gProcessMutex);---> 锁保护

    if (gProcess == NULL) gProcess = new ProcessState;---> 创建一个ProcessState 对象

return gProcess;---> 看见没,这里返回的是指针,但是函数返回的是sp<xxx> ,所以

//sp<xxx> 看成是XXX* 是可以的

}

再来看看ProcessState 构造函数

// 这个构造函数看来很重要

ProcessState::ProcessState()

    : mDriverFD(open_driver())----->Android 很多代码都是这么写的, 稍不留神就没看见这里调用了一个很重要的函数

    , mVMStart(MAP_FAILED)// 映射内存的起始地址

    , mManagesContexts(false)

    , mBinderContextCheckFunc(NULL)

    , mBinderContextUserData(NULL)

    , mThreadPoolStarted(false)

    , mThreadPoolSeq(1)

{

if (mDriverFD >= 0) {

//BIDNER_VM_SIZE 定义为(1*1024*1024) - (4096 *2) 1M-8K

        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE,

 mDriverFD, 0);// 这个需要你自己去man mmap 的用法了,不过大概意思就是

//fd 映射为内存,这样内存的memcpy 等操作就相当于write/read(fd)

    }

    ...

}

最讨厌这种在构造list 中添加函数的写法了,常常疏忽某个变量的初始化是一个函数调用的结果

open_driver ,就是打开/dev/binder 这个设备,这个是android 在内核中搞的一个专门用于完成

进程间通讯而设置的一个虚拟的设备。BTW ,说白了就是内核的提供的一个机制,这个和我们用socketNET_LINK 方式和内核通讯是一个道理。

static int open_driver()

{

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

    if (fd >= 0) {

      ....

        size_t maxThreads = 15;

       // 通过ioctl 方式告诉内核,这个fd 支持最大线程数是15 个。

        result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);    }

return fd;

好了,到这里 Process::self 就分析完了,到底干什么了呢?

l         打开 /dev/binder 设备,这样的话就相当于和内核 binder 机制有了交互的通道

l         映射 fd 到内存,设备的 fd 传进去后,估计这块内存是和 binder 设备共享的

 

接下来,就到调用 defaultServiceManager() 地方了。

2.2 defaultServiceManager

defaultServiceManager 位置在 framework/base/libs/binder/IServiceManager.cpp

sp<IServiceManager> defaultServiceManager()

{

    if (gDefaultServiceManager != NULL) return gDefaultServiceManager;

    // 又是一个单例,设计模式中叫 singleton

    {

        AutoMutex _l(gDefaultServiceManagerLock);

        if (gDefaultServiceManager == NULL) {

// 真正的gDefaultServiceManager 是在这里创建的喔

            gDefaultServiceManager = interface_cast<IServiceManager>(

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

        }

    }

   return gDefaultServiceManager;

}

-----

gDefaultServiceManager = interface_cast<IServiceManager>(

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

ProcessState::self ,肯定返回的是刚才创建的gProcess ,然后调用它的getContextObject ,注意,传进去的是NULL ,即0

// 回到ProcessState 类,

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

{

if (supportsProcesses()) {// 该函数根据打开设备是否成功来判断是否支持process

// 在真机上肯定走这个

        return getStrongProxyForHandle(0);// 注意,这里传入0

    }

}

---- 》进入到getStrongProxyForHandle ,函数名字怪怪的,经常严重阻碍大脑运转

// 注意这个参数的命名,handle 。搞过windows 的应该比较熟悉这个名字,这是对

// 资源的一种标示,其实说白了就是某个数据结构,保存在数组中,然后handle 是它在这个数组中的索引。---> 就是这么一个玩意儿

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

{

    sp<IBinder> result;

    AutoMutex _l(mLock);

handle_entry* e = lookupHandleLocked(handle);-- 》哈哈,果然,从数组中查找对应

索引的资源,lookupHandleLocked 这个就不说了,内部会返回一个handle_entry

  下面是 handle_entry 的结构

/*

struct handle_entry {

                IBinder* binder;--->Binder

                RefBase::weakref_type* refs;--> 不知道是什么,不影响.

            };

*/

    if (e != NULL) {

        IBinder* b = e->binder; --> 第一次进来,肯定为空

        if (b == NULL || !e->refs->attemptIncWeak(this)) {

            b = new BpBinder(handle); ---> 看见了吧,创建了一个新的BpBinder

            e->binder = b;

            result = b;

        }....

    }

    return result; 返回刚才创建的BpBinder

}

// 到这里,是不是有点乱了?对,当人脑分析的函数调用太深的时候,就容易忘记。

我们是从gDefaultServiceManager = interface_cast<IServiceManager>(

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

开始搞的,现在,这个函数调用将变成

gDefaultServiceManager = interface_cast<IServiceManager>(new BpBinder(0));

BpBinder 又是个什么玩意儿? Android 名字起得太眼花缭乱了。

因为还没介绍 Binder 机制的大架构,所以这里介绍 BpBinder 不合适,但是又讲到 BpBinder 了,不介绍 Binder 架构似乎又说不清楚 .... sigh

恩,还是继续把层层深入的函数调用栈化繁为简吧,至少大脑还可以工作。先看看 BpBinder 的构造函数把。

2.3 BpBinder

BpBinder 位置在 framework/base/libs/binder/BpBinder.cpp 中。

BpBinder::BpBinder(int32_t handle)

    : mHandle(handle) // 注意,接上述内容,这里调用的时候传入的是0

    , mAlive(1)

    , mObitsSent(0)

    , mObituaries(NULL)

{

   IPCThreadState::self()->incWeakHandle(handle);//FT ,竟然到IPCThreadState::self()

}

这里一块说说吧,IPCThreadState::self 估计怎么着又是一个singleton 吧?

// 该文件位置在framework/base/libs/binder/IPCThreadState.cpp

IPCThreadState* IPCThreadState::self()

{

    if (gHaveTLS) {// 第一次进来为false

restart:

        const pthread_key_t k = gTLS;

//TLS Thread Local Storage 的意思,不懂得自己去google 下它的作用吧。这里只需要

// 知道这种空间每个线程有一个,而且线程间不共享这些空间,好处是?我就不用去搞什么

// 同步了。在这个线程,我就用这个线程的东西,反正别的线程获取不到其他线程TLS 中的数据。=== 》这句话有漏洞,钻牛角尖的明白大概意思就可以了。

// 从线程本地存储空间中获得保存在其中的IPCThreadState 对象

// 这段代码写法很晦涩,看见没,只有pthread_getspecific, 那么肯定有地方调用

// pthread_setspecific

        IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);

        if (st) return st;

        return new IPCThreadState;//new 一个对象,

    }

   

    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;

    }

    pthread_mutex_unlock(&gTLSMutex);

goto restart; // FT ,其实goto 没有我们说得那样卑鄙,汇编代码很多跳转语句的。

// 关键是要用好。

}

// 这里是构造函数,在构造函数里边pthread_setspecific

IPCThreadState::IPCThreadState()

    : mProcess(ProcessState::self()), mMyThreadId(androidGetTid())

{

    pthread_setspecific(gTLS, this);

    clearCaller();

mIn.setDataCapacity(256);

//mIn,mOut 是两个Parcel ,干嘛用的啊?把它看成是命令的buffer 吧。再深入解释,又会大脑停摆的。

    mOut.setDataCapacity(256);

}

出来了,终于出来了 .... ,恩,回到 BpBinder 那。

BpBinder::BpBinder(int32_t handle)

    : mHandle(handle) // 注意,接上述内容,这里调用的时候传入的是0

    , mAlive(1)

    , mObitsSent(0)

    , mObituaries(NULL)

{

......

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

什么incWeakHandle ,不讲了..

}

喔, new BpBinder 就算完了。到这里,我们创建了些什么呢?

l         ProcessState 有了。

l         IPCThreadState 有了,而且是主线程的。

l         BpBinder 有了,内部 handle 值为 0

 

gDefaultServiceManager = interface_cast<IServiceManager>(new BpBinder(0));

终于回到原点了,大家是不是快疯掉了?

interface_cast ,我第一次接触的时候,把它看做类似的 static_cast 一样的东西,然后死活也搞不明白 BpBinder* 指针怎么能强转为 IServiceManager* ,花了 n 多时间查看 BpBinder 是否和 IServiceManager 继承还是咋的 ....

终于,我用 ctrl+ 鼠标 (source insight) 跟踪进入了 interface_cast

IInterface.h 位于 framework/base/include/binder/IInterface.h

template<typename INTERFACE>

inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)

{

    return INTERFACE::asInterface(obj);

}

所以,上面等价于:

inline sp<IServiceManager> interface_cast(const sp<IBinder>& obj)

{

    return IServiceManager::asInterface(obj);

}

看来,只能跟到IServiceManager 了。

IServiceManager.h---framework/base/include/binder/IServiceManager.h

看看它是如何定义的:

2.4 IServiceManager

class IServiceManager : public IInterface

{

//ServiceManager, 字面上理解就是Service 管理类,管理什么?增加服务,查询服务等

// 这里仅列出增加服务addService 函数

public:

    DECLARE_META_INTERFACE(ServiceManager);

     virtual status_t   addService( const String16& name,

                                            const sp<IBinder>& service) = 0;

};

DECLARE_META_INTERFACE(ServiceManager) ??

怎么和MFC 这么类似?微软的影响很大啊!知道MFC 的,有DELCARE 肯定有IMPLEMENT

果然,这两个宏DECLARE_META_INTERFACEIMPLEMENT_META_INTERFACE(INTERFACE, NAME) 都在

刚才的IInterface.h 中定义。我们先看看DECLARE_META_INTERFACE 这个宏往IServiceManager 加了什么?

下面是DECLARE

#define DECLARE_META_INTERFACE(INTERFACE)                               /

    static const android::String16 descriptor;                          /

    static android::sp<I##INTERFACE> asInterface(                       /

            const android::sp<android::IBinder>& obj);                  /

    virtual const android::String16& getInterfaceDescriptor() const;    /

    I##INTERFACE();                                                     /

    virtual ~I##INTERFACE();    

我们把它兑现到IServiceManager 就是:

static const android::String16 descriptor;  --> 喔,增加一个描述字符串

static android::sp< IServiceManager > asInterface(const android::sp<android::IBinder>&

obj) --- 》增加一个asInterface 函数

virtual const android::String16& getInterfaceDescriptor() const; --- 》增加一个get 函数

估计其返回值就是descriptor 这个字符串

IServiceManager ();                                                     /

virtual ~IServiceManager(); 增加构造和虚析购函数...

IMPLEMENT 宏在哪定义的呢?

IServiceManager.cpp 。位于 framework/base/libs/binder/IServiceManager.cpp

IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");

下面是这个宏的定义

#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() { }                                   /

很麻烦吧?尤其是宏看着头疼。赶紧兑现下吧。

const

android::String16 IServiceManager::descriptor(“android.os.IServiceManager”);

const android::String16& IServiceManager::getInterfaceDescriptor() const

 {  return IServiceManager::descriptor;// 返回上面那个android.os.IServiceManager

   }                                                                      android::sp<IServiceManager> IServiceManager::asInterface(

            const android::sp<android::IBinder>& obj)

    {

        android::sp<IServiceManager> intr;

        if (obj != NULL) {                                             

            intr = static_cast<IServiceManager *>(                         

                obj->queryLocalInterface(IServiceManager::descriptor).get());              

            if (intr == NULL) {                                         

                intr = new BpServiceManager(obj);                         

            }                                                          

        }                                                               

        return intr;                                                   

    }                                                                 

    IServiceManager::IServiceManager () { }                                   

    IServiceManager::~ IServiceManager() { }

  哇塞,asInterface 是这么搞的啊,赶紧分析下吧,还是不知道interface_cast 怎么把BpBinder* 转成了IServiceManager

我们刚才解析过的interface_cast<IServiceManager>(new BpBinder(0)),

原来就是调用asInterface(new BpBinder(0))

android::sp<IServiceManager> IServiceManager::asInterface(

            const android::sp<android::IBinder>& obj)

    {

        android::sp<IServiceManager> intr;

        if (obj != NULL) {                                             

            ....                                      

                intr = new BpServiceManager(obj);

// 神呐,终于看到和IServiceManager 相关的东西了,看来

// 实际返回的是BpServiceManager(new BpBinder(0))                         

            }                                                          

        }                                                              

        return intr;                                                   

}                                

BpServiceManager 是个什么玩意儿? p 是什么个意思?

2.5 BpServiceManager

终于可以讲解点架构上的东西了。 p proxy 即代理的意思, Bp 就是 BinderProxy BpServiceManager ,就是 SM Binder 代理。既然是代理,那肯定希望对用户是透明的,那就是说头文件里边不会有这个 Bp 的定义。是吗?

果然, BpServiceManager 就在刚才的 IServiceManager.cpp 中定义。

class BpServiceManager : public BpInterface<IServiceManager>

// 这种继承方式,表示同时继承BpInterfaceIServiceManager ,这样IServiceManger

addService 必然在这个类中实现

{

public:

// 注意构造函数参数的命名 impl ,难道这里使用了Bridge 模式?真正完成操作的是impl 对象?

// 这里传入的impl 就是new BpBinder(0)

    BpServiceManager(const sp<IBinder>& impl)

        : BpInterface<IServiceManager>(impl)

    {

    }

     virtual status_t addService(const String16& name, const sp<IBinder>& service)

    {

       待会再说..

}

基类BpInterface 的构造函数(经过兑现后)

// 这里的参数又叫remote ,唉,真是害人不浅啊。

inline BpInterface< IServiceManager >::BpInterface(const sp<IBinder>& remote)

    : BpRefBase(remote)

{

}

BpRefBase::BpRefBase(const sp<IBinder>& o)

    : mRemote(o.get()), mRefs(NULL), mState(0)

//o.get() ,这个是sp 类的获取实际数据指针的一个方法,你只要知道

// 它返回的是sp<xxxx>xxx* 指针就行

{

//mRemote 就是刚才的BpBinder(0)

   ...

}

好了,到这里,我们知道了:

sp<IServiceManager> sm = defaultServiceManager(); 返回的实际是 BpServiceManager ,它的 remote 对象是 BpBinder ,传入的那个 handle 参数是 0

现在重新回到 MediaService

int main(int argc, char** argv)

{

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

sp<IServiceManager> sm = defaultServiceManager();

// 上面的讲解已经完了

MediaPlayerService::instantiate();// 实例化MediaPlayerservice

// 看来这里有名堂!

 

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

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

}

到这里,我们把 binder 设备打开了,得到一个 BpServiceManager 对象,这表明我们可以和 SM 打交道了,但是好像没干什么有意义的事情吧?

2.6 MediaPlayerService

那下面我们看看后续又干了什么?以 MediaPlayerService 为例。

它位于 framework/base/media/libmediaplayerservice/libMediaPlayerService.cpp

void MediaPlayerService::instantiate() {

defaultServiceManager()->addService(

// 传进去服务的名字,传进去new 出来的对象

            String16("media.player"), new MediaPlayerService());

}

MediaPlayerService::MediaPlayerService()

{

    LOGV("MediaPlayerService created");// 太简单了

    mNextConnId = 1;

}

defaultServiceManager 返回的是刚才创建的BpServiceManager

调用它的addService 函数。

MediaPlayerService BnMediaPlayerService 派生

class MediaPlayerService : public BnMediaPlayerService

FT MediaPlayerService BnMediaPlayerService 派生, BnXXX,BpXXX ,快晕了。

Bn Binder Native 的含义,是和 Bp 相对的, Bp p proxy 代理的意思,那么另一端一定有一个和代理打交道的东西,这个就是 Bn

讲到这里会有点乱喔。先分析下,到目前为止都构造出来了什么。

l         BpServiceManager

l         BnMediaPlayerService

这两个东西不是相对的两端,从 BnXXX 就可以判断, BpServiceManager 对应的应该是 BnServiceManager BnMediaPlayerService 对应的应该是 BpMediaPlayerService

我们现在在哪里 ? 对了,我们现在是创建了 BnMediaPlayerService ,想把它加入到系统的中去。

喔,明白了。我创建一个新的 Service—BnMediaPlayerService ,想把它告诉 ServiceManager

那我怎么和 ServiceManager 通讯呢?恩,利用 BpServiceManager 。所以嘛,我调用了 BpServiceManager addService 函数!

为什么要搞个 ServiceManager 来呢?这个和 Android 机制有关系。所有 Service 都需要加入到 ServiceManager 来管理。同时也方便了 Client 来查询系统存在哪些 Service ,没看见我们传入了字符串吗?这样就可以通过 Human Readable 的字符串来查找 Service 了。

--- 》感觉没说清楚 ... 饶恕我吧。

2.7 addService

addService 是调用的 BpServiceManager 的函数。前面略去没讲,现在我们看看。

virtual status_t addService(const String16& name, const sp<IBinder>& service)

    {

        Parcel data, reply;

//data 是发送到BnServiceManager 的命令包

// 看见没?先把Interface 名字写进去,也就是什么android.os.IServiceManager

        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());

// 再把新service 的名字写进去 叫media.player

        data.writeString16(name);

// 把新服务service—> 就是MediaPlayerService 写到命令中

        data.writeStrongBinder(service);

// 调用remotetransact 函数

        status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);

        return err == NO_ERROR ? reply.readInt32() : err;

}

我的天, remote() 返回的是什么?

remote(){ return mRemote; }--> 啊?找不到对应的实际对象了???

还记得我们刚才初始化时候说的:

“这里的参数又叫 remote ,唉,真是害人不浅啊“

原来,这里的 mRemote 就是最初创建的 BpBinder..

好吧,到那里去看看:

BpBinder 的位置在framework/base/libs/binder/BpBinder.cpp

status_t BpBinder::transact(

    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)

{

// 又绕回去了,调用IPCThreadStatetransact

// 注意啊,这里的mHandle0,codeADD_SERVICE_TRANSACTION,data 是命令包

//reply 是回复包,flags=0

        status_t status = IPCThreadState::self()->transact(

            mHandle, code, data, reply, flags);

        if (status == DEAD_OBJECT) mAlive = 0;

        return status;

    }

...

}

再看看IPCThreadStatetransact 函数把

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 (err == NO_ERROR) {

        // 调用writeTransactionData 发送数据

err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);

    }

   

      if ((flags & TF_ONE_WAY) == 0) {

        if (reply) {

            err = waitForResponse(reply);

        } else {

            Parcel fakeReply;

            err = waitForResponse(&fakeReply);

        }

      .... 等回复

        err = waitForResponse(NULL, NULL);

   ....   

    return err;

}

再进一步,瞧瞧这个...

status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,

    int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)

{

    binder_transaction_data tr;

 

    tr.target.handle = handle;

    tr.code = code;

    tr.flags = binderFlags;

   

    const status_t err = data.errorCheck();

    if (err == NO_ERROR) {

        tr.data_size = data.ipcDataSize();

        tr.data.ptr.buffer = data.ipcData();

        tr.offsets_size = data.ipcObjectsCount()*sizeof(size_t);

        tr.data.ptr.offsets = data.ipcObjects();

    }

....

上面把命令数据封装成binder_transaction_data ,然后

写到mOut 中,mOut 是命令的缓冲区,也是一个Parcel

    mOut.writeInt32(cmd);

    mOut.write(&tr, sizeof(tr));

// 仅仅写到了Parcel 中,Parcel 好像没和/dev/binder 设备有什么关联啊?

恩,那只能在另外一个地方写到binder 设备中去了。难道是在?

    return NO_ERROR;

}

// 说对了,就是在waitForResponse

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)

{

    int32_t cmd;

    int32_t err;

 

while (1) {

//talkWithDriver ,哈哈,应该是这里了

        if ((err=talkWithDriver()) < NO_ERROR) break;

        err = mIn.errorCheck();

        if (err < NO_ERROR) break;

        if (mIn.dataAvail() == 0) continue;

        // 看见没?这里开始操作mIn 了,看来talkWithDriver

// mOut 发出去,然后从driver 中读到数据放到mIn 中了。

        cmd = mIn.readInt32();

 

        switch (cmd) {

        case BR_TRANSACTION_COMPLETE:

            if (!reply && !acquireResult) goto finish;

            break;

   .....

    return err;

}

status_t IPCThreadState::talkWithDriver(bool doReceive)

{

binder_write_read bwr;

   // 中间东西太复杂了,不就是把mOut 数据和mIn 接收数据的处理后赋值给bwr 吗?

    status_t err;

    do {

// ioctl 来读写

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

            err = NO_ERROR;

        else

            err = -errno;

  } while (err == -EINTR);

// 到这里,回复数据就在bwr 中了,bmr 接收回复数据的buffer 就是mIn 提供的

        if (bwr.read_consumed > 0) {

            mIn.setDataSize(bwr.read_consumed);

            mIn.setDataPosition(0);

        }

return NO_ERROR;

}

好了,到这里,我们发送 addService 的流程就彻底走完了。

BpServiceManager 发送了一个 addService 命令到 BnServiceManager ,然后收到回复。

先继续我们的 main 函数。

int main(int argc, char** argv)

{

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

    sp<IServiceManager> sm = defaultServiceManager();   

MediaPlayerService::instantiate();

--- 》该函数内部调用addService ,把MediaPlayerService 信息 addServiceManager

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

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

}

这里有个容易搞晕的地方:

MediaPlayerService 是一个 BnMediaPlayerService, 那么它是不是应该等着

BpMediaPlayerService 来和他交互呢 ? 但是我们没看见 MediaPlayerService 有打开 binder 设备的操作啊!

这个嘛,到底是继续 addService 操作的另一端 BnServiceManager 还是先说

BnMediaPlayerService 呢?

还是先说 BnServiceManager 吧。顺便把系统的 Binder 架构说说。

2.8 BnServiceManager

上面说了, defaultServiceManager 返回的是一个 BpServiceManager ,通过它可以把命令请求发送到 binder 设备,而且 handle 的值为 0 。那么,系统的另外一端肯定有个接收命令的,那又是谁呢?

很可惜啊, BnServiceManager 不存在,但确实有一个程序完成了 BnServiceManager 的工作,那就是 service .exe ( 如果在 windows 上一定有 exe 后缀,叫 service 的名字太多了,这里加 exe 就表明它是一个程序 )

位置在 framework/base/cmds/servicemanger.c 中。

int main(int argc, char **argv)

{

    struct binder_state *bs;

    void *svcmgr = BINDER_SERVICE_MANAGER;

    bs = binder_open(128*1024);// 应该是打开binder 设备吧?

    binder_become_context_manager(bs) // 成为manager

    svcmgr_handle = svcmgr;

    binder_loop(bs, svcmgr_handler);// 处理BpServiceManager 发过来的命令

}

看看binder_open 是不是和我们猜得一样?

struct binder_state *binder_open(unsigned mapsize)

{

    struct binder_state *bs;

    bs = malloc(sizeof(*bs));

   ....

    bs->fd = open("/dev/binder", O_RDWR);// 果然如此

  ....

    bs->mapsize = mapsize;

    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);

  }

再看看binder_become_context_manager

int binder_become_context_manager(struct binder_state *bs)

{

    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);// 把自己设为MANAGER

}

binder_loop 肯定是从binder 设备中读请求,写回复的这么一个循环吧?

void binder_loop(struct binder_state *bs, binder_handler func)

{

    int res;

    struct binder_write_read bwr;

    readbuf[0] = BC_ENTER_LOOPER;

    binder_write(bs, readbuf, sizeof(unsigned));

    for (;;) {// 果然是循环

        bwr.read_size = sizeof(readbuf);

        bwr.read_consumed = 0;

        bwr.read_buffer = (unsigned) readbuf;

 

        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);

      // 哈哈,收到请求了,解析命令

        res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func);

  }

这个... 后面还要说吗??

恩,最后有一个类似handleMessage 的地方处理各种各样的命令。这个就是

svcmgr_handler, 就在ServiceManager.c

int svcmgr_handler(struct binder_state *bs,

                   struct binder_txn *txn,

                   struct binder_io *msg,

                   struct binder_io *reply)

{

    struct svcinfo *si;

    uint16_t *s;

    unsigned len;

    void *ptr;

 

    s = bio_get_string16(msg, &len);

    switch(txn->code) {

    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;

...

其中,do_add_service 真正添加BnMediaService 信息

int do_add_service(struct binder_state *bs,

                   uint16_t *s, unsigned len,

                   void *ptr, unsigned uid)

{

    struct svcinfo *si;

    si = find_svc(s, len);s 是一个list

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

       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; // 看见没,这个svclist 是一个列表,保存了当前注册到ServiceManager

中的信息

    }

   binder_acquire(bs, ptr);// 这个吗。当这个Service 退出后,我希望系统通知我一下,好释放上面malloc 出来的资源。大概就是干这个事情的。

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

    return 0;

}

喔,对于 addService 来说,看来 ServiceManager 把信息加入到自己维护的一个服务列表中了。

2.9 ServiceManager 存在的意义

为何需要一个这样的东西呢?

原来, Android 系统中 Service 信息都是先 add ServiceManager 中,由 ServiceManager 来集中管理,这样就可以查询当前系统有哪些服务。而且 ,Android 系统中某个服务例如 MediaPlayerService 的客户端想要和 MediaPlayerService 通讯的话,必须先向 ServiceManager 查询 MediaPlayerService 的信息,然后通过 ServiceManager 返回的东西再来和 MediaPlayerService 交互。

毕竟,要是 MediaPlayerService 身体不好,老是挂掉的话,客户的代码就麻烦了,就不知道后续新生的 MediaPlayerService 的信息了,所以只能这样:

l         MediaPlayerService SM 注册

l         MediaPlayerClient 查询当前注册在 SM 中的 MediaPlayerService 的信息

l         根据这个信息, MediaPlayerClient MediaPlayerService 交互

另外, ServiceManager handle 标示是 0 ,所以只要往 handle 0 的服务发送消息了,最终都会被传递到 ServiceManager 中去。

MediaService 的运行

上一节的知识,我们知道了:

l         defaultServiceManager 得到了 BpServiceManager ,然后 MediaPlayerService 实例化后,调用 BpServiceManager addService 函数

l         这个过程中,是 service_manager 收到 addService 的请求,然后把对应信息放到自己保存的一个服务 list

到这儿,我们可看到, service_manager 有一个 binder_looper 函数,专门等着从 binder 中接收请求。虽然 service_manager 没有从 BnServiceManager 中派生,但是它肯定完成了 BnServiceManager 的功能。

同样,我们创建了 MediaPlayerService BnMediaPlayerService ,那它也应该:

l         打开 binder 设备

l         也搞一个 looper 循环,然后坐等请求

serviceservice ,这个和网络编程中的监听socket 的工作很像嘛!

好吧,既然 MediaPlayerService 的构造函数没有看到显示的打开 binder 设备,那么我们看看它的父类即 BnXXX 又到底干了些什么呢?

3.1 MediaPlayerService 打开binder

class MediaPlayerService : public BnMediaPlayerService

// MediaPlayerServiceBnMediaPlayerService 派生

//BnMediaPlayerServiceBnInterfaceIMediaPlayerService 同时派生

class BnMediaPlayerService: public BnInterface<IMediaPlayerService>

{

public:

    virtual status_t    onTransact( uint32_t code,

                                    const Parcel& data,

                                    Parcel* reply,

                                    uint32_t flags = 0);

};

看起来,BnInterface 似乎更加和打开设备相关啊。

template<typename INTERFACE>

class BnInterface : public INTERFACE, public BBinder

{

public:

    virtual sp<IInterface>      queryLocalInterface(const String16& _descriptor);

    virtual const String16&     getInterfaceDescriptor() const;

 

protected:

    virtual IBinder*            onAsBinder();

};

兑现后变成

class BnInterface : public IMediaPlayerService, public BBinder

BBinder?BpBinder ?是不是和BnXXX 以及BpXXX 对应的呢?如果是,为什么又叫BBinder 呢?

BBinder::BBinder()

    : mExtras(NULL)

{

// 没有打开设备的地方啊?

}

完了?难道我们走错方向了吗?难道不是每个 Service 都有对应的 binder 设备 fd 吗?

.......

回想下,我们的 Main_MediaService 程序,有哪里打开过 binder 吗?

int main(int argc, char** argv)

{

// 对啊,我在ProcessState 中不是打开过binder 了吗?

 

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

    sp<IServiceManager> sm = defaultServiceManager();

MediaPlayerService::instantiate();   

  ......

3.2 looper  

? 原来打开 binder 设备的地方是和进程相关的啊?一个进程打开一个就可以了。那么,我在哪里进行类似的消息循环 looper 操作呢?

...

// 难道是下面两个?

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

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

看看startThreadPool

void ProcessState::startThreadPool()

{

  ...

    spawnPooledThread(true);

}

void ProcessState::spawnPooledThread(bool isMain)

{

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

// 创建线程池,然后run 起来,和javaThread 何其像也。

    t->run(buf);

 }

PoolThread Thread 类中派生,那么此时会产生一个线程吗?看看PoolThreadThread 的构造吧

PoolThread::PoolThread(bool isMain)

        : mIsMain(isMain)

    {

    }

Thread::Thread(bool canCallJava)//canCallJava 默认值是true

    :   mCanCallJava(canCallJava),

        mThread(thread_id_t(-1)),

        mLock("Thread::mLock"),

        mStatus(NO_ERROR),

        mExitPending(false), mRunning(false)

{

}

喔,这个时候还没有创建线程呢。然后调用PoolThread::run ,实际调用了基类的run

status_t Thread::run(const char* name, int32_t priority, size_t stack)

{

  bool res;

    if (mCanCallJava) {

        res = createThreadEtc(_threadLoop,// 线程函数是_threadLoop

                this, name, priority, stack, &mThread);

    }

// 终于,在run 函数中,创建线程了。从此

主线程执行

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

新开的线程执行_threadLoop

我们先看看_threadLoop

int Thread::_threadLoop(void* user)

{

    Thread* const self = static_cast<Thread*>(user);

    sp<Thread> strong(self->mHoldSelf);

    wp<Thread> weak(strong);

    self->mHoldSelf.clear();

 

    do {

 ...

        if (result && !self->mExitPending) {

                result = self->threadLoop(); 哇塞,调用自己的threadLoop

            }

        }

我们是PoolThread 对象,所以调用PoolThreadthreadLoop 函数

virtual bool PoolThread ::threadLoop()

    {

//mIsMaintrue

// 而且注意,这是一个新的线程,所以必然会创建一个

新的IPCThreadState 对象(记得线程本地存储吗?TLS ),然后      

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

        return false;

    }

主线程和工作线程都调用了joinThreadPool ,看看这个干嘛了!

void IPCThreadState::joinThreadPool(bool isMain)

{

     mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);

     status_t result;

    do {

        int32_t cmd;

         result = talkWithDriver();

         result = executeCommand(cmd);

        }

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

 

    mOut.writeInt32(BC_EXIT_LOOPER);

    talkWithDriver(false);

}

看到没?有loop 了,但是好像是有两个线程都执行了这个啊!这里有两个消息循环?

下面看看executeCommand

status_t IPCThreadState::executeCommand(int32_t cmd)

{

BBinder* obj;

    RefBase::weakref_type* refs;

    status_t result = NO_ERROR;

case BR_TRANSACTION:

        {

            binder_transaction_data tr;

            result = mIn.read(&tr, sizeof(tr));

// 来了一个命令,解析成BR_TRANSACTION, 然后读取后续的信息

       Parcel reply;

             if (tr.target.ptr) {

// 这里用的是BBinder

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

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

}

让我们看看BBindertransact 函数干嘛了

status_t BBinder::transact(

    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)

{

就是调用自己的onTransact 函数嘛      

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

    return err;

}

BnMediaPlayerService BBinder 派生,所以会调用到它的 onTransact 函数  

终于水落石出了,让我们看看 BnMediaPlayerServcice onTransact 函数。

status_t BnMediaPlayerService::onTransact(

    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)

{

// BnMediaPlayerService BBinderIMediaPlayerService 派生,所有IMediaPlayerService

// 看到下面的switch 没?所有IMediaPlayerService 提供的函数都通过命令类型来区分

//

    switch(code) {

        case CREATE_URL: {

            CHECK_INTERFACE(IMediaPlayerService, data, reply);

            create 是一个虚函数,由MediaPlayerService 来实现!!

sp<IMediaPlayer> player = create(

                    pid, client, url, numHeaders > 0 ? &headers : NULL);

 

            reply->writeStrongBinder(player->asBinder());

            return NO_ERROR;

        } break;

其实,到这里,我们就明白了。 BnXXX onTransact 函数收取命令,然后派发到派生类的函数,由他们完成实际的工作。

说明:

这里有点特殊, startThreadPool joinThreadPool 完后确实有两个线程,主线程和工作线程,而且都在做消息循环。为什么要这么做呢?他们参数 isMain 都是 true 。不知道 google 搞什么。难道是怕一个线程工作量太多,所以搞两个线程来工作?这种解释应该也是合理的。

网上有人测试过把最后一句屏蔽掉,也能正常工作。但是难道主线程提出了,程序还能不退出吗?这个 ... 管它的,反正知道有两个线程在那处理就行了。

MediaPlayerClient

这节讲讲 MediaPlayerClient 怎么和 MediaPlayerService 交互。

使用 MediaPlayerService 的时候,先要创建它的 BpMediaPlayerService 。我们看看一个例子

IMediaDeathNotifier::getMediaPlayerService()

{

        sp<IServiceManager> sm = defaultServiceManager();

        sp<IBinder> binder;

        do {

//SM 查询对应服务的信息,返回binder           

binder = sm->getService(String16("media.player"));

            if (binder != 0) {

                break;

             }

             usleep(500000); // 0.5 s

        } while(true);

 

// 通过interface_cast ,将这个binder 转化成BpMediaPlayerService

// 注意,这个binder 只是用来和binder 设备通讯用的,实际

// 上和IMediaPlayerService 的功能一点关系都没有。

// 还记得我说的Bridge 模式吗?BpMediaPlayerService 用这个binderBnMediaPlayerService

// 通讯。

    sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);

    }

    return sMediaPlayerService;

}

为什么反复强调这个 Bridge ?其实也不一定是 Bridge 模式,但是我真正想说明的是:

Binder 其实就是一个和 binder 设备打交道的接口,而上层 IMediaPlayerService 只不过把它当做一个类似 socket 使用罢了。我以前经常把 binder 和上层类 IMediaPlayerService 的功能混到一起去。

当然,你们不一定会犯这个错误。但是有一点请注意:

4.1 Native

刚才那个 getMediaPlayerService 代码是 C++ 层的,但是整个使用的例子确实 JAVA->JNI 层的调用。如果我要写一个纯 C++ 的程序该怎么办?

int main()

{

  getMediaPlayerService(); 直接调用这个函数能获得BpMediaPlayerService 吗?

不能,为什么?因为我还没打开binder 驱动呐!但是你在JAVA 应用程序里边却有google 已经替你

封装好了。

所以,纯native 层的代码,必须也得像下面这样处理:

sp<ProcessState> proc(ProcessState::self()); // 这个其实不是必须的,因为

// 好多地方都需要这个,所以自动也会创建.

getMediaPlayerService();

还得起消息循环呐,否则如果Bn 那边有消息通知你,你怎么接受得到呢?

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

// 至于主线程是否也需要调用消息循环,就看个人而定了。不过一般是等着接收其他来源的消息,例如socket 发来的命令,然后控制MediaPlayerService 就可以了

}

 

实现自己的 Service

好了,我们学习了这么多 Binder 的东西,那么想要实现一个自己的 Service 该咋办呢?

如果是纯 C++ 程序的话,肯定得类似 main_MediaService 那样干了。

int main()

{

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

sp<IServiceManager> sm = defaultServiceManager();

sm->addService(“service.name”,new XXXService());

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

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

}

看看XXXService 怎么定义呢?

我们需要一个Bn ,需要一个Bp ,而且Bp 不用暴露出来。那么就在BnXXX.cpp 中一起实现好了。

另外,XXXService 提供自己的功能,例如getXXX 调用

5.1 定义XXX 接口

XXX 接口是和 XXX 服务相关的,例如提供 getXXX setXXX 函数,和应用逻辑相关。

需要从 IInterface 派生

class IXXX: public IInterface

{

public:

DECLARE_META_INTERFACE(XXX); 申明宏

virtual getXXX() = 0;

virtual setXXX() = 0;

} 这是一个接口。

5.2 定义BnXXXBpXXX

为了把 IXXX 加入到 Binder 结构,需要定义 BnXXX 和对客户端透明的 BpXXX

其中 BnXXX 是需要有头文件的。 BnXXX 只不过是把 IXXX 接口加入到 Binder 架构中来,而不参与实际的 getXXX setXXX 应用层逻辑。

这个 BnXXX 定义可以和上面的 IXXX 定义放在一块。分开也行。

class BnXXX: public BnInterface<IXXX>

{

public:

    virtual status_t    onTransact( uint32_t code,

                                    const Parcel& data,

                                    Parcel* reply,

                                    uint32_t flags = 0);

// 由于IXXX 是个纯虚类,而BnXXX 只实现了onTransact 函数,所以BnXXX 依然是

一个纯虚类

};

有了 DECLARE ,那我们在某个 CPP IMPLEMNT 它吧。那就在 IXXX.cpp 中吧。

IMPLEMENT_META_INTERFACE(XXX, "android.xxx.IXXX");//IMPLEMENT

 

status_t BnXXX::onTransact(

    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)

{

    switch(code) {

        case GET_XXX: {

            CHECK_INTERFACE(IXXX, data, reply);

           读请求参数

           调用虚函数getXXX()

            return NO_ERROR;

        } break; //SET_XXX 类似

BpXXX 也在这里实现吧。

class BpXXX: public BpInterface<IXXX>

{

public:

    BpXXX (const sp<IBinder>& impl)

        : BpInterface< IXXX >(impl)

    {

}

vitural getXXX()

{

  Parcel data, reply;

  data.writeInterfaceToken(IXXX::getInterfaceDescriptor());

   data.writeInt32(pid);

   remote()->transact(GET_XXX, data, &reply);

   return;

}

//setXXX 类似

至此, Binder 就算分析完了,大家看完后,应该能做到以下几点:

l         如果需要写自己的 Service 的话,总得知道系统是怎么个调用你的函数,恩。对。有 2 个线程在那不停得从 binder 设备中收取命令,然后调用你的函数呢。恩,这是个多线程问题。

l         如果需要跟踪 bug 的话,得知道从 Client 端调用的函数,是怎么最终传到到远端的 Service 。这样,对于一些函数调用, Client 端跟踪完了,我就知道转到 Service 去看对应函数调用了。反正是同步方式。也就是 Client 一个函数调用会一直等待到 Service 返回为止。

 

转自:http://blog.csdn.net/Innost/archive/2011/01/08/6124685.aspx

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值