添加 Java 系统服务

1. 编写 AIDL

Binder 程序示例之 java 篇我们写了一个 Binder java 服务,不过需要我们手动去执行 Java 程序。今天我们就来看一下怎么添加一个在开机就自启动的 Java 系统服务。

frameworks/base/core/java 目录下创建如下的文件与文件夹:

bash 复制代码
com/yuandaima
└── IJavaHelloService.aidl

其中 IJavaHelloService.aidl 的内容如下:

java 复制代码
package com.yuandaima;

interface IJavaHelloService
{
	void sayhello();
	int sayhello_to(String name);
}

AIDL 在我们自定义的 com/yuandaima 包结构下。

2. 将 AIDL 加入 Android.bp

接着修改 frameworks/base/Android.bp,在 framework-defaults 模块的 srcs 节点中添加 "core/java/android/rice14/com/yuandaima/IJavaHelloService.aidl"

java 复制代码
java_defaults {
    name: "framework-defaults",
    installable: true,

    srcs: [
        //......
        "core/java/com/yuandaima/IJavaHelloService.aidl"
    ]
    //......
}

接着我们可以执行:

bash 复制代码
source build/envsetup.sh
# 自定义 Product rice14-eng
lunch rice14-eng
make update-api

然后查看 Frameworks/base/api/current.txt中查看是否存在对应 IJavaHelloService 接口。

3. 定义 Binder 服务端类

frameworks/base/services/core/java/com 目录下新建如下的目录与文件:

bash 复制代码
yuandaima
└── JavaHelloService.java

其中 JavaHelloService.java:

java 复制代码
package com.yuandaima;

import android.util.Log;

public class JavaHelloService extends IJavaHelloService.Stub {
    private static final String TAG = "JavaHelloService";
    private int cnt1 = 0;
    private int cnt2 = 0;

    public void sayhello() throws android.os.RemoteException {
        cnt1++;
        Log.i(TAG, "sayhello : cnt = "+cnt1);
    }
    
    public int sayhello_to(java.lang.String name) throws android.os.RemoteException {
        cnt2++;
        Log.i(TAG, "sayhello_to "+name+" : cnt = "+cnt2);
        return cnt2;
    }
}

4. 开机启动服务

修改 frameworks/base/services/java/com/android/server/SystemServer.java 文件,在 startOtherServices 方法的最后增加以下代码:

java 复制代码
//import 不要忘了
import com.yuandaima.JavaHelloService;


// add hello service
traceBeginAndSlog("JavaHelloService");
ServiceManager.addService("JavaHelloService", new JavaHelloService());
traceEnd();

5. selinux 配置

接着添加 selinux 配置:

同时修改 system/sepolicy/private 和 system/sepolicy/prebuilts/api/29.0/private 目录下的:

service.te:

bash 复制代码
type JavaHelloServiceType,          system_server_service, service_manager_type;

service_contexts:

bash 复制代码
JavaHelloService                          u:object_r:JavaHelloServiceType:s0

platform_app.te

bash 复制代码
allow platform_app JavaHelloServiceType:service_manager find;

6. 添加 Java 接口白名单

我们新添加了 com/yuandaima Java 软件包,这些包需要在白名单中声明才能被上层 App 访问到:

build/make/core/tasks/check_boot_jars/package_whitelist.txt 中添加如下内容:

bash 复制代码
com\.yuandaima
com\.yuandaima\..*

7. 系统 App 使用系统服务

接着我们就可以在我们的系统 App 中使用我们的自定义的系统服务了:

修改我们在玩转 AOSP 之系统 App 源码添加中添加的系统 App Demo:

Android.bp:

json 复制代码
android_app {
    name: "FirstSystemApp",
    srcs: ["src/**/*.java"],
    resource_dirs: ["res"],
    manifest: "AndroidManifest.xml",
    platform_apis: true,
    sdk_version: "",
    certificate: "platform",
    //去掉 product_specific
    // product_specific: true,
    static_libs: ["androidx.appcompat_appcompat",
                 "com.google.android.material_material",
                 "androidx-constraintlayout_constraintlayout",
                 "lib-lottie"],
}

接着修改自定义 Product 配置文件 device/jelly/rice14/rice14.mk

Makefile 复制代码
PRODUCT_PACKAGES += \
    # ......
    FirstSystemApp
 
PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST += \
    # ......
    /system/app/FirstSystemApp/FirstSystemApp.apk

修改 device/jelly/rice14/FirstSystemApp/src/com/yuandaima/firstsystemapp/MainActivity.java 源码:

java 复制代码
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        try {
            IJavaHelloService service = IJavaHelloService.Stub.asInterface(ServiceManager.getService("JavaHelloService"));
            service.sayhello();
        } catch (Exception e) {
           e.printStackTrace();
        }
       
    }
}

接着我们就可以重新编译系统,启动虚拟机了:

bash 复制代码
source build/envsetup.sh
# 自定义 Product rice14
lunch rice14-eng
make -j32
emulator

接着我们就可以打开我们的 FirstSystemApp 了,然后查看 log:

关于

我叫阿豪,2015 年本科毕业于国防科学技术大学指挥信息系统专业,毕业后从事信息化装备的研发工作,主要研究方向是 Android Framework 与 Linux Kernel。

如果你对 Android Framework 感兴趣或者正在学习 Android Framework,可以关注我的微信公众号,我会持续分享我的学习经验,帮助正在学习的你少走一些弯路。学习过程中如果你有疑问或者你的经验想要分享给大家可以添加我的微信,我拉你进技术交流群。

如果你想系统学习 Anroid Framework 也可以关注我的抖音账号,在主页店铺即可购买付费课程。

相关推荐
大白要努力!24 分钟前
Android opencv使用Core.hconcat 进行图像拼接
android·opencv
天空中的野鸟1 小时前
Android音频采集
android·音视频
小白也想学C2 小时前
Android 功耗分析(底层篇)
android·功耗
曙曙学编程3 小时前
初级数据结构——树
android·java·数据结构
闲暇部落5 小时前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin
诸神黄昏EX7 小时前
Android 分区相关介绍
android
大白要努力!8 小时前
android 使用SQLiteOpenHelper 如何优化数据库的性能
android·数据库·oracle
Estar.Lee8 小时前
时间操作[取当前北京时间]免费API接口教程
android·网络·后端·网络协议·tcp/ip
Winston Wood8 小时前
Perfetto学习大全
android·性能优化·perfetto
Dnelic-11 小时前
【单元测试】【Android】JUnit 4 和 JUnit 5 的差异记录
android·junit·单元测试·android studio·自学笔记