Android binder机制学习总结

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/linux_c_language/article/details/90115777

       binder通信机制是Android系统最重要的一种通信机制,也是一种C/S架构的通信机制,客户端和服务器端通过binder驱动进行通信。其架构如下图所示。

      在binder通信机制中,客户端使用的是一个代理类BpBinder,而服务器端使用的是BBinder类,这两个类都是继承了抽象类IBinder。而BpBiner类中的成员函数transact用来向服务器端发送请求(实际上是往binder驱动发的),而binder驱动在收到请求后会通知相应的服务端,该服务端的BBinder的成员函数OnTransact函数会被调用来处理客户端发送过来的数据。这两个成员函数一般都会被具体的代理类和本地类重载。这是业务层的事情了。

       在binder通信机制中有一个抽象类非常重要,且要自己实现。这个类一般使用Ixxx来表示如(IServiceManager),个人认为这个抽象类最重要的有两点,第一定义业务层需要用的纯虚函数(如IServiceManager里的addService和getService)。第二定义和实现两个宏。DECLEAR_META_INTERFACE和IMPLEMENT_META_INTERFACE.在获取代理类的时候需要用到asinterface这个函数。

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

一、ServiceManager

        ServiceManager是一个管理者的角色,服务器端用它来注册服务,而客户端用它来获取服务,通过获取服务可以得到一个IBinder类,从而在客户端可以获取代理类。服务器端注册服务和客户端获取服务时,无论时客户端还是服务器端均可看成是客户端,而ServiceManager则是对应的服务器端。ServiceManager和普通的服务器端不一样,不是用Bnxxx类来处理数据的。

(1)、获取ServiceManager的代理类

      defaultServiceManager函数中调用模板函数interface_cast获取ServiceManager的代理类BpServiceManager,而interface_cast函数就是调用了IMPLEMENT_META_INTERFACE宏中实现的asinterface函数来获取的,而BpServiceManager的mRemoter成员则是使用ProcessSate类的成员函数getContextObject来获得的。

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;
}
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
    return INTERFACE::asInterface(obj);
}
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) {
        // 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) {
                // Special case for context manager...
                // The context manager is the only object for which we create
                // a BpBinder proxy without already holding a reference.
                // Perform a dummy transaction to ensure the context manager
                // is registered before we create the first local reference
                // to it (which will occur when creating the BpBinder).
                // If a local reference is created for the BpBinder when the
                // context manager is not present, the driver will fail to
                // provide a reference to the context manager, but the
                // driver API does not return status.
                //
                // Note that this is not race-free if the context manager
                // dies while this code runs.
                //
                // TODO: add a driver API to wait for context manager, or
                // stop special casing handle 0 for context manager and add
                // a driver API to get a handle to the context manager with
                // proper reference counting.

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

        需要注意handle的值,在binder驱动中根据该值来查找相应的本地类。

(2)、ServiceManager本地端

       ServiceManager本地端没有对应的本地类BnServiceManager,而且其本地端是用C语言而非C++来写的。他是通过循环读取binder驱动的数据然后解析来获得代理类发过来的消息的。具体的可以通过/framework/native/cmds/servicemanager/service_manager.c来查看它的源码。

(3)、添加Service服务

        服务端通过IserviceManager的成员函数addService来通知ServiceManager来注册对应的服务。

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

 (4)、获取Service服务

       客户端通过IServiceManager抽象类的成员函数getService来通知ServiceManager来获取服务(其实就是获取BpBinder)。

template<typename INTERFACE>
status_t getService(const String16& name, sp<INTERFACE>* outService)
{
    const sp<IServiceManager> sm = defaultServiceManager();
    if (sm != NULL) {
        *outService = interface_cast<INTERFACE>(sm->getService(name));
        if ((*outService) != NULL) return NO_ERROR;
    }
    return NAME_NOT_FOUND;
}

特别需要关注的addService函数和getService函数的name参数必须是一致的才能把本地类和代理类对应起来。

二、client 

       客户端通过代理类来发送数据给服务端,最终是通过BpBinder类的成员函数transact向服务端发送数据。BpBinder的获取是向ServiceManager获得的,然后通过函数asInterface函数来获取其自身的代理类。其过程如下。

      第一步,使用defaultServiceManager获得ServiceManager的代理类BpServiceManager。

      第二步,使用BpServiceManager的getService获取其自己的BpBinder。BpServiceManager是继承IServiceManager,所以IServiceManager的成员函数getService也是BpServiceManager的成员函数。

      第三步,通过其自己的抽象类中定义的asInterface函数获取自己的代理类,而后可以通过代理类进行通信。

      代理类的继承关系如下图所示:

三、服务端

       服务端的service继承了他的本地类,而其对应的代理类发送数据过来通信的时候本地类的成员函数OnTransact被调用,可以通过这个函数真正操作一些设备。另外服务端还要想ServiceManager注册服务,才能让其对应的客户端找到相应的代理类。另外service类要实现函数OnTransact,addService函数里第二个参数不用Bnxxx而使用service类xxx。

本地类的继承关系如下图所示:

总结:这是个人对binder机制的理解,可能有些地方写的不是很好,有错误的地方也希望各位能够指正。另外binder机制里面代理类和本地类的继承关系,相当重要,只有搞懂了这些继承关系才能真正的运用好这些类。

展开阅读全文

没有更多推荐了,返回首页