这次从理论联系实际,参考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.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)
三、 拓展:
- 上面是通过
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是两个函数,所以编译会报错