Create a Native Service on Android P
在定制自己的Android嵌入式系统时候,有时我们需要创建一个Native Service用来和底层设备通信。
- Native Service其实是一个Linux守护进程,提供一些必要的服务。
- Android提供了Binder进程间通信机制,Native Service就需要遵循Android的规则来实现
整体框架
- Server (后台Service服务)
- Client (提供和Service通信的接口)
- JNI (持有一个Client端,封装对应的接口,用于和Service通信)
- Java (JNI层提供给Java层的接口)
- Selinux修改(Android 8以后)
- 预编译到系统中,供Framework调用(如何在framework.jar中调用我们自己生成的java接口)
代码实现框架
代码我们以一个LED开关接口为例,添加一个NativeService,用来控制一个独立的LED灯的开关。
创建组织代码目录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17# root directory
mkdir LEDService
cd LEDService
# headers
mkdir include
# hardware interface
mkdir hal
# service implement
mkdir service
# client test
mkdir test
# JNI interface
mkdir jni
# java interface
mkdir java
# summary
ls -l编译脚本
为什么先写编译脚本?
- 编译脚本可以预先帮助我们组织代码
- 我们可以提前知道需要编译输出什么
我们需要生成哪几个文件
- libledservice.so 共享库,提供给Server端和Client端调用
- libledservicemanager_jni.so JNI共享库,供Java接口调用
- ledservicemanager.jar Jar包,提供给其他java层调用
- ledservice.rc 服务启动的rc文件
- com.vectoros.led.xml permission文件
Android.mk
我们在LEDService目录下创建一个Android.mk用于编译C/C++ so, 可执行文件以及rc,xml等资源文件的编译输出。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102################ LIB_LED_SERVICE ############
include $(CLEAR_VARS)
LOCAL_MODULE:= libledservice
LOCAL_SRC_FILES:= \
service/LEDService.cpp \
service/ILEDService.cpp \
service/LEDServiceManager.cpp
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/include
LOCAL_SHARED_LIBRARIES := \
libbinder \
libutils \
libcutils \
liblog
# Export include dir
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
# LOCAL_CFLAGS += -mhard-float
# LOCAL_LDFLAGS += -Wl,--no-warn-mismatch
include $(BUILD_SHARED_LIBRARY)
################ LED_SERVICE ############
include $(CLEAR_VARS)
LOCAL_MODULE:= ledservice
LOCAL_SRC_FILES:= \
service/main_ledservice.cpp
LOCAL_SHARED_LIBRARIES := \
libutils \
liblog \
libbinder \
libledservice
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_INIT_RC := service/ledservice.rc
include $(BUILD_EXECUTABLE)
################ LED_SERVICE_MANAGER_JNI ############
include $(CLEAR_VARS)
LOCAL_MODULE:= libledservicemanager_jni
LOCAL_SRC_FILES:= \
jni/com_vectoros_ledservice_manager_jni.cpp
LOCAL_SHARED_LIBRARIES := \
libutils \
liblog \
libcutils \
libledservice \
libbinder
LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_LDFLAGS += -Wl,--no-warn-mismatch
include $(BUILD_SHARED_LIBRARY)
# Using Android.bp to build java library
# ################# JAVA_LIBRARIES ############
# include $(CLEAR_VARS)
# LOCAL_MODULE:= ledservicemanager
# LOCAL_SRC_FILES:= \
# $(call all-java-files-under,java)
# LOCAL_MODULE_TAGS := optional
# LOCAL_NO_STANDARD_LIBRARIES := true
# LOCAL_DX_FLAGS := --core-library
# include $(BUILD_JAVA_LIBRARY)
# ################ PERMISION_FILES ############
include $(CLEAR_VARS)
LOCAL_MODULE:= com.vectoros.led.xml
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS:= ETC
LOCAL_SRC_FILES:= java/$(LOCAL_MODULE)
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
include $(BUILD_PREBUILT)
################ CMD_TEST_CLIENT ############
include $(CLEAR_VARS)
LOCAL_MODULE:= ledserviceclient
LOCAL_SRC_FILES:= \
test/main_ledservice_client.cpp
LOCAL_SHARED_LIBRARIES := \
libbinder \
libutils \
libcutils \
liblog \
libledservice
LOCAL_LDFLAGS += -Wl,--no-warn-mismatch
LOCAL_MODULE_CLASS := EXECUTABLES
include $(BUILD_EXECUTABLE)Andorid.bp
我们在java目录下,创建一个Android.bp文件,用于生成jar包。至于为什么必须要用Android.bp,会留在集成到framework里面的时候讲。
1
2
3
4
5
6
7
8
9
10java_library {
name: "ledservicemanager",
srcs: [
"com/vectoros/led/*.java",
],
hostdex: true,
java_version: "1.7",
no_framework_libs: true,
}总结
通过以上的编译脚本,我们知道了自己需要写哪些文件,会生成什么样的文件,接下来就可以往下写实现部分的代码了。
头文件实现
主要有三个头文件
- LEDService.h
- LEDServiceManager.h
- ILEDService.h
ILEDService.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
namespace android
{
class ILEDService : public IInterface
{
public:
DECLARE_META_INTERFACE(LEDService);
virtual int initHardware(void) = 0;
virtual void releaseHardware(void) = 0;
virtual void on(void) = 0;
virtual void off(void) = 0;
};
class BnLEDService : public BnInterface<ILEDService>{
public:
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags = 0);
};
enum LED_SERVICE_TYPE{
BASE_START,
ON,
OFF,
};
} // namespace androidLEDService.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
namespace android {
class LEDService : public BinderService<LEDService>, public BnLEDService
{
public:
static char const* getServiceName() {
return "LEDService";
}
LEDService();
~LEDService();
private:
virtual int initHardware(void);
virtual void releaseHardware(void);
virtual void on(void);
virtual void off(void);
};
}; // namespace androidLEDServiceManager.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
namespace android
{
class LEDServiceManager : public Singleton<LEDServiceManager>
{
private:
/* data */
bool isDied;
void ledServiceDied();
mutable sp<ILEDService> mLEDService;
mutable sp<IBinder::DeathRecipient> mDeathObserver;
public:
LEDServiceManager(/* args */);
~LEDServiceManager();
int initHardware(void);
void releaseHardware(void);
void on(void);
void off(void);
status_t assertState();
bool checkService() const;
void resetServiceStatus();
};
} // namespace android
客户端和服务端实现
- ILEDService.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
namespace android
{
enum{
INIT_HARDWARE = IBinder::FIRST_CALL_TRANSACTION,
RELEASE_HARDWARE,
ON,
OFF,
};
class BpLEDService : public BpInterface<ILEDService>
{
public:
BpLEDService(const sp<IBinder>& impl) : BpInterface<ILEDService>(impl)
{
}
int initHardware(void)
{
Parcel data, reply;
data.writeInterfaceToken(ILEDService::getInterfaceDescriptor());
remote()->transact(INIT_HARDWARE, data, &reply);
return (int)reply.readInt32();
}
void releaseHardware(void)
{
Parcel data, reply;
data.writeInterfaceToken(ILEDService::getInterfaceDescriptor());
remote()->transact(RELEASE_HARDWARE, data, &reply);
}
int on(void)
{
Parcel data, reply;
data.writeInterfaceToken(ILEDService::getInterfaceDescriptor());
remote()->transact(ON, data, &reply);
return (int) reply.readInt32();
}
int off(void)
{
Parcel data, reply;
data.writeInterfaceToken(ILEDService::getInterfaceDescriptor());
remote()->transact(OFF, data, &reply);
return (int) reply.readInt32();
}
};
IMPLEMENT_META_INTERFACE(LEDService, "android.vectoros.LEDService");
status_t BnLEDService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
char *buff;
int len, retval;
status_t status;
switch(code) {
case INIT_HARDWARE:{
CHECK_INTERFACE(ILEDService, data, reply);
retval = initHardware();
reply->writeInt32(retval);
return NO_ERROR;
} break;
case RELEASE_HARDWARE:{
CHECK_INTERFACE(ILEDService, data, reply);
releaseHardware();
return NO_ERROR;
} break;
case ON:{
CHECK_INTERFACE(ILEDService, data, reply);
on();
return NO_ERROR;
} break;
case OFF:{
CHECK_INTERFACE(ILEDService, data, reply);
off();
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
} // namespace android - LEDService.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
namespace android {
LEDService::LEDService()
{
ALOGI("LEDService()");
}
LEDService::~LEDService(){
ALOGI("~LEDService()");
}
int LEDService::initHardware(void)
{
ALOGI("initHardware(), check camera env.");
}
void LEDService::releaseHardware(void)
{
ALOGI("releaseHardware()");
}
int LEDService::on(void)
{
ALOGI("on()");
return 0;
}
int LEDService::off(void)
{
ALOGI("off()");
return 0;
}
}; // namespace android - LEDServiceManager.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
namespace android
{
LEDServiceManager::LEDServiceManager() : isDied(false)
{
}
LEDServiceManager::~LEDServiceManager()
{
}
void LEDServiceManager::LEDServiceDied()
{
isDied = true;
mLEDService.clear();
}
status_t LEDServiceManager::assertState() {
if (mLEDService == NULL) {
// try for one second
const String16 name("LEDService");
for (int i=0 ; i<4 ; i++) {
status_t err = getService(name, &mLEDService);
if (err == NAME_NOT_FOUND) {
usleep(250000);
continue;
}
if (err != NO_ERROR) {
ALOGE("LEDService not found");
return err;
}
break;
}
initLEDServiceNative();
class DeathObserver : public IBinder::DeathRecipient {
LEDServiceManager& mLEDServiceManager;
virtual void binderDied(const wp<IBinder>& who) {
ALOGW("LEDService died [%p]", who.unsafe_get());
mLEDServiceManager.LEDServiceDied();
}
public:
DeathObserver(LEDServiceManager& mgr) : mLEDServiceManager(mgr) { }
};
mDeathObserver = new DeathObserver(*const_cast<LEDServiceManager *>(this));
mLEDService->asBinder(mLEDService)->linkToDeath(mDeathObserver);
}
return NO_ERROR;
}
bool LEDServiceManager::checkService() const
{
return isDied? true:false;
}
void LEDServiceManager::resetServiceStatus()
{
isDied = false;
}
int LEDServiceManager::initHardware(void)
{
return mLEDService->initHardware();
}
void LEDServiceManager::releaseHardware(void)
{
mLEDService->releaseHardware();
}
int LEDServiceManager::on()
{
return mLEDService->on();
}
int LEDServiceManager::off()
{
return mLEDService->off();
}
} // namespace android - main_LED_service.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using namespace android;
int main(int argc, char** argv) {
LEDService::publishAndJoinThreadPool(true);
// Like the SurfaceFlinger, limit the number of binder threads to 4.
ProcessState::self()->setThreadPoolMaxThreadCount(4);
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
sm->addService(String16("LEDService"), new LEDService());
ProcessState::self()->startThreadPool();
ProcessState::self()->giveThreadPoolName();
IPCThreadState::self()->joinThreadPool();
ProcessState::self()->setThreadPoolMaxThreadCount(4);
return 0;
}
客户端服务端测试程序
JNI接口
1 | #include <jni.h> |
Java接口
- LEDServiceManager.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21package com.vectoros.led;
/**
*
*/
public class LEDServiceManager{
private static final String TAG = "LEDServiceManager";
static{
System.loadLibrary("LEDServiceManager_jni");
}
public static int on(){
return nativeOn();
}
public static int off(){
return nativeOff();
}
private static native int nativeOn();
private static native int nativeOff();
}