• Android native进程间通讯的实例 (原创)


      前一段时间有一个需求,需要增加一个Native层的服务,做完之后,想总结下,加深些印象....

      两个进程间通信,一般首先想到的就是Socket,这种哪种语言里都通用,不但可以跨语言,还可以跨平台。Android 里有自带的跨进程机制Binder通信,但其实实质上它还是一个Socket + 共享内存完成。进程间通讯也就是说两个进各程之间进行通讯,有一个服务端,有一个客户端。但服务端和客户端需要通过接口来调用,服务端适配接口方法并实现的具体功能,客户端需要调用这个接口,让服务端去做客户想要做的事情。那我们来看看接口的定义:

    class IDemoService: public IInterface
    {
     public:
          DECLARE_META_INTERFACE(DemoService);
          virtual int DemoFunc() = 0;    
    }

         那里面有一个宏定义 DECLARE_META_INTERFACE , 这个是Binder库里的一个宏定义,省下了我们写其接口的过程, 那我们来看库里是怎么定义的:

    #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();                                            

    相当于定义了一个转化接口的函数和获取Descriptor(),这里面是与等会要出场的另一个宏定义对应的IMPLEMENT_META_INTERFACE。

    那有了接口,我们看下服务端需在做什么工作,首先要实现BnDemoService里的onTransact方法:

    status_t BnDemoService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){
         switch(code){
              case DEMO_FUNC: {
                    CHECK_INTERFACE(IDemoService, data, reply);
                    int result = DemoFunc();
                    reply->writeInt32(result);
                    return NO_ERROR;
              }break;  
              default:
                   return BBinder::onTransact(code, data, reply, flags);
         }    
    }

     这里就要调用对应处理的函数了,DemoFunc(), 那我们看下服务端是怎么操作的。

    class DemoService : public BnDemoService {
    public :
        DemoService();
        int DemoFunc(){
             ALOGD("this is DemoService DemoFunc");
        }   
    }

    其实DemoService 是继承BnDemoService, 客户端通过Binder会调用服务端的onTransact(...)函数,那服务端看完了,那我们看服务是如何注册运行的。

    int main(){
      sp<IServiceManager> sm = defaultServiceManager();
      sp<IDemoService> mDemoService = new DemoService();
      status_t ret = sm->addService(Strint16("demo.DemoService"), mDemoService);
      ProcessState::self()->startThreadPool();
      IPCThreadState::self()->joinThreadPool(true); }

    可以看到通过IServiceManager的接口 把DemoService 对象注册成一个服务,通过调用startThreadPool() 在Binder线程池中启动一个线程,通过JoinThreadPool(true), 开启Binder的IPC通讯流程。

    如想细节了解,可以参考http://gityuan.com/2016/10/29/binder-thread-pool/

    那下面我们看看客户端是如何写的。 

    class BpDemoService : public BpInterface<IDemoService>{
    public :
        BpDemoService(const sp<IBinder> impl) : BpInterface<IDemoService>(impl){
        }
    
        int DemoFunc(){
             Parcel data, reply;
             data.writeInterfaceToken(IDemoService::getInterfaceDescriptor);
          remote()->transact(DEMO_FUNC, data, &reply);
          return reply.readInt32(); } };

    IMPLEMENT_META_INTERFACE(DemoService, "android.demo.IDemoService");

    BpInterace<xxx> 是BpBinder的接口,BpBinder 通过与/dev/Binder 驱动进行通讯。

    刚才说的IMPLEMENT_META_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() { }                                   

     其实相当于定义了实现了DECLARE_META_INTERFACE  相对应的函数 asInterface(...)。

    客户端的功能函数写完了,那看怎么调用呢?

    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> iBinder = sm->getService(String16("demo.DemoService"));
    if(iBinder == NULL)
      ALOGE("Client can't find Service");
    sp<IDemoService> mIDemoService = interface_case<IDemoService>(iBinder);
    mIDemoService->DemoFunc();

    与Serice端一样,通过IServiceManager接口,通过getService(ServiceName)获取IBinder, 最后通过interface_case 转化成IDemoService, 最后调用DemoFunc() 就可以调用 DemoService里的DemoFunc()了。

  • 相关阅读:
    window.location.href无法跳转的解决办法
    HTTP 错误 405.0
    C# 浅拷贝与深拷贝
    C# .ToString() 格式化
    深入理解AsyncTask
    【转】Android子线程真的不能更新UI么
    深入理解Activity的启动模式
    Android7.0,剪裁后提示“无法保存经过裁剪的图片”
    Android工程改包名
    javah命令,提示“找不到类文件”
  • 原文地址:https://www.cnblogs.com/jack2010/p/12684484.html
Copyright © 2020-2023  润新知