Android Binder入门指南之addService详解之请求的发送

   Android Binder入门指南之addService详解之请求的发送

  有了前面篇章的铺垫,我想读者对Binder应该有了一定的了解了,那么我们接着继续深入了解。本篇章终于要开始讲解Client-Server交互了,如标题所示,本文要讲解的是addService请求,即添加服务请求。本文选取的切入点是MediaPlayerService服务通过addService请求注册到ServiceManager中。在这个请求中,MediaPlayerService是Client,而ServiceManager是Server。由于涉及到的过程比较复杂,这里会将addService请求分为3篇进行说明,这3篇的主题分别是:请求的发送请求的处理以及请求的反馈。和以往一样,在讲解详细的代码之前,先做个整体介绍。
注意:本文是基于Android 7.xx版本进行介绍的!



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守护进程篇有详细介绍过。

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

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

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

(5) WAIT:MediaPlayerService在知道自己的请求发送成功之后,就会进入中断等待状态,等待请求的反馈。

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

(7) BC_FREE_BUFFER和BC_REPLY:ServiceManager在保存了MediaPlayerService的相关信息之后,便处理完毕了MediaPlayerService的请求。此时,它便反馈BC_FREE_BUFFER和BC_REPLY给Binder驱动。Binder驱动在收到BC_FREE_BUFFER之后,会释放保存请求数据所申请的内存;收到BC_REPLY之后,Binder驱动则知道ServiceManager已经处理完了MediaPlayerService的请求。

(8) WAKE_UP:Binder驱动发送WAKE_UP唤醒MediaPlayerService进程。

(9) BR_NOOP和BR_REPLY:Binder驱动唤醒MediaPlayerService后,继续BR_NOOP和BR_REPLY给MediaPlayerService,告诉MediaPlayerService请求已经处理完毕。

(10) BR_TRANSACTION_COMPLETE:同时,Binder驱动会发送一个BR_TRANSACTION_COMPLETE给ServiceManager,告诉ServiceManager该事务已经处理完毕。 MediaPlayerService在收到BR_REPLY反馈之后,知道addService请求已经成功处理;接着,它会再次进入等待状态,等待Client的请求。

(11) WAIT:最后,ServiceManager处理MediaPlayerService的请求之后,没有其他事务可处理,也再次进入了等待状态。



2.IMediaPlayerService的类图

  本文是以MediaPlayerService为例,对addService进行解析。下面让我们一起看看MediaPlayerService相关联的类图(是不是觉得有点熟悉,在前面的篇章里面也有见过不是)。
在这里插入图片描述
MediaPlayerService的类图和Android Binder机制(五) defaultServiceManager()的实现中IServiceManager的类图类似。这里就不再逐一对每个类进行介绍了。

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



3.addService请求发送代码详解

  在前面的章节里面,我们从时序图和类图两个维度对addService有了一个轮廓上的认识,下面我们从代码层面来分析addService请求发送的流程。


3.1 MediaPlayerService的main()函数

  本篇章是以MediaPlayerService添加到ServiceManager为例来说明addService的过程,所以得先从MediaPlayerService服务入手,通过源码我们知道该服务是一个Native Service所以先从函数入口main()分析起。

int main(int argc __unused, char **argv __unused)
{
	...
    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm(defaultServiceManager());
	...
    MediaPlayerService::instantiate();
    ResourceManagerService::instantiate();
	...
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
}

该源码的路径是frameworks/av/media/mediaserver/main_mediaserver.cpp中。这段代码比较精简(不是简单额),主要功能如下:
(1) ProcessState:self()是获取ProcessState对象,并赋值给proc。ProcessState::self(),详细的介绍在Android Binder机制(五) defaultServiceManager()的实现中已经介绍过了。
(2) defaultServiceManager()是获取IServiceManager对象,它的实现在Android Binder机制(五) defaultServiceManager()的实现中也有详细介绍。
(3) MediaPlayerService::instantiate()是初始化MediaPlayerService服务。


3.2 MediaPlayerService::instantiate()

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

  该代码在frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp中,可以使用一句话来概括就是将MediaPlayerService添加到ServiceManager。它会新建MediaPlayerService对象;然后调用defaultServiceManager()获取到的BpServiceManager的实例然后调用BpServiceManager的addService()方法,将MediaPlayerService对象添加到Service Manager中。MediaPlayerService服务的名称是"media.player"。可以通过service list命令查看:

λ adb shell "service list | grep media.player"
143     media.player: [android.media.IMediaPlayerService]

3.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;

    // reset battery stats
    // if the mediaserver has crashed, battery stats could be left
    // in bad state, reset the state upon service start.
    BatteryNotifier::getInstance().noteResetVideo();

    MediaPlayerFactory::registerBuiltinFactories();
}

  MediaPlayerService的构造函数比较简单,就是进行一些变量的初始化。没有什么好说的,其次这也不是本篇探讨的重点。


3.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;
        //见3.6章节分析
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
        //见3.7章节分析
        data.writeString16(name);
        //见3.8章节分析
        data.writeStrongBinder(service);
        //见3.9章节分析
        data.writeInt32(allowIsolated ? 1 : 0);
        //见3.10章节分析
        status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
        return err == NO_ERROR ? reply.readExceptionCode() : err;
    }
    ...
}

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


3.5 Parcel类分析

  通过上面的分析可知,addService里面会创建两个Parcel的对象,下面我们来看看Parcel的构造函数。

Parcel::Parcel()
{
    LOG_ALLOC("Parcel %p: constructing", this);
    initState();
}

该代码定义在frameworks/native/libs/binder/Parcel.cpp,接着继续分析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;
    mOpenAshmemSize = 0;
	...
}

3.6 Parcel::writeInterfaceToken(getInterfaceDescriptor())

  下面看看data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor())的实现。getInterfaceDescriptor()是通过宏IMPLEMENT_META_INTERFACE()实现的,该宏已经在Android Binder机制(五) 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);
    return writeString16(interface);
}

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


3.6.1 Parcel::writeInt32()

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

writeInt32函数会调用writeAligned()。

Parcel::writeAligned()
template<class T>
//模板函数
status_t Parcel::writeAligned(T val) {
    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(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()的作用是是写入数据,譬如同步相应的变量,下面渐进分析:
(1) 在函数writeAligned()中此时mDataPos的初始值=0,sizeof(val)=4,mDataCapacity的初始值=0。因此,if((mDataPos+sizeof(val)) <= mDataCapacity)为false。
(2) 接下来,会先调用growData(sizeof(val))来增加容量,然后再将数据写入到mData中。

Parcel::growData()
status_t Parcel::growData(size_t len)
{
    if (len > INT32_MAX) {
        return BAD_VALUE;
    }

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

接着继续分析growData(字面理解就可以看出是增加容量),通过代码可以看出Parcel增加容量时,是按1.5倍进行增长,因为此时mDataSize=0,而len=4;因此会执行continueWrite(6)。

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

接着继续分析continueWrite,此时mObjectsSize的初始值为0,mOwner的初始值为NULL,mData非空;并且,desired=6,mDataCapacity=0。因此,会调用realloc()给mData重新分配内存大小为6字节。分配成功后,更新"数据地址mData"和"数据容量mDataCapacity=6"。接下来,回到writeAligned()中,它会跳转到restart_write标签处。先将int32_t的整形数保存到mData中,然后再调用finishWrite()进行同步。

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

下面我们继续分析finishWrite(),在前面的步骤中已经将数据写入到mData中,现在就通过finishWrite()来改变数据的当前指针位置(方便下一次写入)和数据的大小。此时
(1) len是int32_t的大小,很显然是4个字节,len=4。所以,mDataPos=4。
(2) mDataPos=4,mDataSize=0;因此if(mDataPos>mDataSize)为true,所以,mDataSize=4。
到这里我们就已经分析完了writeInterfaceToken()中的writeInt32()的所有过程了。下面让我们再理一理此时Parcel里面各个变量的值。
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中。


3.6.2 writeString16(interface)

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);//重新计算len的长度
        //在将字符串写入之前,增加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;
}

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


在这里插入图片描述
在调用writeInt32(len)写入数据长度之后,再重新计算len的值为52,接着通过writeInplace()写入数据。

Parcel::writeInplace()
#define PAD_SIZE_UNSAFE(s) (((s)+3)&~3)
static size_t pad_size(size_t s) {
    if (s > (SIZE_T_MAX - 3)) {
        abort();
    }
    return PAD_SIZE_UNSAFE(s);
}
void* Parcel::writeInplace(size_t len)
{
    if (len > INT32_MAX) {
        return NULL;
    }
	//4字节对齐
    const size_t padded = pad_size(len);
    if (mDataPos+padded < mDataPos) {
        return NULL;
    }

    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而不是52这个地方不要弄错了,至于为什么大家可以从代码里面查找到原因。下面接着继续分析代码:
(1) pad_size()是4字节对齐的宏,所以pad_size(54)计算后的结果是56。
(2) 函数的初始值为padded=56,mDataPos=8,mDataCapacity=12。因此,会先调用growData(padded)来增加数据容量。growData()在前面已经介绍过;此时,它会将容量mDataCapacity增加至96。
(3) 接着会跳转到restart_write标签处,然后调用finishWrite(padded)来更新mDataPos和mDataSize。
至此,writeInplace()就分析完了,它的作用就是增加mData的容量,并返回即将写入数据的地址。接着,我们继续回到3.6.2 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);//重新计算len的长度
        //在将字符串写入之前,增加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;
}

分析至此,addService的data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor())就分析完了。此时让我们来捋一捋Parcel已经写入的数据,其中mData中数据如下图所示:


在这里插入图片描述



3.7 data.writeString16(name)

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

在这里插入图片描述
接着,addService()会调用data.writeStrongBinder(service)将MediaPlayerService对象写入到data中。这个数据最重要,这个也是Binder设计的精华所在,现在让我们分析学习一下writeStrongBinder()的实现。



3.8 data.writeStrongBinder(service)

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

该函数调用flatten_binder()将数据打包(将服务拍扁打包),在Parcel里面有一个与之相对应的函数unflatten_binder,这个我们在后续的章节和篇章也会讲到的。

3.8.1 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) {
            BpBinder *proxy = binder->remoteBinder();
            if (proxy == NULL) {
                ALOGE("null proxy");
            }
            const int32_t handle = proxy ? proxy->handle() : 0;
            obj.type = BINDER_TYPE_HANDLE;
            obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
            obj.handle = handle;
            obj.cookie = 0;
        } else {
        	//addService会走到该分支里面
            obj.type = BINDER_TYPE_BINDER;
            obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
            obj.cookie = reinterpret_cast<uintptr_t>(local);
        }
    } else {
        obj.type = BINDER_TYPE_BINDER;
        obj.binder = 0;
        obj.cookie = 0;
    }

    return finish_flatten_binder(binder, obj, out);
}

下面让我们来分析分析该函数,该函数在addService的过程中会将MediaPlayerService对象打扁封装到结构体flat_binder_object中。Binder驱动认识flat_binder_object结构体类型的数据,在C++层将数据发送给Binder驱动后,Binder驱动能够解析该结构体。
(1) 先看看参数,proc是ProcessState对象,binder是MediaPlayerService对象,out是Parcel自己。
(2) binder不为NULL,因此,执行if(binder!=NULL)中的语句。binder->localBinder()返回的BBinder对象,即本地Binder对象。(BBinder是MediaPlayerService的父类,localBinder()函数在frameworks/native/libs/binder/Binder.cpp中实现)。因此,local不为NULL。此时的obj的赋值如下:

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

从上面的赋值结果可以看出,MediaPlayerService添加服务时,发送给驱动的数据是MediaPlayerService的本地Binder对象,即BBinder实例。准确的来说,该数据是保存在obj.cookie中的,该数据的类型是BINDER_TYPE_BINDER。
(3) 最后调用finish_flatten_binder()将数据写入到Parcel中。

3.8.2 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中。

3.8.3 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 != 0) {
        	//将地址偏移位置保存到mObjects[0]中
            mObjects[mObjectsSize] = mDataPos;
            acquire_object(ProcessState::self(), val, this, &mOpenAshmemSize);
            // 增加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;
        //分配内存
        if (newSize*sizeof(binder_size_t) < mObjectsSize) return NO_MEMORY;   
        binder_size_t* objects = (binder_size_t*)realloc(mObjects, newSize*sizeof(binder_size_t));
        if (objects == NULL) return NO_MEMORY;
        //设置mObjects的内存起始地址
        mObjects = objects;
        //设置mObjects对象的容量
        mObjectsCapacity = newSize;
    }

    goto restart_write;
}

至此,让我回过头看看Parcel里面各个变量的值,此时,mDataPos=96, sizeof(val)=32, mDataCapacity=96,让我们带着这些数据来分析这段代码:
(1) 根据此时Parcel里面数据数值计算,因此,enoughData=false。mObjectsSize和mObjectsCapacity的初始值=0,因此,enoughObjects=false。
(2) 首先,执行if(!enoughData)部分,通过growData()将数据的容量增加至192(1.5倍)。即mDataCapacity=192。
(3) 接着,执行if(!enoughObjects)部分,该部分的目的是分配对象空间,并修改mObjects和mObjectsCapacity的值。增加之后的容量mObjectsCapacity=3。
(4) 然后,跳转到restart_write标签处。 reinterpret_cast<flat_binder_object>(mData+mDataPos) = val是保存val对象到mDataPos+mDataPos所指的地址中。
(5) mObjects[mObjectsSize]=mDataPos,此处的mObjectsSize=0;这里是将对象的地址偏移mDataPos保存到mObjects[0]中。随后执行mObjectsSize++增加mObjectsSize的值为1。
(6) 最后,调用finishWrite()更新mDataPos和mDataSize的值。
至此,data.writeStrongBinder()就分析完了。下面我们来捋一捋在将MediaPlayerService写入data之后,Parcel的数据如下图所示:
在这里插入图片描述



3.9 data.writeInt32(allowIsolated ? 1 : 0)

让我们继续回到addService源码里面,最后调用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()。



3.10 BpBinder::transact()

status_t BpBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    //初始值为1,在BpBinder构造的时候被赋值
    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()。 下面我们继续分析IPCThreadState::transact()。



3.11 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 {
    	//当不需要驱动反馈的时候设置flag为TF_ONE_WAY,会节省一定时间,在某些场合可以使用
        err = waitForResponse(NULL, NULL);
    }    
    return err;
}

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


3.11.1 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.ptr = 0; 
    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(binder_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驱动能够识别并对之进行解析的数据结构,在前面Android Binder机制(二) Binder中的数据结构中已经有关详细的介绍了,就不多赘述了。
ipcDataSize()是返回mDataSize,ipcData()是返回mData,ipcObjectsCount()是返回mObjectsSize,而ipcObjects则是返回mObjects。这些数据就是前面我们在addService中分析的Parcel对象的数据。下面给出初始化之后tr的值。

tr.target.handle = handler;    //0, 即ServiceManager代理对象的默认句柄
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(binder_size_t);	// data中保存的对象个数(对应mObjectsSize)
tr.data.ptr.offsets = data.ipcObjects();	// data中保存的对象的偏移地址数组(对应mObjects)

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

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


3.11.2 IPCThreadState::waitForResponse()

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

    while (1) {
        if ((err=talkWithDriver()) < NO_ERROR) break;
		...
        if (mIn.dataAvail() == 0) continue;
        
        cmd = (uint32_t)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;
}    

writeTransactionData()分析完毕之后,再看看waitForResponse()的代码,waitForResponse()会先调用talkWithDriver()和Binder驱动交互,然后根据反馈结果来分别进行处理。


3.11.3 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 = (uintptr_t)mOut.data();

    // This is what we'll read.
    if (doReceive && needRead) {
        bwr.read_size = mIn.dataCapacity();
        bwr.read_buffer = (uintptr_t)mIn.data();
    } else {
        bwr.read_size = 0;
        bwr.read_buffer = 0;
    }
	...
    if ((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
            err = -errno;
		...
    } while (err == -EINTR);

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

talkWithDriver()会先初始化bwr(binder_write_read类型的变量),然后将bwr变量通过ioctl()发送给Binder驱动。该函数的参数doReceive的默认值为true。
(1) 现在,mIn中还没有被写入数据,因此它的值都是初始值。那么,mIn.dataPosition()返回mDataPos,它的值为0;mIn.dataSize()返回mDataSize,它的初始值也为0。因此,needRead=true。
(2) 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;

(3) 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比较熟悉的话,一般考官都会喜欢问上面的数据结构图看看你是否真的掌握了。
总体来看,数据经过了三次封装。下面我们继续分析在Binder驱动中是如何一层层将它们剖析开来的。



3.12 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))) {
			ret = -EFAULT;
			goto err;
		}
		...

		//如果write_size>0,则进行写操作
		if (bwr.write_size > 0) {
			ret = binder_thread_write(proc, thread, bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
			...
		}
		//如果read_size>0,则进行读操作
		if (bwr.read_size > 0) {
			ret = binder_thread_read(proc, thread, 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,因此先写后读,下面我们来逐个分析,各个击破。


3.12.1 Binder驱动中binder_thread_write()的源码

static int binder_thread_write(struct binder_proc *proc,
			struct binder_thread *thread,
			binder_uintptr_t binder_buffer, size_t size,
			binder_size_t *consumed)
{
	uint32_t cmd;
	void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
	void __user *ptr = buffer + *consumed;
	void __user *end = buffer + size;

	//读取binder_write_read.write_buffer中的内容。
	//每次读取32bit(即四个字节)
	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,所以此处走BC_TRANSACTION,在通过copy_from_user()将数据拷贝从用户空间拷贝到内核空间之后,就调用binder_transaction()进行处理。


3.12.2 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;
	binder_size_t *offp, *off_end;
	binder_size_t off_min;
	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;

	...
	//此时参数reply的值为0,所以会进入非replay分支
	if (reply) {
		...
	} else {
		//此时handle的值为0
		if (tr->target.handle) {
			...
		} else {
			//事务目标对象是ServiceManager得Binder实体
			//即该事务是交给ServiceManager来处理的
			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 = (binder_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, (const void __user *)(uintptr_t)
			   tr->data.ptr.buffer, tr->data_size)) {
		...
	}
    // 将"用户空间的数据中所含对象的偏移地址"拷贝到内核中
    // tr->data.ptr.offsets就是数据中的对象偏移地址数组,tr->offsets_size就数据中的对象个数
    // 拷贝之后,offp就是flat_binder_object对象数组在内核空间的偏移数组的起始地址
	if (copy_from_user(offp, (const void __user *)(uintptr_t)
			   tr->data.ptr.offsets, tr->offsets_size)) {
		...
	}
	...
	// off_end就是flat_binder_object对象数组在内核空间的偏移地址的结束地址
	off_end = (void *)offp + tr->offsets_size;
	off_min = 0;
	//将所有的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);
		off_min = *offp + sizeof(struct flat_binder_object);
		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;
			fp->binder = 0;
            // 修改handle。handle和binder是联合体,这里将handle设为引用的描述。
            // 根据该handle可以找到"该binder实体在target_proc中的binder引用";
            // 即,可以根据该handle,可以从Service Manager找到对应的Binder实体的引用,从而获取Binder实体。
            fp->handle = ref->desc;
            // 增加引用计数,防止"该binder实体"在使用过程中被销毁。
			fp->handle = ref->desc;
			fp->cookie = 0;
			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;
	...
}

(1) 先对入参的参数分析一把,此时tr->target.handle=0且reply也为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;    // 等待队列

(2) 分析至此,我们现在已经知道目标节点是Service Manager对应的Binder实体。这是指MediaPlayerService的addService()这个指令是来提交给Service Manager进行处理的,它最终会发送给Service Manager进行处理。

(3) 在初始化完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;
    ...

	//设置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);

(4) 在初始化完待处理事务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.offsets就是数据中的对象偏移地址数组,tr->offsets_size就数据中的对象个数
    // 拷贝之后,offp就是flat_binder_object对象数组在内核空间的偏移数组的起始地址
	if (copy_from_user(offp, (const void __user *)(uintptr_t)
			   tr->data.ptr.offsets, tr->offsets_size)) {
		...
	}
	...
	// off_end就是flat_binder_object对象数组在内核空间的偏移地址的结束地址
	off_end = (void *)offp + tr->offsets_size;
	off_min = 0;
	//将所有的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);
		off_min = *offp + sizeof(struct flat_binder_object);
		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;
			fp->binder = 0;
            // 修改handle。handle和binder是联合体,这里将handle设为引用的描述。
            // 根据该handle可以找到"该binder实体在target_proc中的binder引用";
            // 即,可以根据该handle,可以从Service Manager找到对应的Binder实体的引用,从而获取Binder实体。
            fp->handle = ref->desc;
            // 增加引用计数,防止"该binder实体"在使用过程中被销毁。
			fp->handle = ref->desc;
			fp->cookie = 0;
			binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
				       &thread->todo);

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

(5) 然后,设置待处理事务的类型为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) 新建了待完成工作,并将待完成工作添加到当前线程的待完成工作队列中中。


3.12.3 Binder驱动中binder_thread_write()的源码

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

static int binder_thread_write(struct binder_proc *proc,
			struct binder_thread *thread,
			binder_uintptr_t binder_buffer, size_t size,
			binder_size_t *consumed)
{
	uint32_t cmd;
	void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
	void __user *ptr = buffer + *consumed;
	void __user *end = buffer + size;

	//读取binder_write_read.write_buffer中的内容。
	//每次读取32bit(即四个字节)
	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;
}	

3.12.4 Binder驱动中binder_thread_read()的源码

让我们继续分析,接下来ioctl()会执行binder_thread_read()来设置反馈数据给MediaPlayerService进程。让我们带着愉悦的心情分析一番:

static int binder_thread_read(struct binder_proc *proc,
			      struct binder_thread *thread,
			      binder_uintptr_t binder_buffer, size_t size,
			      binder_size_t *consumed, int non_block)
{
	void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
	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);
	...

	thread->looper |= BINDER_LOOPER_STATE_WAITING;
	if (wait_for_proc_work)
		proc->ready_threads++;

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

	binder_lock(__func__);

	if (wait_for_proc_work)
		proc->ready_threads--;
	thread->looper &= ~BINDER_LOOPER_STATE_WAITING;

	...

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

代码虽然不多,但是信息量还是比较大的,下面让我们来逐层分析,步步为营:
(1) 先看看函数的参数,buffer是bwr.read_buffer,是反馈数据缓冲区。size是bwr.read_size,是缓冲区大小,为256字节;而consumed是指向bwr.read_consumed的,它的值是0,表示反馈数据还没有被MediaPlayerService读取过。non_block为0。
(2) consumed=0,因此会先将BR_NOOP从内核空间拷贝到用户空间,即拷贝到bwr.read_buffer中。
(3) 在binder_transaction()中,我们有添加待完成工作到thread的待完成工作队列中。因此,wait_for_proc_work是false。
(4) binder_has_thread_work(thread)为ture,因此wait_event_interruptible()不会进入中断等待状态,而是继续往下运行。
(5) 接着,进入while循环。list_empty(&thread->todo)为flase,执行list_first_entry(&thread->todo, struct binder_work, entry)从thread的待完成工作队列中取出待完成的工作t。
(6) 根据binder_transaction()中的分析可知,t->type的值为BINDER_WORK_TRANSACTION_COMPLETE。执行对应的case分支,会将数据cmd=BR_TRANSACTION_COMPLETE拷贝到用户空间,即bwr.read_buffer中。拷贝之后,即代表该工作已完成,然后从当前线程的工作队列中将该工作删除,并释放所分配的空间。
(7) 由于t=null,因此,会再次从头开始执行while循环。而此时,list_empty(&thread->todo)为true,并且list_empty(&proc->todo)也为true;因此会执行break跳出while循环。
(8) 在跳出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;                              // 等于read_size

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



3.13 重返IPCThreadState::transact()

   通过前面分析可知,此时代码已经从驱动层返回到了应用层,那么让我们一起跟着代码的脚步来到应用层继续分析吗。

3.13.1 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 = (uintptr_t)mOut.data();

    // This is what we'll read.
    if (doReceive && needRead) {
        bwr.read_size = mIn.dataCapacity();
        bwr.read_buffer = (uintptr_t)mIn.data();
    } else {
        bwr.read_size = 0;
        bwr.read_buffer = 0;
    }
	...
    if ((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
            err = -errno;
		...
    } while (err == -EINTR);

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

ioctl()从驱动层返回以后的返回值为0,所以err=NO_ERROR,此时退出while循环。接着代码往下执行:
(1) bwr.write_consumed>0,并且bwr.write_consumed=mOut.dataSize。因此,调用mOut.setDataSize(0)将释放mOut的内存,并且将mOut的mDataSize和mObjectsSize设为0。
(2) bwr.read_consumed>0,因此调用mIn.setDataSize()为mIn分配空间,并将mIn的mDataSize设为=bwr.read_consumed。然后,将位置mDataPos初始化为0。
之后,跳出talkWithDriver(),返回到waitForResponse()中。


3.13.2 IPCThreadState::waitForResponse()

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

    while (1) {
        if ((err=talkWithDriver()) < NO_ERROR) break;
		...
        if (mIn.dataAvail() == 0) continue;
        
        cmd = (uint32_t)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)。(读者可以缓一缓,上个厕所干个啥的,内容有点多啊)


3.13.3 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;
}

此时入参的参数cmd=BR_NOOP没有进行任何的操作,直接返回。继续回到waitForResponse()中,重新开始while循环,执行talkWithDriver()。


3.13.4 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 = (uintptr_t)mOut.data();

    // This is what we'll read.
    if (doReceive && needRead) {
        bwr.read_size = mIn.dataCapacity();
        bwr.read_buffer = (uintptr_t)mIn.data();
    } else {
        bwr.read_size = 0;
        bwr.read_buffer = 0;
    }
	...
    if ((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
            err = -errno;
		...
    } while (err == -EINTR);

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

弯弯绕绕又回到了这里,你说我们容易吗。好吗,废话有点多,让我们接着继续分析:
(1) 此时,因为在waitForResponse()中已经通过mIn.readInt32()读取了4个字节,因此mIn.dataPosition()=4,而此时mIn.dataSize()=8;因此,needRead=false。
(2) 此时needRead=false,而doRecive=true,所以计算得出outAvail=0。最终,由于 bwr.write_size和bwr.read_size都为0,因此直接返回NO_ERROR。
(3) 再次回到waitForResponse()中,此时读出的cmd为BR_TRANSACTION_COMPLETE。此时,由于reply不为NULL,不会跳出while循环,因此再次重新执行while循环,调用talkWithDriver()。
(4) 此时,已经读取了mIn中的全部数据,因此mIn.dataPosition()=8,而mIn.dataSize()=8;因此,needRead=true。
(5) 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;

(7) 分析到这里,此时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的请求。能有啥办法呢,只能接着继续分析了。



3.14 再探Binder驱动

   各位读者请系好安全带,抓紧扶手,振作精神,我们得继续Binder驱动层深入分析了。木有办法Binder深入就是有这么的折腾。

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))) {
			ret = -EFAULT;
			goto err;
		}
		...

		//如果write_size>0,则进行写操作
		if (bwr.write_size > 0) {
			ret = binder_thread_write(proc, thread, bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
			...
		}
		//如果read_size>0,则进行读操作
		if (bwr.read_size > 0) {
			ret = binder_thread_read(proc, thread, 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()进行读取动作。

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 {
      ...
  }
  ...
}

此时的我有点凌乱,有点紧张因为本篇章快要结束了。继续分析
(1) 此时,bwr.read_consumed=0,意味着*consumed=0。因此,还是会先将BR_NOOP写入到bwr.read_buffer中。
(2) 此时,当前线程的事务栈和待处理事务队列都是空,因此wait_for_proc_work=true。
(3) 在调用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被唤醒后,具体都做了些什么工作!聪明的你应该可以想得到做了些什么,让我们下个篇章继续分析。

发布了89 篇原创文章 · 获赞 92 · 访问量 31万+

猜你喜欢

转载自blog.csdn.net/tkwxty/article/details/103243685