添加 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 也可以关注我的抖音账号,在主页店铺即可购买付费课程。

相关推荐
q***57741 分钟前
MySql的慢查询(慢日志)
android·mysql·adb
JavaNoober26 分钟前
Android 前台服务 "Bad Notification" 崩溃机制分析文档
android
城东米粉儿1 小时前
关于ObjectAnimator
android
zhangphil2 小时前
Android渲染线程Render Thread的RenderNode与DisplayList,引用Bitmap及Open GL纹理上传GPU
android
火柴就是我3 小时前
从头写一个自己的app
android·前端·flutter
lichong9514 小时前
XLog debug 开启打印日志,release 关闭打印日志
android·java·前端
用户69371750013844 小时前
14.Kotlin 类:类的形态(一):抽象类 (Abstract Class)
android·后端·kotlin
火柴就是我5 小时前
NekoBoxForAndroid 编译libcore.aar
android
Kaede66 小时前
MySQL中如何使用命令行修改root密码
android·mysql·adb
明君879977 小时前
Flutter 图纸标注功能的实现:踩坑与架构设计
android·ios