Binder 框架 -- binder 用户空间框架

来源:互联网 发布:图森未来 知乎 编辑:程序博客网 时间:2024/06/07 11:32

Binder 框架 – binder 用户空间框架

Binder框架 – android AIDL 的使用

Binder框架 – 用户空间和驱动的交互

Binder框架 – Binder 驱动

Binder 框架 – binder 用户空间框架

一 ServiceManager 启动

int main(int argc, char **argv){    struct binder_state *bs;    bs = binder_open(128*1024);    if (!bs) {        ALOGE("failed to open binder driver\n");        return -1;    }    if (binder_become_context_manager(bs)) {        ALOGE("cannot become context manager (%s)\n", strerror(errno));        return -1;    }    ......    binder_loop(bs, svcmgr_handler);    return 0;}

1. 打开binder 设备

bs = binder_open(128*1024); 打开binder 设备驱动。相关的信息保存在binder_state 结构中。

struct binder_state{     int fd;                binder 设备的fd     void *mapped;          映射到用户空间的地址     size_t mapsize;        大小 };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 | O_CLOEXEC);    if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||        (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {        ......    }    bs->mapsize = mapsize;    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);    return bs;}

binder_open 中做的工作主要是打开binder 设备,然后通过mmap 将binder内核空间映射到用户空间。标准的linux 设备访问方法:

  1. open(“/dev/binder”, O_RDWR | O_CLOEXEC); 打开设备
  2. ioctl(bs->fd, BINDER_VERSION, &vers) ioctl 命令设置版本号。 在下面对binder 驱动的访问中主要是通过 ioctl 函数,没有用我们常见的 read write, 这个也是binder 驱动设计的一个特点
  3. mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0); 内核空间mapsize大小映射到用户空间,注意映射的空间是只读权限。
  4. 设备的文件描述符, 用户空间地址, 大小用binder_state结构体保存。

2. binder_become_context_manager 通知binder驱动成为管理者。

int binder_become_context_manager(struct binder_state *bs){    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);}

注意最后一个参数为0;函数设计上可能是为了表示ServiceManager hander为0.但是在驱动中收到的消息为BINDER_SET_CONTEXT_MGR,已经表示是表示ServiceManager自己,直接把自己的 hander置为0,没有使用这个参数。ServiceManager 本身管理服务的特殊性,没有其它进程负责它的注册,ServiceManager需要自己完成注册,同时自己的handler 为0.

3. binder_loop 进入循环

binder_loop调用的时候同时传入回调函数。

  1. binder_write(bs, readbuf, sizeof(uint32_t)); 调用 ioctl(bs->fd, BINDER_WRITE_READ, &bwr); 通知binder 驱动进入循环。这次调用没有阻塞。
  2. 在 for 循环中的 res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); 阻塞,当有消息来得时候,读出数据,交给binder_parse解析同时指定svcmgr_handler func处理解析数据。
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] =  ;    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);        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);        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;        }    }}

4. svcmgr_handler 处理信息

svcmgr_handler func 函数指针指向svcmgr_handler
信息主要有这几个类型:

  • SVC_MGR_GET_SERVICE 获取服务
  • SVC_MGR_CHECK_SERVICE 检查服务
  • SVC_MGR_ADD_SERVICE 添加服务,如mediaservice 添加就会到这里
  • SVC_MGR_LIST_SERVICES 主要是 service list 命令使用
int svcmgr_handler(struct binder_state *bs,                   struct binder_transaction_data *txn,                   struct binder_io *msg,                   struct binder_io *reply){    struct svcinfo *si;    uint16_t *s;    size_t len;    uint32_t handle;    uint32_t strict_policy;    int allow_isolated;    if (txn->target.ptr != BINDER_SERVICE_MANAGER)        return -1;    if (txn->code == PING_TRANSACTION)        return 0;    ......    switch(txn->code) {    case SVC_MGR_GET_SERVICE:    case SVC_MGR_CHECK_SERVICE:        s = bio_get_string16(msg, &len);        if (s == NULL) {            return -1;        }        handle = do_find_service(bs, s, len, txn->sender_euid, txn->sender_pid);        if (!handle)            break;        bio_put_ref(reply, handle);        return 0;    case SVC_MGR_ADD_SERVICE:        s = bio_get_string16(msg, &len);        if (s == NULL) {            return -1;        }        handle = bio_get_ref(msg);        allow_isolated = bio_get_uint32(msg) ? 1 : 0;        if (do_add_service(bs, s, len, handle, txn->sender_euid,            allow_isolated, txn->sender_pid))            return -1;        break;    case SVC_MGR_LIST_SERVICES: {        uint32_t n = bio_get_uint32(msg);        if (!svc_can_list(txn->sender_pid)) {            ALOGE("list_service() uid=%d - PERMISSION DENIED\n",                    txn->sender_euid);            return -1;        }        si = svclist;        while ((n-- > 0) && si)            si = si->next;        if (si) {            bio_put_string16(reply, si->name);            return 0;        }        return -1;    }    default:        ALOGE("unknown code %d\n", txn->code);        return -1;    }    bio_put_uint32(reply, 0);    return 0;}

5 servicemanager 是一单线程,

可能因为是工作不太繁忙,不需要多线程加班。
ps -t | grep servicemanager
system 2450 1761 10228 752 ffffffff f7685976 S /system/bin/servicemanager

servicemanager 已经启动,并且在一个while 循环中阻塞,等待唤醒。

ProcessState

ProcessState 是单例模式,每个进程只有一个实例。ProcessState在构造函数中会打开binder 驱动获取文件描述符mDriverFD,设置binder的参数,为进程进行binder 通信准备必要的条件。

sp<ProcessState> ProcessState::self(){    Mutex::Autolock _l(gProcessMutex);    if (gProcess != NULL) {        return gProcess;    }    gProcess = new ProcessState;    return gProcess;}ProcessState::ProcessState()    : mDriverFD(open_driver())    , 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) {         mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);    } }static int open_driver(){    int fd = open("/dev/binder", O_RDWR | O_CLOEXEC);    if (fd >= 0) {        int vers = 0;        status_t result = ioctl(fd, BINDER_VERSION, &vers);        size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;        result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);        }    } else {    }    return fd;}

open_driver 函数和binder_open 差不多,打开设备驱动,设置版本号并检查, 然后设置BINDER_SET_MAX_THREADS ,支持的最大线程数。

  1. open(“/dev/binder”, O_RDWR | O_CLOEXEC);
  2. octl(fd, BINDER_VERSION, &vers);
  3. ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
  4. 最后在构造函数中mmap。 为什么不在 open_driver 中一起把这个事情给做了呢?从API调用的角度放在一起比较合适吧。

startThreadPool 函数

从名字上看启动一个线程池,创建一个新的线程,spawnPooledThread isMain 参数为true,new了一个PoolThread,然后run函数 启动threadLoop(),在threadLoop 调用 IPCThreadState::self()->joinThreadPool(mIsMain); 对线程调用的封装,具体可以参考线程使用的方法。

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);        t->run(name.string());    }}class PoolThread : public Thread{public:    PoolThread(bool isMain)        : mIsMain(isMain)    {    }protected:    virtual bool threadLoop()    {        IPCThreadState::self()->joinThreadPool(mIsMain);        return false;    }    const bool mIsMain;};

IPCThreadState

IPCThreadState 是一个线程单例模式

IPCThreadState 是一个看似单例却不是单例的类。主要涉及了线程的局部存储,看下self 的实现:
第一次进来 gHaveTLS == false 所以走下边的代码:

  1. if (pthread_key_create(&gTLS, threadDestructor) != 0)
    创建线程的局部存储然后goto 到 restart;
  2. 调用pthread_getspecific,由于线程的局部key k还没有关联变量这是返回值为空;所以
    new IPCThreadState;看到这里很疑惑,创建了线程的局部存储key 却没有变量存储到线程的局部存储里面,直接new 了一个IPCThreadState,和self 函数名也不匹配,搞什么鬼呢。
  3. 继续看IPCThreadState的构造函数:这下明白了 在构造函数里面IPCThreadState把自己作为线程的局部存储
    pthread_setspecific(gTLS, this);
  4. 如果是第二次进来 gHaveTLS == true.直接pthread_getspecific 获取IPCThreadState自身。

IPCThreadState 是一个线程单例模式, 持有两个类型为Parcel 的变量

class IPCThreadState{            ......        private:       Parcel              mIn;       Parcel              mOut;}IPCThreadState* IPCThreadState::self(){    if (gHaveTLS) {restart:        const pthread_key_t k = gTLS;        IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);        if (st) return st;        return new IPCThreadState;    }    if (gShutdown) return NULL;    pthread_mutex_lock(&gTLSMutex);    if (!gHaveTLS) {        if (pthread_key_create(&gTLS, threadDestructor) != 0) {            pthread_mutex_unlock(&gTLSMutex);            return NULL;        }        gHaveTLS = true;    }    pthread_mutex_unlock(&gTLSMutex);    goto restart;}IPCThreadState::IPCThreadState()    : mProcess(ProcessState::self()),      mMyThreadId(gettid()),      mStrictModePolicy(0),      mLastTransactionBinderFlags(0){    pthread_setspecific(gTLS, this);    clearCaller();    mIn.setDataCapacity(256);    mOut.setDataCapacity(256);}

IPCThreadState::joinThreadPool

在上面的ProcessState::startThreadPool() 中调用了IPCThreadState::joinThreadPool 那这个函数到底干了什么呢。

  1. 首先根据是否主线程 mOut.writeInt32,注意参数为BC_ENTER_LOOPER 或者BC_REGISTER_LOOPER 这个后边分析。
  2. 在一个循环中不停的getAndExecuteCommand。
  3. 在getAndExecuteCommand 首先talkWithDriver, 然后executeCommand,和ServiceManager 类似,在一个循环中不停的读取binder 驱动,然后解析数据。

到这里其实服务端和客户端的交互框架已经建立。在后边的MediaPlayerService中看下具体的细节。

void IPCThreadState::joinThreadPool(bool isMain){       mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);    status_t result;    do {        ......        result = getAndExecuteCommand();        ......    } while (result != -ECONNREFUSED && result != -EBADF);    ......}status_t IPCThreadState::getAndExecuteCommand(){    status_t result;    int32_t cmd;    result = talkWithDriver();     if (result >= NO_ERROR) {        size_t IN = mIn.dataAvail();        if (IN < sizeof(int32_t)) return result;        cmd = mIn.readInt32();        result = executeCommand(cmd);        ......        }    }    return result;}

Binder 通信架构

Android 为了便于使用Binder 通信,提供了一套框架,只要继承这个框架的各个类,就能够实现一个Binder通信服务。主要分为代理端和服务端。代理端和服务端通的通信通过 IInterface BpInterface BnInterface IBinder BpBinder BBinder 这几个模板类进行。

binder 下的相关类类图:
binder 对象图

MediaPlayerService 启动

ServiceManager 单独运行在一个进程中,其它的Android系统服务如MediaPlayerService 如何启动和注册呢,在ServiceManager 的启动过程中分析到有一个 SVC_MGR_ADD_SERVICE 处理流程,在while 循环中已经阻塞。在上面分析IPCThreadState::joinThreadPool 的时候也会在循环中阻塞,根据linux 进程间通信的知识,双方应该互相发送数据唤醒对方。在这里就是MediaPlayerService 进程和ServiceManager 相互交互了,MediaPlayerService 对它的Client 来说是一个服务端,但是对ServiceManager 来说是一个客户端。
MediaPlayerService 同样基于上面的Binder通信框架,继承了相关的子类。
看一下MediaPlayerService 的启动代码。

int main(int argc __unused, char** argv){        sp<ProcessState> proc(ProcessState::self());        sp<IServiceManager> sm = defaultServiceManager();        ALOGI("ServiceManager: %p", sm.get());        AudioFlinger::instantiate();        MediaPlayerService::instantiate();        ResourceManagerService::instantiate();        CameraService::instantiate();        AudioPolicyService::instantiate();        SoundTriggerHwService::instantiate();        RadioService::instantiate();        registerExtensions();        ProcessState::self()->startThreadPool();        IPCThreadState::self()->joinThreadPool();}

defaultServiceManager

调用 sp sm = defaultServiceManager()获取ServiceManger 的代理; 函数定义在IServiceManager.cpp 中

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

ProcessState::getStrongProxyForHandle

  1. 依次调用ProcessState 的 getContextObject ->
  2. getStrongProxyForHandle 函数,参数为0,
    首先查表 lookupHandleLocked。注意BpBinder.mHander = 0;

ProcessState 为单例模式,持有一个 VectormHandleToObject对象,进程中所有的Binder 对象都会添加到这个容器中。由于是是第一次查找,mHandleToObject为空,lookupHandleLocked会添加一个未初始化过的handle_entry对象,所以e->binder == NULL。

struct handle_entry {    IBinder* binder;    RefBase::weakref_type* refs;};ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle){    const size_t N=mHandleToObject.size();    if (N <= (size_t)handle) {        handle_entry e;        e.binder = NULL;        e.refs = NULL;        status_t err = mHandleToObject.insertAt(e, N, handle+1-N);        if (err < NO_ERROR) return NULL;    }    return &mHandleToObject.editItemAt(handle);}sp<IBinder> ProcessState::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);    if (e != NULL) {        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);             e->binder = b;            if (b) e->refs = b->getWeakRefs();            result = b;        } else {            result.force_set(b);            e->refs->decWeak(this);        }    }    return result;}

e->binder == NULL handle == 0 条件成立,经过下面两步调用

status_t status = IPCThreadState::self()->transact(0, IBinder::PING_TRANSACTION, data, NULL, 0);b = new BpBinder(handle); 

变成了

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

其中ServiceManager 的hander 为0,
transact 函数第一个参数为0,表示的是传递给 handle 为0 的Service,就是ServiceManager,

interface_cast 以及DECLARE_META_INTERFACE IMPLEMENT_META_INTERFACE

interface_cast 以及DECLARE_META_INTERFACE IMPLEMENT_META_INTERFACE 这几个宏定义在
IInterface.h 中。

template<typename INTERFACE>inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj){    return INTERFACE::asInterface(obj);}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() { }                                   \

替换掉INTERFACE 变成了, 这段代码变成了:

android::sp<IServiceManager> interface_cast<IServiceManager>(const sp<IBinder>& obj){    return IServiceManager::asInterface(obj);}android::sp<IServiceManager> IServiceManager::asInterface(const android::sp<android::IBinder>& obj){     android::sp<IServiceManager> intr;                                      if (obj != NULL) {                                                       intr = static_cast<IServiceManager>(obj->queryLocalInterface(IServiceManager::descriptor).get());                        if (intr == NULL) {                                                         intr = new BpServiceManager(obj);                                    }                                                                 }                                                                     return intr; }

BpBinder(0)->queryLocalInterface, queryLocalInterface 为IBinder 的虚函数,默认返回空值,BpBinder 继承IBinder,并且没有覆盖queryLocalInterface。所以sp sm = defaultServiceManager()实际是这个样子:

sp<IServiceManager> sm = new BpServiceManager(obj);

这段代码就是为了拿到ServiceManager的BpServiceManager. 当中在线程中做了记录,然后对引用计数做了处理,通过transact 通知了ServiceManager 。这样我们就拿到了ServiceManger 的客户端BpServiceManager。代码好绕,有没有看到其他的代码使用这个机制?

MediaPlayerService 注册到 ServiceManger

再回到MediaPlayerService 初始化的代码:

int main(int argc __unused, char** argv){        ......        AudioFlinger::instantiate();        MediaPlayerService::instantiate();        。。。。。。        ProcessState::self()->startThreadPool();        IPCThreadState::self()->joinThreadPool();}

MediaPlayerService::instantiate

调用 MediaPlayerService::instantiate();

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

defaultServiceManager() 返回的结果就是BpServiceManager,所以这段代码变成了:

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

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);        return err == NO_ERROR ? reply.readExceptionCode() : err;}

在 remote 就是在new BpServiceManager 中穿进去的BpBinder(0)。

BpBinder 的 transact

BpBinder 的 transact 函数如下:

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

IPCThreadState transact 先后调用了writeTransactionData 和 waitForResponse, writeTransactionData中把binder 相关的通信数据写入binder 驱动。然后呢,然后呢,其实在一开始ServiceManger 已经在binder_loop 中阻塞了,现在写入binder 驱动数据,binder_loop会被激活,读出数据 解析,然后ServiceManger 向bindr 驱动注册Service,将结果写入reply 参数。waitForResponse 读取reply 结果。通信完成,MediaPlayService 注册完成。

启动线程池

在最后先后调用了,根据上面的分析,startThreadPool 最后也调用了joinThreadPool。也就是启动了两个线程。

        ProcessState::self()->startThreadPool(); //启动子线程        IPCThreadState::self()->joinThreadPool(); //主线程循环

在LoopThread 反复调用 joinThreadPool 函数做如下工作:

 result = talkWithDriver();     if (result >= NO_ERROR) {        size_t IN = mIn.dataAvail();        if (IN < sizeof(int32_t)) return result;        cmd = mIn.readInt32();        result = executeCommand(cmd);        ......        }    }

有一个疑问,为什么需要两个线程

总结:

  1. ProcessState.self() 建立实例
  2. defaultServiceManager()
  3. ProcessState::self()->getContextObject(nuLl)->ProcessState::self()->getStrongProxyForHandle(0)-> New BpBinder(0)
  4. interface_cast(BpBinder(0))->asInterface(BpBinder(0)) -> new BpServiceManager(BpBinder(0));
  5. 依次调用 BpServiceManger::addService ->BpBinder::transact->IPCThreadState::self()->transact 通知服务端
  6. IPCThreadState::waitForResponse 等待服务端返回。
  7. 启动线程池

调用序列图:

mediaservice 序列图

binder 调用过程图

为什么需要两个线程,在需要用到回调函数的Binder通信中,在BnClass::doSome 是有callback ,而此时BpClass 进程中只有一个线程,这个线程正在waitRespose,而无法响应callback , 就会造成异常。

参考Binder 调用异常

0 0
原创粉丝点击