Android Binder机制(五) addService详解01之 请求的发送

终于要开始讲解Client-Server交互了,若标题所示,本文要讲解的是addService请求,即添加服务请求。本文选取的题材是MediaPlayerService服务通过addService请求注册到ServiceManager中。
在这个addService请求中,MediaPlayerService是Client,而ServiceManager是Server。由于涉及到的过程比较复杂,这里会将addService请求分为3篇进行说明,这3篇的主题分别是:请求的发送,请求的处理,以及请求的反馈。和以往一样,在讲解详细的代码之前,先做个整体介绍。

注意:本文是基于Android 4.4.2版本进行介绍的!

1. addService流程的时序图

上面是addService流程的时序图。理解这个图的前提是理解图中的三种角色之间的关系:
(01) MediaPlayerService和ServiceManager是两个不同的进程。它们都位于用户空间,都有各自的内存单元,两者之间不能直接进行通信;因此,需要Binder驱动的帮助才能通信。
(02) Binder驱动位于内核空间,它映射到节点"/dev/binder"上。MediaPlayerService和ServiceManager都有通过open("/dev/binder")打开该节点,并通过mmap()将内存映射到各自所在的进程中;这也就是说MediaPlayerService能和Binder驱动通信,而且ServiceManager也能和Binder驱动通信。而在Binder驱动中,有一个全局变量,依靠这个全局变量,就能实现MediaPlayerService和ServiceManager之间的通信。 依靠的这个全局变量,就是Android Binder机制(三) ServiceManager守护进程中介绍过的binder_context_mgr_node变量,它是ServiceManager的Binder实体。

搞清楚它们三者之间的关系之后,再回到上面的时序图中。
1. WAIT
这表示ServiceManager进入了中断等待状态。它进入等待状态的详细流程,在Android Binder机制(三) ServiceManager守护进程有介绍过。

  1. BC_TRANSACTION
    这是MediaPlayerService向ServiceManager发送addService请求对应的事务。这个事务是请求,而不是回复;因此是BC开发,B代表Binder,而C代表Command。如果是回复,则会以BR开发,R表示Reply。Binder驱动在收到BC_TRANSACTION之后,会将分配内存,将请求数据保存到所分配的内存中。

  2. WAKE_UP
    MediaPlayerService通过BC_TRANSACTION提交一个请求,该请求是交给ServiceManager来处理的。因此,Binder驱动在收到该请求后,会将其发送到ServiceManager的待处理事务队列中,并将ServiceManager唤醒。

  3. BR_TRANSACTION_COMPLETE
    MediaPlayerService在发起了一个请求之后,它需要知道该请求是否发送成功。因此,Binder驱动在将该请求提交给ServiceManager之后,会反馈一个BR_TRANSACTION_COMPLETE给MediaPlayerService,表示MediaPlayerService发送的请求已经被Binder驱动收到了。

  4. WAIT
    MediaPlayerService在知道自己的请求已经发送成功之后,就进入等待状态,等待请求的反馈结果。

  5. BR_NOOP和BR_TRANSACTION
    ServiceManager被唤醒之后,收到Binder驱动的BR_NOOP和BR_TRANSACTION指令。BR_NOOP指令什么也不会做;而对于BR_TRANSACTION指令时,ServiceManager在解析出该事务是添加服务请求,会将MediaPlayerService的相关信息保存到一个链表中。

  6. BC_FREE_BUFFER和BC_REPLY
    ServiceManager在保存了MediaPlayerService的相关信息之后,便处理完毕了MediaPlayerService的请求。此时,它便反馈BC_FREE_BUFFER和BC_REPLY给Binder驱动。Binder驱动在收到BC_FREE_BUFFER之后,会释放保存请求数据所申请的内存;收到BC_REPLY之后,Binder驱动则知道ServiceManager已经处理完了MediaPlayerService的请求。
    接着,Binder驱动便会唤醒MediaPlayerService,并发送BR_NOOP和BR_REPLY给MediaPlayerService,告诉MediaPlayerService请求已经处理完毕。同时,它还会发送一个BR_TRANSACTION_COMPLETE给ServiceManager,告诉ServiceManager该事务已经处理完毕。 MediaPlayerService在收到BR_REPLY反馈之后,知道addService请求已经成功处理;接着,它会再次进入等待状态,等待Client的请求。
    最后,ServiceManager处理MediaPlayerService的请求之后,没有其他事务可处理,也再次进入了等待状态。

2. IMediaPlayerService的类图

本文是以MediaPlayerService为例,对addService进行解析。下面看看MediaPlayerService相关联的类图。

IMediaPlayerService的类图和"Android Binder机制(四) defaultServiceManager()的实现"中IServiceManager的类图类似。这里就不再逐一对每个类进行介绍了。

需要知道的是,对于一个MediaPlayerService而言,它存在一个"远程BpBinder对象"和"本地BBinder对象"。
(01) 远程BpBinder对象的作用,是和Binder驱动进行交互。例如,当本文所讲到的addService请求,就是通过defaultServiceManager()调用到远程BpBinder对象的transact()方法,而该方法又会调用到IPCThreadState::transact()接口,通过IPCThreadState类来和Binder驱动交互。
(02) MediaPlayerService是"本地BBinder的子类"。当Client向MediaPlayerService发起请求时,会调用BBinder的onTransact()方法,而BnServiceManager又重写了该方法,从而调用onTransact()完成对请求的处理。

addService请求发送的代码解析

下面通过代码来查看addService请求的发送流程。

1. MediaPlayerService的main()函数

先看看MediaPlayerService的main()函数代码。

int main(int argc, char** argv)
{
    signal(SIGPIPE, SIG_IGN);
    char value[PROPERTY_VALUE_MAX];
    bool doLog = (property_get("ro.test_harness", value, "0") > 0) && (atoi(value) == 1);
    pid_t childPid;

    if (doLog && (childPid = fork()) != 0) {
        ...
    } else {
        // all other services
        ...
        sp<ProcessState> proc(ProcessState::self());
        sp<IServiceManager> sm = defaultServiceManager();
        ...
        MediaPlayerService::instantiate();
        ...
        ProcessState::self()->startThreadPool();
        IPCThreadState::self()->joinThreadPool();
    }
}

说明:该代码在frameworks/av/media/mediaserver/main_mediaserver.cpp中。
(01) property_get("ro.test_harness", value, "0")是获取"ro.test_harness"属性,为false。
(02) ProcessState:self()是获取ProcessState对象,并赋值给proc。ProcessState::self()在Android Binder机制(四) defaultServiceManager()的实现中已经介绍过了。
(03) defaultServiceManager()是获取IServiceManager对象,它的实现在Android Binder机制(四) defaultServiceManager()的实现中也有详细介绍。
(04) MediaPlayerService::instantiate()是初始化MediaPlayerService服务。

2. MediaPlayerService::instantiate()

void MediaPlayerService::instantiate() {
    defaultServiceManager()->addService(
            String16("media.player"), new MediaPlayerService());
}

说明:该代码在frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp中。它会新建MediaPlayerService对象;然后调用defaultServiceManager()获取到的BpServiceManager的实例;最后,调用BpServiceManager的addService()方法,将MediaPlayerService对象添加到Service Manager中。MediaPlayerService服务的名称是"media.player"。

3. MediaPlayerService::MediaPlayerService()

MediaPlayerService::MediaPlayerService()
{
    ALOGV("MediaPlayerService created");
    mNextConnId = 1; 

    mBatteryAudio.refCount = 0; 
    for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
        mBatteryAudio.deviceOn[i] = 0; 
        mBatteryAudio.lastTime[i] = 0; 
        mBatteryAudio.totalTime[i] = 0; 
    }    
    // speaker is on by default
    mBatteryAudio.deviceOn[SPEAKER] = 1; 
    mOOMKilling = false;
    MediaPlayerFactory::registerBuiltinFactories();
}

说明:MediaPlayerService的构造函数比较简单,就是进行一些变量的初始化。

4. BpServiceManager::addService()

class BpServiceManager : public BpInterface<IServiceManager>
{
public:
    ...

    virtual status_t addService(const String16& name, const sp<IBinder>& service,          
            bool allowIsolated)         
    {     
        Parcel data, reply;             
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
        data.writeString16(name);       
        data.writeStrongBinder(service);
        data.writeInt32(allowIsolated ? 1 : 0);
        status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);          
        return err == NO_ERROR ? reply.readExceptionCode() : err;
    }     

    ...
}

说明:该代码在frameworks/native/libs/binder/IServiceManager.cpp中。addService()会现将MediaPlayerService服务的名称("media.player")以及它的实例等参数保存到data(Parcel对象)中,然后再调用remote()返回的BpBinder对象的transact()与Binder驱动进行交互。
(01) 先看看addService()的各个参数。name="media.player",即MediaPlayerService服务的名称;service就是MediaPlayerService对象,而IBinder是MediaPlayerService的父类;allowIsolated这个值默认为false,默认值的定义在frameworks/native/include/binder/IServiceManager.h的addService()函数声明中。
(02) Parcel是Binder通信的数据存储结构,它的各个成员和函数在Android Binder机制(二) Binder中的数据结构中有详细说明。
在向data中写入数据时,先通过writeInterfaceToken()写入数据头,这里的数据头是:int32的整形数+字符串(字符串是"android.os.IServiceManager")。writeString16(name)写入的是服务的名称,即"media.player"。writeStrongBinder(service)是将MediaPlayerService封装到flat_binder_object结构体中。最后的writeInt32()暂时不用关心。
下面,我们逐个对data的赋值进行介绍。

5. Parcel::Parcel()

先看看Parcel的构造函数。

Parcel::Parcel()
{   
    initState(); 
}   

说明:该代码在frameworks/native/libs/binder/Parcel.cpp中。

6. Parcel::initState()

void Parcel::initState()
{
    mError = NO_ERROR;
    mData = 0;              // 数据的地址指针
    mDataSize = 0;          // 数据的大小
    mDataCapacity = 0;      // 数据的容量
    mDataPos = 0;           // 数据的位置
    mObjects = NULL;        // 保存对象的地址指针
    mObjectsSize = 0;       // 对象的个数
    mObjectsCapacity = 0;   // 对象的容量
    mNextObjectHint = 0;
    mHasFds = false;
    mFdsKnown = true;
    mAllowFds = true;
    mOwner = NULL;
}

说明:该函数对Parcel的成员进行了初始化。

7. Parcel::writeInterfaceToken()

下面看看data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor())的实现。getInterfaceDescriptor()是通过宏IMPLEMENT_META_INTERFACE()实现的,该宏已经在[Android Binder机制(四) defaultServiceManager()的实现][link_binder_04_defaultServiceManager]中介绍过了;getInterfaceDescriptor()的返回值是"android.os.IServiceManager"。  
即data.writeInterfaceToken("android.os.IServiceManager")。下面看看writeInterfaceToken()的实现。

status_t Parcel::writeInterfaceToken(const String16& interface)
{       
    writeInt32(IPCThreadState::self()->getStrictModePolicy() |
               STRICT_MODE_PENALTY_GATHER);
    // currently the interface identification token is just its name as a string
    return writeString16(interface);
}   

说明:该函数先通过writeInt32()写入一个32位的int数到Parcel中,然后再通过writeString16()将字符串写入到Parcel中。它所写入的是数据头,ServiceManager中收到该数据之后,会先获取数据头,并根据数据头来判断数据的有效性!
(01) IPCThreadState::self()返回IPCThreadState对象;然后,调用IPCThreadState::getStrictModePolicy(),返回的是mStrictModePolicy,mStrictModePolicy的初始值是0。因此,writeInt32()就可以简化为writeInt32(STRICT_MODE_PENALTY_GATHER)。
(02) writeString16(interface)是writeString16("android.os.IServiceManager")。

8. Parcel::writeInt32()

status_t Parcel::writeInt32(int32_t val)
{   
    return writeAligned(val);
}   

说明:该函数调用writeAligned()。

9. Parcel::writeAligned()

template<class T>
status_t Parcel::writeAligned(T val) {
    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T));

    if ((mDataPos+sizeof(val)) <= mDataCapacity) {
restart_write:
        *reinterpret_cast<T*>(mData+mDataPos) = val;
        return finishWrite(sizeof(val));
    }

    status_t err = growData(sizeof(val));
    if (err == NO_ERROR) goto restart_write;
    return err;
}

说明:writeAligned()的作用是是写入数据,比同步相应的变量。
(01) mDataPos的初始值=0,sizeof(val)=4,mDataCapacity的初始值=0。因此,if((mDataPos+sizeof(val)) <= mDataCapacity)为false。
(02) 接下来,会先调用growData(sizeof(val))来增加容量,然后再将数据写入到mData中。

10. Parcel::growData()

status_t Parcel::growData(size_t len)
{
    size_t newSize = ((mDataSize+len)*3)/2;
    return (newSize <= mDataSize)
            ? (status_t) NO_MEMORY
            : continueWrite(newSize);
}

说明:Parcel增加容量时,是按1.5倍进行增长。mDataSize=0,而len=4;因此会执行continueWrite(6)。

11. Parcel::continueWrite()

status_t Parcel::continueWrite(size_t desired)
{
    size_t objectsSize = mObjectsSize;

    ...

    if (mOwner) {
        ...
    } else if (mData) {
        ...

        // We own the data, so we can just do a realloc().
        if (desired > mDataCapacity) {
            uint8_t* data = (uint8_t*)realloc(mData, desired);
            if (data) {
                mData = data;
                mDataCapacity = desired;
            } else if (desired > mDataCapacity) {
                ...
            }
        } else {
            ...
        }

    } else {
        ...
    }

    return NO_ERROR;
}

说明:mObjectsSize的初始值为0,mOwner的初始值为NULL,mData非空;并且,desired=6,mDataCapacity=0。因此,会调用realloc()给mData重新分配内存大小为6字节。分配成功后,更新"数据地址mData"和"数据容量mDataCapacity=6"。

接下来,回到writeAligned()中,它会跳转到restart_write标签处。先将int32_t的整形数保存到mData中,然后再调用finishWrite()进行同步。

12. Parcel::finishWrite()

status_t Parcel::finishWrite(size_t len)
{
    mDataPos += len;
    if (mDataPos > mDataSize) {
        mDataSize = mDataPos;
        ...
    }
    return NO_ERROR;
}

说明:前面已经将数据写入到mData中,现在就通过finishWrite()来改变数据的当前指针位置(方便下一次写入)和数据的大小。
(01) len是int32_t的大小,很显然是4个字节,len=4。所以,mDataPos=4。
(02) mDataPos=4,mDataSize=0;因此if(mDataPos>mDataSize)为true,所以,mDataSize=4。

此时,就分析完了writeInterfaceToken()中的writeInt32()就分析完毕了.
mData:它的第0~3个字节保存了int32_t类型的数据STRICT_MODE_PENALTY_GATHER。
mDataPos:值为4,即下一个写入mData中的数据从第4个字节开始。
mDataSize:值为4,即mData中数据的大小。
mDataCapacity:值为6,即mData的数据容量为6字节。
此时,mData的数据如下图所示:

接下来,看看再writeString16("android.os.IServiceManager")如何将字符串写入到Parcel中。

13. Parcel::writeString16()

status_t Parcel::writeString16(const String16& str)
{
    return writeString16(str.string(), str.size());
}

status_t Parcel::writeString16(const char16_t* str, size_t len)
{
    if (str == NULL) return writeInt32(-1);

    // 将字符串长度写入到Parcel中
    status_t err = writeInt32(len);
    if (err == NO_ERROR) {
        len *= sizeof(char16_t);
        // 在将字符串写入之前,增加mData的容量
        uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char16_t));
        if (data) {
            // 将字符串拷贝到mData中
            memcpy(data, str, len);
            // 字符串结束符
            *reinterpret_cast<char16_t*>(data+len) = 0;
            return NO_ERROR;
        }
        err = mError;
    }
    return err;
}

说明:writeString16()是重载函数。
(01) writeString16(str, len)中,str="android.os.IServiceManager";len是由str.size()得来,虽然这里的字符串是String16类型(即每个字符占2个字节),但是str.size()是获取str中有效数据的个数(不包含字符串结束符),因此,len=26。
(02) 首先调用writeInt32(len)将字符串的长度写入到Parcel中,writeInt32()在前面已经介绍过了。当再次写入int32_t类型的数据时,数据容量不够,会再次增长为12,即mDataCapacity=12;而写入int32_t类型的数据之后,mDataPos和mDataSize都增长为8。 此时,mData的数据如下图所示:

在通过writeInt32(len)写入数据长度之后,再重新计算len=52;接着,通过writeInplace()写入数据。

14. Parcel::writeInplace()

#define PAD_SIZE(s) (((s)+3)&~3)

void* Parcel::writeInplace(size_t len)
{   
    // 4字节对齐
    const size_t padded = PAD_SIZE(len);

    ...

    if ((mDataPos+padded) <= mDataCapacity) {
restart_write:                        
        uint8_t* const data = mData+mDataPos;

        // 如果padded!=len,则根据大端法还是小端法进行地址对齐设置。
        if (padded != len) {
            ...
        }

        finishWrite(padded);
        return data;
    }   

    status_t err = growData(padded);
    if (err == NO_ERROR) goto restart_write;
    return NULL;
}

说明:参数len=54。
(01) PAD_SIZE()是4字节对齐的宏,PAD_SIZE(54)=56。
(02) 函数的初始值为padded=56,mDataPos=8,mDataCapacity=12。因此,会先调用growData(padded)来增加数据容量。growData()在前面已经介绍过;此时,它会将容量mDataCapacity增加至96。
(03) 接着会跳转到restart_write标签处,然后调用finishWrite(padded)来更新mDataPos和mDataSize。

至此,writeInplace()就分析完了,它的作用就是增加mData的容量,并返回即将写入数据的地址。接着,回到writeString16()中,执行mmap(data, str, len)将数据拷贝到mData中;拷贝完毕之后,设置字符串的结束符为0。

status_t Parcel::writeString16(const char16_t* str, size_t len)
{
    if (str == NULL) return writeInt32(-1);

    // 将字符串长度写入到Parcel中
    status_t err = writeInt32(len);
    if (err == NO_ERROR) {
        len *= sizeof(char16_t);
        // 在将字符串写入之前,增加mData的容量
        uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char16_t));
        if (data) {
            // 将字符串拷贝到mData中
            memcpy(data, str, len);
            // 字符串结束符
            *reinterpret_cast<char16_t*>(data+len) = 0;
            return NO_ERROR;
        }
        err = mError;
    }
    return err;
}


这样,data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor())就分析完了。此时,mData中数据如下图所示:

15. Parcel::writeString16()

继续回到addService()中,接着会通过data.writeString16(name)将MediaPlayerService服务的名称写入到data中,此处的name="media.player"。在前面已经详细介绍过writeString16(),这里执行完该语句后,mData中的数据如下:

接着,addService()会调用data.writeStrongBinder(service)将MediaPlayerService对象写入到data中。这个数据最重要,下面分析下writeStrongBinder()的实现。

16. Parcel::writeStrongBinder()

status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
    return flatten_binder(ProcessState::self(), val, this);
}

说明:该函数调用flatten_binder()将数据打包。

17. Parcel::flatten_binder()

status_t flatten_binder(const sp<ProcessState>& proc,
    const sp<IBinder>& binder, Parcel* out)
{       
    flat_binder_object obj;

    obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
    if (binder != NULL) {
        IBinder *local = binder->localBinder();
        if (!local) {
            ...
        } else {
            obj.type = BINDER_TYPE_BINDER;
            obj.binder = local->getWeakRefs();
            obj.cookie = local;
        }       
    } else {
        ...
    }

    return finish_flatten_binder(binder, obj, out);
}

说明:该函数是将MediaPlayerService对象封装到结构体flat_binder_object中。Binder驱动认识flat_binder_object结构体类型的数据,在C++层将数据发送给Binder驱动后,Binder驱动能够解析该结构体。
(01) 先看看参数,proc是ProcessState对象,binder是MediaPlayerService对象,out是Parcel自己。
(02) binder不为NULL,因此,执行if(binder!=NULL)中的语句。binder->localBinder()返回的BBinder对象,即本地Binder对象。(BBinder是MediaPlayerService的父类,localBinder()函数在frameworks/native/libs/binder/Binder.cpp中实现)。因此,local不为NULL。

obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;    // 标记
obj.type = BINDER_TYPE_BINDER;                      // 类型
obj.binder = local->getWeakRefs();                  // MediaPlayerService的弱引用
obj.cookie = local;                                 // MediaPlayerService自身

注意:从这里就可以看出,MediaPlayerService添加服务时,发送给驱动的数据是MediaPlayerService的本地Binder对象,即BBinder实例。准确的来说,该数据是保存在obj.cookie中的,该数据的类型是BINDER_TYPE_BINDER。

(03) 调用finish_flatten_binder()将数据写入到Parcel中。

18. Parcel::finish_flatten_binder()

inline static status_t finish_flatten_binder(
    const sp<IBinder>& binder, const flat_binder_object& flat, Parcel* out)
{       
    return out->writeObject(flat, false);
}       

说明:该函数是flat_binder_object对象写入到Parcel中。

19. Parcel::writeObject()

status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData)
{   
    const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;
    const bool enoughObjects = mObjectsSize < mObjectsCapacity;
    if (enoughData && enoughObjects) {
restart_write:
        *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;

        // val.binder非空
        if (nullMetaData || val.binder != NULL) {
            // 将地址偏移位置保存到mObjects[0]中
            mObjects[mObjectsSize] = mDataPos;
            acquire_object(ProcessState::self(), val, this);
            // 增加mObjectsSize的值
            mObjectsSize++;
        }

        ...

        return finishWrite(sizeof(flat_binder_object));
    }

    if (!enoughData) {
        const status_t err = growData(sizeof(val));
        if (err != NO_ERROR) return err;
    }
    if (!enoughObjects) {
        // 增加容量
        size_t newSize = ((mObjectsSize+2)*3)/2;
        // 分配内存
        size_t* objects = (size_t*)realloc(mObjects, newSize*sizeof(size_t));
        if (objects == NULL) return NO_MEMORY;
        // 设置mObjects的内存地址起始地址
        mObjects = objects;
        // 设置mObjects对象的容量
        mObjectsCapacity = newSize;
    }

    goto restart_write;
}

说明: (01) 此时,mDataPos=96, sizeof(val)=32, mDataCapacity=96;因此,enoughData=false。mObjectsSize和mObjectsCapacity的初始值=0,因此,enoughObjects=false。
(02) 首先,执行if(!enoughData)部分,通过growData()将数据的容量增加至192。即,mDataCapacity=192。
(03) 接着,执行if(!enoughObjects)部分,该部分的目的是分配对象空间,并修改mObjects和mObjectsCapacity的值。增加之后的容量mObjectsCapacity=3。
(04) 然后,跳转到restart_write标签处。 reinterpret_cast<flat_binder_object>(mData+mDataPos) = val是保存val对象到mDataPos+mDataPos所指的地址中。
(04) mObjects[mObjectsSize]=mDataPos,此处的mObjectsSize=0;这里是将对象的地址偏移mDataPos保存到mObjects[0]中。随后执行mObjectsSize++增加mObjectsSize的值为1。
(05) 最后,调用finishWrite()更新mDataPos和mDataSize的值。


至此,data.writeStrongBinder()就分析完了。将MediaPlayerService写入data之后,它的数据如下图所示:

最后,调用data.writeInt32(allowIsolated ? 1 : 0)。allowIsolated为false,因此,data.writeInt32(0)。执行该函数之后,data的数据如下图所示:

以上就是addService()中的data的数据。接下来执行remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply)。前面已经说过,remote()返回的是BpBinder对象,该BpBinder对象是在Android Binder机制(四) defaultServiceManager()的实现中调用defaultServiceManager()时初始化的。下面查看BpBinder的transact()。

20. BpBinder::transact()

status_t BpBinder::transact(            
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    // mAlive的初始值为1
    if (mAlive) {
        status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }

    return DEAD_OBJECT;
}

说明:该代码在frameworks/native/libs/binder/BpBinder.cpp中。由于mAlive的初始值为1,因此该函数会调用IPCThreadState::self()->transact()。我们知道,IPCThreadState::self()是获取全局IPCThreadState对象,因此最终会调用IPCThreadState::transact()。

21. IPCThreadState::transact()

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) {
        ...
        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
    }

    ...

    if ((flags & TF_ONE_WAY) == 0) {
        if (reply) {
            err = waitForResponse(reply);
        } else {
            ...
        }
    } else {
        ...
    }

    return err;
}

说明:该代码在frameworks/native/libs/binder/IPCThreadState.cpp中。
(01) 先看看函数的参数。handle是BpBinder中的mHandle对象,BpBinder中的mHandle是ServiceManager的句柄,值为0。code=ADD_SERVICE_TRANSACTION。data就是在addService中设置的Parcel对象。reply是用来接收Binder驱动反馈数据的Parcel对象。flags是默认值0。
(02) 该函数会先通过writeTransactionData()将数据打包。
(03) flags的初始化为0,并且reply非空。因此,将数据打包号之后,会调用waitForResponse()将数据发送给Binder驱动,然后等待Binder驱动反馈。

22. IPCThreadState::writeTransactionData()

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;
    tr.cookie = 0;
    tr.sender_pid = 0;
    tr.sender_euid = 0;

    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();
    } else if (statusBuffer) {
        ..
    } else {
        ...
    }

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

    return NO_ERROR;
}

说明:该函数会读取Parcel中的数据,然后将其打包到binder_transaction_data结构体中。binder_transaction_data结构体是Binder驱动能够识别并对之进行解析的数据结构。
ipcDataSize()是返回mDataSize,ipcData()是返回mData,ipcObjectsCount()是返回mObjectsSize,而ipcObjects则是返回mObjects。这些数据就是前面我们在addService中分析的Parcel对象的数据。下面给出初始化之后tr的值。

tr.target.handle = handle;  // 0,即Service Manager的句柄
tr.code = code;             // ADD_SERVICE_TRANSACTION
tr.flags = binderFlags;     // TF_ACCEPT_FDS
tr.cookie = 0;
tr.sender_pid = 0;

tr.data_size = data.ipcDataSize();      // 数据大小(对应mDataSize)
tr.data.ptr.buffer = data.ipcData();    // 数据的起始地址(对应mData)
tr.offsets_size = data.ipcObjectsCount()*sizeof(size_t); // data中保存的对象个数(对应mObjectsSize)
tr.data.ptr.offsets = data.ipcObjects();                 // data中保存的对象的偏移地址数组(对应mObjects)

初始化tr之后,将cmd=BC_TRANSACTION和tr重新打包到mOut中。mOut中的数据将来会被以请求的方式发送给Binder驱动。重新打包后的数据如下图所示:

在上图中,mOut包含了"事务指令"+"binder_transaction_data"结构体对象。而具体的MediaPlayerService对象,则包含在binder_transaction_data的data数据区域;它是被封装在flat_binder_object结构体中的。

23. IPCThreadState::waitForResponse()

writeTransactionData()分析完毕之后,再看看waitForResponse()的代码。

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    int32_t cmd;
    int32_t err;

    while (1) {
        // 先通过talkWithDriver()和Binder驱动交互
        if ((err=talkWithDriver()) < NO_ERROR) break;
        ...
        if (mIn.dataAvail() == 0) continue;

        // 然后读取返回结果,再根据结果进行处理
        cmd = mIn.readInt32();

        switch (cmd) {
        case BR_TRANSACTION_COMPLETE:
            ...
        case BR_DEAD_REPLY:
            ...
        case BR_FAILED_REPLY:
            ...
        case BR_ACQUIRE_RESULT:
            ...
        case BR_REPLY:
            ...
        default:
            err = executeCommand(cmd);
            if (err != NO_ERROR) goto finish;
            break;
        }
    }

finish:
    ...

    return err;
}

说明:waitForResponse()会先调用talkWithDriver()和Binder驱动交互,然后根据反馈结果来进行处理。

24. IPCThreadState::talkWithDriver()

status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    ...
    binder_write_read bwr;

    // Is the read buffer empty?
    const bool needRead = mIn.dataPosition() >= mIn.dataSize();
    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;

    bwr.write_size = outAvail;
    bwr.write_buffer = (long unsigned int)mOut.data();

    // This is what we'll read.
    if (doReceive && needRead) {
        bwr.read_size = mIn.dataCapacity();
        bwr.read_buffer = (long unsigned int)mIn.data();
    } else {
        bwr.read_size = 0;
        bwr.read_buffer = 0;
    }

    ...
    if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;

    bwr.write_consumed = 0;
    bwr.read_consumed = 0;
    status_t err;
    do {
        ...
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        else
            ...
        ...
    } while (err == -EINTR);

    ...

    if (err >= NO_ERROR) {
        // 清空已写的数据
        if (bwr.write_consumed > 0) {
            if (bwr.write_consumed < (ssize_t)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);
        }
        ...
        return NO_ERROR;
    }

    return err;
}

说明:talkWithDriver()会先初始化bwr(binder_write_read类型的变量),然后将bwr变量通过ioctl()发送给Binder驱动。该函数的参数doReceive的默认值为true。
(01) 现在,mIn中还没有被写入数据,因此它的值都是初始值。那么,mIn.dataPosition()返回mDataPos,它的值为0;mIn.dataSize()返回mDataSize,它的初始值也为0。因此,needRead=true。
(02) doReceive=true,但是needRead=true;因此,outAvail=mOut.dataSize,outAvail不为0。接下来,就对bwr进行初始化,关于bwr的介绍,请参考Android Binder机制(二) Binder中的数据结构。bwr初始化完毕之后,各个成员的值如下:

bwr.write_size = outAvail;                          // mOut中数据大小,大于0
bwr.write_buffer = (long unsigned int)mOut.data();  // mOut中数据的地址
bwr.write_consumed = 0;
bwr.read_size = mIn.dataCapacity();                 // 256
bwr.read_buffer = (long unsigned int)mIn.data();    // mIn.mData,实际上为空
bwr.read_consumed = 0;

(03) bwr初始化完成之后,调用ioctl(,BINDER_WRITE_READ,)和Binder驱动进行交互。

通过binder_write_read再次打包后的数据如下图所示:

如上图所示,ioctl()传输的数据包含"BINDER_WRITE_READ"+"binder_write_read结构体对象"。在binder_write_read的write_buffer中包含了事务数据;而在数据数据的data中又包含了flat_binder_object等数据。在flat_binder_object中就包含了需要传输的MediaPlayerService对象。
总体来看,数据经过了三次封装。下面看看在Binder驱动中是如何一层层将它们剖析开来的。

25. Binder驱动中binder_ioctl()的BINDER_WRITE_READ相关部分的源码

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
  int ret;
  struct binder_proc *proc = filp->private_data;
  struct binder_thread *thread;
  unsigned int size = _IOC_SIZE(cmd);
  void __user *ubuf = (void __user *)arg;

  // 中断等待函数。
  // 1. 当binder_stop_on_user_error < 2为true时;不会进入等待状态;直接跳过。
  // 2. 当binder_stop_on_user_error < 2为false时,进入等待状态。
  //    当有其他进程通过wake_up_interruptible来唤醒binder_user_error_wait队列,并且binder_stop_on_user_error < 2为true时;
  //    则继续执行;否则,再进入等待状态。
  ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);

  binder_lock(__func__);
  // 在proc进程中查找该线程对应的binder_thread;若查找失败,则新建一个binder_thread,并添加到proc->threads中。
  thread = binder_get_thread(proc);
  ...

  switch (cmd) {
  case BINDER_WRITE_READ: {
      struct binder_write_read bwr;
      ...

      // 将binder_write_read从"用户空间" 拷贝到 "内核空间"
      if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
          ...
      }

      // 如果write_size>0,则进行写操作
      if (bwr.write_size > 0) {
          ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
          ...
      }

      // 如果read_size>0,则进行读操作
      if (bwr.read_size > 0) {
          ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags   & O_NONBLOCK);
          ...
      }
      ...

      if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
          ret = -EFAULT;
          goto err;
      }
      break;
  }
  ...
  }
  ret = 0;

  ...
  return ret;
}

说明:关于该函数在Android Binder机制(三) ServiceManager守护进程中已经介绍过了。这里将binder_write_read从用户空间拷贝到内核空间之后,读取bwr.write_size和bwr.read_size都>0,因此先写后读。

26. Binder驱动中binder_thread_write()的源码

int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
          void __user *buffer, int size, signed long *consumed)
{
  uint32_t cmd;
  void __user *ptr = buffer + *consumed;
  void __user *end = buffer + size;

  // 读取binder_write_read.write_buffer中的内容。
  // 每次读取32bit(即4个字节)
  while (ptr < end && thread->return_error == BR_OK) {
      // 从用户空间读取32bit到内核中,并赋值给cmd。
      if (get_user(cmd, (uint32_t __user *)ptr))
          return -EFAULT;

      ptr += sizeof(uint32_t);
      ...
      switch (cmd) {
      ...
        case BC_TRANSACTION:
        case BC_REPLY: {
            struct binder_transaction_data tr;

            if (copy_from_user(&tr, ptr, sizeof(tr)))
                return -EFAULT;
            ptr += sizeof(tr);
            binder_transaction(proc, thread, &tr, cmd == BC_REPLY);
            break;
        }
      ...
      }
      // 更新bwr.write_consumed的值
      *consumed = ptr - buffer;
  }
  return 0;
}

说明:读取出来的交易码是BC_TRANSACTION。在通过copy_from_user()将数据拷贝从用户空间拷贝到内核空间之后,就调用binder_transaction()进行处理。

27. Binder驱动中binder_transaction()的源码

static void binder_transaction(struct binder_proc *proc,
                   struct binder_thread *thread,
                   struct binder_transaction_data *tr, int reply)
{
    struct binder_transaction *t;
    struct binder_work *tcomplete;
    size_t *offp, *off_end;
    struct binder_proc *target_proc;
    struct binder_thread *target_thread = NULL;
    struct binder_node *target_node = NULL;
    struct list_head *target_list;
    wait_queue_head_t *target_wait;
    struct binder_transaction *in_reply_to = NULL;
    struct binder_transaction_log_entry *e;
    uint32_t return_error;

    ...

    if (reply) {
        ...
    } else {
        if (tr->target.handle) {
            ...
        } else {
            // 事务目标对象是ServiceManager的binder实体
            // 即,该事务是交给Service Manager来处理的。
            target_node = binder_context_mgr_node;
            ...
        }
        ...
        // 设置处理事务的目标进程
        target_proc = target_node->proc;
        ...
    }

    if (target_thread) {
        ...
    } else {
        target_list = &target_proc->todo;
        target_wait = &target_proc->wait;
    }
    ...

    // 分配一个待处理的事务t,t是binder事务(binder_transaction对象)
    t = kzalloc(sizeof(*t), GFP_KERNEL);
    ...

    // 分配一个待完成的工作tcomplete,tcomplete是binder_work对象。
    tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
    ...

    t->debug_id = ++binder_last_id;
    ...

    // 设置from,表示该事务是MediaPlayerService发起的
    if (!reply && !(tr->flags & TF_ONE_WAY))
        t->from = thread;
    else
        t->from = NULL;
    // 下面的一些赋值是初始化事务t
    t->sender_euid = proc->tsk->cred->euid;
    // 事务将交给target_proc进程进行处理
    t->to_proc = target_proc;
    // 事务将交给target_thread线程进行处理
    t->to_thread = target_thread;
    // 事务编码
    t->code = tr->code;
    // 事务标志
    t->flags = tr->flags;
    // 事务优先级
    t->priority = task_nice(current);

    ...

    // 分配空间
    t->buffer = binder_alloc_buf(target_proc, tr->data_size,
        tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));
    ...
    t->buffer->allow_user_free = 0;
    t->buffer->debug_id = t->debug_id;
    // 保存事务
    t->buffer->transaction = t;
    // 保存事务的目标对象(即处理该事务的binder对象)
    t->buffer->target_node = target_node;
    trace_binder_transaction_alloc_buf(t->buffer);
    if (target_node)
        binder_inc_node(target_node, 1, 0, NULL);

    offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));

    // 将"用户空间的数据"拷贝到内核中
    // tr->data.ptr.buffer就是用户空间数据的起始地址,tr->data_size就是数据大小
    if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {
        ...
    }
    // 将"用户空间的数据中所含对象的偏移地址"拷贝到内核中
    // tr->data.ptr.offsets就是数据中的对象偏移地址数组,tr->offsets_size就数据中的对象个数
    // 拷贝之后,offp就是flat_binder_object对象数组在内核空间的偏移数组的起始地址
    if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {
        ...
    }
    ...
    // off_end就是flat_binder_object对象数组在内核空间的偏移地址的结束地址
    off_end = (void *)offp + tr->offsets_size;
    // 将所有的flat_binder_object对象读取出来
    // 对MediaPlayerService而言,只有一个flat_binder_object对象。
    for (; offp < off_end; offp++) {
        struct flat_binder_object *fp;
        ...
        fp = (struct flat_binder_object *)(t->buffer->data + *offp);

        switch (fp->type) {
        case BINDER_TYPE_BINDER:
        case BINDER_TYPE_WEAK_BINDER: {
            struct binder_ref *ref;
            // 在proc中查找binder实体对应的binder_node
            struct binder_node *node = binder_get_node(proc, fp->binder);
            // 若找不到,则新建一个binder_node;下次就可以直接使用了。
            if (node == NULL) {
                node = binder_new_node(proc, fp->binder, fp->cookie);
                if (node == NULL) {
                    ...
                }
                node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
                node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
            }
            ...
            // 在target_proc(即,ServiceManager的进程上下文)中查找是否包行"该Binder实体的引用",
            // 如果没有找到的话,则将"该binder实体的引用"添加到target_proc->refs_by_node红黑树中。这样,就可以通过Service Manager对该
Binder实体进行管理了。
            ref = binder_get_ref_for_node(target_proc, node);
            if (ref == NULL) {
                ...
            }
            // 修改type
            if (fp->type == BINDER_TYPE_BINDER)
                fp->type = BINDER_TYPE_HANDLE;
            else
                fp->type = BINDER_TYPE_WEAK_HANDLE;
            // 修改handle。handle和binder是联合体,这里将handle设为引用的描述。
            // 根据该handle可以找到"该binder实体在target_proc中的binder引用";
            // 即,可以根据该handle,可以从Service Manager找到对应的Binder实体的引用,从而获取Binder实体。
            fp->handle = ref->desc;
            // 增加引用计数,防止"该binder实体"在使用过程中被销毁。
            binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
                       &thread->todo);

            trace_binder_transaction_node_to_ref(t, node, ref);
            ...
        } break;
        ...
        }
    }
    if (reply) {
        ..
    } else if (!(t->flags & TF_ONE_WAY)) {
        BUG_ON(t->buffer->async_transaction != 0);
        t->need_reply = 1;
        t->from_parent = thread->transaction_stack;
        // 将当前事务添加到当前线程的事务栈中
        thread->transaction_stack = t;
    } else {
        ...
    }
    // 设置事务的类型为BINDER_WORK_TRANSACTION
    t->work.type = BINDER_WORK_TRANSACTION;
    // 将事务添加到target_list队列中,即target_list的待处理事务中
    list_add_tail(&t->work.entry, target_list);
    // 设置待完成工作的类型为BINDER_WORK_TRANSACTION_COMPLETE
    tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
    // 将待完成工作添加到thread->todo队列中,即当前线程的待完成工作中。
    list_add_tail(&tcomplete->entry, &thread->todo);
    // 唤醒目标进程
    if (target_wait)
        wake_up_interruptible(target_wait);
    return;

    ...
}

说明:这里的tr->target.handle=0,因此,会设置target_node为ServiceManager对应的Binder实体。下面是target_node,target_proc等值初始化之后的值。

target_node = binder_context_mgr_node; // 目标节点为Service Manager对应的Binder实体
target_proc = target_node->proc;       // 目标进程为Service Manager对应的binder_proc进程上下文信息
target_list = &target_thread->todo;    // 待处理事务队列
target_wait = &target_thread->wait;    // 等待队列

目标节点是Service Manager对应的Binder实体。这是指MediaPlayerService的addService()这个指令是来提交给Service Manager进行处理的,它最终会发送给Service Manager进行处理。。

在初始化完target_node等目标节点之后,会新建一个待处理事务t和待完成的工作tcomplete,并对它们进行初始化。待处理事务t会被提交给目标(即ServiceManager对应的Binder实体)进行处理;而待完成的工作tcomplete则是为了反馈给MediaPlayerService服务,告诉MediaPlayerService它的请求Binder驱动已经收到了。注意,这里仅仅是告诉MediaPlayerService该请求已经被收到,而不是处理完毕!待ServiceManager处理完毕该请求之后,Binder驱动会再次反馈相应的消息给MediaPlayerService。

    // 分配一个待处理的事务t,t是binder事务(binder_transaction对象)
    t = kzalloc(sizeof(*t), GFP_KERNEL);
    ...

    // 分配一个待完成的工作tcomplete,tcomplete是binder_work对象。
    tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
    ...

    t->debug_id = ++binder_last_id;
    ...

    if (!reply && !(tr->flags & TF_ONE_WAY))
        t->from = thread;
    else
        t->from = NULL;
    // 下面的一些赋值是初始化事务t
    t->sender_euid = proc->tsk->cred->euid;
    // 事务将交给target_proc进程进行处理
    t->to_proc = target_proc;
    // 事务将交给target_thread线程进行处理
    t->to_thread = target_thread;
    // 事务编码
    t->code = tr->code;
    // 事务标志
    t->flags = tr->flags;
    // 事务优先级
    t->priority = task_nice(current);

    ...

    // 分配空间
    t->buffer = binder_alloc_buf(target_proc, tr->data_size,
        tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));
    ...
    t->buffer->allow_user_free = 0;
    t->buffer->debug_id = t->debug_id;
    // 保存事务
    t->buffer->transaction = t;
    // 保存事务的目标对象(即处理该事务的binder对象)
    t->buffer->target_node = target_node;
    trace_binder_transaction_alloc_buf(t->buffer);
    if (target_node)
        binder_inc_node(target_node, 1, 0, NULL);

在初始化完待处理事务t之后,接着将MediaPlayerService请求的数据拷贝到内核空间并解析出来。从数据中解析出MediaPlayerService请求数据中的flat_binder_object对象,只有一个flat_binder_object对象。该flat_binder_object对象的类型是BINDER_TYPE_BINDER,然后调用binder_get_node()在当前进程的上下文环境proc中查找fp->binder对应的Binder实体,fp->binder是Android的flatten_binder()中赋值的,它是MediaPlayerService对象的本地引用的描述(即MediaPlayerService对应的BBinder对象的描述);此外,在MediaPlayerService是初次与Binder驱动通信,因此肯定找不到该对象fp->binder对应的Binder实体;因此node=NULL。 接下来,就调用binder_new_node()新建fp->binder对应的Binder实体,这也就是MediaPlayerService对应的Binder实体。然后,调用binder_get_ref_for_node(target_proc, node)获取该Binder实体在target_proc(即ServiceManager的进程上下文环境)中的Binder引用,此时,在target_proc中肯定也找不到该Binder实体对应的引用;那么,就新建Binder实体的引用,并将其添加到target_proc->refs_by_node红黑树 和 target_proc->refs_by_desc红黑树中。 这样,Service Manager的进程上下文中就存在MediaPlayerService的Binder引用,Service Manager也就可以对MediaPlayerService进行管理了!
然后,修改fp->type=BINDER_TYPE_HANDLE,并使fp->handle = ref->desc。

这样,就将MediaPlayerService的请求数据解析出来,并且在Binder驱动中创建了MediaPlayerService对应的Binder实体,而且将该Binder实体添加到MediaPlayerService的进程上下文proc中。更重要的是,在ServiceManager的refs_by_node和refs_by_desc这两颗红黑树中创建了"MediaPlayerService对应的Binder实体的Binder引用"。这意味着,在Binder驱动中,已经能在ServiceManager的进程上下文中找到MediaPlayerService。

    // 将"用户空间的数据"拷贝到内核中
    // tr->data.ptr.buffer就是用户空间数据的起始地址,tr->data_size就是数据大小
    if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {
        ...
    }
    // 将"用户空间的数据中所含对象的偏移地址"拷贝到内核中
    // tr->data.ptr.offsets就是数据中的对象偏移地址数组,tr->offsets_size就数据中的对象个数
    // 拷贝之后,offp就是flat_binder_object对象数组在内核空间的起始地址
    if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {
        ...
    }
    ...
    // off_end就是flat_binder_object对象数组在内核空间的结束地址
    off_end = (void *)offp + tr->offsets_size;
    // 将所有的flat_binder_object对象读取出来
    // 对MediaPlayerService而言,只有一个flat_binder_object对象。
    for (; offp < off_end; offp++) {
        struct flat_binder_object *fp;
        ...
        fp = (struct flat_binder_object *)(t->buffer->data + *offp);

        switch (fp->type) {
        case BINDER_TYPE_BINDER:
        case BINDER_TYPE_WEAK_BINDER: {
            struct binder_ref *ref;
            // 在proc中查找binder实体对应的binder_node
            struct binder_node *node = binder_get_node(proc, fp->binder);
            // 若找不到,则新建一个binder_node;下次就可以直接使用了。
            if (node == NULL) {
                node = binder_new_node(proc, fp->binder, fp->cookie);
                if (node == NULL) {
                    ...
                }
                node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
                node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
            }
            ...
            // 在target_proc(即,Service Manager的进程上下文)中查找是否包行"该binder实体的引用",
            // 如果没有找到的话,则将"该binder实体的引用"添加到target_proc->refs_by_node红黑树中。这样,就可以通过Service Manager对该
Binder实体进行管理了。
            ref = binder_get_ref_for_node(target_proc, node);
            if (ref == NULL) {
                ...
            }
            // 修改type
            if (fp->type == BINDER_TYPE_BINDER)
                fp->type = BINDER_TYPE_HANDLE;
            else
                fp->type = BINDER_TYPE_WEAK_HANDLE;
            // 修改handle。handle和binder是联合体,这里将handle设为引用的描述。
            // 根据该handle可以找到"该binder实体在target_proc中的binder引用";
            // 即,可以根据该handle,可以从Service Manager找到对应的binder实体的引用,从而获取binder实体。
            fp->handle = ref->desc;
            // 增加引用计数,防止"该binder实体"在使用过程中被销毁。
            binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
                       &thread->todo);

            trace_binder_transaction_node_to_ref(t, node, ref);
            ...
        } break;
        ...
        }
    }

然后,设置待处理事务的类型为BINDER_WORK_TRANSACTION,并将其添加到target_list中。即,添加事务到Service Manager对应的待处理事务队列中。
设置待完成工作的类型为BINDER_WORK_TRANSACTION_COMPLETE,并将其添加到当前线程的待完成工作中。此时,Binder驱动已经收到了MediaPlayerService的请求,这个所谓的待完成工作,就是用来让Binder驱动告诉MediaPlayerService,它的请求已经被处理了。
最后,target_wait是ServiceManager的等待队列,肯定不为空(因为前面刚刚将BINDER_WORK_TRANSACTION事务添加到待处理事务中)。因此,便会执行wake_up_interruptible(target_wait)唤醒Service Manager进程。
注意,此时都是运行在MediaPlayerService的进程中的!

    // 设置事务的类型为BINDER_WORK_TRANSACTION
    t->work.type = BINDER_WORK_TRANSACTION;
    // 将事务添加到target_list队列中,即target_list的待处理事务中
    list_add_tail(&t->work.entry, target_list);
    // 设置待完成工作的类型为BINDER_WORK_TRANSACTION_COMPLETE
    tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
    // 将待完成工作添加到thread->todo队列中,即当前线程的待完成工作中。
    list_add_tail(&tcomplete->entry, &thread->todo);
    // 唤醒目标进程
    if (target_wait)
        wake_up_interruptible(target_wait);
    return;

此时,MediaPlayerService进程还会继续运行,而且它也通过wake_up_interruptible()唤醒了ServiceManager进程。ServiceManager被唤醒后,所做的工作就是将MediaPlayerService注册到它的服务队列中进行管理;它的具体流程稍候再分析,现在还是先分析完MediaPlayerService进程。

至此,binder_transaction()就分析完了。在binder_transaction()中,我们主要进行了以下工作: (01) 解析出来MediaPlayerService的请求数据。
(02) 新建MediaPlayerService对应的Binder实体和Binder引用,并将ServiceManager的进程上下文中存在MediaPlayerService的Binder引用。
(03) 新建了待处理事务,并将该事务添加到了ServiceManager的待处理事务队列中。然后,唤醒ServiceManager来处理该事务。
(04) 新建了待完成工作,并将待完成工作添加到了当前线程的待完成工作队列中。

28. Binder驱动中binder_thread_write()的源码

接着分析MediaPlayerService进程的工作。binder_thread_write()中执行binder_transaction()后,会更新*consumed的值,即bwr.write_consumed的值。意味着,Binder驱动已经驱动完成MediaPlayerService的请求数据。

int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
          void __user *buffer, int size, signed long *consumed)
{
  uint32_t cmd;
  void __user *ptr = buffer + *consumed;
  void __user *end = buffer + size;

  // 读取binder_write_read.write_buffer中的内容。
  // 每次读取32bit(即4个字节)
  while (ptr < end && thread->return_error == BR_OK) {
      // 从用户空间读取32bit到内核中,并赋值给cmd。
      if (get_user(cmd, (uint32_t __user *)ptr))
          return -EFAULT;

      ptr += sizeof(uint32_t);
      ...
      switch (cmd) {
      ...
        case BC_TRANSACTION:
        case BC_REPLY: {
            struct binder_transaction_data tr;

            if (copy_from_user(&tr, ptr, sizeof(tr)))
                return -EFAULT;
            ptr += sizeof(tr);
            binder_transaction(proc, thread, &tr, cmd == BC_REPLY);
            break;
        }
      ...
      }
      // 更新bwr.write_consumed的值
      *consumed = ptr - buffer;
  }
  return 0;
}

29. Binder驱动中binder_thread_read()的源码

接下来,ioctl()会执行binder_thread_read()来设置反馈数据给MediaPlayerService进程。

static int binder_thread_read(struct binder_proc *proc,
                  struct binder_thread *thread,
                  void  __user *buffer, int size,
                  signed long *consumed, int non_block)
{
    void __user *ptr = buffer + *consumed;
    void __user *end = buffer + size;

    int ret = 0;
    int wait_for_proc_work;

    // 如果*consumed=0,则写入BR_NOOP到用户传进来的bwr.read_buffer缓存区
    if (*consumed == 0) {
        if (put_user(BR_NOOP, (uint32_t __user *)ptr))
            return -EFAULT;
        ptr += sizeof(uint32_t);
    }

retry:
    // 等待proc进程的事务标记。
    // 当线程的事务栈为空 并且 待处理事务队列为空时,该标记位true。
    wait_for_proc_work = thread->transaction_stack == NULL &&
                list_empty(&thread->todo);

    ...

    if (wait_for_proc_work) {
        ...
    } else {
        if (non_block) {
            ...
        } else
            ret = wait_event_interruptible(thread->wait, binder_has_thread_work(thread));
    }

    ...

    while (1) {
        uint32_t cmd;
        struct binder_transaction_data tr;
        struct binder_work *w;
        struct binder_transaction *t = NULL;

        // 如果当前线程的"待完成工作"不为空,则取出待完成工作。
        if (!list_empty(&thread->todo))
            w = list_first_entry(&thread->todo, struct binder_work, entry);
        else if (!list_empty(&proc->todo) && wait_for_proc_work)
            ...
        else {
            if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)) /* no data added */
                goto retry;
            break;
        }

        ...

        switch (w->type) {
        ...
        case BINDER_WORK_TRANSACTION_COMPLETE: {
            cmd = BR_TRANSACTION_COMPLETE;
            // 将BR_TRANSACTION_COMPLETE写入到用户缓冲空间中
            if (put_user(cmd, (uint32_t __user *)ptr))
                return -EFAULT;
            ptr += sizeof(uint32_t);

            binder_stat_br(proc, thread, cmd);
            ...

            // 待完成事务已经处理完毕,将其从待完成事务队列中删除。
            list_del(&w->entry);
            kfree(w);
            binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
        } break;
        ...
        }

        if (!t)
            continue;

        ...
    }

    ...
    // 更新bwr.read_consumed的值
    *consumed = ptr - buffer;

    ...
    return 0;
}

说明:
(01) 先看看函数的参数,buffer是bwr.read_buffer,是反馈数据缓冲区。size是bwr.read_size,是缓冲区大小,为256字节;而consumed是指向bwr.read_consumed的,它的值是0,表示反馈数据还没有被MediaPlayerService读取过。non_block为0。
(02) consumed=0,因此会先将BR_NOOP从内核空间拷贝到用户空间,即拷贝到bwr.read_buffer中。
(03) 在binder_transaction()中,我们有添加待完成工作到thread的待完成工作队列中。因此,wait_for_proc_work是false。
(04) binder_has_thread_work(thread)为ture,因此wait_event_interruptible()不会进入中断等待状态,而是继续往下运行。
(05) 接着,进入while循环。list_empty(&thread->todo)为flase,执行list_first_entry(&thread->todo, struct binder_work, entry)从thread的待完成工作队列中取出待完成的工作t。
(06) 根据binder_transaction()中的分析可知,t->type的值为BINDER_WORK_TRANSACTION_COMPLETE。执行对应的case分支,会将数据cmd=BR_TRANSACTION_COMPLETE拷贝到用户空间,即bwr.read_buffer中。拷贝之后,即代表该工作已完成,然后从当前线程的工作队列中将该工作删除,并释放所分配的空间。
(07) 由于t=null,因此,会再次从头开始执行while循环。而此时,list_empty(&thread->todo)为true,并且list_empty(&proc->todo)也为true;因此会执行break跳出while循环。
(08) 在跳出while循环之后,会更新
consumed的值。即,更新bwr.read_consumed的值。此时,由于写入了BR_NOOP和BR_TRANSACTION_COMPLETE两个指令,bwr.read_consumed=8。


接下来,回到binder_ioctl()中。将bwr数据拷贝到用户空间后返回。此时,bwr中各个参数的值如下:

bwr.write_size = outAvail;                          
bwr.write_buffer = (long unsigned int)mOut.data();
bwr.write_consumed = outAvail;                      // 等于write_size
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (long unsigned int)mIn.data();    // 存储了BR_NOOP和BR_TRANSACTION_COMPLETE两个返回指令
bwr.read_consumed = 8;                              // 等于write_size

bwr中的write*参数是保存"MediaPlayerService发送给Binder驱动的请求内容的",而read*则是保存"Binder驱动反馈给MediaPlayerService的内容的"。此时,write_consumed和write_size相同,意味着"Binder驱动已经将请求的内容都处理完毕了";而read_consumed>0,则意味着"Binder驱动有反馈内容给MediaPlayerService"。
回到talkWithDriver()中,看看ioctl()之后做了些什么?

30. IPCThreadState::talkWithDriver()

status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    ...
    do {
        ...
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        else
            ...
        ...
    } while (err == -EINTR);

    ...

    if (err >= NO_ERROR) {
        // 清空已写的数据
        if (bwr.write_consumed > 0) {
            if (bwr.write_consumed < (ssize_t)mOut.dataSize())
                ...
            else
                mOut.setDataSize(0);
        }
        // 设置已读数据
        if (bwr.read_consumed > 0) {
            mIn.setDataSize(bwr.read_consumed);
            mIn.setDataPosition(0);
        }
        ...
        return NO_ERROR;
    }

    return err;
}

说明:ioctl()返回值为0,err=NO_ERROR,退出while循环。
(01) bwr.write_consumed>0,并且bwr.write_consumed=mOut.dataSize。因此,调用mOut.setDataSize(0)将释放mOut的内存,并且将mOut的mDataSize和mObjectsSize设为0。
(02) bwr.read_consumed>0,因此调用mIn.setDataSize()为mIn分配空间,并将mIn的mDataSize设为=bwr.read_consumed。然后,将位置mDataPos初始化为0。
之后,跳出talkWithDriver(),返回到waitForResponse()中。

31. IPCThreadState::waitForResponse()

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{       
    int32_t cmd;
    int32_t err;

    while (1) {
        // 先通过talkWithDriver()和Binder驱动交互
        if ((err=talkWithDriver()) < NO_ERROR) break;
        err = mIn.errorCheck();
        if (err < NO_ERROR) break;
        if (mIn.dataAvail() == 0) continue;

        // 然后读取返回结果,再根据结果进行处理
        cmd = mIn.readInt32();

        switch (cmd) {
        case BR_TRANSACTION_COMPLETE:
            ...
        case BR_DEAD_REPLY:
            ...
        case BR_FAILED_REPLY:
            ...
        case BR_ACQUIRE_RESULT:
            ...
        case BR_REPLY:
            ...
        default:
            err = executeCommand(cmd);
            if (err != NO_ERROR) goto finish;
            break;
        }
    }

finish:
    ...

    return err;
}

说明:从talkWithDriver()正常返回之后,会读取mIn中的数据。而mIn中的数据就是Binder驱动返回的"BR_NOOP和BR_TRANSACTION_COMPLETE两个指令"。先读出的指令是BR_NOOP,因此这里执行executeCommand(cmd)。

32. IPCThreadState::executeCommand()

status_t IPCThreadState::executeCommand(int32_t cmd)
{
    BBinder* obj;
    RefBase::weakref_type* refs;
    status_t result = NO_ERROR;

    switch (cmd) {
    case BR_ERROR:
        ...
    case BR_OK:
        ...
    case BR_NOOP:
        break;
    default:
        ...
    }

    if (result != NO_ERROR) {
        mLastError = result;
    }

    return result;
}

说明:BR_NOOP没有进行任何操作,直接返回。继续回到waitForResponse()中,重新开始while循环,执行talkWithDriver()。

33. IPCThreadState::talkWithDriver()

status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    ...
    binder_write_read bwr;

    // Is the read buffer empty?
    const bool needRead = mIn.dataPosition() >= mIn.dataSize();
    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;

    bwr.write_size = outAvail;
    bwr.write_buffer = (long unsigned int)mOut.data();

    // This is what we'll read.
    if (doReceive && needRead) {
        bwr.read_size = mIn.dataCapacity();
        bwr.read_buffer = (long unsigned int)mIn.data();
    } else {
        bwr.read_size = 0;
        bwr.read_buffer = 0;
    }

    ...
    if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;

    bwr.write_consumed = 0;
    bwr.read_consumed = 0;
    status_t err;
    do {
        ...
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        else
            ...
        ...
    } while (err == -EINTR);

    ...

    if (err >= NO_ERROR) {
        // 清空已写的数据
        if (bwr.write_consumed > 0) {
            if (bwr.write_consumed < (ssize_t)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);
        }
        ...
        return NO_ERROR;
    }

    return err;
}

说明: (01) 此时,因为在waitForResponse()中已经通过mIn.readInt32()读取了4个字节,因此mIn.dataPosition()=4,而mIn.dataSize()=8;因此,needRead=false。
(02) needRead=false,而doReceive=true;因此,outAvail=0。
最终,由于 bwr.write_size和bwr.read_size都为0,因此直接返回NO_ERROR。

再次回到waitForResponse()中,此时读出的cmd为BR_TRANSACTION_COMPLETE。此时,由于reply不为NULL,因此再次重新执行while循环,调用talkWithDriver()。

(01) 此时,已经读取了mIn中的全部数据,因此mIn.dataPosition()=8,而mIn.dataSize()=8;因此,needRead=true。
(02) outAvail=mOut.dataSize(),前面已经将mOut清空,因此outAvail=0。bwr初始化完毕之后,各个成员的值如下:

    bwr.write_size = 0;
    bwr.write_buffer = (long unsigned int)mOut.data();
    bwr.write_consumed = 0;
    bwr.read_size = mIn.dataCapacity();                 // 256字节
    bwr.read_buffer = (long unsigned int)mIn.data();
    bwr.read_consumed = 0;

其实,此时MediaPlayerService已经处理完"addService()这个请求,包括已经处理完了该请求的反馈"。对MediaPlayerService而言,它已经成功的注册到Service Manager中;接下来,就是等待Client的请求了。
那么如何去等待Client的请求呢?这和前面分析Service Manager服务启动之后等待Client的请求类似。MediaPlayerService服务,会通过ioctl()给Binder驱动发送读写请求,而此时的bwr.write_size=0,意味着不会进行写;bwr.read_size>0,意味着会进行读。这样,Binder驱动就会执行读取动作,进而去查看"MediaPlayerService在Binder驱动中的待处理事务队列"是否有事务需要处理,有的话,就进行事务处理;否则,就进入中断等待状态,等待Client的请求。

下面,看看它到底是如何做到的。

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
  int ret;
  struct binder_proc *proc = filp->private_data;
  struct binder_thread *thread;
  unsigned int size = _IOC_SIZE(cmd);
  void __user *ubuf = (void __user *)arg;

  ...

  switch (cmd) {
  case BINDER_WRITE_READ: {
      struct binder_write_read bwr;
      ...

      // 将binder_write_read从"用户空间" 拷贝到 "内核空间"
      if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
          ...
      }

      // 如果write_size>0,则进行写操作
      if (bwr.write_size > 0) {
          ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
          ...
      }

      // 如果read_size>0,则进行读操作
      if (bwr.read_size > 0) {
          ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags   & O_NONBLOCK);
          ...
      }
      ...

      if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
          ret = -EFAULT;
          goto err;
      }
      break;
  }
  ...
  }
  ret = 0;

  ...
  return ret;
}

此时,bwr.write_size=0,因此不会执行binder_thread_write()。而bwr.read_size>0,因此会调用binder_thread_read()进行读取动作。

34. Binder驱动中binder_thread_read()的源码

static int binder_thread_read(struct binder_proc *proc,
                struct binder_thread *thread,
                void  __user *buffer, int size,
                signed long *consumed, int non_block)
{
  void __user *ptr = buffer + *consumed;
  void __user *end = buffer + size;

  int ret = 0;
  int wait_for_proc_work;

  // 如果*consumed=0,则写入BR_NOOP到用户传进来的bwr.read_buffer缓存区
  if (*consumed == 0) {
      if (put_user(BR_NOOP, (uint32_t __user *)ptr))
          return -EFAULT;
      // 修改指针位置
      ptr += sizeof(uint32_t);
  }

retry:
  // 等待proc进程的事务标记。
  // 当线程的事务栈为空 并且 待处理事务队列为空时,该标记位true。
  wait_for_proc_work = thread->transaction_stack == NULL &&
              list_empty(&thread->todo);

  ...
  if (wait_for_proc_work) {
      ...
      // 设置当前线程的优先级=proc->default_priority。
      // 即,当前线程要处理proc的事务,所以设置优先级和proc一样。
      binder_set_nice(proc->default_priority);
      if (non_block) {
          ...
      } else
          // 阻塞式的读取,则阻塞等待事务的发生。
          ret = wait_event_interruptible_exclusive(proc->wait, binder_has_proc_work(proc, thread));
  } else {
      ...
  }
  ...
}

(01) 此时,bwr.read_consumed=0,意味着*consumed=0。因此,还是会先将BR_NOOP写入到bwr.read_buffer中。
(02) 此时,当前线程的事务栈和待处理事务队列都是空,因此wait_for_proc_work=true。
(03) 在调用binder_set_nice()设置当前线程的优先级之后,就会调用wait_event_interruptible()。而此时binder_has_proc_work()为false,因此当前线程会进入中断等待状态。当Service Manager处理完MediaPlayerService的请求之后,就会将其唤醒。


至此,MediaPlayerService进程的addService的请求发送部分就讲解完了。在继续了解请求的处理之前,先回顾一下本部分的内容。

如上图所示,MediaPlayerService发送一个BC_TRANSACTION事务给Binder驱动。Binder驱动收到该事务之后,对请求数据进行解析,在Kernel中新建了MediaPlayerService对应的Binder实体,并将在ServiceManager的进程上下文中添加了该Binder实体的Binder引用。解析完数据之后,新增一个待处理事务并提交到ServiceManager的待处理事务列表中;接着,就唤醒了ServiceManager。与此同时,Binder驱动还反馈了一个BR_TRANSACTION_COMPLETE给MediaPlayerService,告诉MediaPlayerService它的addService请求已经发送成功;MediaPlayerService在解析完BR_TRANSACTION_COMPLETE之后,就进入等待状态,等待ServiceManager的处理完请求之后反馈结果给它。

下面一篇文章,就看看ServiceManager被唤醒之后,具体都做了些什么工作!

by skywang
Previous     Next