一、需求分析
1.1 功能需求
基于提供的 patch 文件,本次需求是在 Android 13 的 AOSP 源代码中创建一个自定义的 MyService,并实现以下功能:
| 需求点 | 描述 | 实现位置 |
|---|---|---|
| 创建自定义 Service | 实现 IMyService AIDL 接口 |
MyService.java |
| 开机启动注册 | 在 SystemServer 中注册服务 |
SystemServer.java |
| 开机动画开始调用 | 开机动画开始时调用 doSomething()
|
WindowManagerService.java |
| 开机动画结束调用 | 开机动画结束时调用 doSomething()
|
WindowManagerService.java |
| SELinux 权限配置 | 配置服务注册所需的 SELinux 权限 |
service.te / system_server.te / service_contexts
|
1.2 技术架构
┌─────────────────────────────────────────────────────────────────┐
│ SystemServer │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ startOtherServices() │ │
│ │ └── ServiceManager.addService("myservice", myService) │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────┬───────────────────────────────────┘
│ Binder IPC
▼
┌─────────────────────────────────────────────────────────────────┐
│ WindowManagerService │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ performEnableScreen() │ │
│ │ ├── 开机动画开始 → getMyService().doSomething() │ │
│ │ └── 开机动画结束 → getMyService().doSomething() │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────┬───────────────────────────────────┘
│ Binder IPC
▼
┌─────────────────────────────────────────────────────────────────┐
│ MyService │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ implements IMyService.Stub │ │
│ │ └── doSomething() → Log.v(TAG, "duxiwei22") │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
二、实现方案
2.1 整体流程
开机启动
│
▼
SystemServer.startOtherServices()
│
├── 创建 MyService 实例
│
└── ServiceManager.addService("myservice", myService)
│
▼
WindowManagerService.performEnableScreen()
│
├── 设置 service.bootanim.exit=1
│ │
│ ▼
│ 开机动画开始
│ │
│ └── getMyService().doSomething()
│
└── 开机动画完成
│
└── getMyService().doSomething()
三、代码修改详解
3.1 Framework 修改 (fwk.txt)
3.1.1 Android.bp 构建配置
文件: frameworks/base/services/core/Android.bp
修改目的: 将自定义的 AIDL 文件添加到编译系统中。
filegroup {
name: "services.core-sources-ms-aidls",
srcs: [
"java/com/android/server/ms/*.aidl",
],
path: "java",
visibility: ["//frameworks/base/services"],
}
java_library_static {
name: "services.core.unboosted",
srcs: [
":services.core-sources-ms-aidls", // 添加 AIDL 文件组
// ... 其他源文件
],
}
说明:
-
filegroup定义了 AIDL 文件集合 -
path: "java"指定相对路径 - 在
services.core.unboosted模块中引用该文件组
3.1.2 MyService 实现类
文件: frameworks/base/services/core/java/com/android/server/ms/MyService.java
修改目的: 实现自定义服务的业务逻辑。
package com.android.server.ms;
import android.util.Log;
public class MyService extends IMyService.Stub {
String TAG = "MyService";
private int mValue;
@Override
public void doSomething() {
// 实现自定义功能
Log.v(TAG, "duxiwei22");
}
}
说明:
- 继承
IMyService.Stub实现 AIDL 接口 -
doSomething()方法是对外暴露的服务方法 - 实现简单的日志输出功能
3.1.3 WindowManagerService 集成
文件: frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
修改目的: 在开机动画开始和结束时调用 MyService.doSomething()。
关键代码:
// 1. 添加导入
import com.android.server.ms.IMyService;
// 2. 添加成员变量
boolean mBootAnimationStartNotified = false;
// 3. 添加服务获取方法
private IMyService getMyService() {
IBinder binder = ServiceManager.getService("myservice");
if (binder != null) {
return IMyService.Stub.asInterface(binder);
}
return null;
}
// 4. 开机动画开始时调用
if (!mBootAnimationStartNotified) {
IMyService myService = getMyService();
if (myService != null) {
try {
myService.doSomething();
} catch (RemoteException e) {
Slog.e(TAG_WM, "Failed to call doSomething on boot animation start", e);
}
}
mBootAnimationStartNotified = true;
}
// 5. 开机动画结束时调用
EventLogTags.writeWmBootAnimationDone(SystemClock.uptimeMillis());
IMyService myService = getMyService();
if (myService != null) {
try {
myService.doSomething();
} catch (RemoteException e) {
Slog.e(TAG_WM, "Failed to call doSomething on boot animation end", e);
}
}
说明:
-
getMyService()通过ServiceManager获取服务引用 - 开机动画开始时机:设置
service.bootanim.exit=1之前 - 开机动画结束时机:调用
writeWmBootAnimationDone()之后
3.1.4 SystemServer 注册服务
文件: frameworks/base/services/java/com/android/server/SystemServer.java
修改目的: 在系统启动时注册 MyService。
// 1. 添加导入
import com.android.server.ms.MyService;
// 2. 在 startOtherServices() 中注册服务
t.traceBegin("myservice");
MyService myService = new MyService();
ServiceManager.addService("myservice", (IBinder) myService);
t.traceEnd();
说明:
- 在
WindowManagerService启动之前注册服务 - 使用
ServiceManager.addService()将服务添加到全局服务管理器
3.2 SELinux 权限配置 (selinux.txt)
3.2.1 服务类型定义
文件: system/sepolicy/private/service.te
type myservice, system_server_service, service_manager_type;
说明:
-
system_server_service属性表示此服务由 system_server 管理 -
service_manager_type属性表示这是一个服务管理器类型
3.2.2 服务上下文映射
文件: system/sepolicy/private/service_contexts
myservice u:object_r:myservice:s0
说明:
- 将服务名称
myservice映射到安全上下文u:object_r:myservice:s0 - 格式:
<服务名> <安全上下文>
3.2.3 服务注册权限
文件: system/sepolicy/private/system_server.te
add_service(system_server, myservice)
说明:
-
add_service()宏展开后会生成:allow system_server myservice:service_manager { add find };neverallow { domain -system_server } myservice:service_manager add;
- 允许
system_server注册和查找myservice - 禁止其他域注册
myservice
3.2.4 预构建文件同步
说明: 所有修改需要同步到 prebuilts/api/33.0/private/ 目录,保持公共 API 版本一致。
四、编译与测试
4.1 编译步骤
# 1. 初始化编译环境
source build/envsetup.sh
lunch coral-userdebug # 选择目标设备
# 2. 编译 SELinux 策略
m sepolicy
# 3. 编译 Framework 服务
m services.core
# 4. 完整编译(可选)
make -j$(nproc)
4.2 推送文件
# 1. 推送 SELinux 策略文件
adb root
adb remount
adb push out/target/product/coral/system/etc/selinux /system/etc/
# 2. 推送 Framework 服务
adb push out/target/product/coral/system/framework/services.jar /system/framework/services.jar
# 3. 重启设备
adb reboot
4.3 验证方法
# 1. 查看服务是否注册成功
adb shell service list | grep myservice
# 2. 查看日志输出
adb logcat | grep MyService
# 期望输出:
# V/MyService: duxiwei22 (开机动画开始时)
# V/MyService: duxiwei22 (开机动画结束时)
五、关键技术要点
5.1 AIDL 通信机制
-
接口定义:
IMyService.aidl定义了服务接口 -
Stub 实现:
MyService继承IMyService.Stub实现服务端逻辑 -
客户端调用: 通过
IMyService.Stub.asInterface(binder)获取代理对象
5.2 ServiceManager 工作原理
ServiceManager 作为 Binder 上下文管理器:
1. SystemServer 调用 addService() 注册服务
2. WindowManagerService 调用 getService() 获取服务引用
3. 基于 Binder IPC 机制进行进程间通信
5.3 SELinux 安全机制
- 类型强制: 每个服务都有独立的安全类型
-
权限检查: 注册服务需要
add权限 -
上下文映射:
service_contexts文件定义服务名称到安全上下文的映射
5.4 开机动画流程
BootAnimation 进程启动
│
▼
SurfaceFlinger 显示开机动画
│
▼
WindowManagerService.performEnableScreen()
│
├── SystemProperties.set("service.bootanim.exit", "1")
│ │
│ ▼
│ BootAnimation 收到退出信号
│
└── EventLogTags.writeWmBootAnimationDone()
│
▼
屏幕点亮,显示 Launcher
六、文件清单
| 文件路径 | 修改类型 | 说明 |
|---|---|---|
frameworks/base/services/core/Android.bp |
修改 | 添加 AIDL 文件组 |
frameworks/base/services/core/java/com/android/server/ms/MyService.java |
修改 | 服务实现类 |
frameworks/base/services/core/java/com/android/server/ms/IMyService.aidl |
新增 | AIDL 接口定义 |
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java |
修改 | 开机动画回调 |
frameworks/base/services/java/com/android/server/SystemServer.java |
修改 | 服务注册 |
system/sepolicy/private/service.te |
修改 | 服务类型定义 |
system/sepolicy/private/service_contexts |
修改 | 服务上下文映射 |
system/sepolicy/private/system_server.te |
修改 | 服务注册权限 |
system/sepolicy/prebuilts/api/33.0/private/service.te |
修改 | 预构建同步 |
system/sepolicy/prebuilts/api/33.0/private/service_contexts |
修改 | 预构建同步 |
system/sepolicy/prebuilts/api/33.0/private/system_server.te |
修改 | 预构建同步 |
七、注意事项
- SELinux 策略必须完整: 缺少任何一个 SELinux 文件修改都会导致服务注册失败
- 预构建文件必须同步: API 版本目录下的文件也需要同步修改
-
服务名称一致性: Java 代码中的服务名称必须与
service_contexts中的名称一致 - 编译顺序: 先编译 SELinux 策略,再编译 Framework
- 设备分区权限: 需要 root 权限和 remount 系统分区才能推送文件
八、总结
本方案完整实现了在 Android 13 AOSP 中创建自定义 MyService 并在开机动画阶段调用其方法的功能。核心步骤包括:
- 创建 AIDL 接口和服务实现
- 在 SystemServer 中注册服务
- 在 WindowManagerService 中调用服务方法
- 配置 SELinux 安全策略
通过以上步骤,可以实现自定义服务的开机启动和开机动画阶段的回调功能,为系统级功能扩展提供了完整的实现路径。