前言
我们在开发当中难免要自定义一个系统服务去获取系统数据或者操作,常见的AMS、PWS、WMS等等都是系统服务,运行于system_server进程,并且向servicemanager进程注册其Binder以便其他进程获取binder与对应的服务进行通信。为了新增自定义系统服务,我们可以参考AMS等原生系统服务编写如下文件:
1、AIDL文件:生成Binder类,其中Stub即为Binder的服务端;
2、XXManagerService:系统服务类,继承自Stub;
3、XXManager:封装了AIDL接口方法的类,相当于Binder客户端(Proxy),其他进程通过此类完成与系统服务的通信。
一、增加系统服务
1.1 AIDL
在frameworks/base/core/java/android/app/service中编写IZxxManager.aidl
package android.app;
/**
* {@hide}
*/
interface IZxxManager {
String request(String msg);
}
1.2 系统服务
/frameworks/base/services/core/java/com/android/server/zxx/ZxxManagerService.java
package com.android.server.zxx;
import android.app.IZxxManager;
import android.os.RemoteException;
public class ZxxManagerService extends IZxxManager.Stub {
@Override
public String request(String msg) throws RemoteException {
return "ZxxManagerService接收数据:"+msg;
}
}
注意:如果以当前案例的方式新增自定义系统服务,因为SystemServiceRegistry 中需要使用到com.zxx
下的类,为了让其获取此包下类的引用,需要配置:build/core/tasks/check_boot_jars/package_whitelist.txt ,加入:com.zxx..*
。否则会因为无法获取类引用而编译报错!
dalvik..*
libcore..*
android..*
com.android..*
com.zxx..*
1.3 添加上下文常量
/frameworks/base/core/java/android/context/Context.java
添加 public static final String ZXX_SERVICE = "zxx";
@StringDef(suffix = { "_SERVICE" }, value = {
POWER_SERVICE,
//@hide: POWER_STATS_SERVICE,
WINDOW_SERVICE,
LAYOUT_INFLATER_SERVICE,
ACCOUNT_SERVICE,
ACTIVITY_SERVICE,
ZXX_SERVICE,
1.4 客户端代理
/frameworks/base/core/java/android/app/ZxxManager.java
package android.app;
import android.annotation.SystemService;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Singleton;
import android.os.ServiceManager;
import android.annotation.Nullable;
import android.app.IZxxManager;
//代表系统服务
@SystemService(Context.ZXX_SERVICE)
public class ZxxManager {
/**
* @hide 只能系统调用
*/
public ZxxManager() {
}
/**
* @hide 只能系统调用
*/
public static IZxxManager getServerice(){
return I_ZXX_MANAGER_SINGLETON.get();
}
//限制framework中的定义无法被外部应用访问
@UnsupportedAppUsage
private static final Singleton I_ZXX_MANAGER_SINGLETON =
new Singleton() {
@Override
protected IZxxManager create() {
final IBinder b= ServiceManager.getService(Context.ZXX_SERVICE);
final IZxxManager im=IZxxManager.Stub.asInterface(b);
return im;
}
};
@Nullable
public String request(@Nullable String msg){
try{
return getServerice().request(msg);
}catch (RemoteException e){
throw e.rethrowFromSystemServer();
}
}
}
1.5 注册系统服务
1.5.1 SystemServer
1.5.1.1 无生命周期注册
frameworks/base/services/java/com/android/server/SystemServer.java中 startOtherServices方法中注册系统服务
import com.android.server.zxx.ZxxManagerService;
private void startOtherServices(){
//......
ServiceManager.addService(Context.ZXX_SERVICE,new ZxxManagerService());
//......
}
1.5.1.2 有生命周期注册
系统服务需要通过ServiceManager.addService("xx", new XXManagerService);
将自己(Binder Stub)注册进入SM才能够让其他进程利用Binder与之通信。而自定义系统服务如果需要根据系统启动的不同阶段进行不同的处理则需要注册生命周期回调。以AMS为例:
/frameworks/base/services/java/com/android/server/SystemService中启动AMS:
private void startBootstrapServices() {
//...
// Activity manager runs the show.
traceBeginAndSlog("StartActivityManager");
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);
traceEnd();
//...
mActivityManagerService.setSystemProcess();
//...
}
AMS中的setSystemProcess方法的实现为:
public void setSystemProcess() {
//...
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ true,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);
//...
}
setSystemProcess中会完成向SM注册AMS的实现。而在setSystemProcess之前有一段代码:
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
则为注册生命周期监听,ActivityManagerService.Lifecycle就相当于生命周期的回调接口对象,它继承自:
/frameworks/base/services/core/java/com/android/server/SystemService。这个SystemService中主要需要实现两个方法:
-
onStart() :mSystemServiceManager.startService第一时间回调该函数。
-
onBootPhase(int phase) : 系统启动的各个阶段会回调该函数
- SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY:这是一个依赖项,只有DisplayManagerService中进行了对应处理;
- SystemService.PHASE_LOCK_SETTINGS_READY:经过这个引导阶段后,服务才可以接收到wakelock相关设置数据;
- SystemService.PHASE_SYSTEM_SERVICES_READY:经过这个引导阶段 后,服务才可以安全地使用核心系统服务
- SystemService.PHASE_ACTIVITY_MANAGER_READY:经过这个引导阶 段后,服务可以发送广播
- SystemService.PHASE_THIRD_PARTY_APPS_CAN_START:经过这个引导阶段后,服务可以启动第三方应用,第三方应用也可以通过Binder来调用服务。
- SystemService.PHASE_BOOT_COMPLETED:经过这个引导阶段后,说明服务启动完成,这时用户就可以和设备进行交互。
比如AMS中的Lifecycle:
public static final class Lifecycle extends SystemService {
@Override
public void onBootPhase(int phase) {
mService.mBootPhase = phase;
if (phase == PHASE_SYSTEM_SERVICES_READY) {
mService.mBatteryStatsService.systemServicesReady();
mService.mServices.systemServicesReady();
} else if (phase == PHASE_ACTIVITY_MANAGER_READY) {
// 准备广播处理
mService.startBroadcastObservers();
} else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
mService.mPackageWatchdog.onPackagesReady();
}
}
}
在AMS中会处理PHASE_ACTIVITY_MANAGER_READY
,经过这个阶段后,也就是需要在下一个阶段PHASE_THIRD_PARTY_APPS_CAN_START
才可以发送广播。
1.5.2 SystemServiceRegistry
在frameworks/base/core/java/android/app/SystemServiceRegistry.java注册应用系统服务获取器,有一个static块 执行了registerService用于注册
import android.app.ZxxManager;
static{
registerService(Context.ZXX_SERVICE, ZxxManager.class,
new CachedServiceFetcher() {
@Override
public ZxxManager createService(ContextImpl ctx) {
return new ZxxManager();
}});
}
1.6 配置SELinux权限
1.6.1 修改的文件路径有:
system/sepolicy/private/service_contexts;
activity u:object_r:activity_service:s0
zxx u:object_r:zxx_service:s0
system/sepolicy/private/untrusted_app_all.te;
allow untrusted_app zxx_service:service_manager find;
system/sepolicy/public/service.te;
type activity_service, app_api_service, ephemeral_app_api_service, system_server_service, service_manager_type;
type zxx_service, app_api_service, ephemeral_app_api_service, system_server_service, service_manager_type;
注意:system/sepolicy/prebuilt/api/底下也有28.0、29.0、30.0、31.0、32.0、33.0里面的private/public对应的文件也要同样添加以上代码
1.6.2 去除检查权限校准
在system/sepolicy/build/soong/service_fuzzer_bindings.go
var (
ServiceFuzzerBindings = map[string][]string{
...
"activity": EXCEPTION_NO_FUZZER,
"zxx": EXCEPTION_NO_FUZZER,
...
}
)
1.7 更新并编译、刷机
#方式一:更新编译运行
# 更新api
make update-api
# 编译
m
#运行模拟器
emulator
#方式一:更新编译刷机
#编译
make update-api
make –j4
#刷机
adb reboot bootloader
reboot flashall -w
1.8 验证服务是否添加成功
adb shell service list | grep zxx
二、使用自定义服务
2.1 方式一 创建相同的壳类
创建同样的包和类,方法可以不实现,利用双亲委托机制一般只是用来调试自己的服务功能是否正常
package android.app;
public class ZxxManager {
public String request(String msg){
return null;
}
}
2.2 方式二 通过修改SDK配置自定义SDK
make sdk
2.2.1 复制SDK
把正在使用的SDK复制一份并改名为android-33.car,android-33.car中的platforms和sources下的平台同样也复制一份
2.2.2 替换android.jar
将复制出来的原生SDK/platforms中的android.jar用自己编译出的替换
out/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/classes-header.jar
或者
out/target/common/obj/PACKAGING/android_jar_intermediates 目录下面,会生成 android.jar 和 android--stubs-src.jar 两个文件,将这个两个文件替换到Android Studio使用的sdk的对应平台目录下面,我使用的是api33,目录为 platforms/android-66(自定义)/
2.2.3 修改SDK配置
2.2.3.1 source.properties
修改android-33.carplatformsandroid-66source.properties
#指定自定义平台标识为66(可以是任意数字,但为了与原生标识区分)
#修改:
Pkg.Desc=Android SDK Platform 66
Pkg.UserSrc=false
#修改:
Platform.Version=66
Platform.CodeName=
Pkg.Revision=1
#修改:
AndroidVersion.ApiLevel=66
Layoutlib.Api=15
Layoutlib.Revision=1
Platform.MinToolsRev=22
2.2.3.2 package.xml
修改 android-32.carplatformsandroid-321package.xml
66
1
Android SDK Platform 66
2.2.4 配置源码跳转
修改android-33.carsourcesandroid-66目录下的参考第3步source.properties和package.xml文件
2.3 方式三 使用framework.jar
make javac-check-framework
在out/target/common/obj/JAVA_LIBRARIES/framework_intermediates拷贝classes.jar重新命名framework.jar,AS导入jar使用
三、常见问题
1、在system/sepolicy/prebuilt/api/* 底下所以sdk版本的private/public按照1.6的形式所有都给它添加
2、$ANDROID_BUILD_TOP/system/sepolicy/BUILD/soong/service_fuzzer_bindings.go,按activity这种格式,自定义的服务的加进去,就不会检查了
//system/sepolicy/contexts:fuzzer_bindings_test running service:fu
FAILED: out/soong/.intermediates/system/sepolicy/contexts/fuzzer_bindings_test/android_common/timestamp
out/host/linux-x86/bin/fuzzer_bindings_check -s out/soong/.intermediates/system/sepolicy/contexts/plat_service_contexts/android_common/gen/plat_service_contexts -b out/soong/.intermediates/bindings.json && touch out/soong/.intermediates/system/sepolicy/contexts/fuzzer_bindings_test/android_common/timestamp # hash of input list: d6d7c35d085ab532427370293bbe7778939ca920eb7f04227649468b94741599
error: Service 'zxx' is being added, but we have no fuzzer on file for it. Fuzzers are listed at $ANDROID_BUILD_TOP/system/sepolicy/build/soong/service_fuzzer_bindings.go
NOTE: automatic service fuzzers are currently not supported in Java (b/232439254) and Rust (b/164122727). In this case, please ignore this for now and add an entry for yournew service in service_fuzzer_bindings.go
If you are writing a new service, it may be subject to attack from other potentially malicious processes. A fuzzer can be written automatically by adding these things:
- a cc_fuzz Android.bp entry
- a main file that constructs your service and calls 'fuzzService'
An examples can be found here:
- $ANDROID_BUILD_TOP/hardware/interfaces/vibrator/aidl/default/fuzzer.cpp
- https://source.android.com/docs/core/architecture/aidl/aidl-fuzzing
This is only ~30 lines of configuration. It requires dependency injection for your service which is a good practice, and (in AOSP) you will get bugs automatically filed on you. You will find out about issues without needing to backport changes years later, and the system will automatically find ways to reproduce difficult to solve issues for you.
This error can be bypassed by adding entry for new service in $ANDROID_BUILD_TOP/system/sepolicy/build/soong/service_fuzzer_bindings.go
- Android Fuzzing and Security teams