02 · 应用启动与首页架构
一、App 入口
| 角色 | 类 | 路径 |
|---|---|---|
| Application | com.android.car.settings.miauto.SettingsApplication | app/src/main/java/com/android/car/settings/miauto/SettingsApplication.java |
| Launcher 入口 | CarSettingActivities$HomepageActivity → HomePageActivityReal | app/.../miauto/HomePageActivityReal.java |
| Launcher 别名 | Settings_Launcher_Homepage(响应 MAIN+LAUNCHER) | manifest |
| 备用 HOME | FallbackHome(priority -900) | app/.../FallbackHome.java |
| 语音中转 | DeeplinkActivity | app/.../miauto/common/DeeplinkActivity.kt |
进程身份:系统特权应用 —— sharedUserId="android.uid.system" + coreApp="true" + platform.keystore 平台签名。这意味着它能访问系统 API、Car Service、隐藏 API。
二、启动初始化链路
继承:SettingsApplication → BaseApplication(base/settingsBaseLib) → Application
SettingsApplication 头部有路由合并注解(驱动 RouterHelper 生成):
@Module(SettingsConstant.TAG)
@Modules({ TAG, TAG_AUTOPILOT, TAG_Light, TAG_VEHICLECONTROL, TAG_LOCK,
TAG_DRIVING, TAG_CHARGE, TAG_IOT, TAG_XIAOAI, TAG_DISPLAY,
TAG_SAFETY_SERVICE, TAG_CONNECTION, TAG_VOLUME, TAG_SYSTEM })
public class SettingsApplication extends BaseApplication { ... }onCreate 执行顺序
SettingsApplication.onCreate()
│
├─ DfxManager.init() // DFX 监控
├─ checkAppMatchRom("application#onCreate") // ROM 与构建一致性校验
├─ registerActivityLifecycleCallbacks(AppLifecycleTracker) // UI 模式追踪
├─ AutoDensityConfig.init() // miuix 自动密度
├─ initLogging() // MLog (mi.car.logger)
│
└─ AppStartTaskDispatcher.start() ← 核心:主/异步双任务并行
│
├─ MainThreadStartTask (主线程, 注释 ~71ms / 实测 ~247ms)
│ ├─ GlobalCarPropertyManager.init() + VehiclePermanentListener.init() // 车辆配置加载
│ ├─ MiCarSettings.setConfigManager(CarConfigManager) // 配置字
│ ├─ LicenseControlMgr / MiCarLcsControlHelper // 许可证
│ ├─ PreferenceVisibleStatusHelperWrapper 注册 4 个可见性 helper
│ ├─ initConnection() // 蓝牙 + 热点 + WiFi(必须主线程,实测蓝牙 ~188ms)
│ ├─ Router.getInstance().init(mApplication) // 路由表合并
│ └─ initInAsync() → ASYNC.execute(...) // 二次派发:License/MisDevice/儿童座椅
│
├─ AsyncThreadStartTask (ASYNC 线程池, 注释 ~61ms)
│ ├─ SettingsTrack.init() // 埋点
│ ├─ VoiceAssistProvider.initialize() // 语音
│ ├─ initCustomSyncHandler() // 11 个账号同步 handler
│ ├─ registerAccountsUpdateListener()
│ ├─ VoiceSearchManager.SearchInitBuilder // 语音搜索
│ ├─ initHudConfig() + initLinkManager() + MQTTManagerHelper.initMQTTManager()
│ ├─ GlobalCarAudioControlManager.init()
│ └─ TrackTrigger.init() → countDown()
│
└─ CountDownLatch.await(1000ms) // 阻塞直到异步完成或超时
⚠️ 启动风险点(详见 docs/启动慢白屏分析)
- 白屏元凶:
CarPropertyCacheManager.java:192—— 主线程同步registerCallback,Activity 阶段 44 个 callback 占 893ms。优化方案:扔单线程 executor。 - 蓝牙同步初始化 ~188ms(主线程大头)。
- 二次派发盲区:
MainThreadStartTask.initInAsync和AsyncThreadStartTask内ASYNC.execute派发的任务不受 latch 约束,onCreate 返回后仍可能在跑(竞态)。 - CountDownLatch 超时 1000ms:异步卡死时主线程阻塞 1 秒。
- ASYNC 线程池无界(0 核心、MAX 最大):高并发可能线程爆炸。
三、首页:双面板架构
承载布局 car_setting_activity.xml
RelativeLayout#car_settings_activity_wrapper
├── CarModelSwitcher (3D 车辆模型, 右侧)
├── FrameLayout#content_menu_wrapper (可选第三面板, 默认隐藏)
├── <fragment>#top_level_menu ← 左栏: TopLevelMenuFragment
├── View#top_level_divider
└── LinearLayout#content_ll
├── Toolbar
└── FrameLayout#fragment_container ← 右栏: 当前选中 Fragment
由 BaseCarSettingsActivity.onCreate 加载,启动时:
- 左栏挂载
TopLevelMenuFragment - 右栏挂载初始 Fragment =
VehicleControlSettingsFragment(车辆控制,默认选中第一项)
左栏:TopLevelMenuFragment
- 继承
SettingsFragment→BaseXmlParserSettingsFragment(基于micarx.preference.PreferenceFragmentCompat) - 加载
R.xml.miauto_top_level_menu_fragment(region/cn 或 region/global 两份) - 用
CustomFocusLayoutManager拦截车机 DPAD 方向键 MenuHighlightableAdapter处理左↔右联动高亮performMenuClick(prefKey)驱动右栏切换
菜单项声明(XML 驱动)
菜单项通过 PreferenceScreen XML 声明式定义,每项是一个 VoiceAssistMenuPreference:
<!-- app/src/region/cn/res/xml/miauto_top_level_menu_fragment.xml -->
<com.android.car.settings.miauto.preferences.VoiceAssistMenuPreference
android:fragment="com.android.micar.settings.energy.EnergyManagerFragment"
android:key="@string/psk_settings_energy_entry"
android:title="@string/top_level_menu_energy_management"
settings:controller="com.android.car.settings.common.DefaultRestrictionsPreferenceController"
settings:menuIcon="@drawable/micarx_icon_charge_circle"
settings:hiddenFeatures="@string/micar_common_settings_lemans_ece" />android:fragment= 点击后在右栏实例化的 Fragmentandroid:key=@string/psk_*,用于高亮/路由settings:controller= 控制可见性的 Controller(多为DefaultRestrictionsPreferenceController)settings:hiddenFeatures= ECE 合规隐藏标记
国内菜单(15 项):车辆控制 → 灯光 → 门窗锁 → 驾驶偏好 → 辅助驾驶 → 安全 → 充电&能量 → 连接 → 显示 → 声音 → 智能设备 → 智能语音 → 服务 → 系统 → 个人中心。
海外菜单(17 项):额外增加 位置(LocationSettingsFragment)和 隐私(PrivacySettingsFragment),辅助驾驶换 GlobalAutopilotSettingsFragment。
四、外部入口 → 首页的三条路径
路径 A:桌面/Launcher 启动
Settings_Launcher_Homepage 别名(MAIN+LAUNCHER)→ HomepageActivity → 默认选中车辆控制。
路径 B:深链接(外部 App / adb)
Intent(action=android.settings.SETTINGS, data="carsettings://homepage/?subPage=volume")
→ BaseCarSettingsActivity.onNewIntent → handlePageSwitchIntent
→ PageRouterConfig.getPskByPageId(subPage) 把 alias 转成 preference key
→ TopLevelMenuFragment.performMenuClick(prefKey) 高亮 + 切右栏
路径 C:语音(小爱)
小爱返回 widgetId/subPage Bundle → 启动 DeeplinkActivity(透明中转,action android.settings.VEHICLE_PROPERTY_DELIVER)→ 转发到 HomepageActivity → 走路径 B。
内部下钻子页(Fragment 内部点击进二级页)不走 Router,而是
SubSettingsActivity.newInstance(ctx, fragment)在新 Activity 打开。