通过Binder实现 Native Service

来源:互联网 发布:symbian3软件 编辑:程序博客网 时间:2024/05/22 13:13

这次从理论联系实际,参考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.cppLOCAL_SHARED_LIBRARIES := \        libutils \        libcutils \        liblog \        libbinderLOCAL_MODULE:= TestPlayServerinclude $(BUILD_EXECUTABLE)include $(CLEAR_VARS)LOCAL_SRC_FILES:= \        ITestPlayService.cpp \        main_testplayclient.cppLOCAL_SHARED_LIBRARIES:= \        libutils \        libcutils \        liblog \        libbinderLOCAL_MODULE:= TestPlayClientinclude $(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是两个函数,所以编译会报错

阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 柯南之以吾之名 柯南之蓝羽 柯南之恶魔守护 柯南之白衣人 柯南之工藤希 柯南之推理系统 柯南之梦星夜 柯南之罪恶一生 柯南之白枫 柯南之风流 柯南之我可爱的小侦探 柯南之超级boss 柯南之永远的青空 柯南之飘 柯南之暗 柯南之黑暗组织 柯南之我是琴酒 柯南之时代的魔王 柯南之华森 雪舞之柯南的世界 柯南之大后宫 柯南之全知全能 柯南之白衣组织 柯南聊天 流放者柯南吧 柯南情头 目标杀掉柯南 目标是杀掉柯南 柯南村 柯南之全能秀 柯南全能秀 柯南秀 柯南之全能秀 18帅 柯占军 柯叔元 柯受良 柯受良怎么死 柯受良资料 柯受良个人资料 飞跃黄河柯受良 柯受良儿子