CarSettings-多车型车模资源适配

一、背景

settings工程多车型共线,一级页面右侧车模图不同车型使用资源有所不同,如-U车型有固定尾翼, lemans车型是SUV,后续还有Kunlun、Mann等等。

如果把所有车型车模资源放到当前工程里, apk的size会越来越大,apk瘦身的压力与日俱增, 加载目标资源判断逻辑不断增长,资源命名需增加车型后缀等一系列问题。

二、Android Overlay机制

Android Overlay是一种资源替换机制,它能在不重新打包apk的情况下,实现资源文件的替换(res目录非assert目录),Overlay又分为静态Overlay(Static Resource Overlay)与运行时Overlay(Runtime Resource Overlay)。

  • 静态Overlay (SRO):发生在编译时,需要在 AOSP 源码中配置。
  • 运行时Overlay (RRO):发生在运行时,可以直接覆盖替换其他 apk 的资源而不需要其源码。

以下几类资源能够通过该机制实现替换:

  • Configurations (string, bool, bool-array)
  • Localization (string, string-array)
  • UI Appearance (color, drawable, layout, style, theme, animation)
  • Raw resources (audio, video, xml)

2.1. 静态替换 (Static Resource Overlay, SRO)

  • 编译时覆盖资源

  • 适用于系统级资源修改(如壁纸、配置文件等)

  • 适用有源码的情况下使用

  • 需要在 PRODUCT_PACKAGE_OVERLAYS 中指定overlay目录

  • 示例 — Face id 资源overlay

    /s-watt-dev/lagvm/LINUX/android/device/micar/common/dcd/
    H A Dcommon-pre.mk5 PRODUCT_PACKAGE_OVERLAYS += vendor/micar/frameworks/base/overlay
     
    xref: /s-watt-dev/lagvm/LINUX/android/device/micar/common/dcd/common-pre.mk
     
    /s-watt-dev/lagvm/LINUX/android/vendor/micar/frameworks/base/overlay/frameworks/base/core/res/res/values-zh-rCN/
     
    /s-watt-dev/lagvm/LINUX/android/vendor/micar/frameworks/base/overlay/frameworks/base/core/res/res/values-zh-rCN/strings.xml

2.2 动态替换 (Runtime Resource Overlay, RRO)

  • 运行时动态替换资源
  • 适用于应用级资源修改
  • 需要配置Overlay清单文件
  • ROM中包含两个apk, 一个目标.apk, 一个资源目标_Overlay.apk
  • 可以存在多个Overlay apk, 通过AndroidManifest.xml中指定priority指定优先级

2.3 源码浅析

三、车控配图适配方案

从适用性、开发、维护便捷性上考虑,车控应用采用RRO方式实现配图资源替换方案。

🧭 [白板:车控配图 RRO 资源替换架构]

白板 token:CaSDwwhPEhLLbebAseuc9bPcnrc,描绘三种车型(Modena / Modena-U / Lemans)下 MiCarSettingsRRO 与 CarSettings 的资源覆盖关系。

节点(按拓扑整理)

  1. MiCarSettingsRRO(中心源 apk,编译期产出,位于左侧)

    ↓ 编译时根据 device 选择对应车型资源目录打包

  2. On Modena-U 区(hertz):

    • MiCarSettingsRRO → (with resource for Modena-U(hertz)) → 覆盖到 CarSettings
  3. On Lemans 区(suiren):

    • MiCarSettingsRRO → (with resource for Lemans(suiren)) → 覆盖到 CarSettings
  4. On Modena 区(watt,默认):

    • MiCarSettingsRRO → (with no overlay resource on Modena(watt)) → CarSettings(即使用 CarSettings 默认 Modena 资源,无 overlay)

流向总结

  • MiCarSettingsRRO.apk(编译期按 device 切换 res 目录) → 打包出 “hertz 资源包” / “suiren 资源包” / “watt 空资源包” → 安装到目标车型后,RRO 静态覆盖 CarSettings.apkoverlayable 声明的资源。
  • Modena(watt)走 CarSettings 默认资源,无需 overlay 替换。
  • 3.1、提供维护所有车型资源的overlay apk,编译时根据rom类型动态打包车型对应的资源

    • MiCarSettingsRRO.apk // RRO short for Runtime Resource Overlay新增Settings资源apk, 用于提供不同车型的车模(图片)资源

    • In android.mk

    车型以及对应的device命名可以参考该文档, 后续适配新车型,可以参考这个文档,在Overlay工程里创建对应的资源目录。座舱多车型Android Device命名

    // 仅示意,随着车型的增加 扩展if-else编译控制
    if (device == watt) {
       res = '/path/to/modena/res'
    } else if (device == suiren) {
       res = '/path/to/suiren/res'
    } else if (device == kunlun) {
       res = '/path/to/kunlun/res'
    } else if (device == hertz) {
       res = '/path/to/hertz/res'
    }
    • 工程目录结构示意

    res/ 下含 hertz / suiren / watt 等子目录,hertz 内含 drawable、drawable-night、values、values-night、values-zh-rCN、xml 等文件夹;底部为 Android.mk 与 AndroidManifest.xml。

  • 3.2 资源打包的维度仅区分车型,不区分配置字

同一个资源apk中包含某一车型的所有资源,同一个页面下不同配置的配图需要有不同的细节体现,如车身雷达有、无,刹车盘卡钳样式不同都需有对应图片资源,这些资源会在运行时通过配置字动态控制加载,打包的时候需要统一打包到overlay apk中。

  • 3.3、车型差异

有的整车配置是车型特有功能配置,这种非共性的配置需要针对特定车型(Modena-U \ Lemans) 进行适配。这种场景通过在Settings里增加特殊功能配置的默认资源图(placeholder resource),用作占位以便生成resource id在布局或者代码中引用,然后在目标车型的资源apk中配置正确的替换资源实现覆盖。

  • -U车型固定尾翼

    • 资源后缀”_fixed_tail_wing
    • 示例
    // in CarSettings apk
    res/drawable/micar_car_model_autopilot_lcc.webp
    res/drawable/micar_car_model_autopilot_lcc_fixed_tail_wing.webp //只是用来生成resource id,图片内容并非正确的
     
    // in CarSettings RRO apk
    hertz/res/drawable/micar_car_model_autopilot_lcc_fixed_tail_wing.webp // 这才是真正的-U车型的lcc场景使用图片
  • Lemans 矩形两幅方向盘

    • 资源后缀”_2_spokers
    • 示例 (灯光页面——氛围灯配图: 左图位于CarSettings工程,用于占位,右图位于Settings RRO工程)
    // in CarSettings apk
    res/drawable/micar_car_model_atmosphere.webp
    res/drawable/micar_car_model_atmosphere_2_spokers.webp
     
    // in CarSettings RRO apk
    suiren/res/drawable/micar_car_model_atmosphere_2_spokers.webp

白色线条勾勒车辆前后整体外观,含车头、车尾、车门、车窗等。位于 CarSettings 工程作为占位图,等待目标车型资源 apk 覆盖。

顶视角度呈现的车辆 3D 模型,前后排白色座椅(后排可折叠),车门、方向盘亦为白色,背景浅灰渐变。用于覆盖 Lemans 氛围灯占位资源。

四、开发 & 验证 & 问题排查:

4.1、需求输入材料和代码

4.2、原生系统参考

  • CarPermissionControllerRRO 模块

相关源码搜集如下:

  • apk源码

/home/dominic/home_ssd980/desay8295_master/lagvm/LINUX/android**/packages/services/Car/car_product/rro/PermissionControllerRRO**

Android Studio 中 car_product 文件夹下含 bootanimations、build、car_ui_portrait、init、occupant_awareness、overlay、overlay-visual 等;rpo 文件夹下含 CarRotaryImRRO、PermissionControllerRRO 等。PermissionControllerRRO/res/xml 下 overlays.xml 高亮显示。

  • apk文件清单

desay8295_master/lagvm/LINUX/android/device/generic/car/gsi_car_base.mk

左侧 Android Studio Project 视图,右侧 generic_car_base.mk 文件内容,红框高亮 system/app/CarPermissionControllerRRO/CarPermissionControllerRRO.apk 行。

  • RRO apk vs Target apk
// RRO apk
package: com.android.permissioncontroller.car.rro
name: CarPermissionControllerRRO
path: /system/app/CarPermissionControllerRRO/CarPermissionControllerRRO.apk
 
// Target apk
package: com.android.permissioncontroller
name : MiPermissionController.apk
path: /system/priv-app/MiPermissionController/MiPermissionController.apk
 

4.3、资源替换工程配置

  • In Settings.apk

    • 配置可被替换资源清单

目标apk中resource目录下需增加overlayable.xml, 该文件用于配置哪些资源文件可被替换, 其中 标签需要指定一个name,在接下来创建的资源覆盖apk中需要创建与之对应的overlays.xml。

其中Settings.apk中的默认资源都是Modena(SU7)使用的资源。

<resources>
    <overlayable name="CarSettingsStyles">
        <policy type="product|system|vendor">
            <!--这里示例 车辆控制页面有以下资源可以被替换 -->
            <item type="drawable" name="micar_car_model_vehicle_control_main" />
            <item type="drawable" name="micar_dialog_bg_steering_wheel" />
            <item type="drawable" name="micar_dialog_bg_steering_wheel_2_spokers" />
        </policy>
    </overlayable>
</resources>

policy属性

overlayable.xml中,policy属性用来定义哪些资源可以被覆盖。每个条目都有一个policy属性,这个属性决定了该资源的覆盖策略。

  • public:表示该资源可以被任何overlay使用。这是最常见的设置,允许广泛的自定义和覆盖。
  • signature|privileged:这类资源仅限于具有签名权限的应用或系统应用可以覆盖。这通常用于保护核心系统功能不被随意更改,但仍允许制造商或开发者通过签名的方式来覆盖这些资源。
  • system|privileged:这类资源仅限于系统应用可以覆盖。这是最严格的策略,通常用于那些绝对不应该被普通应用覆盖的系统级资源。
  • system:这类资源可以被系统应用覆盖,但不包括签名权限的应用。这是一种介于signature|privilegedsystem|privileged之间的策略,允许更广泛的覆盖,但仍然有一定的保护措施。

图示为CarSettings工程里的overlayable.xml

  • In MiCarSettingsRRO.apk

Su7 Ultra\Lemans\Kunlun使用的资源在MiCarSettingsRRO.apk中打包,用于在目标车型上覆盖默认的Modena使用的默认资源。

  • 创建Androidmanifest.xml

首先需要在Androidmanifest.xml中需声明 标签,并指定targetPackage—目标资源需替换apk, targetName需要和目标apk中的overlayable.xml中的命名一致,而resourcesMap属性用于配置用于覆盖目标资源的资源清单文件,这里创建overlays.xml文件放到xml目录下,完成的配置如下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.android.car.settings.rro">
    <application android:hasCode="false"/>
    <overlay android:priority="10"
             android:targetPackage="com.android.car.settings"
             android:targetName="CarSettingsStyles"
             android:resourcesMap="@xml/overlays"
             android:isStatic="true" />
</manifest>

图示为位于hertz车型资源目录下的overlays.xml

MiCarSettingsRRO 项目 res/hertz/xml 下,红色箭头指向 overlays.xml。

  • In overlays.xml这里可以配置的资源类型包括图片、文案、dimension、color、layout等类型资源
<!--
  每一item用来声明资源替换的映射关系,target指的被替换的目标资源,value是用于覆盖默认资源的resources.
-->
<overlay xmlns:android="http://schemas.android.com/apk/res/android">
 
    <!--Overlays string/config1 and string/config2 with the same resource.-->
    <!--车辆控制-->
    <item target="drawable/micar_car_model_vehicle_control_main"
          value="@drawable/micar_car_model_vehicle_control_main" />
    <item target="drawable/micar_dialog_bg_steering_wheel"
        value="@drawable/micar_dialog_bg_steering_wheel" />
 
    <!--三合一弹窗-->
    <item target="drawable/micar_car_model_hud_display_adjust_right"
        value="@drawable/micar_car_model_hud_display_adjust_right" />
</overlay>
  • 各车型overlays.xml工程目录结构如下

MiCarSettingsRRO 项目下 hertz / suiren / watt 车型资源目录的 xml 文件夹中均存在 overlays.xml,hertz 的 overlays.xml 蓝色高亮。

4.4、打包 & 验证

  • 新增资源如果是新功能引用到的新增资源,在Settings中增加目标资源,如micar_car_mode_light_xxx_new.webp, 须在overlable.xml中声明该资源可被覆盖:

    // in settings overlayable.xml
    <!--灯光-->
    <item type="drawable" name="micar_car_mode_light_xxx_new" />

修改后,直接install settings.apk即可。

  • 配置替换资源

在MiCarSettingsRRO中替换完目标车型资源后,make 工程构建apk后,push到目标路径下即可。

adb push MiCarSettingsRRO.apk system/product/app/MiCarSettingsRRO/MiCarSettingsRRO.apk
  • 编译环节确认资源打包情况

在make rro apk时可以通过mk文件中输出的日志哪些资源会被最终打包到MiCarSettingsRRO.apk

红框标注关键内容:TARGET_PRODUCT=surya_gvm6RESOURCE_PRODUCT_DEVICE=watt、资源目录 vendor/mcar/packages/CarSettingsRRO/devices/res-wattvendor/mcar/packages/CarSettingsRRO/res-watt

  • 验证结果

完成apk替换后,如果看到展示的是覆盖后的目标车型的资源,则表示资源配置正确。

反之,则可以通过如下步骤检查错误。参考4.5章节

4.5、 错误排查

  • 资源包是否生效

    • 确认overlay资源包是否有问题 执行:adb shell cmd overlay list --user current
// 发现资源包,但是资源包有错误, 需要进一步排查
// 这时候需要检查一下overlay.xml中的资源,可能存在重复、资源不存在等问题。
com.android.car.settings
--- com.android.car.settings.rro
 
// 发现资源包, 正常
com.android.car.settings
[x] com.android.car.settings.rro

如果是资源包仍无法生效,可以执行一下adb logcat | grep id2map, 可以定位一下是哪个资源导致的,错误信息如下:

📎 附件: idmap2d 日志 markdown

86651:03-19 13:30:50.658 32665 32665 I idmap2d : Starting
86673:03-19 13:30:50.673 32665 32668 W idmap2d : failed to parse idmap header of '/data/resource-cache/product@app@MiCarSettingsRRO@MiCarSettingsRRO.apk@idmap'
86687:03-19 13:30:50.686 32665 32668 E idmap2d : target resource id "0x7f0806d9" mapped to multiple values -> failed to add mapping for 'drawable/micar_car_model_vehicle_control_safety' -> failed to generate resource map for '/product/app/MiCarSettingsRRO/MiCarSettingsRRO.apk'
86697:03-19 13:30:50.701 32665 32668 W idmap2d : failed to parse idmap header of '/data/resource-cache/product@app@MiCarSettingsRRO@MiCarSettingsRRO.apk@idmap'

上述错误信息表示由于micar_car_model_vehicle_control_safety导致无法生成idmap,可能是overlays.xml中存在同名的资源配置。

  • 个别资源未生效

可以确认下对应资源覆盖情况,执行:

adb shell cmd overlay dump com.android.car.settings.rro | grep -ani apa

➜  adb shell cmd overlay dump com.android.car.settings.rro | grep -ani apa // 检查泊车辅助配图资源未能覆盖生效原因
34:    W overlay '/system/product/app/MiCarSettingsRRO/MiCarSettingsRRO.apk' is not allowed to overlay resource 'drawable/micar_car_model_autopilot_apa_fixed_tail_wing' in target: target resource has no overlayable declaration
115:    0x7f0804ad -> 0x7f03004c (drawable/micar_pilot_studio_apa_not_learn -> drawable/micar_pilot_studio_apa_not_learn)
 
  • 查看有无覆盖失败的资源

如果是资源包可以正常运行,但是部分资源覆盖失败,可以查看一下所有资源overlay配置情况,执行命令:

adb shell cmd overlay dump com.android.car.settings

IDMAP OF com.android.car.settings.rro
Paths:
    target path  : /system/priv-app/CarSettings/CarSettings.apk
    overlay path : /product/app/MiCarSettingsRRO/MiCarSettingsRRO.apk
    // 如果有覆盖失败的资源,会在这里显示
Mapping:
    0x7f070644 -> 0x7f020005 (dimen/micar_light_atmosphere_mask_margin_end -> dimen/micar_light_atmosphere_mask_margin_end)
    0x7f070645 -> 0x7f020006 (dimen/micar_light_atmosphere_mask_margin_top -> dimen/micar_light_atmosphere_mask_margin_top)
    0x7f070698 -> 0x7f020007 (dimen/micar_steering_wheel_mirror_adjust_h_guideline_margin_begin -> dimen/micar_steering_wheel_mirror_adjust_h_guideline_margin_begin)
    0x7f070699 -> 0x7f020008 (dimen/micar_steering_wheel_mirror_adjust_v_guideline_margin_start -> dimen/micar_steering_wheel_mirror_adjust_v_guideline_margin_start)
    0x7f0803cd -> 0x7f030000 (drawable/micar_autopilot_studio_entry_bg -> drawable/micar_autopilot_studio_entry_bg)
    //... 略
    0x7f0803f9 -> 0x7f030011 (drawable/micar_car_model_autopilot_default -> drawable/micar_car_model_autopilot_default)
    0x7f0803fb -> 0x7f030012 (drawable/micar_car_model_autopilot_default_low_no_radar -> drawable/micar_car_model_autopilot_default_low_no_radar)
    0x7f0803fc -> 0x7f030013 (drawable/micar_car_model_autopilot_hpp -> drawable/micar_car_model_autopilot_hpp)
    0x7f0803fe -> 0x7f030014 (drawable/micar_car_model_autopilot_hpp_low_no_radar -> drawable/micar_car_model_autopilot_hpp_low_no_radar)
    0x7f0803ff -> 0x7f030015 (drawable/micar_car_model_autopilot_lcc -> drawable/micar_car_model_autopilot_lcc)
 

可以控制rro资源包是启用、停用:

adb shell cmd overlay enable --user curent com.android.car.settings.rro // 注意rro包名准确
 
//停用rro
adb shell cmd overlay disable --user curent com.android.car.settings.rro // 注意rro包名准确

五、车控资源功能验证

  • 车辆控制

    • 车头视角默认图
  • 灯光

    • 默认图
    // HIGH_BEAM
    mockProVal 0x61409102 -i 1 or 0
     
    // FOG_BEAM_STATUS
    mockProVal 0x61409105 -i 1 or 0
     
    // LOW_BEAM_STATUS
    mockProVal 0x61409103 -i 1 or 0
     
    // POSITION_BEAM_STATUS
    mockProVal 0x61409104 -i 1 or 0
    • 氛围灯
    ➜  hertz_images mockLight_MOOD_LIGHT_TRIGGER 1 // 打开氛围灯
    ➜  hertz_images mockLight_MOOD_LIGHT_MODE_SETTINGS 1 // 切换到自定义设置
     
    alias mockon='adb shell settings put --user 0 GLOBAL vehicle_mock_data'
    mockon 0 关闭
    mockon 1 打开
  • 门窗锁

  • 驾驶偏好

    • 直线竞赛加速
    • 悬架高度调节
    ➜  hertz_images mockBody_SUSPENSION_HEIGHT_TARGET_STATE 5
    ➜  hertz_images mockBody_SUSPENSION_HEIGHT_UNAVAILABLE 0  // 使能设置项高亮,然后操作即可
     
    mockBody_SUSPENSION_HEIGHT_TARGET_STATE 5 && mockBody_SUSPENSION_HEIGHT_UNAVAILABLE 0
  • 辅助驾驶

    • 智驾行车
    • HPP
mockDriving_ADS_MODE_SWITCH_STATUS 0/1/2/3  // 默认、、ACC、LCC、NOA
mockDriving_HPP 1

Android 官方RRO说明:

📥 抓取自飞书 wiki 空间 7542035374667726876,obj_token: Z33vdddTXokTpvxp0fuc5MesnPI