Android Binder通信原理(六):native下的C-S

源码基于:Android R

0. 前言

在之前的几篇博文中,对Android binder 的通信原理进行的深入的剖析,这些博文包括:binder 简介servicemanager启动service注册service获取Java 端的service 注册和获取。本文在之前的基础上,以实例的形式进一步的分析 native 下的 C-S 通信。

1. server 端

main.cpp

int main(int argc, char** argv)
{
    sp <IBinder> binder = defaultServiceManager()->checkService(String16(IPC_SERVICE_NAME));
    if (binder != 0) {
        printf("%s has been registered.\n", IPC_SERVICE_NAME);
        return 0;
    }
    if (IPCService::instantiate() < 0) {
        printf("regitster %s failed.\n", IPC_SERVICE_NAME);
        return -1;
    }
    printf("register %s successfully.\n", IPC_SERVICE_NAME);
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
    return 0;
}

在server 端运行的 main() 函数中,需要执行:

  • 通过 defaultServiceManager() 获取到 sp<IServiceManager>,即 ServiceManager 的client 端代理;
  • 通过 sp<IServiceManager> 调用函数 checkService(),并传入 service name,确定该 service 是否已经启动中,如果启动中,可以通过 service name 在 ServiceManager 中的 mNameToService map 中查找到,详细可以查看《Android Binder通信原理(三):service获取》2.3 节 和 《Android Binder通信原理(三):service注册》 4.1.1 节;
  • 如果该 server 已经启动,会根据 service name 返回该 server 的代理,如果该 server 没有启动,则返回的代理为 NULL;
  • 当通过 checkService() 发现该 server 没有启动时,需要调用 addService() 接口进行注册。该实例中用 IPCService::instantiate() 接口进行封装,后面会补充代码;
  • 另外,这里最重要的两个函数是需要执行的。
    • ProcessState::self()->startThreadPool(); 函数其实是卵生 IPCThreadState 的初始化函数,调用该函数后binder 之后的卵生工作就可以正常进行。详细可以查看《servicemanager 启动》一文第 4.5 节;
    • IPCThreadState::self()->joinThreadPool(); 启动一个循环,等待与binder 驱动的交互;

service.cpp

int IPCService::instantiate()
{
    ALOGD("register ipc service .");
    android::status_t ret = defaultServiceManager()->addService(String16(IPC_SERVICE_NAME), new IPCService());
    if (ret != android::OK) {
        ALOGE("Couldn't register %s!, ret = %d", IPC_SERVICE_NAME, ret);
        return ret;
    }
    return 0;
}

这个就是上面说的封装函数,当server 没有启动时,通过addService() 接口将该 service 添加到 servicemanager 中。

2. Client 端

const sp<IIPCService> IIPCDeathNotifier::getIPCService()
{
    JMutex::Autolock _l(mServiceLock);
    if (mIPCService.get() == 0 || !IInterface::asBinder(mIPCService)->isBinderAlive()) {
        sp<IServiceManager> sm = defaultServiceManager();
        sp<IBinder> binder;
        do {
            binder = sm->getService(String16(IPC_SERVICE_NAME));
            if (binder != 0) {
                break;
            }
            ALOGE("IPC service is not published, waiting...");
            usleep(500000); // 0.5 s
        } while (true);
        if (mDeathNotifier == NULL) {
            mDeathNotifier = new DeathNotifier();
        }
        binder->linkToDeath(mDeathNotifier);
        mIPCService = interface_cast<IIPCService>(binder);
        ALOGD("IPC SERVICE %p", mIPCService.get());
    }
    if (mIPCService == NULL) {
        ALOGE("wrong... can't get ipc service.");
    }
    return mIPCService;
}
  • 在 Client 有一个成员变量 mIPCService 来存储 server 的代理,最开始check 一下该值是否为 null,并且确认该 server 是否处于 alive 状态;
  • 接着,通过 defaultServiceManager() 接口获取 servicemanager 的代理,接着通过该代理查询 servcie name 对应的server 的代理 binder,如果获取失败,则每隔0.5 秒retry 一次;
  • 如果server 的代理获取成功,则通过 linkToDeath() 注册个监听,用以监听 server 是否die 掉;
  • 最后,将代理 binder 通过 interface_case<> 强制转换给想要的类型的代理,并进行存储;

3. BpBinder 和 BBinder 的创建

当 client 端通过 getService() 获取到 server 端的代理后,就可以进行binder 通信。这就涉及到了 BpBinder 和 BBinder 的创建。

加入我们创建 IPCService 接口的头文件,命名为 IIPCService.h

#ifndef IPC_BINDER_IIPCSERVICE_H_
#define IPC_BINDER_IIPCSERVICE_H_


#include <binder/IInterface.h>
#include <binder/Parcel.h>


namespace shift {

enum {
    FOCUS_STOP = 1,
};

class IIPCService : public IInterface
{
public:
    DECLARE_META_INTERFACE (IPCService);

    virtual int focusStop() = 0;
}; //end class IIPCService


class BnIPCService : public BnInterface<IIPCService>
{
public:
    virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
}; //end class BnIPCService


} //end namespace



#endif

头文件中创建了普通的 IIPCService 类,该类继承自 IInterface,定义了DECLARE_META_INTERFACE(),并指定 interface name 为 IPCService。该类是BpBinder 和BBinder 的依赖父类。

头文件中还定义了 BnIPCService 类,这就是 BBinder。

下面来看下 BpBinder 和 BBinder 的实现,文件名为 IIPCService.cpp

#include "IIPCService.h"

#include <binder/IInterface.h>
#include <binder/Parcel.h>

using namespace shift;

class BpIPCService : public BpInterface<IIPCService>
{
public:
    BpIPCService(const sp<IBinder> &impl) : BpInterface<IIPCService>(impl) {}

    virtual int focusStop()
    {
        Parcel data, reply;
        data.writeInterfaceToken(IIPCService::getInterfaceDescriptor());
        int ret = remote()->transact(FOCUS_STOP, data, &reply);
        if (ret != NO_ERROR) {
            return -1;
        }

        return reply.readInt32();
    }

}; //end class BpIPCService

IMPLEMENT_META_INTERFACE(IPCService, "my.IPCService");
//----------------------------------------------------------------------------------------
status_t BnIPCService::onTransact(
    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags)
{
    switch (code) {
    case FOCUS_STOP: {
        CHECK_INTERFACE(IIPCService, data, reply);
        int ret = focusStop();
        reply->writeInt32(ret);
        return NO_ERROR;
    }

    return NO_ERROR;
}

至此,native 下 C-S 的实例已经基本说明完毕,结合实际操作可以更好的理解 binder 的通信。

猜你喜欢

转载自blog.csdn.net/jingerppp/article/details/131430621
今日推荐