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

关于Android技术储备

最近几年国内的初级Android程序员已经很多了,但是中高级的Android技术人才仍然稀缺“;这的确不假,今年已经是2023年了,距离Android巅峰时期那会已经过去七八年了,现在想找一个适合的中高级Android工程师的确不容易,一般需要进行大量的面试才能挑选出一个比较满意的。

所以 要学好Android 还是很有必要的,但必须得有一个学习规划。最后大家分享一份全套的Android学习资料,给那些想学习 Android 的小伙伴们一点帮助!

本文适用于:

  • 任何想学习Android开发但不知道从哪里开始的人
  • 也适用于已经开始进行Android开发但想要变得更好的任何人

一、Android所有方向的学习路线

为了成为更好的 Android 开发者,这里为大家提供了总的路线图。它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。如果下面这个学习路线能帮助大家成为一个更好的 Android 开发者,那么我的使命也就完成了:

包括:Android应用开发、系统开发、音视频开发、Flutter开发、小程序开发、UI界面、车载系统开发等等

在这里插入图片描述

二、学习软件

工欲善其事必先利其器。学习Android常用的Android Studio视频教程和Android Studio最新的安装包都在这里了,给大家节省了很多时间。


三、进阶学习视频

我们在学习的时候,往往书籍源码难以理解,阅读困难,这时候视频教程教程是就很适合了,生动形象加上案例实战,科学有趣才能更方便的学习下去。

在这里插入图片描述

四、实战案例

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

在这里插入图片描述

五、经典书籍阅读

阅读Android经典书籍可以帮助读者提高技术水平,开拓视野,掌握核心技术,提高解决问题的能力,同时也可以借鉴他人的经验。对于想要深入学习Android开发的读者来说,阅读Android经典书籍是非常有必要的。

在这里插入图片描述

六、面试资料

我们学习Android必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

图片

请添加图片描述

这份完整版的Android全套学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

猜你喜欢

转载自blog.csdn.net/Coo123_/article/details/133323257