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 源码浅析
-
核心类
- PackageManagerService
- Overlay
- Android RRO机制源码浅析(注:xiaomi.f 域内链接)
三、车控配图适配方案
从适用性、开发、维护便捷性上考虑,车控应用采用RRO方式实现配图资源替换方案。
🧭 [白板:车控配图 RRO 资源替换架构]
白板 token:
CaSDwwhPEhLLbebAseuc9bPcnrc,描绘三种车型(Modena / Modena-U / Lemans)下 MiCarSettingsRRO 与 CarSettings 的资源覆盖关系。节点(按拓扑整理):
MiCarSettingsRRO(中心源 apk,编译期产出,位于左侧)
↓ 编译时根据
device选择对应车型资源目录打包On Modena-U 区(hertz):
MiCarSettingsRRO→ (with resource for Modena-U(hertz)) → 覆盖到 CarSettingsOn Lemans 区(suiren):
MiCarSettingsRRO→ (with resource for Lemans(suiren)) → 覆盖到 CarSettingsOn Modena 区(watt,默认):
MiCarSettingsRRO→ (with no overlay resource on Modena(watt)) → CarSettings(即使用 CarSettings 默认 Modena 资源,无 overlay)流向总结:
MiCarSettingsRRO.apk(编译期按 device 切换 res 目录) → 打包出 “hertz 资源包” / “suiren 资源包” / “watt 空资源包” → 安装到目标车型后,RRO 静态覆盖CarSettings.apk中overlayable声明的资源。- 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、需求输入材料和代码
-
Figma (lemans & Modena-U)
🌈 Figma 链接集合
-
For Modena-U
-
Manifest —— 增加rro 模块 - MiCarSettingsRRO
- https://gerrit.auto.mioffice.cn/c/platform/manifest/+/135305 for HyperOS.1.3.0
-
device/common —— 编辑系统.mk中增加MiCarSettingsRRO
-
settings模块调整 —— 增加overlayable.xml <—关键
-
MiCarSettingsRRO
-
-
For XCD (Lemans) https://gerrit.auto.mioffice.cn/q/topic:Lemans_CarModel https://gerrit.auto.mioffice.cn/c/platform/manifest/+/157806
-
Manifest —— 增加rro 模块 - MiCarSettingsRRO
-
MiCarSettings —— 增加overlayable.xml <—关键
-
device/common
-
MiCarSettingsRRO
-
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, 该文件用于配置哪些资源文件可被替换, 其中
其中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|privileged和system|privileged之间的策略,允许更广泛的覆盖,但仍然有一定的保护措施。
图示为CarSettings工程里的overlayable.xml

- In MiCarSettingsRRO.apk
Su7 Ultra\Lemans\Kunlun使用的资源在MiCarSettingsRRO.apk中打包,用于在目标车型上覆盖默认的Modena使用的默认资源。
- 创建Androidmanifest.xml
首先需要在Androidmanifest.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_gvm6、RESOURCE_PRODUCT_DEVICE=watt、资源目录vendor/mcar/packages/CarSettingsRRO/devices/res-watt、vendor/mcar/packages/CarSettingsRRO/res-watt。
- 验证结果
完成apk替换后,如果看到展示的是覆盖后的目标车型的资源,则表示资源配置正确。
反之,则可以通过如下步骤检查错误。参考4.5章节
4.5、 错误排查
-
资源包是否生效
- 确认overlay资源包是否有问题
执行:
adb shell cmd overlay list --user current
- 确认overlay资源包是否有问题
执行:
// 发现资源包,但是资源包有错误, 需要进一步排查
// 这时候需要检查一下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, 可以定位一下是哪个资源导致的,错误信息如下:
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 1Android 官方RRO说明:
- source.android.com
- Android 运行时资源替换机制RRO(Runtime Resource Overlay )_android rro-CSDN博客
- Android Overlay机制
- medium.com
📥 抓取自飞书 wiki 空间 7542035374667726876,obj_token: Z33vdddTXokTpvxp0fuc5MesnPI