永恒的码流

万物皆流,无物常驻

0%

编写Android的Java系统服务

说明

参考闹钟服务编写一个HelloWorldService服务,功能为打印字符串”Hello, World!”,然后基于编译后的系统,编写APP使用该服务。

1
2
3
4
5
6
7
闹钟服务相关接口和类
- /frameworks/base/core/java/android/app/IAlarmManager.aidl 接口定义
- out/soong/.intermediates/frameworks/base/framemwork/android_common/
gen/aidl/frameworks/base/core/java/android/app/IAlarmManager.java 自动生成的接口以及Stub、Proxy
- /frameworks/base/services/core/java/com/android/server/AlarmManagerService.java 服务实现
- /frameworks/base/core/java/android/app/AlarmManager.java 客户端使用的服务代理

编写Framwork代码

编写和配置 IHelloWorld.aidl

编写接口。目录:/frameworks/base/core/java/android/app

1
2
3
4
5
6
7
8
9
package android.app
/**
* System private API for talking with the alarm manager service.
*
* {@hide}
*/
interface IHelloWorld {
void printHello();
}

待编译时,会自动生成对应的java接口和Stub、Proxy类,不用手动处理,生成的代码位于:out/soong/.intermediates/frameworks/base/framemwork/android_common/gen/aidl/frameworks/base/core/java/android/app

配置接口。在 /framwork/base/Android.bp中配置接口,在srcs数组里增加HelloWorld.aidl的路径地址即可:

1
2
3
4
5
6
7
8
9
10
11
java_defaults {
name: "framework-defaults",
installable: true,

srcs: [
...
"core/java/android/app/IAlarmManager.aidl",
"core/java/android/app/HelloWorld.aidl",
...
],
}

编写和注册HelloWorldService

配置常量。在编写服务之前需要在Context.java里配置常量,参照ALARM_SERVICE,进行如下配置。

1
2
3
4
5
6
7
8
9
10
// 定义常量
public static final String HELLO_WORLD_SERVICE = "hello_world";

// 将常量添加到注解值列表中
@StringDef(suffix = { "_SERVICE" }, value = {
...
HELLO_WORLD_SERVICE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ServiceName {}

编写服务。参考AlarmManagerService ,目录: /frameworks/base/services/core/java/com/android/server

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
package com.android.server;

import android.app.IHelloWorld;
import android.content.Context;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;

public class HelloWorldService extends SystemService{
/**
* Initializes the system service.
* <p>
* Subclasses must define a single argument constructor that accepts the context
* and passes it to super.
* </p>
*
* @param context The system server context.
*/
public HelloWorldService(Context context) {
super(context);
}

@Override
public void onStart() {
// 之前已经在Context中定义过常量
publishBinderService(Context.HELLO_WORLD, mService);
}

private final IBinder mService = new IHelloWorld.Stub() {
private static final String TAG = "HelloWorldService";
@Override
public void printHello() throws RemoteException {
Slog.i(TAG, "Hello, World!");
}
};
}

注册HelloWorldService服务。在SystemServer.java里向服务管理者注册服务。

目录: /frameworks/base/services/java/com/android/server/SystemServer.java

1
2
3
4
5
6
7
8
9
10
11
12
private void startOtherServices() {
...
traceBeginAndSlog("StartAlarmManagerService");
mSystemServiceManager.startService(new AlarmManagerService(context));
traceEnd();

traceBeginAndSlog("StartHelloWorldService");
// 此处实例化并注册HelloWorldService
mSystemServiceManager.startService(new HelloWorldService(context));
traceEnd();
...
}

编写和注册HelloWorldManager

编写HelloWorldManager。参考AlarmManager编写客户端的HelloWorldManager,基于此应用开发者可以使用HelloWorldService。

目录:/frameworks/base/core/java/android/app

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package android.app;

import android.annotation.SystemService;
import android.content.Context;

@SystemService(Context.HELLO_WORLD)
public class HelloWorldManager {
private static final String TAG = "HelloWorldManager";
private final IHelloWorld mService;
HelloWorldManager(IHelloWorld mService) {
this.mService = mService;
}

public void printHello() {
try {
mService.printHello();
} catch (Exception e) {
e.printStackTrace();
}
}
}

注册ServiceFetcher。要利用ContextImpl.getSystemService(String name) 获取服务的Manager,需要首先在SystemServiceRegistry里注册相应的ServiceFetcher

1
2
3
4
5
6
7
8
9
10
11
12
13
14
final class SystemServiceRegistry {
static {
...
registerService(Context.HELLO_WORLD, HelloWorldManager.class,
new CachedServiceFetcher<HelloWorldManager>() {
@Override
public HelloWorldManager createService(ContextImpl ctx) throws ServiceNotFoundException {
IBinder b = ServiceManager.getServiceOrThrow(Context.HELLO_WORLD);
IHelloWorld service = IHelloWorld.Stub.asInterface(b);
return new HelloWorldManager(service);
}});
...
}
}

配置SELinux权限

在system/sepolicy 目录下的service.te 和 service_contexts 中配置 HelloWorldService的权限。TODO,待详细了解

编译和烧录

编译Android系统,并烧录到实机设备或虚拟设备中:

1
$ m update-api

编写APP并验证

将系统编译出的class.jar导入到工程中,编写APP,获取服务并调用服务的方法。

在主Activity的onCreate()里加入如下两代码:

1
2
3
4
5
protected void onCreate(Bundle savedInstanceState) {
...
HelloWorldManager hwm = (HelloWorldManager)getSystemService(Context.HELLO_WORLD);
hwm.printHW();
}

运行APP并查看Log

参考