AOSP-Framework自定义系统服务

我们开发过程中常见的ActivityManagerService,WindowManagerService,PackageManagerService等等都属于系统服务,运行于SystemServer进程,并且向ServiceManager进程注册了Binder以便其他进程获取binder与对应的服务进行通信。同样,在AOSP中我们也可以加入我们自定义的系统服务。

增加自定义服务

AndroidStudio导入AOSP源码后,使用studio编写相关代码。

编写服务接口aidl

frameworks/base/core/java/android/app目录下创建ITaurusManager.aidl文件

1
2
3
4
5
6
7
8
9
10
11
12
//ITaurusManager.aidl
package android.app;

/**
* System private API for talking with the activity manager service. This
* provides calls from the application back to the activity manager.
*
* {@hide}
*/
interface ITaurusManager {
String request(String msg);
}

Context中定义服务的常量名

frameworks/base/core/java/android/content/Context.java中加入常量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//......
/** @hide */
@StringDef(suffix = { "_SERVICE" }, value = {
POWER_SERVICE,
//@hide: POWER_STATS_SERVICE,
WINDOW_SERVICE,
LAYOUT_INFLATER_SERVICE,
ACCOUNT_SERVICE,
ACTIVITY_SERVICE,
TAURUS_SERVICE,
ALARM_SERVICE,
//......
})
@Retention(RetentionPolicy.SOURCE)
public @interface ServiceName {}

/**
* TaurusService
*/
public static final String TAURUS_SERVICE="taurus";

//......

创建暴露给外部调用的Manager类TaurusManager

如同我们使用ActivityManager一样,我们需要一个自己的Manager

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

import android.annotation.Nullable;
import android.annotation.SystemService;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Singleton;

@SystemService(Context.TAURUS_SERVICE)
public class TaurusManager {

/**
* @hide
*/
public TaurusManager(){

}

@UnsupportedAppUsage
private static final Singleton<ITaurusManager> iTaurusManagerSingleton
= new Singleton<ITaurusManager>() {
@Override
protected ITaurusManager create() {
final IBinder b = ServiceManager.getService(Context.TAURUS_SERVICE);
final ITaurusManager im = ITaurusManager.Stub.asInterface(b);
return im;
}
};

/**
* @hide
*/
public static ITaurusManager getService(){
return iTaurusManagerSingleton.get();
}

//相当于aidl的代理方法
@Nullable
public String request( @Nullable String msg) {
try {
return getService().request(msg);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}

}

创建服务的具体实现类即aidl接口的实现类TaurusManagerService

frameworks/base/services/core/java/com/android/service/taurus 中编写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.android.server.taurus;

import android.os.RemoteException;
import android.app.ITaurusManager;

/**
* TaurusManagerService
*/
public class TaurusManagerService extends ITaurusManager.Stub{

@Override
public String request(String msg) throws RemoteException{
return "TaurusManagerService receive data : " + msg;
}

}

ServiceManager中注册Binder实例

frameworks/base/services/java/com/android/server/SystemServer.java中 注册系统服务

1
2
3
4
5
6
import com.android.server.taurus.TaurusManagerService;
private void startOtherServices(){
//......
ServiceManager.addService(Context.TAURUS_SERVICE,new TaurusManagerService());
//......
}

SystemServiceRegistry中注册服务获取器

为什么要在这里注册?

通过ActivityManager的获取,我们追溯一下。

使用ActivityManager时

1
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);

我们追溯到ContextImpl中的getSystemService方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//......
@Override
public Object getSystemService(String name) {
if (vmIncorrectContextUseEnabled()) {
// Check incorrect Context usage.
if (WINDOW_SERVICE.equals(name) && !isUiContext()) {
final String errorMessage = "Tried to access visual service "
+ SystemServiceRegistry.getSystemServiceClassName(name)
+ " from a non-visual Context:" + getOuterContext();
final String message = "WindowManager should be accessed from Activity or other "
+ "visual Context. Use an Activity or a Context created with "
+ "Context#createWindowContext(int, Bundle), which are adjusted to "
+ "the configuration and visual bounds of an area on screen.";
final Exception exception = new IllegalAccessException(errorMessage);
StrictMode.onIncorrectContextUsed(message, exception);
Log.e(TAG, errorMessage + " " + message, exception);
}
}
return SystemServiceRegistry.getSystemService(this, name);
}
//......

看最后return的代码,是从SystemServiceRegistry中进行获取的。所以,我们需要在SystemServiceRegistry中进行注册获取器。

frameworks/base/core/java/android/app/SystemServiceRegistry.java的静态代码块中增加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
//......
static {
registerService(Context.TAURUS_SERVICE, TaurusManager.class,
new CachedServiceFetcher<TaurusManager>() {
@Override
public TaurusManager createService(ContextImpl ctx) throws ServiceNotFoundException {
return new TaurusManager();
}
});
//......
}
//......

配置SELinux权限

system/sepolicy/prebuilts/api/31.0/private/system/sepolicy/private/ 目录下,分别修改:service_contexts、service.te、untrusted_app_all.te

service_contexts

1
2
3
4
5
//......
activity u:object_r:activity_service:s0
#配置自定义服务selinux角色
taurus u:object_r:taurus_service:s0\
//......

service.te

1
2
#配置自定义服务类型
type taurus_service, app_api_service, ephemeral_app_api_service,system_server_service,service_manager_type;

untrusted_app_all.te

1
2
#允许所有app使用自定义服务
allow untrusted_app_all taurus_service:service_manager find;

注意:两个目录下文件需要一致,否则报错,如:
Files system/sepolicy/prebuilts/api/31.0/private/untrusted_app_all.te and
system/sepolicy/private/untrusted_app_all.te differ
ninja failed with: exit status 1

更新并编译

在终端中操作以下命令

1
2
3
4
5
6
# 更新api
make update-api
# 编译
m
#运行模拟器
emulator

模拟器启动后,可以通过adb shell去查看服务是否存在

1
2
3
jia@jia-virtual-machine:~/AOSP/aosp$ adb shell service list| grep taurus
#输出: 表示成功加入自定义服务
102 taurus: [android.app.ITaurusManager]

遇到的错误

由于Android12编译时,开启了lint检查,在Android12新增系统服务后,执行update-api过程中遇到如下问题:

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
out/srcjars/android/app/ITaurusManager.java:135: error: Methods calling system APIs should
rethrow `RemoteException` as `RuntimeException` (but do not list it in the throws clause)
[RethrowRemoteException]
out/srcjars/android/app/ITaurusManager.java:135: error: Missing nullability on method
`request` return [MissingNullability]
out/srcjars/android/app/ITaurusManager.java:135: error: Missing nullability on parameter
`msg` in method `request` [MissingNullability]
out/srcjars/android/app/ITaurusManager.java:11: error: Methods calling system APIs should
rethrow `RemoteException` as `RuntimeException` (but do not list it in the throws clause)
[RethrowRemoteException]
out/srcjars/android/app/ITaurusManager.java:11: error: Missing nullability on method
`request` return [MissingNullability]
out/srcjars/android/app/ITaurusManager.java:11: error: Missing nullability on parameter
`msg` in method `request` [MissingNullability]
out/srcjars/android/app/ITaurusManager.java:15: error: Missing nullability on method
`asBinder` return [MissingNullability]
out/srcjars/android/app/ITaurusManager.java:20: error: Raw AIDL interfaces must not be
exposed: Stub extends Binder [RawAidl]
out/srcjars/android/app/ITaurusManager.java:28: error: Missing nullability on method
`asInterface` return [MissingNullability]
out/srcjars/android/app/ITaurusManager.java:32: error: Missing nullability on parameter
`obj` in method `asInterface` [MissingNullability]
out/srcjars/android/app/ITaurusManager.java:43: error: Missing nullability on method
`asBinder` return [MissingNullability]
out/srcjars/android/app/ITaurusManager.java:47: error: Methods calling system APIs should
rethrow `RemoteException` as `RuntimeException` (but do not list it in the throws clause)
[RethrowRemoteException]
out/srcjars/android/app/ITaurusManager.java:47: error: Missing nullability on parameter
`data` in method `onTransact` [MissingNullability]
out/srcjars/android/app/ITaurusManager.java:47: error: Missing nullability on parameter
`reply` in method `onTransact` [MissingNullability]
out/srcjars/android/app/ITaurusManager.java:117: error: Missing nullability on parameter
`impl` in method `setDefaultImpl` [MissingNullability]
out/srcjars/android/app/ITaurusManager.java:130: error: Missing nullability on method
`getDefaultImpl` return [MissingNullability]
frameworks/base/core/java/android/app/TaurusManager.java:15: error: Managers must always be
obtained from Context; no direct constructors [ManagerConstructor]
frameworks/base/core/java/android/app/TaurusManager.java:20: error: Missing nullability on
method `getService` return [MissingNullability]Error: metalava detected the following
problems:
out/srcjars/android/app/ITaurusManager.java:135: error: Methods calling system APIs should
rethrow `RemoteException` as `RuntimeException` (but do not list it in the throws clause)
[RethrowRemoteException]
out/srcjars/android/app/ITaurusManager.java:135: error: Missing nullability on method
`request` return [MissingNullability]
out/srcjars/android/app/ITaurusManager.java:135: error: Missing nullability on parameter
`msg` in method `request` [MissingNullability]
out/srcjars/android/app/ITaurusManager.java:11: error: Methods calling system APIs should
rethrow `RemoteException` as `RuntimeException` (but do not list it in the throws clause)
[RethrowRemoteException]
out/srcjars/android/app/ITaurusManager.java:11: error: Missing nullability on method
`request` return [MissingNullability]
out/srcjars/android/app/ITaurusManager.java:11: error: Missing nullability on parameter
`msg` in method `request` [MissingNullability]
out/srcjars/android/app/ITaurusManager.java:15: error: Missing nullability on method
`asBinder` return [MissingNullability]
out/srcjars/android/app/ITaurusManager.java:20: error: Raw AIDL interfaces must not be
exposed: Stub extends Binder [RawAidl]
out/srcjars/android/app/ITaurusManager.java:28: error: Missing nullability on method
`asInterface` return [MissingNullability]
out/srcjars/android/app/ITaurusManager.java:32: error: Missing nullability on parameter
`obj` in method `asInterface` [MissingNullability]

仔细查看日志,发现问题主要由TaurusManager以及aidl接口生成的ITaurusManager报错。主要是因为改加@hide与@Nullable注解的地方没有加上注解。

使用自定义服务

修改SDK配置

拷贝出aosp下编译的SDK的jar文件

通过make sdk生成SDK的jar包

out/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/classes.jar路径下。

配置studio使用的SDK

在SDK/platforms 目录下复制一份android-31(Android12)目录并改名为:android-31.car

image

将classes.jar拷贝至该目录,删除原有的android.jar,重命名classes.jar为android.jar。

image

同样,在SDK/sources 目录下复制一份android-31(Android12)目录并改名为:android-31.car

修改SDK/platforms/android-31.car目录下的source.properties为:

1
2
3
4
5
6
7
8
9
10
11
12
13
#指定自定义平台标识为311(可以是任意数字,但为了与原生标识区分,请使用三位数)
#修改:
Pkg.Desc=Android SDK Platform 311
Pkg.UserSrc=false
#修改:
Platform.Version=311
Platform.CodeName=
Pkg.Revision=1
#修改:
AndroidVersion.ApiLevel=311
Layoutlib.Api=15
Layoutlib.Revision=1
Platform.MinToolsRev=22

最后将SDK/platforms/package.xml中最后的内容改为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<localPackage path="platforms;android-311" obsolete="false">
<type-details xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="ns5:platformDetailsType">
<!-- 修改 -->
<api-level>311</api-level>
<codename></codename>
<layoutlib api="15"/>
</type-details>
<revision>
<major>1</major>
</revision>
<!-- 修改 -->
<display-name>Android SDK Platform 311</display-name>
<uses-license ref="android-sdk-license"/>
</localPackage>

修改SDK/sources/android-31.car目录下的source.properties为:

1
2
3
Pkg.UserSrc=false
Pkg.Revision=1
AndroidVersion.ApiLevel=311

修改SDK/sources/android-31.car目录下的package.xml最后的为:

1
2
3
4
5
6
7
8
9
10
11
12
13
<localPackage path="sources;android-311" obsolete="false">
<type-details xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="ns11:sourceDetailsType">
<api-level>311</api-level>
<codename></codename>
<base-extension>true</base-extension>
</type-details>
<revision>
<major>1</major>
</revision>
<display-name>Sources for Android 311</display-name>
<uses-license ref="android-sdk-license"/>
</localPackage>

编写app使用自定义服务

创建测试应用TestService

修改gradle配置

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
android {
namespace 'com.example.testservice'
//指定为修改的SDK版本
compileSdk 311

defaultConfig {
applicationId "com.example.testservice"
minSdk 24
//指定为修改的SDK版本
targetSdk 311
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

修改后同步一下gradle配置。

编写调用自定义服务的测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.example.testservice;

import androidx.appcompat.app.AppCompatActivity;

import android.app.TaurusManager;
import android.content.Context;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

TaurusManager taurusManager = (TaurusManager) getSystemService(Context.TAURUS_SERVICE);

String result = taurusManager.request("AppRequest");
Toast.makeText(this, result, Toast.LENGTH_SHORT).show();

}
}

可正常引用到SDK中添加的自定义服务类。安装到aosp下编译出的模拟器上,运行即可正常调用。