实战Android Framework: 新增一个系统服务

系统版本: Ubuntu 22.04 lts

AOSP分支: android-16.0.0_r4

本文将介绍如何在AOSP16中新增一个Java层的系统服务

一 创建功能发布标志

在最新的AOSP开发中,Google推荐使用功能发布标志来进行新功能的开发和迭代,具体可以查看这里:

功能发布标志概览

首先我们先创建一个功能发布标志,由于我们的服务将创建在android.os包下,所以我们使用现有的aconfig文件即可,如果希望使用自定义的aconfig文件,可以在上面的链接中查看如何创建自定义文件并修改Android BP文件使自定义aconfig文件生效。

打开AOSP16/frameworks/base/core/java/android/os/flags.aconfig,声明aconfig标志:

Aconfig 复制代码
flag {
    name: "jyc_battery_service_enabled"
    namespace: "jyc_power"
    description: "check battery status"
    bug: "none"
    is_exported: true
}

之后打开AOSP16/build/release/aconfig/trunk_staging/android.os目录,创建新文件jyc_battery_service_enabled_flag_values.textproto,并写入如下内容:

Aconfig 复制代码
flag_value {
  package: "android.os"
  name: "jyc_battery_service_enabled"
  state: ENABLED
  permission: READ_WRITE
}

最后由于我们新增了aconfig,所以需要部分编译一下:

shell 复制代码
. build/envsetup.sh
lunch aosp_cf_x86_64_phone-trunk_staging-userdebug
m update-api

这时,在Java代码中,就已经可以android.os包下找到对应方法,并且能看到声明的发布标志:

Java 复制代码
android.os.Flags.jycBatteryServiceEnabled()
android.os.Flags.FLAG_JYC_BATTERY_SERVICE_ENABLED

二 新建AIDL文件

打开/AOSP16/frameworks/base/core/java/android/os,新建文件夹jycservice,并创建文件IJYCBatteryService.aidl:

Java 复制代码
package android.os.jycservice;

/** @hide **/
interface IJYCBatteryService {
    int getBattery();
}

之后进行编译:

Shell 复制代码
m framework-minus-apex

三 创建Service

打开AOSP16/frameworks/base/core/java/android/content/Context.java,新增:

Java 复制代码
/**
 * @hide
 */
@FlaggedApi(android.os.Flags.FLAG_JYC_BATTERY_SERVICE_ENABLED)
@SystemApi
public static final String JYC_BATTERY_SERVICE = "jyc_battery";

打开AOSP16/frameworks/base/services/core/java/com/android/server,创建文件夹jycservice,并在此文件夹下创建JYCBatteryService.java:

Java 复制代码
package com.android.server.jycservice;

import android.annotation.FlaggedApi;
import android.content.Context;
import android.os.BatteryManagerInternal;
import android.os.jycservice.IJYCBatteryService;

import com.android.server.LocalServices;
import com.android.server.SystemService;

@FlaggedApi(android.os.Flags.FLAG_JYC_BATTERY_SERVICE_ENABLED)
public class JYCBatteryService extends IJYCBatteryService.Stub {
    public static final String SERVICE_TAG = "jyc_battery";

    private Context mContext;

    public JYCBatteryService(Context context) {
        this.mContext = context;
    }

    public static final class Lifecycle extends SystemService {
        private JYCBatteryService mService;

        public Lifecycle(Context context) {
            super(context);
        }

        @Override
        public void onStart() {
            mService = new JYCBatteryService(getContext());
            publishBinderService(Context.JYC_BATTERY_SERVICE, mService);
        }
    }

    @Override
    public int getBattery() {
        BatteryManagerInternal bmi = LocalServices.getService(BatteryManagerInternal.class);
        if (bmi != null) {
            return bmi.getBatteryLevel();
        }
        return -1;
    }
}

四 注册Service

打开AOSP16/frameworks/base/services/java/com/android/server/SystemServer.java,在startOtherServices方法中,添加:

Java 复制代码
/* Add JYCBatteryService */
if (android.os.Flags.jycBatteryServiceEnabled()) {
    t.traceBegin("StartJYCBatteryService");
    mSystemServiceManager.startService(JYCBatteryService.Lifecycle.class);
    t.traceEnd();
}
/* End Add JYCBatteryService */

五 创建对应的Manager

如果我们的Service需要开放给系统App或第三方App使用,那么与其他系统服务一样,需要一个Service对应的ServiceManager。 在AOSP16/frameworks/base/core/java/android/os下,创建文件夹jycservice,并新增文件JycBatteryManager.java:

Java 复制代码
package android.os.jycservice;

import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.SystemService;
import android.content.Context;
import android.os.RemoteException;
import android.util.Log;

@SystemService(Context.JYC_BATTERY_SERVICE)
@FlaggedApi(android.os.Flags.FLAG_JYC_BATTERY_SERVICE_ENABLED)
public class JycBatteryManager {
    private static final String TAG = "JYCBatteryManager";
    private final Context mContext;
    private final IJYCBatteryService mService;

    /** @hide **/
    @FlaggedApi(android.os.Flags.FLAG_JYC_BATTERY_SERVICE_ENABLED)
    public JycBatteryManager(@NonNull Context context, @NonNull IJYCBatteryService service) {
        mContext = context;
        mService = service;
    }

    /**
     * 获取当前电量
     */
    @FlaggedApi(android.os.Flags.FLAG_JYC_BATTERY_SERVICE_ENABLED)
    public int getBatteryLevel() {
        try {
            return mService.getBattery();
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in getBatteryLevel", e);
            return -1;
        }
    }
}

六 注册Manager

打开AOSP16/frameworks/base/core/java/android/app/SystemServiceRegistry.java,在registerServices方法中,新增注册逻辑:

Java 复制代码
if (android.os.Flags.jycBatteryServiceEnabled()) {
    registerService(Context.JYC_BATTERY_SERVICE, JycBatteryManager.class,
        new CachedServiceFetcher<JycBatteryManager>() {
            @Override
            public JycBatteryManager createService(ContextImpl ctx) throws ServiceNotFoundException {
                IBinder b = ServiceManager.getServiceOrThrow(Context.JYC_BATTERY_SERVICE);
                IJYCBatteryService service = IJYCBatteryService.Stub.asInterface(b);
                return new JycBatteryManager(ctx.getOuterContext(), service);
            }});
}

由于我们新增了Service并创建了对应的manager,所以我们需要更新:

shell 复制代码
m update-api

七 配置Selinux

在Android系统中,我们的系统服务必须配置相应的selinux权限,才能生效。 打开AOSP16/system/sepolicy/private/service.te,新增如下代码:

shell 复制代码
###
### JYC Services
###
type jyc_battery_service, app_api_service, system_api_service, system_server_service, service_manager_type;

接着打开AOSP16/system/sepolicy/private/service_contexts,新增:

bash 复制代码
# JYC Service
jyc_battery                               u:object_r:jyc_battery_service:s0

然后打开AOSP16/system/sepolicy/private/system_server.te,新增:

scss 复制代码
# Add JYC Service
add_service(system_server, jyc_battery_service)

最后打开AOSP16/system/sepolicy/private/untrusted_app_all.te,新增配置允许第三方App访问我们的服务:

ini 复制代码
# Allow Other App Can Find JYCBatteryService
allow untrusted_app jyc_battery_service:service_manager find;

最后进行编译:

复制代码
m

八 验证服务

编译成功之后,运行:

Shell 复制代码
launch_cvd --daemon

等待启动成功之后,运行命令查找服务:

Shell 复制代码
adb shell service list | grep jyc_battery

之后我们会看到输出:

Shell 复制代码
190	jyc_battery: [android.os.jycservice.IJYCBatteryService]

然后我们可以尝试调用Service中的方法:

Shell 复制代码
adb shell service call jyc_battery 1

之后可以看到输出:

Shell 复制代码
Result: Parcel(	00000000 00000055   '....U...')
相关推荐
火山上的企鹅1 小时前
Codex实战:APP远程升级服务搭建(五)App端远程升级接入
android·服务器·远程升级·qgc
BreezeDove2 小时前
【Android】Flutter3.35项目启动超时问题
android·flutter
故渊at2 小时前
第十四板块:Android 硬件抽象与安全加固 | 第三十四篇:Hardware Composer (HWC) 与 显示安全(HDCP)
android·安全·composer·安全加固·hwc·硬件抽象
KIO no way2 小时前
AI内容编排是什么_聊聊CSDN_AI数字营销背后的分发逻辑
android·人工智能
故渊at2 小时前
第十四板块:Android 硬件抽象与安全加固 | 第三十三篇:Verified Boot 与 硬件信任链(Trusty TEE)
android·安全·信任链·verified
Tangyuewei2 小时前
我用 AI 辅助开发了一个发型 App,然后打包成了 APK
android·人工智能·ai编程
程序课代表3 小时前
Android源码分析挖掘(二) fork大师zygote进程
android·zygote
帅次3 小时前
Android 16(API Level 36)Activity 启动流程源码级解析
android·framework·源码解析·activity启动流程·android 16
chian-ocean3 小时前
Microi吾码:从零到服装ERP:低代码打造企业级系统的实战之旅
android·低代码·rxjava