通过Binder实现 Native Service

这次从理论联系实际,参考MediaPlayerService来实现自己需要的Service

注意:下面的代码只在Android N上验证,Android O 编译规则比较严格,warning的也会报错

一、理论分析

从之前分析MediaPlayerService的结果可以得到如下结果:
MediaPlayerServiceUML图

从图中可以看出,我们需要自己实现:

  1. IXXXService
  2. BpXXXService
  3. BnXXXService
  4. XXXService

如果我们要实现TestPlayService并包含一个check方法,那么如下图:
TestPlayServiceUML图

  1. ITestPlayService.h
    这里除了定义了ITestPlayService,还定义了BnTestPlayService,
  2. ITestPlayService.cpp
    这里定义了BpTestPlayService
    实现了BnTestPlayService的onTransact方法
    BpTestPlayService实现了ITestPlayService中声明的方法
  3. TestPlayService.h
    这里定义了服务端
  4. TestPlayService.cpp
    实现了TestPlayService.h中定义的方法

二、具体实现

1. ITestPlayService.h

#include <binder/IInterface.h>

namespace android {
class ITestPlayService: public IInterface
{
public:
    DECLARE_META_INTERFACE(TestPlayService);
    virtual void check(uint32_t params) const = 0;
};


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

};

2. ITestPlayService.cpp

#include <binder/Parcel.h>
#include "ITestPlayService.h"

namespace android {

enum {
    //这里有一点疑问,开始我觉得"= IBinder::FIRST_CALL_TRANSACTION"这个是一定要加的,因为服务端是根据enum中的顺序来识别客户端的请求的
    //但是我注释到这句,发现程序依然可以运行,这点有待查看
    CHECK = IBinder::FIRST_CALL_TRANSACTION,  
};

class BpTestPlayService: public BpInterface<ITestPlayService>
{
public:
    explicit BpTestPlayService(const sp<IBinder>& impl)
        : BpInterface<ITestPlayService>(impl)
    {
    }

    virtual void check(uint32_t params) const {
        Parcel data, reply;
        data.writeInterfaceToken(ITestPlayService::getInterfaceDescriptor());
        data.writeInt32(params); 
        remote()->transact(CHECK, data, &reply);
    }
};

IMPLEMENT_META_INTERFACE(TestPlayService, "android.chengming.TestPlayService");


status_t BnTestPlayService::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch (code) {
    case CHECK: {
        CHECK_INTERFACE(ITestPlayService, data, reply);
        uint32_t params = data.readInt32();
        check(params);
        return NO_ERROR;
    } break;
    default:
        return BBinder::onTransact(code, data, reply, flags);
    }
};

};

3. TestPlayService.h

#include "ITestPlayService.h"
#include <binder/BinderService.h>

namespace android {

class TestPlayService : public BinderService<TestPlayService>, public BnTestPlayService
{
public:
    TestPlayService();
    //static  void instantiate();
    virtual void check(uint32_t params) const;
    virtual status_t dump(int fd, const Vector<String16>& args);
    static char const* getServiceName() { return "test.player"; }

private:
    virtual ~TestPlayService();
};

};

4. TestPlayService.cpp

#define LOG_TAG "TestPlayService"

#include <utils/Log.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <unistd.h>

#include "TestPlayService.h"

namespace android {

TestPlayService::TestPlayService() {
    ALOGD("TestPlayService created");
}

TestPlayService::~TestPlayService() {
    ALOGD("TestPlayService destroyed");
}

/*void TestPlayService::instantiate() {
    defaultServiceManager()->addService(
            String16("test.player"), new TestPlayService());
}*/

status_t TestPlayService::dump(int fd, const Vector<String16>& args) {
    String8 result;
    ALOGD("dump() is called.");
    result = "dump";
    write(fd, result.string(), result.size());
    return NO_ERROR;
}



void TestPlayService::check(uint32_t params) const {
    if(params == 5) {
        ALOGI("params yes");
    }else {
        ALOGI("params no");
    }
}

};

5. main_testplayservice.cpp

#define LOG_TAG "TestPlayService"

#include <utils/Log.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>

#include "TestPlayService.h"

using namespace android;

int main(int argc __unused, char **argv __unused)
{

    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm(defaultServiceManager());
    ALOGI("ServiceManager1: %p", sm.get());

    //TestPlayService::instantiate();

    //ProcessState::self()->startThreadPool();
    //IPCThreadState::self()->joinThreadPool();
    TestPlayService::publishAndJoinThreadPool();
}

6. main_testplayclient.cpp

#define LOG_TAG "TestPlayService"

#include <utils/Log.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>


#include "ITestPlayService.h"

using namespace android;

int main(int argc __unused, char **argv __unused)
{
    sp<IBinder> binder;  

    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm(defaultServiceManager());
    ALOGI("ServiceManager: %p", sm.get());

    binder = sm->getService(String16("test.player"));  

    sp<ITestPlayService> service = interface_cast<ITestPlayService>(binder);

    uint32_t params = 5;
    service->check(params);

    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
}

7. Android.mk

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
        TestPlayService.cpp \
        ITestPlayService.cpp \
        main_testplayservice.cpp

LOCAL_SHARED_LIBRARIES := \
        libutils \
        libcutils \
        liblog \
        libbinder

LOCAL_MODULE:= TestPlayServer

include $(BUILD_EXECUTABLE)

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
        ITestPlayService.cpp \
        main_testplayclient.cpp

LOCAL_SHARED_LIBRARIES:= \
        libutils \
        libcutils \
        liblog \
        libbinder

LOCAL_MODULE:= TestPlayClient
include $(BUILD_EXECUTABLE)

三、 拓展:

  1. 上面是通过TestPlayService::publishAndJoinThreadPool()(TestPlayService继承了BinderService)来把TestPlayService加入到ServiceManager中的
    在Android源码中,大部分用的还是defaultServiceManager()->addService的方式
    其实,这两种方式是差不多的,简单看下publishAndJoinThreadPool函数:
    可以看到最终还是调用了addService方法
    static void publishAndJoinThreadPool(bool allowIsolated = false) {
        publish(allowIsolated);
        joinThreadPool();
    }
    static status_t publish(bool allowIsolated = false) {
        sp<IServiceManager> sm(defaultServiceManager());
        return sm->addService(
                String16(SERVICE::getServiceName()),
                new SERVICE(), allowIsolated);
    }
  1. 这里展示的只是简单的例子,监听binder的死亡等见源码:

git@gitee.com:ShuttleCheng/TestPlayService.git

四、 注意点:

  1. 代码要用namespace android包起来

  2. C++ 打印log的方法:
    ALOGD(“onFirstRef() is called.”);
    如果想要加入tag:#define LOG_TAG “TestPlayService”

    注意:
    发现如果使用ALOGV的话,并不会在终端上打出,换成ALOGD即可
    不知道为什么,有空再看下Log系统

编译报错记录:
1.error: allocating an object of abstract class type ‘android::TestPlayService’
一开始总是会报这个错误,网上搜索给出的结果是可能有父类的虚函数没有实现
实际上虚函数已经实现了,丢了个const,原因如下:
在ITestPlayService.h中定义的方法是:
virtual void check(uint32_t params) const = 0;
可是在TestPlayService.h中定义的方法是:
virtual void check(uint32_t params) ; //没有const
有和没有const是两个函数,所以编译会报错

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值