AOSP学习(四)Android13自定义系统服务

前言

我们在开发当中难免要自定义一个系统服务去获取系统数据或者操作,常见的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<IZxxManager> I_ZXX_MANAGER_SINGLETON =
            new Singleton<IZxxManager>() {
                @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<ZxxManager>() {
                    @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
3731683730369.jpg

二、使用自定义服务

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.car\platforms\android-66\source.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.car\platforms\android-321\package.xml

<localPackage path="platforms;android-66" obsolete="false"> 
 <type-details xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:type="ns5:platformDetailsType"> 
 <!-- 修改 --> 
 <api-level>66</api-level> 
 <codename></codename> 
 <layoutlib api="15"/></type-details> 
 <revision> 
 <major>1</major> 
 </revision> 
 <!-- 修改 --> 
 <display-name>Android SDK Platform 66</display-name> 
 <uses-license ref="android-sdk-license"/> 
</localPackage>

2.2.4 配置源码跳转

修改android-33.car\sources\android-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的形式所有都给它添加


3721683728201.jpg

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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,997评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,603评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,359评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,309评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,346评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,258评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,122评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,970评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,403评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,596评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,769评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,464评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,075评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,705评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,848评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,831评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,678评论 2 354

推荐阅读更多精彩内容