通过Binder实现 Native Service
来源:互联网 发布:symbian3软件 编辑:程序博客网 时间:2024/05/22 13:13
这次从理论联系实际,参考MediaPlayerService来实现自己需要的Service
注意:下面的代码只在Android N上验证,Android O 编译规则比较严格,warning的也会报错
一、理论分析
从之前分析MediaPlayerService的结果可以得到如下结果:
从图中可以看出,我们需要自己实现:
- IXXXService
- BpXXXService
- BnXXXService
- XXXService
如果我们要实现TestPlayService并包含一个check方法,那么如下图:
- ITestPlayService.h
这里除了定义了ITestPlayService,还定义了BnTestPlayService, - ITestPlayService.cpp
这里定义了BpTestPlayService
实现了BnTestPlayService的onTransact方法
BpTestPlayService实现了ITestPlayService中声明的方法 - TestPlayService.h
这里定义了服务端 - 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)
三、 拓展:
- 上面是通过
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); }
- 这里展示的只是简单的例子,监听binder的死亡等见源码:
git@gitee.com:ShuttleCheng/TestPlayService.git
四、 注意点:
代码要用
namespace android
包起来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是两个函数,所以编译会报错
阅读全文