Binder系列7 SMgr守护进程的获取

一 概述

我们知道在 Android 系统中,无论是 Server 端进程注册服务 (addService) 或者是 Client 端进程获取服务 (getService) ,都需要获取 SMgr 的 Binder 代理,通过 SMgr 的 Binder 代理接口来调用相关函数进而实现相关操作,但是该如何获取呢?我们在系列3中只是分析了 SMgr 的启动和工作机制,并没有阐述其它进程是如何获取 SMgr 接口的,在本篇文章中将讨论这个问题.

在源码中可以看到其它进程都是通过 IServiceManager 的 defaultServiceManager() 方法来完成对 SMgr代理接口的获取,我们来看代码如下:

framework/native/libs/binder/IServiceManager.cpp

1.1 入口函数 defaultServiceManager

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

获取 SMgr 对象采用单例模式,当 gDefaultServiceManager 存在,则直接返回,否则创建一个新对象。 发现与一般的单例模式不太一样,里面多了一层while循环,这个是因为当创建 gDefaultServiceManager 时,SMgr 所在进程可能尚未准备就绪,这时通过sleep 1秒后,循环尝试获取直到成功。gDefaultServiceManager 的创建过程,可分解为以下3个部分:

  • ProcessState::self():用于获取 ProcessState 对象,也是单例模式,这个之前讲过,每个进程有且只有一个ProcessState 对象,存在则直接返回,不存在则创建
  • getContextObject(null): 用于获取 BpBinder 对象,我们已经知道 SMgr 对应的句柄值为0
  • interface_cast<IServiceManage>:用于获取BpServiceManager对象

接下来详细分析

二 获取ProcessState对象

2.1 ProcessState::self()

sp<ProcessState> ProcessState::self()
{
    Mutex::Autolock _l(gProcessMutex);
    if (gProcess != NULL) {
        return gProcess;//存在则返回,不存在则创建
    }
    gProcess = new ProcessState("/dev/binder");//直接new出来
    return gProcess;
}

ProcessState在创建的过程中会执行打开Binder驱动,并调用mmap函数建立内存映射等相关操作.

ProcessState::ProcessState(const char *driver)
    : mDriverName(String8(driver))
    , mDriverFD(open_driver(driver))//打开Binder驱动,这个driver参数为"/dev/binder"
    , mVMStart(MAP_FAILED)
    , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
    , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
    , mExecutingThreadsCount(0)
    , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
    , mStarvationStartTimeMs(0)
    , mManagesContexts(false)
    , mBinderContextCheckFunc(NULL)
    , mBinderContextUserData(NULL)
    , mThreadPoolStarted(false)
    , mThreadPoolSeq(1)
{
    if (mDriverFD >= 0) {
        // mmap the binder, providing a chunk of virtual address space to receive transactions.
        //调用mmap函数建立内存映射
        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;
            mDriverName.clear();
        }
    }

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

我们知道每个进程有且只有一个 ProcessState 对象,这个也是设计为单例模式的原因,在 ProcessState 的构造方法中会调用 open_driver 函数打开Binder驱动,并把打开驱动之后的文件描述符 fd 赋值给了 mDriverFD,并调用mmap函数建立内存映射,需要注意的是映射空间的大小 BINDER_VM_SIZE,这个值为(1*1024*1024) - (4096 *2),也就是Binder分配的默认内存大小为1M-8k.


static int open_driver(const char *driver)
{
    int fd = open(driver, O_RDWR | O_CLOEXEC);//打开Binder驱动"/dev/binder"
    if (fd >= 0) {
        int vers = 0;
        status_t result = ioctl(fd, BINDER_VERSION, &vers);//调用ioctl函数查看Binder驱动版本
        
        ........
        
        size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;//这个值为15
        result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);//通过ioctl设置Binder驱动支持的最大线程数
        if (result == -1) {
            ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
        }
    } else {
        ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));
    }
    return fd;
}

可以看到 open_driver 的主要作用是打开 “/dev/binder” 设备,并设定Binder驱动支持的最大线程数为15.

#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
#define DEFAULT_MAX_BINDER_THREADS 15

三 获取BpBinder对象

3.1 getContextObject

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

3.2 getStrongProxyForHandle(0)

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;
    AutoMutex _l(mLock);
    //根据句柄值查询handle_entry,这个handle_entry里的binder就是句柄值对应的BpBinder对象
    //这个handle_entry我们在系列2中讲述ProcessState的时候已经讲过
    handle_entry* e = lookupHandleLocked(handle);

    if (e != NULL) {        
        IBinder* b = e->binder;
        if (b == NULL || !e->refs->attemptIncWeak(this)) {
            if (handle == 0) {//如果句柄值为0
                Parcel data;
                //通过ping操作测试Binder是否准备就绪
                status_t status = IPCThreadState::self()->transact(
                        0, IBinder::PING_TRANSACTION, data, NULL, 0);
                if (status == DEAD_OBJECT)
                   return NULL;
            }
            b = new BpBinder(handle); //根据句柄值handle,直接创建BpBinder
            e->binder = b;//把创建好的BpBinder赋值给handle_entry的binder域
            if (b) e->refs = b->getWeakRefs();
            result = b;
        } else {
            result.force_set(b);
            e->refs->decWeak(this);
        }
    }
    return result;
}

先调用lookupHandleLocked函数根据句柄值在mHandleToObject中查询对应的handle_entry,其中handle_entry里的binder就是句柄值对应的BpBinder对象

3.3 lookupHandleLocked

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

在lookupHandleLocked函数中,主要是针对向量表mHandleToObject的操作,查询与句柄值对应的handle_entry,如果不存在的话就创建然后插入到这个向量表中,如果存在的话就返回.这个向量表mHandleToObject在系列2中介绍ProcessState的时候已经讲过,大家可以回顾下.在某个进程获取SMgr之前,这个mHandleToObject中的handle_entry项的个数为0,所以执行到的这里时候会生成一个handle_entry,并插入到mHandleToObject中,然后返回这个handle_entry.

接下来继续回到getStrongProxyForHandle函数中,可以看到会走到b == NULL分支,然后生成一个句柄值为0的BpBinder对象并返回.

四 获取BpServiceManager

4.1 interface_cast

这个在系列2中已经介绍过,代码如下:

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

最终调用的是asInterface函数,在系列2中我们讲述DECLARE_META_INTERFACE和IMPLEMENT_META_INTERFACE模板的时候已经介绍过了,大家回顾下,结果就是通过这些模板new 了一个BpServiceManager出来,并把这个BpBinder作为参数传递到BpServiceManager中,BpServiceManager的构造方法代码如下:

    explicit BpServiceManager(const sp<IBinder>& impl)
        : BpInterface<IServiceManager>(impl)//这里的impl就是新创建的BpBinder
    {
    }

BpServiceManager继承自BpInterface

template<typename INTERFACE>
    class BpInterface : public INTERFACE, public BpRefBase
{
public:
    explicit                    BpInterface(const sp<IBinder>& remote);
 
protected:
    virtual IBinder*            onAsBinder();
};

BpInterface又继承自BpRefBase,BpRefBase类的定义如下:

class BpRefBase : public virtual RefBase
{
protected:
    explicit                BpRefBase(const sp<IBinder>& o);
    virtual                 ~BpRefBase();
    virtual void            onFirstRef();
    virtual void            onLastStrongRef(const void* id);
    virtual bool            onIncStrongAttempted(uint32_t flags, const void* id);
 
    inline  IBinder*        remote()                { return mRemote; }
    inline  IBinder*        remote() const          { return mRemote; }
 
private:
                            BpRefBase(const BpRefBase& o);
    BpRefBase&              operator=(const BpRefBase& o);
 
    IBinder* const          mRemote;
    RefBase::weakref_type*  mRefs;
    std::atomic<int32_t>    mState;
};

BpRefBase的构造函数

BpRefBase::BpRefBase(const sp<IBinder>& o)
    : mRemote(o.get()), mRefs(NULL), mState(0)
{
    extendObjectLifetime(OBJECT_LIFETIME_WEAK);

    if (mRemote) {
        mRemote->incStrong(this);           // Removed on first IncStrong().
        mRefs = mRemote->createWeak(this);  // Held for our entire lifetime.
    }
}

这里的impl就是我们创建的BpBinder对象,我们知道BpXXXX继承自BpInterface<IXXXX>,而BpInterface又继承自BpRefBase,我们再看BpRefBase的构造函数中,把这个BpBinder参数赋值给了mRemote,这个就是我们在系列2中所说的:Client进程并不直接和BpBinder(Binder代理)打交道,而是通过调用BpInterface(接口代理)的成员函数来完成远程调用的,此时,BpBinder已经被聚合进BpInterface了,它在BpInterface内部完成了一切跨进程通信的机制.我们回顾下图加深理解.

在这里插入图片描述
我们继续看BpServiceManager是怎么跨进程通信的,代码如下:

class BpServiceManager : public BpInterface<IServiceManager>
{
public:
    explicit BpServiceManager(const sp<IBinder>& impl)
        : BpInterface<IServiceManager>(impl)
    {
    }
   ........
    virtual sp<IBinder> checkService( const String16& name) const
    {
        Parcel data, reply;
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
        data.writeString16(name);
        remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);//调用remote()通过transact传输
        return reply.readStrongBinder();
    }

    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);//调用remote()通过transact传输
        return err == NO_ERROR ? reply.readExceptionCode() : err;
    }

    virtual Vector<String16> listServices()
    {
        Vector<String16> res;
        int n = 0;

        for (;;) {
            Parcel data, reply;
            data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
            data.writeInt32(n++);
            status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply);//调用remote()通过transact传输
            if (err != NO_ERROR)
                break;
            res.add(reply.readString16());
        }
        return res;
    }
};

可以看到都是通过调用remote()实现跨进程传输的,而根据BpRefBase的定义我们这个这个方法返回的就是mRemote,而这个值就是我们传递过去的BpBinder对象.

五 总结

defaultServiceManager 等价于 new BpServiceManager(new BpBinder(0));

ProcessState::self()主要工作:

调用open(),打开/dev/binder驱动设备;
再利用mmap(),创建大小为1M-8K的内存地址空间;
设定当前进程最大的最大并发Binder线程个数为16。
BpServiceManager巧妙将通信层与业务层逻辑合为一体,

通过继承接口IServiceManager实现了接口中的业务逻辑函数;
通过成员变量mRemote= new BpBinder(0)进行Binder通信工作。
BpBinder通过handler来指向所对应BBinder, 在整个Binder系统中handle=0代表ServiceManager所对应的BBinder。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值