注意:本文基于 Android 11 进行分析
Qidi 2023.11.28 (MarkDown & Haroopad)


0. 简介 Android RO (Resource Overlay) 机制

Overlay 实现的效果正如其字面意思,就是“在原有效果的基础上再叠加一些效果”。

Android 提供了两种实现方式:

  • 编译时:https://source.android.com/docs/setup/create/new-device#use-resource-overlays
  • 运行时:https://source.android.com/docs/core/runtime/rros

通过 RO 机制,我们就可以将自己编写的 Java 服务在系统启动时运行起来。


1. 实现自定义 Java 服务

假设我们要实现的自定义服务名叫 myService,为了使它可以正常被 CarAudioService 拉起,需要在myServiceAndroidManifest.xml 中添加 directBootAware 属性:

    ......                                                                                        

随后实现 myService 代码,和实现普通 service 没有区别,示例 vendor/your_company_name/packages/src/com/your_company_name/myService.java 如下:

package com.your_company_name.myService;// some dependent packagesimport android.util.Log;import xxxx;public class myService extends Service {private static final String TAG = "myService";......    @Override    public IBinder onBind(Intent intent) {        // return a binder object to caller    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        return START_STICKY;    }    @Override    public void onCreate() {    Log.i(TAG, "Creating myService...");        super.onCreate();        // creating and initializing myService    }// implementation of some myService methods here    ......    @Override    public boolean onUnbind(Intent intent) {        return super.onUnbind(intent);    }    @Override    public void onDestroy() {        super.onDestroy();    }    @Override    protected void attachBaseContext(Context base) {        super.attachBaseContext(base);    }}

如此,自定义服务 myService 就编写完成了。接下来我们还要做一些改动,让 myService 在系统启动时能自动被 CarAudioService 拉起。


2. 对 CarAudioService 配置文件进行编译时 Overlay

CarAudioService 新建 Overlay 配置文件device/your_company_name/qcom/lunch_target_name/overlay/packages/services/Car/service/res/values/config.xml

    <!-- The services that needs to be started earlier in the boot sequence and in particular order.         Every item in this array contains a flatten component name of a service that needs to be         started and a list of parameters after hashtag symbol. Here's the format:         com.bar.foo/.Service#bind={bind|start|startForeground},user={all|system|foreground},         trigger={asap,userUnlocked}         bind: bind - start service with Context#bindService               start - start service with Context#startService               startForeground - start service with Context#startForegroundService               If service was bound it will be restarted unless it is constantly crashing.               The default value is 'start'         user: all - the service will be bound/started for system and all foreground users               system - the service will be started/bound only for system user (u0)               foreground - the service will be bound/started only for foreground users               The default value is 'all'         trigger: indicates when the service needs to be started/bound               asap - the service might be bound when user is not fully loaded, be careful with                      this value, the service also needs to have directBootAware flag set to true               userUnlocked - start service when user unlocked the device               The default value is 'userUnlocked'         If the service bound/started for foreground user it will be unbound/stopped when user         is no longer foreground.     -->            com.your_company_name.myService/.myService#bind=start,user=system,trigger=asap    

然后在 makefile 中将上述 overlay 文件路径添加到环境变量 PRODUCT_PACKAGE_OVERLAYS 中。以我使用的代码环境为例,在 device/your_company_name/qcom/lunch_target_name/lunch_target_name.mk 中添加以下语句(当然你也可以添加到别的 makefile 中,比如 device.mk):

PRODUCT_PACKAGE_OVERLAYS += device/your_company_name/qcom/$(TARGET_PRODUCT)/overlay

至此,所有需要的改动都已完成。接下来只要确保编译通过,并烧写到板子上,就能在开机日志中看到 myService 被拉起来的打印了。