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()了。

 

posted @ 2020-04-20 20:12  five.li  阅读(913)  评论(0编辑  收藏  举报