zoukankan      html  css  js  c++  java
  • Binder学习—— C++实现分析

    一、测试Demo的实现

    1.Binder C++实现参考文件

    frameworks/av/include/media/IMediaPlayerService.h
    frameworks/av/media/libmedia/IMediaPlayerService.cpp
    frameworks/av/media/libmediaplayerservice/MediaPlayerService.h
    frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
    frameworks/av/media/mediaserver/Main_mediaserver.cpp

    2.实现代码

    实现Service端和Client端,test_server.cpp中注册两个服务"hello""goodbye",test_client.cpp来获取使用服务。
    
    定义抽象类,包含Service和Client两端都要实现的函数:
    IHelloService.h
    IGoodbyeService.h
    
    Service端的实现(Bn: Binder native):
    BnHelloService.h
    BnGoodbyeService.h
    BnHelloService.cpp
    BnGoodbyeService.cpp
    
    Client端的实现(Bp: Binder proxy):
    BpHelloService.cpp
    BpGoodbyeService.cpp
    
    # tree
    .
    ├── Android.mk
    ├── BnGoodbyeService.cpp
    ├── BnGoodbyeService.h
    ├── BnHelloService.cpp
    ├── BnHelloService.h
    ├── BpGoodbyeService.cpp
    ├── BpHelloService.cpp
    ├── IGoodbyeService.h
    ├── IHelloService.h
    ├── test_client.cpp
    └── test_server.cpp

    IHelloService.h

    /* 参考: frameworksavincludemediaIMediaPlayerService.h */
    
    #ifndef ANDROID_IHELLOERVICE_H
    #define ANDROID_IHELLOERVICE_H
    
    #include <utils/Errors.h>  // for status_t
    #include <utils/KeyedVector.h>
    #include <utils/RefBase.h>
    #include <utils/String8.h>
    #include <binder/IInterface.h>
    #include <binder/Parcel.h>
    
    #define HELLO_SVR_CMD_SAYHELLO     0
    #define HELLO_SVR_CMD_SAYHELLO_TO  1
    
    #if 1
    /*-----DECLARE_META_INTERFACE(HelloService);等效如下:-----*/
    
    static const android::String16 descriptor;
    static android::sp<IHelloService> asInterface(const android::sp<android::IBinder>& obj);
    virtual const android::String16& getInterfaceDescriptor() const;
    IHelloService();
    virtual ~IHelloService();
    /*--------------------------------------------------------*/
    
    #endif
    
    
    namespace android {
    
    class IHelloService: public IInterface
    {
    public:
        DECLARE_META_INTERFACE(HelloService);
        /*使用纯虚函数做成抽象类*/
        virtual void sayhello(void) = 0;
        virtual int sayhello_to(const char *name) = 0;
    };
    
    }
    
    #endif
    View Code

    IGoodbyeService.h

    /* 参考: frameworksavincludemediaIMediaPlayerService.h */
    
    #ifndef ANDROID_IGOODBYEERVICE_H
    #define ANDROID_IGOODBYEERVICE_H
    
    #include <utils/Errors.h>  // for status_t
    #include <utils/KeyedVector.h>
    #include <utils/RefBase.h>
    #include <utils/String8.h>
    #include <binder/IInterface.h>
    #include <binder/Parcel.h>
    
    #define GOODBYE_SVR_CMD_SAYGOODBYE     0
    #define GOODBYE_SVR_CMD_SAYGOODBYE_TO  1
    
    
    namespace android {
    
    class IGoodbyeService: public IInterface
    {
    public:
        DECLARE_META_INTERFACE(GoodbyeService);
        virtual void saygoodbye(void) = 0;
        virtual int saygoodbye_to(const char *name) = 0;
    };
    
    }
    
    #endif
    View Code

    BnHelloService.h

    #ifndef ANDROID_BNHELLOERVICE_H
    #define ANDROID_BNHELLOERVICE_H
    
    #include "IHelloService.h"
    
    namespace android {
    
    class BnHelloService: public BnInterface<IHelloService>
    {
    public:
        /*自己又添加了一个函数*/
        virtual status_t onTransact( uint32_t code,
                                        const Parcel& data,
                                        Parcel* reply,
                                        uint32_t flags = 0);
    
        /*继承来的纯虚函数需要实现*/
        virtual void sayhello(void);
        virtual int sayhello_to(const char *name);
    
    };
    
    }
    
    #endif
    View Code

    BnGoodbyeService.h

    #ifndef ANDROID_BNGOODBYEERVICE_H
    #define ANDROID_BNGOODBYEERVICE_H
    
    #include "IGoodbyeService.h"
    
    namespace android {
    
    class BnGoodbyeService: public BnInterface<IGoodbyeService>
    {
    public:
        virtual status_t    onTransact( uint32_t code,
                                        const Parcel& data,
                                        Parcel* reply,
                                        uint32_t flags = 0);
    
        virtual void saygoodbye(void);
        virtual int saygoodbye_to(const char *name);
    
    };
    
    
    }
    
    #endif
    View Code

    BnHelloService.cpp

    /* 参考: frameworksavmedialibmediaIMediaPlayerService.cpp */
    
    #define LOG_TAG "HelloService"
    
    #include "BnHelloService.h"
    
    
    namespace android {
    
    status_t BnHelloService::onTransact(uint32_t code, const Parcel& data,
                                    Parcel* reply, uint32_t flags)
    {
        /* 解析数据,调用sayhello/sayhello_to */
    
        switch (code) {
            case HELLO_SVR_CMD_SAYHELLO: {
                sayhello();
                return NO_ERROR;
            } break;
            
            case HELLO_SVR_CMD_SAYHELLO_TO: {
    
                /* 从data中取出参数 */
                int32_t policy =  data.readInt32();
                String16 name16 = data.readString16();
                String8 name8(name16);
    
                int cnt = sayhello_to(name8.string());
    
                /* 把返回值写入reply传回去 */
                reply->writeInt32(cnt);
                
                return NO_ERROR;
            } break;
            default:
                return BBinder::onTransact(code, data, reply, flags);
        }
    }
    
    void BnHelloService::sayhello(void)
    {
        static int cnt = 0;
        ALOGI("say hello : %d
    ", cnt++);
    
    }
    
    int BnHelloService::sayhello_to(const char *name)
    {
        static int cnt = 0;
        ALOGI("say hello to %s : %d
    ", name, cnt++);
        return cnt;
    }
    
    }
    View Code

    BnGoodbyeService.cpp

    /* 参考: frameworksavmedialibmediaIMediaPlayerService.cpp */
    
    #define LOG_TAG "GoodbyeService"
    
    #include "BnGoodbyeService.h"
    
    
    namespace android {
    
    status_t BnGoodbyeService::onTransact( uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags)
    {
        /* 解析数据,调用saygoodbye/saygoodbye_to */
    
        switch (code) {
            case GOODBYE_SVR_CMD_SAYGOODBYE: {
                saygoodbye();
                return NO_ERROR;
            } break;
            
            case GOODBYE_SVR_CMD_SAYGOODBYE_TO: {
    
                /* 从data中取出参数 */
                int32_t policy =  data.readInt32();
                String16 name16 = data.readString16();
                String8 name8(name16);
    
                int cnt = saygoodbye_to(name8.string());
    
                /* 把返回值写入reply传回去 */
                reply->writeInt32(cnt);
                
                return NO_ERROR;
            } break;
            default:
                return BBinder::onTransact(code, data, reply, flags);
        }
    }
    
    void BnGoodbyeService::saygoodbye(void)
    {
        static int cnt = 0;
        ALOGI("say goodbye : %d
    ", cnt++);
    
    }
    
    int BnGoodbyeService::saygoodbye_to(const char *name)
    {
        static int cnt = 0;
        ALOGI("say goodbye to %s : %d
    ", name, cnt++);
        return cnt;
    }
    
    }
    View Code

    BpHelloService.cpp

    /* 参考: frameworksavmedialibmediaIMediaPlayerService.cpp */
    
    #include "IHelloService.h"
    
    namespace android {
    
    class BpHelloService: public BpInterface<IHelloService>
    {
    public:
        BpHelloService(const sp<IBinder>& impl) : BpInterface<IHelloService>(impl)
        {
        }
    
        void sayhello(void)
        {
            /* 构造/发送数据 */
            Parcel data, reply;
    
            /*为了兼容之前的C程序才写入这个垃圾数据的*/
            data.writeInt32(0);
    
            /*调用远端的hello函数*/
            remote()->transact(HELLO_SVR_CMD_SAYHELLO, data, &reply); /*remote() ?*/
        }
        
        int sayhello_to(const char *name)
        {
            /* 构造/发送数据 */
            Parcel data, reply;
    
            /*为了兼容之前的C程序才写入这个垃圾数据(0)的*/
            data.writeInt32(0);
            data.writeString16(String16(name));
    
            remote()->transact(HELLO_SVR_CMD_SAYHELLO_TO, data, &reply);
    
            /*传送回返回值*/
            return reply.readInt32();
        }
    
    };
    
    IMPLEMENT_META_INTERFACE(HelloService, "android.media.IHelloService");
    
    }
    
    #if 1
    /*------IMPLEMENT_META_INTERFACE(HelloService, "android.media.IHelloService"); 等效如下:-------*/
    
    
    const android::String16 IHelloService::descriptor("android.media.IHelloService");
    const android::String16& IHelloService::getInterfaceDescriptor() const {
        return IHelloService::descriptor;
    }
    android::sp<IHelloService> IHelloService::asInterface(
            const android::sp<android::IBinder>& obj)
    {
        android::sp<IHelloService> intr;
        if (obj != NULL) {
            intr = static_cast<IHelloService*>(
                obj->queryLocalInterface(IHelloService::descriptor).
                get());
            if (intr == NULL) {
                intr = new BpHelloService(obj);
            }
        }
        return intr;
    }
    IHelloService::IHelloService() { }
    IHelloService::~IHelloService() { }
    #endif
    View Code

    BpGoodbyeService.cpp

    /* 参考: frameworksavmedialibmediaIMediaPlayerService.cpp */
    
    #include "IGoodbyeService.h"
    
    namespace android {
    
    class BpGoodbyeService: public BpInterface<IGoodbyeService>
    {
    public:
        BpGoodbyeService(const sp<IBinder>& impl)
            : BpInterface<IGoodbyeService>(impl)
        {
        }
    
        void saygoodbye(void)
        {
            /* 构造/发送数据 */
    
            Parcel data, reply;
            data.writeInt32(0);
    
            remote()->transact(GOODBYE_SVR_CMD_SAYGOODBYE, data, &reply);
        }
        
        int saygoodbye_to(const char *name)
        {
            /* 构造/发送数据 */
            Parcel data, reply;
    
            data.writeInt32(0);
            data.writeString16(String16(name));
    
            remote()->transact(GOODBYE_SVR_CMD_SAYGOODBYE_TO, data, &reply);
    
            return reply.readInt32();
        }
    
    };
    
    IMPLEMENT_META_INTERFACE(GoodbyeService, "android.media.IGoodbyeService");
    
    }
    View Code

    参考:http://github.com/weidongshan/APP_0004_Binder_CPP_App.git

    3.编译测试

    将代码放在frameworks/testing/biner_cpp_v1下,然后mm编译。

    二、分析

    1.Service的注册过程处理过程分析(test_server.cpp)

    (1)获取SM分析

    defaultServiceManager    //IServiceManager.cpp
        gDefaultServiceManager = interface_cast<IServiceManager>(ProcessState::self()->getContextObject(NULL));
            obj = ProcessState::self()->getContextObject(NULL)
                getStrongProxyForHandle(0); //ProcessState.cpp 直接指定的是handle=0了,是SM
                    return new BpBinder(0); //BpBinder.cpp SM就表示为一个handle=0的BpBinder对象。obj=此BpBinder对象
            IServiceManager::asInterface(obj); //obj=此BpBinder对象
                return new BpServiceManager(obj); //IServiceManager.cpp BpServiceManager充当SM的角色。

    (2)addService()分析

    sm->addService(String16("hello"), new BnHelloService()); //test_server.cpp
        virtual status_t addService(const String16& name, const sp<IBinder>& service, bool allowIsolated); //IServiceManager.cpp
        //allowIsolated声明的时候声明为: bool allowIsolated=false,使用的是默认参数
        data.writeStrongBinder(service); //service=BnHelloService
            flatten_binder(ProcessState::self(), val, this); //Parcel.cpp val=service=BnHelloService
                IBinder *local = binder->localBinder(); //binder=val,根据继承关系,localBinder直接return this, local也就是BnHelloService对象。
                flat_binder_object obj;
                obj.type = BINDER_TYPE_BINDER; //add service的时候的type
                obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
                obj.cookie = reinterpret_cast<uintptr_t>(local); // BnHelloService对象赋值给flat_binder_object的cookie域
                finish_flatten_binder //Parcel.cpp 应该是写到驱动
                    out->writeObject(flat, false); 

    (3)创建一个子线程循环read-parse-process

    ProcessState::self()->startThreadPool(); //test_server.cpp 它会以一个线程的状态存在,可以通过/proc/$(PID)/task来验证。
        spawnPooledThread(true); //ProcessState.cpp isMain=true
            sp<Thread> t = new PoolThread(isMain);
            t->run(name.string()); //相当于执行PoolThread中的threadLoop
                 IPCThreadState::self()->joinThreadPool(true);
                    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER); //IPCThreadState.cpp
                    //若是isMain=true表示注册是主线程,为false表示新创建的子线程
                        //循环读取数据,解析数据,执行,答复
                        getAndExecuteCommand
                            executeCommand(cmd) //IPCThreadState.cpp
                                case BR_TRANSACTION:
                                    sp<BBinder> b((BBinder*)tr.cookie); //cookie就是BnHelloService对象
                                    b->transact(tr.code, buffer, &reply, tr.flags); //这里调用的就是BnHelloService.transact()
                                case BR_SPAWN_LOOPER:
                                    mProcess->spawnPooledThread(false); //Service创建多线程   

    IPCThreadState::self()->joinThreadPool(); //test_server.cpp 也是进入解析数据,执行,答复的循环

    补充:

    ① ProcessState::self():获取ProcessState的单例模式,每个进程有一个唯一的实例

    ② IPCThreadState::self():获取IPCThreadState的单例模式,每个线程都有一个唯一的实例,实现如下: ###################

    处理涉及线程特有数据(Thread Specific Data)
    这里,每个线程都有一个IPCThreadState对象,也就是说这个对象是每个线程特有的东西,各不相同,因此它应该存在这个线程的局部空间里。
    K = pthread_key_create()
    (K, V) 同一个K对于不同的线程可以设置不同的Value
    每个线程设置不同的Value
    线程1:pthread_setspecific(K, V1);
    线程2:pthread_setspecific(K, V2); // V1和V2都存在于线程的局部空间里

    线程1:pthread_getspecific(K); 得到V1
    线程2:pthread_getspecific(K); 得到V2

    这里不同的线程使用的是同一个键,但是不同的值,通过判断值是否为NULL来判断是否每个线程已经分配过了。

    2.Client获取服务过程和使用服务分析(test_client.cpp)

    (1)打开binder设备节点和获取SM

    sp<ProcessState> proc(ProcessState::self()); //test_client.cpp 构造函数中打开binder设备并进行mmap了
    sp<IServiceManager> sm = defaultServiceManager(); //test_client.cpp 获得BpServiceManager 在IServiceManager.cpp中定义的

    (2)获取BpBinder对象的过程

    sp<IBinder> binder = sm->getService(String16("hello")); //test_client.cpp 
    //binder是BpBinder对象,里面含有HelloService的handle
        sp<IBinder> svc = checkService(name);
            remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply); //remote()?????
            return reply.readStrongBinder();
                unflatten_binder //Parcel.cpp 
                    *out = proc->getStrongProxyForHandle(flat->handle); 
                    //获取到一个flat_binder_object结构,里面有Service的handle,通过flat->handle获取一个sp<IBinder>对象。

    (3)获得BpHelloService对象的过程

    调用BpServiceManager的getService函数获得一个flat_binder_object,从中取出handle, 创建一个BpBinder(handle),
    然后使用interface_cast使用这个BpBinder创建一个BpHelloService对象
    
    sp<IHelloService> service = interface_cast<IHelloService>(binder);
    //binder是BpBinder对象, 里面含有HelloService的handle,把binder转换为IHelloService接口(BpHelloService对象)
    
    之后就可以通过service来访问这个服务里面提供的函数了。

    补充:

    IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");展开后:
    android::sp<IServiceManager> IServiceManager::asInterface(const android::sp<android::IBinder>& obj)      
    {                                                      
        android::sp<IServiceManager> intr;                    
        if (obj != NULL) { /*这个是Client端获取执行*/                              
            intr = static_cast<IServiceManager*>(obj->queryLocalInterface(IServiceManager::descriptor).get());  
            if (intr == NULL) {  /*这个是Service端注册执行*/                         
                intr = new BpServiceManager(obj);             
            }                                              
        }                                                  
        return intr;                                       
    } 
  • 相关阅读:
    docker清理无用资源
    为什么不需要在 Docker 容器中运行 sshd
    转载:SQL注入演示demo
    docker方式安装prometheus主控
    promethus监控结构
    oracle的函数
    oracle冷备份后恢复
    oracle的冷备份
    oracle常用
    oracle的系统文件的查询
  • 原文地址:https://www.cnblogs.com/hellokitty2/p/10846044.html
Copyright © 2011-2022 走看看