Binder通信和启动流程详解

所有源码均基于android M

本篇从情景化角度出发分析Binder的通信逻辑。

其中会涉及到几个概念
· media server - 系统多媒体服务
· media player server - 多媒体服务下的视频服务
· Binder驱动

先总结一下本篇所会涉及到的概念和他们之间的关系。

media server 是安卓系统中用来管理各个多媒体服务的“服务的服务类”。media server管理着多个服务的启动和加载,包括 AudioFlinger,Camera,MediaPlayerService,等等。

这些服务都需要通过media server注册到系统的ServiceManager中。

ServiceManager是android系统用来管理服务的管理器。在android里这些服务是以C/S架构存在的。所有的客户端想是用服务端功能,都需要先向系统的ServiceManager申请调用这些服务,而不能够直接使用服务的实际对象。

在C端使用S端的服务的过程中,C端所持有的是一个BinderProxy对象,它用BinderProxy,通过Binder驱动向S端发起调用,S端再通过Binder驱动把处理结果返回给C端。S端也持有一个Binder对象,和C端不同的是它不是proxy这种代理对象,它在Java层是我们写AIDL时候经常见到的Stub,在C++或者JNI层,是BBinder的派生类。

我们先从Binder驱动的启动开始。

Binder驱动的启动

android系统本质上也是个Linux系统,它的启动也依据 init.rc 的配置。在init.rc中,启动binder驱动的部分在servicemanager,

service servicemanager /system/bin/servicemanager
    class core
    user system
    group system
    critical
    onrestart restart healthd
    onrestart restart zygote
    onrestart restart media
    onrestart restart surfaceflinger
    onrestart restart drm

servicemanger是系统侧的进程,我们看看它代码的main入口。
Mashmallow/frameworks/native/cmds/servicemanager/service_manager.c

int main(int argc, char **argv)
{
    struct binder_state *bs;

    bs = binder_open(128*1024); // 打开binder驱动
    if (!bs) {
        ALOGE("failed to open binder driver\n");
        return -1;
    }

    if (binder_become_context_manager(bs)) { //设置fd为当前binder上下文
        ALOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1;
    }

    selinux_enabled = is_selinux_enabled();
    sehandle = selinux_android_service_context_handle();
    selinux_status_open(true);

    if (selinux_enabled > 0) {
        if (sehandle == NULL) {
            ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");
            abort();
        }

        if (getcon(&service_manager_context) != 0) {
            ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");
            abort();
        }
    }

    union selinux_callback cb;
    cb.func_audit = audit_callback;
    selinux_set_callback(SELINUX_CB_AUDIT, cb);
    cb.func_log = selinux_log_callback;
    selinux_set_callback(SELINUX_CB_LOG, cb);

    binder_loop(bs, svcmgr_handler); //开始事件循环,svcmgr_handler很重要,是处理事件的主要入口

    return 0;
}

binder驱动的启动流程比较简单。首先它调用binder_open()去打开binder节点,我们知道在linux中一切皆是文件。
Mashmallow/frameworks/native/cmds/servicemanager/binder.c

struct binder_state *binder_open(size_t mapsize)
{
    struct binder_state *bs;
    struct binder_version vers;

    bs = malloc(sizeof(*bs)); 
    if (!bs) {
        errno = ENOMEM;
        return NULL;
    }

    bs->fd = open("/dev/binder", O_RDWR);//打开binder驱动
    if (bs->fd < 0) {
        fprintf(stderr,"binder: cannot open device (%s)\n",
                strerror(errno));
        goto fail_open;
    }

    if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
        (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
        fprintf(stderr,
                "binder: kernel driver version (%d) differs from user space version (%d)\n",
                vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION);
        goto fail_open;
    }

    bs->mapsize = mapsize;
    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);//设定映射空间大小
    if (bs->mapped == MAP_FAILED) {
        fprintf(stderr,"binder: cannot map device (%s)\n",
                strerror(errno));
        goto fail_map;
    }

    return bs;

fail_map:
    close(bs->fd);
fail_open:
    free(bs);
    return NULL;
}

/dev/binder是所有binder设备的节点。binder框架的内存拷贝我们都知道只有一次,它是使用mmap在binder设备驱动上开辟了一个内存映射空间用来做内存拷贝的。因为省去了 用户空间-内核空间 的拷贝流程,所以本质上它能够做到比传统的IPC少一次内存拷贝。

但这里有个细节需要注意,这里的内存映射空间大小实际只有 128x 1024 字节,并不是我们所熟悉的1M。因为这是在系统侧的binder通信,这个内存空间实际上只有ServiceManager在使用,所以设计上只需要128K。

看到binder_loop之后就应该猜的到,这里是个事件循环机制,在一个for里面不停地等待事件的发生和处理。

void binder_loop(struct binder_state *bs, binder_handler func)
{
    int res;
    struct binder_write_read bwr;
    uint32_t readbuf[32];

    bwr.write_size = 0;
    bwr.write_consumed = 0;
    bwr.write_buffer = 0;

    readbuf[0] = BC_ENTER_LOOPER;
    binder_write(bs, readbuf, sizeof(uint32_t));

    for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (uintptr_t) readbuf;

        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); //通过ioctl等待事件

        if (res < 0) {
            ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
            break;
        }

        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func); //解析数据结构并且调用 func
        if (res == 0) {
            ALOGE("binder_loop: unexpected reply?!\n");
            break;
        }
        if (res < 0) {
            ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));
            break;
        }
    }
}

调用loop()的时候第二个参数 func是一个函数指针,它所指向的是service_manager中的函数svcmgr_handler()。
loop的逻辑比较简单,就是一般的事件驱动逻辑。

到这里binder驱动就启动完毕,并且进入循环模式不停地等待和处理从C端传过来的数据了。总的来说binder驱动做的事情包括
· 添加服务
· 查询服务
· 获取服务
这三个是主要功能,具体代码逻辑在 service_manager 的 svcmgr_handler里,也就是上面说的binder_loop()的第二个参数,

int svcmgr_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    ...
}

bingder驱动启动完毕后,就等待C端的ServiceManager和它通信了。到这里还只是bidner框架的其中一个部分,得结合C端的逻辑才能明白整个binder的工作原理

MediaService的启动

这里说的 media service 是提供多媒体服务的S端,它里面使用了ServiceManager的C端。在init.rc中,SM的C端的启动比S端稍微慢一点。并且它是在mediaserver进程里启动的。

service media /system/bin/mediaserver
    class main
    user media
    group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
    ioprio rt 4

media sever是我们即将要启动的多媒体服务,它的主入口在
Mashmallow/frameworks/av/media/mediaserver/main_mediaserver.cpp

int main(int argc __unused, char** argv)
{
    ...
    if (doLog && (childPid = fork()) != 0) { //从主进程fork出来子进程
        //主进程部分继续做一些逻辑
    } else { //子进程部分
        // all other services
        if (doLog) {
            prctl(PR_SET_PDEATHSIG, SIGKILL);   // if parent media.log dies before me, kill me also
            setpgid(0, 0);                      // but if I die first, don't kill my parent
        }
        InitializeIcuOrDie();
        sp<ProcessState> proc(ProcessState::self()); //在本地进程中打开binder驱动
        sp<IServiceManager> sm = defaultServiceManager(); //启动C端的SM
        ALOGI("ServiceManager: %p", sm.get());
        AudioFlinger::instantiate();
        MediaPlayerService::instantiate(); //启动MediaPlayerService,添加到S端的SM中
        ResourceManagerService::instantiate();
        CameraService::instantiate();
        AudioPolicyService::instantiate();
        SoundTriggerHwService::instantiate();
        RadioService::instantiate();
        registerExtensions();
        ProcessState::self()->startThreadPool();//开始C端的事件循环
        IPCThreadState::self()->joinThreadPool();
    }
}

这个文件的代码很简单只有一百多行。我们删掉与fork出来的子进程逻辑无关的代码之后就剩下这些。

这里涉及到三个东西,ProcessState,ServiceManager,MediaPlayerService。

MediaPlayerService其实只是系统提供的多媒体服务的其中一个,类似的还有Camera,SurfaceFlinger等。还记得我们一开始说的,服务必须先添加到系统的SM里作为S端,C端再通过SM去获取服务吗。这里的media player service就是一个S端的服务,并且对比其他服务来说,它的代码和逻辑关系相对简单,所以下面我们会用它来做例子。

需要先明确一个基本关系,既在这里谁是C端谁是S端?

首先这里有两个东西,一个是ServiceManager,另外一个是MediaPlayerService。

_ServiceManager_是MediaPlayerService启动过程中需要用到的C端SM,在这里的任务是把服务添加到SM的S端中,它扮演的逻辑角色是SM的C端。而它的S端是在第一节里我们分析的binder启动那里。

_MediaPlayService_在这里扮演的角色是一个S端服务,它在等待SM的C端把它注册到系统中。

明确这两点后我们才能接着往下走,不然下面的很多逻辑都会想不明白。

ProcessState的启动

ProcessState做了几件事情,创建自己的实例,打开binder。
Mashmallow/frameworks/native/libs/binder/ProcessState.cpp

sp<ProcessState> ProcessState::self()
{
    Mutex::Autolock _l(gProcessMutex);
    if (gProcess != NULL) {
        return gProcess;
    }
    gProcess = new ProcessState;
    return gProcess;
}

self()很简短,看的出来这里是个单例模式。第一次创建的时候是空的,然后 new 一个出来,第二次就直接返回第一次创建的对象了。创建对象调用了ProcessState的构造函数,

ProcessState::ProcessState()
    : mDriverFD(open_driver())//注意这里打开binder
    , mVMStart(MAP_FAILED)
    , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
    , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
    , mExecutingThreadsCount(0)
    , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
    , mManagesContexts(false)
    , mBinderContextCheckFunc(NULL)
    , mBinderContextUserData(NULL)
    , mThreadPoolStarted(false)
    , mThreadPoolSeq(1)
{
    if (mDriverFD >= 0) {
        // XXX Ideally, there should be a specific define for whether we
        // have mmap (or whether we could possibly have the kernel module
        // availabla).
#if !defined(HAVE_WIN32_IPC)
        // mmap the binder, providing a chunk of virtual address space to receive transactions.
        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0); //内存映射
        if (mVMStart == MAP_FAILED) {
            // *sigh*
            ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
            close(mDriverFD);
            mDriverFD = -1;
        }
#else
        mDriverFD = -1;
#endif
    }

    LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened.  Terminating.");
}

构造函数里比较重要的是open_driver调用。它打开了binder驱动,返回一个fd,然后就可以用这个fd做内存映射了。在这里的内存映射大小是 BINDER_VM_SIZE,

#define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2))

它的大小刚好是1M-8K。为什么-8K有兴趣的可以自行了解。这里不是重点。

open_binder()代码,

static int open_driver()
{
    int fd = open("/dev/binder", O_RDWR);//打开binder驱动
    if (fd >= 0) {
        fcntl(fd, F_SETFD, FD_CLOEXEC);
        int vers = 0;
        status_t result = ioctl(fd, BINDER_VERSION, &vers);
        if (result == -1) {
            ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
            close(fd);
            fd = -1;
        }
        if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
            ALOGE("Binder driver protocol does not match user space protocol!");
            close(fd);
            fd = -1;
        }
        size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
        result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
        if (result == -1) {
            ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
        }
    } else {
        ALOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
    }
    return fd;//返回文件描述符
}

注意这里只做了打开驱动一件事,并且把文件描述符返回。也许有会疑惑,这里没见到预想的事件循环?没错,这里只做打开驱动一件事,事件循环在mediaserver启动的最后一步才会开始。在这个阶段,所有的多媒体服务都还没有加入到系统SM中,因此还不需要事件循环来接受消息。

defaultServiceManager()

让我们回到 main_mediaserver 中。在ProcessState::self()之后是defaultServiceManager()。它在IServiceManager.cpp里,
Mashmallow/frameworks/native/libs/binder/IServiceManager.cpp

sp<IServiceManager> defaultServiceManager()
{
    if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
    
    {
        AutoMutex _l(gDefaultServiceManagerLock);
        while (gDefaultServiceManager == NULL) {
            gDefaultServiceManager = interface_cast<IServiceManager>(
                ProcessState::self()->getContextObject(NULL)); //获取BpBinder
            if (gDefaultServiceManager == NULL)
                sleep(1);
        }
    }
    
    return gDefaultServiceManager;
}

OK,这里又是一个单例。但这里就稍微有点复杂了。

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

上一步我们实例化了ProcessState,这里我们还是调用 self(),拿到的也还是那个单例。然后去获取上下文对象,传入的是NULL也就是0.我们看看它做了什么

sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
    return getStrongProxyForHandle(0);
}

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;

    AutoMutex _l(mLock);

    handle_entry* e = lookupHandleLocked(handle); //查找entry

    if (e != NULL) {
        // We need to create a new BpBinder if there isn't currently one, OR we
        // are unable to acquire a weak reference on this current one.  See comment
        // in getWeakProxyForHandle() for more info about this.
        IBinder* b = e->binder;
        if (b == NULL || !e->refs->attemptIncWeak(this)) {
            if (handle == 0) {
                Parcel data;
                status_t status = IPCThreadState::self()->transact(
                        0, IBinder::PING_TRANSACTION, data, NULL, 0);
                if (status == DEAD_OBJECT)
                   return NULL;
            }

            b = new BpBinder(handle);  //创建BpBinder对象
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
            result = b;
        } else {
            // This little bit of nastyness is to allow us to add a primary
            // reference to the remote proxy when this team doesn't have one
            // but another team is sending the handle to us.
            result.force_set(b);
            e->refs->decWeak(this);
        }
    }

    return result;
}

传进来的NULL也就是0对吧,首先它会去lookup一遍,拿到一个entry之后,看看entry里保存的e->binder是不是空的。空的就创建一个。然后把它返回。
这里创建的binder是BpBinder,参数handle也很特殊是0。

让我们回到IServiceManager中。从上面的分析知道从ProcessState里拿到的是一个 BpBinder。至于sp是个什么玩意不用太在意,IBinder表示返回的BpBinder是IBinder的派生。

问题来了,BpBinder怎么转成sp< IServiceManager >的?

sp<IServiceManager> defaultServiceManager()
{
    if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
    
    {
        AutoMutex _l(gDefaultServiceManagerLock);
        while (gDefaultServiceManager == NULL) {
            gDefaultServiceManager = interface_cast<IServiceManager>(
                ProcessState::self()->getContextObject(NULL));
            if (gDefaultServiceManager == NULL)
                sleep(1);
        }
    }
    
    return gDefaultServiceManager;
}

这是高科技,关键在于interface_cast这个玩意。展开这一段会有点复杂,但它里面涉及到后面要用到的remote对象,没办法绕开它理解。

interface_cast类似于java中的代理模式,或者类型强转。转换的类型必须是实现了同一套接口的对象。这里做的转换是BpBinder -> BpServiceManager。

个人觉得这里看成代理模式会好理解一些

interface_cast是一个内联函数,
Mashmallow/frameworks/native/include/binder/IInterface.h

template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
    return INTERFACE::asInterface(obj);
}

它定义了一个模板 INTERFACE,展开后调用的是 INTERFACE:asInterface()。

INTERFACE:asInterface()又是个什么高科技?其实它是一个宏,也在 IInterface.h 中定义。它涉及到两个宏,DECLARE_META_INTERFACE 和 IMPLEMENT_META_INTERFACE。

#define DECLARE_META_INTERFACE(INTERFACE)                               \
    static const android::String16 descriptor;                          \
    static android::sp<I##INTERFACE> asInterface(                       \
            const android::sp<android::IBinder>& obj);                  \
    virtual const android::String16& getInterfaceDescriptor() const;    \
    I##INTERFACE();                                                     \
    virtual ~I##INTERFACE();                                            \


#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
    const android::String16 I##INTERFACE::descriptor(NAME);             \
    const android::String16&                                            \
            I##INTERFACE::getInterfaceDescriptor() const {              \
        return I##INTERFACE::descriptor;                                \
    }                                                                   \
    android::sp<I##INTERFACE> I##INTERFACE::asInterface(                \
            const android::sp<android::IBinder>& obj)                   \
    {                                                                   \
        android::sp<I##INTERFACE> intr;                                 \
        if (obj != NULL) {                                              \
            intr = static_cast<I##INTERFACE*>(                          \
                obj->queryLocalInterface(                               \
                        I##INTERFACE::descriptor).get());               \
            if (intr == NULL) {                                         \
                intr = new Bp##INTERFACE(obj); //在这里做转换           \
            }                                                           \
        }                                                               \
        return intr;                                                    \
    }                                                                   \
    I##INTERFACE::I##INTERFACE() { }                                    \
    I##INTERFACE::~I##INTERFACE() { }                                   \

IMPLEMENT是对DECLEAR的实现。DECLEAR定义了一系列api。
回到 IServiceManager.h中,它使用DECLEAR做了函数声明,

class IServiceManager : public IInterface
{
public:
    DECLARE_META_INTERFACE(ServiceManager);

这里把宏展开,在宏展开后就有了这么个函数声明,

static android::sp<ServiceManager> asInterface(                       \
        const android::sp<android::IBinder>& obj);    

android::是一个命名域,关于命名域可以回头自己再去查是个什么概念。
这里的关键是 asInterface() 是个声明。那么它的实现在哪里?

答案在 IServiceManager.cpp 中,

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

我们对IMPLEMENT进行宏展开,就变成

android::sp<IServiceManager> IServiceManager::asInterface(                \
        const android::sp<android::IBinder>& obj)                   \
{                                                                   \
    android::sp<IServiceManager> intr;                                 \
    if (obj != NULL) {                                              \
        intr = static_cast<IServiceManager*>(                          \
            obj->queryLocalInterface(                               \
                    I##INTERFACE::descriptor).get());               \
        if (intr == NULL) {                                         \
            intr = new BpServiceManager(obj); //真正返回的东西      \
        }                                                           \
    }                                                               \
    return intr;                                                    \
}  

所以最后得到的是一个 BpServiceManager 对象。而传入的obj则是BpBinder。

MediaPlayerService::instantiate();

如果你还没晕的话,继续往下看。如果已经晕了,建议把 ProcessState::self()defaultServiceManager() 这两部分再看一次。如果没有C/C++功底的话,这两部分得花不少时间反复看才能看明白。

在经过上面两部分的逻辑之后,mediaserver进程就打开了binder驱动,并且获得了一个BpServiceManager对象。

Bp前缀表示的是BinderProxy,它代表着一个Binder对象在C端的代理。与之相对的有BnXXX,前缀Bn代表的是BinderNative,代表一个在S端的服务。

相对应的,MediaPlayerService也有Bp和Bn。
/Mashmallow/frameworks/av/media/libmediaplayerservice/MediaPlayerService.h

class MediaPlayerService : public BnMediaPlayerService

我们在 mediaserver 所要启动的MediaPlayerService实际是个 BnMediaPlayerService 派生类。那么BpXXX在哪里呢?熟悉Proxy的设计的话就知道,不管是在哪种语言哪种平台下,Proxy都希望是对用户透明的,也可以说用户看不见代理。那么BpXXX一定不会在 .h 头文件里对不?

再往前猜一步,media player service 的S端叫MediaPlayerService,那它的C端是不是应该有个对应的叫 IMediaPlayerService?
Mashmallow/frameworks/av/media/libmedia/IMediaPlayerService.cpp

class BpMediaPlayerService: public BpInterface<IMediaPlayerService>
{
public:
    BpMediaPlayerService(const sp<IBinder>& impl)
        : BpInterface<IMediaPlayerService>(impl)
    {
    }

果然在这里有个BpMediaPlayerService,并且在头文件IMediaPlayerService.h是没有声明的。

OK,回到 MediaPlayerService::instantiate(),这时候S端的MediaPlayerService准备启动,
Mashmallow/frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp

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

它调用了 defaultServiceManager,然后把实例化的 MediaPlayerService addService进去。

addService的实现在
Mashmallow/frameworks/native/libs/binder/IServiceManager.cpp
还记得 defaultServiceManager 拿到的 BpBinder 通过 interface_cast 变成了什么玩意吗?

BpServiceManager是这个东西。 addService的实现也就在它的类实现里面,

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);//调用binder驱动传递消息
    return err == NO_ERROR ? reply.readExceptionCode() : err;
}

关键在于 remote()->transact,这里是通过Binder驱动真正进行消息传递的地方。传递的方向是,
BpServiceManager -> BnServiceManager
新的问题出现了
remote() 返回的是啥?
BnServiceManager 在哪?

OK,第一个问题,remote()返回什么。
BpServiceManager是从BpInterface派生的,

class BpServiceManager : public BpInterface<IServiceManager>

那么BpInterface的声明我们看看,

template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
{
public:
                                BpInterface(const sp<IBinder>& remote);//这里的remote

protected:
    virtual IBinder*            onAsBinder();
};

是不是看到熟悉的remote了。

再回想BpServiceManager构造的时候传入的参数是啥? BpBinder对不对?
所以这里 remote()返回的其实是 BpBinder对象,也就是Binder驱动在C端的一个代理。

OK,下一个问题,BnServiceManager 在哪?
很不幸,虽然在 IServiceManager.cpp 里确实有 BnServiceManager 的实现,但这里的 BnServiceManager 实际上并不是这个东西,而是我们最开始的时候讲的 Binder驱动的启动 里的 servicemanager 进程里的binder。

明确这两点后回到 remote()->transact。现在知道是BpBinder的 transact() 使用了Binder驱动进行消息通信,
Mashmallow/frameworks/native/libs/binder/BpBinder.cpp

status_t BpBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    // Once a binder has died, it will never come back to life.
    if (mAlive) {
        status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags); //发出消息的地方
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }

    return DEAD_OBJECT;
}

这里出现的IPCThreadState是个什么玩意?

IPCThreadState

从名字上来看可以猜到 IPCThreadState 是一个用来进行跨进程通信(IPC)的线程。而且它并不是我们第一次见到,在ProcessState::self()->getContextObject(NULL)中,创建BpBinder的时候已经调用过一次 IPCThreadState::self()了。
可想而知它也是个单例。调用transact是为了向Binder的S端发消息,

Mashmallow/frameworks/native/libs/binder/IPCThreadState.cpp

status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    status_t err = data.errorCheck();

    flags |= TF_ACCEPT_FDS;

    IF_LOG_TRANSACTIONS() {
        TextOutput::Bundle _b(alog);
        alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "
            << handle << " / code " << TypeCode(code) << ": "
            << indent << data << dedent << endl;
    }
    
    if (err == NO_ERROR) {
        LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
            (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);//数据写入到mOut
    }
    
    if (err != NO_ERROR) {
        if (reply) reply->setError(err);
        return (mLastError = err);
    }
    
    if ((flags & TF_ONE_WAY) == 0) {
        #if 0
        if (code == 4) { // relayout
            ALOGI(">>>>>> CALLING transaction 4");
        } else {
            ALOGI(">>>>>> CALLING transaction %d", code);
        }
        #endif
        if (reply) {
            err = waitForResponse(reply); //mOut写入到 /dev/binder 内存映射
        } else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }
        #if 0
        if (code == 4) { // relayout
            ALOGI("<<<<<< RETURNING transaction 4");
        } else {
            ALOGI("<<<<<< RETURNING transaction %d", code);
        }
        #endif
        
        IF_LOG_TRANSACTIONS() {
            TextOutput::Bundle _b(alog);
            alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
                << handle << ": ";
            if (reply) alog << indent << *reply << dedent << endl;
            else alog << "(none requested)" << endl;
        }
    } else {
        err = waitForResponse(NULL, NULL);
    }
    
    return err;
}

代码里有两处可疑的地方,分别是

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

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; /* Don't pass uninitialized stack data to a remote process */
    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) {
        tr.flags |= TF_STATUS_CODE;
        *statusBuffer = err;
        tr.data_size = sizeof(status_t);
        tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
        tr.offsets_size = 0;
        tr.data.ptr.offsets = 0;
    } else {
        return (mLastError = err);
    }
    
    mOut.writeInt32(cmd);
    mOut.write(&tr, sizeof(tr));
    
    return NO_ERROR;
}

看到没,这里一点跟驱动交互的事情都没有。最终只是把要发送的数据写入到mOut这个buffer里。

waitForResponse做了什么呢,

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

    while (1) {
        if ((err=talkWithDriver()) < NO_ERROR) break; //和驱动交互
        err = mIn.errorCheck();
        if (err < NO_ERROR) break;
        if (mIn.dataAvail() == 0) continue;
        
        cmd = (uint32_t)mIn.readInt32();
        
        IF_LOG_COMMANDS() {
            alog << "Processing waitForResponse Command: "
                << getReturnString(cmd) << endl;
        }

        switch (cmd) {
        ...
            goto finish;

        default:
            err = executeCommand(cmd);
            if (err != NO_ERROR) goto finish;
            break;
        }
    }

finish:
    if (err != NO_ERROR) {
        if (acquireResult) *acquireResult = err;
        if (reply) reply->setError(err);
        mLastError = err;
    }
    
    return err;
}

这里省略了一些代码。它一上来就跟驱动交互,通过talkWithDriver,把mOut里的东西往内存映射里写。然后等待通信完成,把返回的数据读到 mIn 里。talkWithDriver的代码虽然多但并不复杂,这里就不展开分析了。接收方是谁呢?上面已经说了,是 servicemanager 进程。

细心的会发现,binder的IPC过程,似乎是个同步过程?是的没错,它就是个同步过程。

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

到上面IPCThreadState的transact这里,其实整个流程还没结束。实际上到transact这里只是把MediaPlayerService启动起来,并且注册到servicemanager里。此时MediaPlayerService还没准备好接受消息。
这句话啥意思?

通过上面的分析可以知道,启动起来的MPS是个S端的服务,那么它是要提供服务给C端的。既然要提供服务,那么它就要有监听事件的能力对吧。也就是说,必然有个类似 event loop的逻辑。那么这个逻辑在哪里呢?

回到最开始的 main_mediaserver 启动流程,

sp<ProcessState> proc(ProcessState::self()); 
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
MediaPlayerService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();

这里还有两行代码没有分析,关键的event loop就在这里。

ProcessState::self()->startThreadPool() 会启动一个线程用于监听事件,也就是所谓的event loop。看看它的实现,

void ProcessState::startThreadPool()
{
    AutoMutex _l(mLock);
    if (!mThreadPoolStarted) {
        mThreadPoolStarted = true;
        spawnPooledThread(true);
    }
}

void ProcessState::spawnPooledThread(bool isMain)
{
    if (mThreadPoolStarted) {
        String8 name = makeBinderThreadName();
        ALOGV("Spawning new pooled thread, name=%s\n", name.string());
        sp<Thread> t = new PoolThread(isMain); //创建PoolThread
        t->run(name.string()); //启动线程
    }
}

调用链最后会创建一个 PoolThread 对象,然后调用它的 run 方法。PoolThread是Threads的派生类,android源码里的Threads有很多实现,这里是从
Mashmallow/system/core/libutils/Threads.cpp派生的,
省略一些代码后它的run方法如下,

status_t Thread::run(const char* name, int32_t priority, size_t stack)
{
    Mutex::Autolock _l(mLock);

    if (mRunning) {
        // thread already started
        return INVALID_OPERATION;
    }

    // reset status and exitPending to their default value, so we can
    // try again after an error happened (either below, or in readyToRun())
    mStatus = NO_ERROR;
    mExitPending = false;
    mThread = thread_id_t(-1);

    // hold a strong reference on ourself
    mHoldSelf = this;

    mRunning = true;

    bool res;
    if (mCanCallJava) {
        res = createThreadEtc(_threadLoop, // _threadLoop
                this, name, priority, stack, &mThread);
    } else {
        res = androidCreateRawThreadEtc(_threadLoop, // _threadLoop
                this, name, priority, stack, &mThread);
    }

它调用了一个叫 _threadLoop的东西,我们直接忽略其他代码看最终调用,

int Thread::_threadLoop(void* user)
{
    ...

    do {
        ...
        } else {
            result = self->threadLoop();
        }

看到了吗,它会回去调用派生类的 threadLoop() 方法,也就是在PoolThread中的threadLoop().

protected:
    virtual bool threadLoop()
    {
        IPCThreadState::self()->joinThreadPool(mIsMain);
        return false;
    }
    
    const bool mIsMain;
};

而threadLoop() 又会去调用 joinThreadPool()。

void IPCThreadState::joinThreadPool(bool isMain)
{
    LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());

    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
    
    // This thread may have been spawned by a thread that was in the background
    // scheduling group, so first we will make sure it is in the foreground
    // one to avoid performing an initial transaction in the background.
    set_sched_policy(mMyThreadId, SP_FOREGROUND);
        
    status_t result;
    do {
        processPendingDerefs();
        // now get the next command to be processed, waiting if necessary
        result = getAndExecuteCommand(); //执行C端的命令

        if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
            ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
                  mProcess->mDriverFD, result);
            abort();
        }
        
        // Let this thread exit the thread pool if it is no longer
        // needed and it is not the main process thread.
        if(result == TIMED_OUT && !isMain) {
            break;
        }
    } while (result != -ECONNREFUSED && result != -EBADF);

    LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n",
        (void*)pthread_self(), getpid(), (void*)result);
    
    mOut.writeInt32(BC_EXIT_LOOPER);
    talkWithDriver(false);
}

到 do{…}while() 就真相大白了,终于可以看到类似 event loop 的逻辑。此时 media player service 才真正具有了S端的能力,这里的event loop会等待消息进来,然后通过getAndExecuteCommand把C端的命令派发给S端服务去执行。

最后

整一个binder通信流程基本到这里就清晰了。但还有个问题没解决,main_mediaserver在startThreadPool之后又有一行 joinThreadPool,那是干嘛?
在查阅了很多资料后我也没有明白这个设计。它实际做的事情不过是开另外个线程等事件进来,而网上有开发者在屏蔽了这行代码后也能正常执行所有流程,所以这个可能是谷歌的容错设计?万一挂了一个线程还有一个辅助线程么?如果有人明白的话欢迎解疑。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章