0%

Android Native Service 示例 第二篇

在安卓里面实现一个 native 的系统服务,不仅可以通过定义 Interface ,还可以通过直接继承 BBinder 来实现。本篇文章即讲述如何通过继承 Bbinder 来实现一个系统服务,并且讲述如何在 native 上使用 binder 的 linktoDeath 机制

首先列出需要包含的头文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// CommonHeader.h
#ifndef _COMMON_HEADER_H_
#define _COMMON_HEADER_H_
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>
#include <binder/PermissionController.h>
#include <binder/ProcessInfoService.h>
#include <binder/IResultReceiver.h>
#include <utils/String8.h>
#include <utils/String16.h>
#include <log/log_main.h>
#include "Cmdid.h"
#ifdef LOG_TAG
#undef LOG_TAG
#endif
#define LOG_TAG "NativeService"
#define NATIVESERVICE_NAME "nativeservice"
#endif

这里为了方便,我将可能用到的头文件都聚在一起了。

服务端

然后服务端的声明

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
//NativeServiceSampleService.h
#ifndef _NATIVE_SERVICE_SAMPLE_SERVICE_H_
#define _NATIVE_SERVICE_SAMPLE_SERVICE_H_

#include "CommonHeader.h"
#include <map>

namespace android
{
enum STATUS {
SUCCESS = NO_ERROR,
FAILED = UNKNOWN_TRANSACTION
};
typedef status_t (*local_method)(const Parcel &data, Parcel *reply);
class NativeServiceSampleService : public BBinder {
public:
NativeServiceSampleService();
virtual status_t onTransact(uint32_t code,const Parcel& data, Parcel* reply,uint32_t flags = 0);
status_t dump(int fd, const Vector<String16> &args);
int onShellCommand(int in, int out, int err, const Vector<String16> &args);
virtual status_t invoke(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
virtual const String16& getInterfaceDescriptor() const{return this->interface;};
private:
int shellCommand(int in, int out, int err, const Vector<String16> &args);
int getCallingPid(){return IPCThreadState::self()->getCallingPid();}
int getCallingUid(){return IPCThreadState::self()->getCallingUid();}
std::map<uint32_t,local_method> methods;
String16 interface = String16(NATIVESERVICE_NAME);
};
} // namespace android

#endif

这里最重要的依然是 onTransact ,Binder 通信的第一站就是这里,来看看服务端的实现

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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
//NativeServiceSampleService.cpp
#include "NativeServiceSampleService.h"
#include "Cmdid.h"
namespace android
{
status_t sampleCallFunction(const Parcel&data, Parcel* reply){
String8 str = String8(data.readString16());
ALOGD("call funcion called with \"%s\"",str.string());
return SUCCESS;
}

status_t sampleGetFunction(const Parcel&data, Parcel* reply){
ALOGD("get function called");
String16 hello = String16("this is message from service");
reply->writeString16(hello);
return SUCCESS;
}

status_t getMacByInterfaceName(const Parcel &data, Parcel *reply)
{
String16 ifname = data.readString16();
ALOGV("get mac of ifname: %s",String8(ifname).string());
String8 path = String8("/sys/class/net/");
path += String8(ifname);
path += String8("/address");
FILE* fp = fopen(path.string(),"ro");
if(fp == NULL){
ALOGE("open %s failed(%d): %s",path.string(),errno,strerror(errno));
return FAILED;
}

char mac[18] = {0};
size_t readsize = fread(mac,1,17,fp);
if(readsize != 17){
ALOGE("read mac failed");
fclose(fp);
return FAILED;
}
String16 result = String16(mac);
reply->writeString16(result);
fclose(fp);
return SUCCESS;
}

status_t SampleExitService(const Parcel &data,Parcel *reply)
{
ALOGI("service exit now");
printf("service received exit message\n");
exit(0);
return SUCCESS;
}

NativeServiceSampleService::NativeServiceSampleService()
{
methods[SAMPLE_CALL] = &sampleCallFunction;
methods[SAMPLE_GET] = &sampleGetFunction;
methods[SAMPLE_GET_MAC] = &getMacByInterfaceName;
methods[SAMPLE_EXIT_SERVER] = &SampleExitService;
}

status_t NativeServiceSampleService::onTransact(uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags)
{
if (code == SHELL_COMMAND_TRANSACTION)
{
int in = data.readFileDescriptor();
int out = data.readFileDescriptor();
int err = data.readFileDescriptor();
int argc = data.readInt32();
Vector<String16> args;
for (int i = 0; i < argc && data.dataAvail() > 0; i++)
{
args.add(data.readString16());
}
status_t result = 0;
sp<IBinder> unusedCallback;
sp<IResultReceiver> resultReceiver;
if ((result = data.readNullableStrongBinder(&unusedCallback)) != NO_ERROR)
{
return result;
}
if ((result = data.readNullableStrongBinder(&resultReceiver)) != NO_ERROR)
{
return result;
}
result = shellCommand(in, out, err, args);
if (resultReceiver != nullptr)
{
resultReceiver->send(result);
}
return result;
}
else if (IBinder::FIRST_CALL_TRANSACTION <= code && code <= IBinder::LAST_CALL_TRANSACTION)
{
CHECK_INTERFACE(INativeServiceSampleService, data, reply);
return invoke(code, data, reply, flags);
}
else
{
return BBinder::onTransact(code, data, reply, flags);
}
}

status_t NativeServiceSampleService::shellCommand(int in, int out, int err, const Vector<String16> &args)
{
return onShellCommand(in, out, err, args);
}

status_t NativeServiceSampleService::onShellCommand(int in, int out, int err, const Vector<String16> &args)
{
ALOGI("onShellCommand not implementation yet");
write(out, "onShellCommand not implementation yet\n", 38);
size_t size = args.size();
for (size_t i = 0; i < size; i++)
{
ALOGI("Received No.%zu arg: %s", i, String8(args[i]).string());
}
return SUCCESS;
}

status_t NativeServiceSampleService::dump(int fd, const Vector<String16> &args)
{
ALOGI("dump not implementation yet");
write(fd, "dump not implementation yet\n", 28);
size_t size = args.size();
for (size_t i = 0; i < size; i++)
{
ALOGI("Received No.%zu arg: %s", i, String8(args[i]).string());
}
return SUCCESS;
}

status_t NativeServiceSampleService::invoke(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
std::map<uint32_t, local_method>::iterator iter = methods.find(code);
ALOGV("uid:%d pid:%d called method %u",getCallingUid(),getCallingPid(),code);
if (iter != methods.end())
{
return (*(iter->second))(data, reply);
}
else
{
ALOGE("can't find such a method whose cmdid is %u", code);
return -1;
}
}
}

同样的,这里用一个 map 来保存了不同code和对应的函数的指针,服务端接收到调用时,可以判断 code 来直接从 map 里面取到相应的函数指针来调用并返回。
dump 和 shellcommand 是通过 dumpsys servicename 和 cmd servicename 这两种方式,会接收到的特殊 code ,这里同样封装成了接口,以供实现。
这个时候,服务端的实现已经完成了,可以参考下面的办法来启动一个服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//server.cpp
#include "NativeServiceSampleService.h"
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include <utils/String8.h>
#include <utils/String16.h>

int main(int argc, char **argv)
{
printf("start %s\n",NATIVESERVICE_NAME);
ALOGI("start %s",NATIVESERVICE_NAME);
android::defaultServiceManager()->addService(android::String16(NATIVESERVICE_NAME), new android::NativeServiceSampleService());
android::ProcessState::self()->startThreadPool();
android::IPCThreadState::self()->joinThreadPool();
return 0;
}

addService 见名知意,android::ProcessState::self()->startThreadPool(); 则是监听Binder通信的各种消息。android::IPCThreadState::self()->joinThreadPool(); 会阻塞在这里,通常我们是希望服务端保持运行的。

客户端

客户端是调用方,调用方最后调用的都是 Binder 的 transact ,当一个服务没有通过 interface 来声明的时候,我们可以直接调用 Binder 的 transact 来调用服务端。这里我们为客户端加上监听服务端是否退出的机制,这样客户端在调用过程中,如果服务端推出了,那么后续的调用则不再接收。

首先是 DeathRecipient ,与 java 层的类似,native 的也是继承相应的类

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
//NativeServiceSampleDeathRecipient.h
#ifndef _NATIVE_SERVICE_SAMPLE_DEATH_RECIPIENT_H_
#define _NATIVE_SERVICE_SAMPLE_DEATH_RECIPIENT_H_

#include "CommonHeader.h"
#include <mutex>
#include <atomic>

namespace android{
class NativeServiceSampleDeathRecipient : public IBinder::DeathRecipient
{
public:
NativeServiceSampleDeathRecipient(){mValidVar.store(invalid,std::memory_order_relaxed);};
bool setValid(){
return mValidVar.compare_exchange_strong(invalid,valid);
}
bool setInvalid(){
return mValidVar.compare_exchange_strong(valid,invalid);
}
bool isValid(){
return mValidVar.load();
}
private:
virtual void binderDied(const wp<IBinder>& who) {
ALOGE("service died. set service invalid");
setInvalid();
};
std::atomic_bool mValidVar;
bool valid = true;
bool invalid = false;
};
}

#endif

定义一个类,继承于 IBinder::DeathRecipient ,并覆写 binderDied 。

来看客户端的声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//NativeServiceSampleClient.h
#ifndef _NATIVE_SERVICE_SAMPLE_CLIENT_H_
#define _NATIVE_SERVICE_SAMPLE_CLIENT_H_
#include "CommonHeader.h"
#include "NativeServiceSampleDeathRecipient.h"
namespace android{
class NativeServiceSampleClient{
public:
NativeServiceSampleClient();
~NativeServiceSampleClient();
status_t invoke(uint32_t code, const Parcel &data, Parcel *reply,int flag);
status_t invoke(uint32_t code, const Parcel &data, Parcel *reply);
private:
sp<IBinder> service;
sp<NativeServiceSampleDeathRecipient> mdeathRecipient;
};
}
#endif

看客户端的实现

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
//NativeServiceSampleClient.cpp
#include "NativeServiceSampleClient.h"

namespace android{
NativeServiceSampleClient::NativeServiceSampleClient(){
sp<IServiceManager> sm = defaultServiceManager();
if (sm == NULL)
{
ALOGE("can not get service manager");
return;
}
service = sm->getService(String16(NATIVESERVICE_NAME));
if (service == NULL)
{
ALOGE("can not get service");
return;
}
mdeathRecipient = new NativeServiceSampleDeathRecipient();
if(service->linkToDeath(mdeathRecipient) != NO_ERROR)
{
ALOGE("link to death failed");
return;
}
ALOGI("client link to death success");
if(!mdeathRecipient->setValid()){
ALOGE("set death recipient valid failed");
}
if(mdeathRecipient->isValid()){
ALOGI("service is running");
}else{
ALOGE("service is not running and why ?");
}
}

NativeServiceSampleClient::~NativeServiceSampleClient()
{
if(service != nullptr)
{
if(mdeathRecipient->isValid())
{
if(service->unlinkToDeath(mdeathRecipient) == NO_ERROR)
ALOGD("unlinktodeath success");
else
ALOGE("unlinktodeath failed");
}
else
{
ALOGE("service is not running. need unlinkToDeath ?");
}
}
}

status_t NativeServiceSampleClient::invoke(uint32_t code, const Parcel &data, Parcel *reply)
{
return invoke(code,data,reply,0);
}

status_t NativeServiceSampleClient::invoke(uint32_t code, const Parcel &data, Parcel *reply,int flags)
{
if (!mdeathRecipient->isValid())
{
ALOGE("service is not running");
return -1;
}

Parcel send;
send.writeInterfaceToken(android::String16(NATIVESERVICE_NAME));
send.appendFrom(&data, 0, data.dataSize());
return service->transact(code, send, reply,flags);
}
}

客户端主要干两个事情,定义一个对外提供 transact 调用的接口,以及在构造的时候,为服务端的 binder 对象 linktoDeath ,这样服务端中途退出时,客户端可以知道相应的消息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Cmdid.h
#ifndef _CMDID_H_
#define _CMDID_H_
#include "binder/IBinder.h"
namespace android{
enum ENUME_CMD{
SAMPLE_CALL = IBinder::FIRST_CALL_TRANSACTION,
SAMPLE_GET,
SAMPLE_GET_MAC,
SAMPLE_EXIT_SERVER,
LAST_COMMAND = IBinder::LAST_CALL_TRANSACTION
};
}
#endif

cmdid 依旧是服务端和客户端共同约定的通信 code。

调用服务端可以参考下面的实现

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
//client.cpp
#include "CommonHeader.h"
#include "NativeServiceSampleClient.h"
#include "cmdline.h"
#include <string>
#include <unistd.h>
using namespace android;

void sampleSendStringToServer(NativeServiceSampleClient &service)
{
Parcel data, reply;

printf("send \"sample message\" to service\n");
String16 str = String16("sample message to service\"");
data.writeString16(str);
int ret = service.invoke(android::SAMPLE_CALL, data, &reply);
if (ret == NO_ERROR)
{
printf("service has received message\n");
}
else
{
printf("send msg to service failed\n");
}
}

void sampleGetStringFromServer(NativeServiceSampleClient &service)
{
Parcel data, reply;
int ret = service.invoke(android::SAMPLE_GET, data, &reply);
if (ret == NO_ERROR)
{
String8 str = String8(reply.readString16());
printf("received msg from server: \"%s\"\n",str.string());
}
}

void sampleExitServer(NativeServiceSampleClient &service)
{
Parcel data,reply;
// no wait reply;
int ret = service.invoke(android::SAMPLE_EXIT_SERVER, data, &reply,1);
if(ret == NO_ERROR)
{
printf("call service exit function success\n");
}else{
printf("call service exit function failed\n");
}
}

void sampleGetmacByInterfaceName(NativeServiceSampleClient &service,std::string& ifname)
{
Parcel data, reply;
data.writeString16(String16(ifname.c_str()));
int ret = service.invoke(android::SAMPLE_GET_MAC, data, &reply);
if (ret == NO_ERROR)
{
printf("get mac %s's mac address is %s\n",ifname.c_str(), String8(reply.readString16()).string());
}
else
{
printf("call get mac function failed\n");
}
}

int main(int argc, char *argv[])
{
cmdline::parser args;
args.add("call",'\0',"call sample send msg to service");
args.add("get",'\0',"call sample get msg from service");
args.add<std::string>("ifname",'i',"get supplied interface name",false,"");
args.add("exit",'\0',"call function make service exit and link death recipient");

args.parse_check(argc,argv);

NativeServiceSampleClient service;
ProcessState::self()->startThreadPool();
if(args.exist("call")){
sampleSendStringToServer(service);
}
if(args.exist("get")){
sampleGetStringFromServer(service);
}
if(args.exist("exit")){
sampleExitServer(service);
// listen to wait service died msg;
sleep(5);
}
if(args.exist("ifname")){
std::string ifname = args.get<std::string>("ifname");
sampleGetmacByInterfaceName(service,ifname);
}
// printf("press any key exit\n");
// getchar();
return 0;
}

cmdline.h是一个解析命令行参数的库,见 https://github.com/tanakh/cmdline

在安卓的源码环境中,可以参考以下 Android.bp 来将服务端和客户端的可执行文件都编译出来

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
cc_defaults{
name: "nativeservicesample_defaults",
shared_libs: [
"libutils",
"libcutils",
"libbinder",
"libhardware",
"liblog"
],

include_dirs: [
"frameworks/native/include",
"system/core/include",
"system/libhwbinder/include"
],
cflags: [
"-Wall",
"-Wextra",
"-Werror",
"-Wno-ignored-qualifiers",
"-Wno-unused-parameter",
],
}

cc_binary{
name: "server",
defaults: [
"nativeservicesample_defaults",
],
srcs: [
"server.cpp",
"NativeServiceSampleService.cpp",
],
}

cc_library{
name: "libnativeservicesampleclient",
srcs: [
"NativeServiceSampleClient.cpp",
],
defaults: [
"nativeservicesample_defaults",
],
}

cc_binary{
name: "client",
defaults: [
"nativeservicesample_defaults",
],
cflags: [
"-fexceptions",
],
static_libs: [
"libnativeservicesampleclient",
],
rtti: true,
srcs: [
"client.cpp",
],
}

服务端直接执行即可,客户端可以通过 –help 参数来查看帮助。

客户端想要监听服务端退出的消息,除了需要 linktodeath 之外,还需要 ProcessState::self()->startThreadPool();

如何在 java 层调用

通过jni调用

我们可以通过 jni 调用 NativeServiceSampleClient::invoke 来获取返回值,参考实现如下

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
111
112
113
114
115
116
117
#include <stdio.h>
#include <android_os_Parcel.h>
#include <binder/Parcel.h>
#include "jni.h"

#include "NativeServiceSampleClient.h"

static android::NativeServiceSampleClient* g_client = nullptr;

static int
invoke(JNIEnv* env , jobject /* thiz */,jint code, jobject dataObj, jobject replyObj, jint flags) {
ALOGI("invoke called");
if (dataObj == NULL) {
// jniThrowNullPointerException(env, NULL);
return -1;
}

android::Parcel* data = android::parcelForJavaObject(env, dataObj);
if (data == NULL) {
return -1;
}
android::Parcel* reply = android::parcelForJavaObject(env, replyObj);
if (reply == NULL && replyObj != NULL) {
return -1;
}

if(g_client == nullptr){
return -1;
}

return g_client->invoke(code, *data,reply,flags);
}

static const char *classPathName = "com/example/NativeServiceSample";

static const JNINativeMethod methods[] = {
{"invoke","(ILandroid/os/Parcel;Landroid/os/Parcel;I)I",(void*)invoke},
};

/*
* Register several native methods for one class.
*/
static int registerNativeMethods(JNIEnv* env, const char* className,
const JNINativeMethod* gMethods, int numMethods)
{
jclass clazz;

clazz = env->FindClass(className);
if (clazz == NULL) {
ALOGE("Native registration unable to find class '%s'", className);
return JNI_FALSE;
}
if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
ALOGE("RegisterNatives failed for '%s'", className);
return JNI_FALSE;
}

return JNI_TRUE;
}

/*
* Register native methods for all classes we know about.
*
* returns JNI_TRUE on success.
*/
static int registerNatives(JNIEnv* env)
{
if (!registerNativeMethods(env, classPathName,
methods, sizeof(methods) / sizeof(methods[0]))) {
return JNI_FALSE;
}

return JNI_TRUE;
}


// ----------------------------------------------------------------------------

/*
* This is called by the VM when the shared library is first loaded.
*/

typedef union {
JNIEnv* env;
void* venv;
} UnionJNIEnvToVoid;

jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
ALOGI("Jni_OnLoad called");
UnionJNIEnvToVoid uenv;
uenv.venv = NULL;
jint result = -1;
JNIEnv* env = NULL;

ALOGI("JNI_OnLoad");

if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {
ALOGE("ERROR: GetEnv failed");
goto bail;
}
env = uenv.env;

if (registerNatives(env) != JNI_TRUE) {
ALOGE("ERROR: registerNatives failed");
goto bail;
}

if(g_client == nullptr){
g_client = new android::NativeServiceSampleClient();
}

result = JNI_VERSION_1_4;

bail:
return result;
}

我们新建一个全局的静态变量,在 jni_onload 的时候初始化它,定义了一个用于与 java 层交互的 invoke 函数,此函数的再调用 NativeServiceSampleClient 的 invoke 并获取返回结果
p.s: 需要在源码环境下 link liblog libbinder libandroid_runtime,这种方法需要系统开放私有的库,对应用开放的库见 /system/etc/public.libraries.txt 。

通过安卓的 IBinder 调用

安卓的 android.os.IBinder 本身已经封装成对应的 java api了,系统应用可以通过 ServiceManager.getService 拿到对应的binder对象,参考实现如下

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
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;

public class NativeService {
private static final String SERVICE_NAME = "nativeservice";
private boolean valid = false;
IBinder service = null;
public NativeService(){
valid = false;
service = ServiceManager.getService(SERVICE_NAME);
if(service != null){
try{
service.linkToDeath(()->{
Log.e("shell","service died");
setInvlaid();
},0);
setValid();
}catch (RemoteException e){
Log.e("shell","link to death failed",e);
setInvlaid();
}
}
}

public boolean invoke(int code,Parcel data,Parcel reply) throws RemoteException {
if(isValid()){
Parcel send = Parcel.obtain();
send.writeInterfaceToken(SERVICE_NAME);
send.appendFrom(data,0,data.dataSize());
boolean result = service.transact(code,send,reply,0);
send.recycle();
return result;
}
Log.e("shell","service not running");
return false;
};

private void setInvlaid(){
synchronized(this){
valid = false;
}
}

private void setValid(){
synchronized(this){
valid = true;
}
}

private boolean isValid(){
synchronized(this){
return valid;
}
}
}

p.s: 此方式需要应用为系统应用或反射 ServiceManager 或在源码环境下编译