02 - 主线程链路与前置依赖
维度 B:研究
SettingsApplication在主线程上发生的所有初始化、前置依赖、MainThreadStartTask全貌 关注点:attachBaseContext→onCreate链路、前置依赖组件、主线程任务、Intent 拦截、缓存机制、路由注解
一、主线程初始化清单(按执行顺序)
1.1 attachBaseContext 阶段
文件:app/src/main/java/com/android/car/settings/miauto/SettingsApplication.java:41-44
| 步骤 | 操作 | 说明 |
|---|---|---|
| 1.1 | super.attachBaseContext(base) | 调用 BaseApplication,父类初始化 |
| 1.2 | mApp = this | 保存 Application 全局引用,供 BaseApplication.getGlobalApp() 访问 |
1.2 BaseApplication.onCreate(base/.../common/BaseApplication.java:44-62)
| 步骤 | 操作 | 说明 |
|---|---|---|
| 2.1 | super.onCreate() | Application 基类 |
| 2.2 | initOthers() → initGlobalViewModel() | 通过 ViewModelProvider.AndroidViewModelFactory 创建 GlobalViewModel 单例,供跨页面数据共享 |
1.3 SettingsApplication.onCreate 前置依赖(SettingsApplication.java:47-60)
注释标注「MainThreadStartTask 和 AsyncThreadStartTask 都依赖的(前置条件)」
| 步骤 | 操作 | 文件:行号 | 职责 |
|---|---|---|---|
| 3.1 | DfxManager.INSTANCE.init | :49 | 小米汽车 DFX(数据框架/体验)SDK 初始化 |
| 3.2 | MiCarSettingsExtKt.checkAppMatchRom | :51 | ROM 匹配检查,见下方详解 |
| 3.3 | registerActivityLifecycleCallbacks(AppLifecycleTracker) | :53 | Activity 生命周期监听(logUIMode 排障) |
| 3.4 | AutoDensityConfig.init(this) | :55 | 自动密度适配(mi.car.autodensity) |
| 3.5 | initLogging() → MLog.init | :56,:119-128 | 日志系统初始化 |
1.4 AppStartTaskDispatcher.start()(SettingsApplication.java:62-65)
AppStartTaskDispatcher appStartTaskDispatcher = new AppStartTaskDispatcher();
appStartTaskDispatcher.setMainAppStartTask(new MainThreadStartTask(appStartTaskDispatcher, this));
appStartTaskDispatcher.setAsyncStartTask(new AsyncThreadStartTask(appStartTaskDispatcher, this));
appStartTaskDispatcher.start(); // 阻塞,直到 AsyncThreadStartTask 完成(最多 1000ms)详见 01-启动框架与调度机制。
二、前置依赖组件详解
2.1 checkAppMatchRom —— ROM 匹配检查
文件:base/settingsBaseUi/src/main/java/com/android/car/settings/common/MiCarSettingsExt.kt:81-86
fun checkAppMatchRom(stage: String? = null): Boolean {
val isDcdApp: Boolean = BuildConfig.FLAVOR.contains("dcd")
val isDcdRom = DeviceUtil.isDCDPlatform()
MLog.d("check rom match at stage: $stage, isDcdApp = $isDcdApp, isDcdRom = $isDcdRom")
return isDcdRom && isDcdApp || !isDcdRom && !isDcdApp
}职责:确保 App 变体(DCD/XCD/global)与 ROM 平台匹配。DCD ROM 必须装 DCD App,否则功能异常。用于启动期快速发现装错包的问题。
2.2 AppLifecycleTracker —— UI 模式排障
文件:SettingsApplication.java:69-116
onActivityPreCreated 在 Activity 创建前后各打印一次 UI 模式:
MiCarSettings.logUIMode(TAG, " onActivityPreCreated before super", activity);
ActivityLifecycleCallbacks.super.onActivityPreCreated(activity, savedInstanceState);
MiCarSettings.logUIMode(TAG, " onActivityPreCreated after super", activity);用途:出现 UI 模式(深色/浅色)与实际不符时,根据日志判定是系统问题还是应用问题。其他回调均为空实现。
2.3 initLogging —— MLog 配置
文件:SettingsApplication.java:119-128
LogConfiguration configuration = new LogConfiguration.Builder()
.logLevel(LogLevel.DEBUG)
.tag(SettingsConstant.TAG)
.tab(" ")
.tagFormat(LogConfiguration.TAG_FORMAT_APPEND) // 一次性 tag 拼接
.enableInnerLog(false)
.withChannels(LogChannel.Android)
.build();
MLog.init(configuration);三、MainThreadStartTask.execute() 全貌(逐行核对)
文件:app/src/main/java/com/android/car/settings/miauto/MainThreadStartTask.java
类注释(:48):「主线程执行 dev分支耗时 71MS」 —— 这是开发者标注值;bugreport 实测 247ms(见 05)。
@Override
protected void execute() { // :56
mApplication.registerActivityLifecycleCallbacks( // :57 注册 Intent 拦截回调
new ActivityLifecycleCallbacks());
/* 获取、监听车型配置字信息 耗时52Ms */ // :58-60 整块注释标 52ms
{
GlobalCarPropertyManager.init(mApplication); // :62 全局 CarProperty 管理器
LicenseControlMgr.getInstance() // :64-65 扩展 license 能力
.setLicenseControl(MiCarLcsControlHelper.INSTANCE);
VehiclePermanentListener.getInstance().init(); // :66 车辆属性监听器(注册~68个 propId)
MiCarSettings.setConfigManager(CarConfigManager.INSTANCE); // :67 设置配置管理器
}
PreferenceVisibleStatusHelperWrapper.getInstance() // :69-70 可见性管理器
.setPreferenceVisibleStatusHandler(getHandler());
initConnection(); // 必须在主线程执行,否则黑屏 27MS // :72 蓝牙/热点/WiFi
Router.getInstance().init(mApplication); // 0MS,有反射 // :74 路由表合并
initInAsync(); // :76 二次派发(不受 latch 约束)
}⚠️ 纠正常见误读:注释里的
52ms是整个配置字块(:61-68四行合计),不是VehiclePermanentListener单独。实测该块内 CarProperty 注册约 31ms(白皮书)。
3.1 Intent 拦截 ActivityLifecycleCallbacks(易被忽略的业务)
文件:MainThreadStartTask.java:126-188
这是 MainThreadStartTask 自己注册的 ActivityLifecycleCallbacks(与 SettingsApplication.AppLifecycleTracker 不同),在 onActivityCreated 中拦截 Intent 跳转:
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Intent intent = activity.getIntent();
String newIntent = shouldInterceptAndNewIntent(action, data); // 判断是否拦截
if (newIntent != null) {
activity.finish();
activity.startActivity(new Intent(newIntent)); // 重定向到新 Intent
}
}拦截规则(shouldInterceptAndNewIntent,:162-187):
| 触发条件 | 配置判定 | 重定向目标 |
|---|---|---|
POSITION_ADJUST_ACTION + 后视镜调节 + 单后视镜车型 | !isSteeringAdjustEnabled && !isCfgWHudEnabled && !isCfgPHudEnabled | MIRROR_ADJUST_ACTION |
POSITION_ADJUST_ACTION + HUD 调节 + WHUD 使能 + WHUD 关闭 | isCfgWHudEnabled && !isHudSwitchEnable() | HUD_SETTINGS_ACTION |
作用:根据车型配置字(单/双后视镜、HUD 是否使能),把不适用的「位置调节」Intent 重定向到正确的子页面,避免进了空白页。
3.2 配置字块详解(:61-68)
| 组件 | 文件 | 职责 |
|---|---|---|
GlobalCarPropertyManager | base/settingsVehicleLib/.../GlobalCarPropertyManager.kt:23-30 | 全局单例管理 CarPropertyManager,SoftReference 持有,触发 VehicleControlManager 初始化 |
LicenseControlMgr.setLicenseControl | com.android.license.master | 扩展 license 查询能力,供其他 module 判断功能可见性 |
VehiclePermanentListener.init | base/settingsVehicleLib/.../VehiclePermanentListener.java:102-107 | 配置信号映射 + 注册 ~68 个 CarProperty callback,为 Preference 可见性提供缓存,避免闪烁 |
MiCarSettings.setConfigManager | - | 设置 CarConfigManager 单例 |
VehiclePermanentListener 缓存机制(:325-343):
public static CarPropertyValue getCachePropertyValue(int propertyId, int areaId) {
CarPropertyValue v = mPropertyValueMap.get(getCachedPropertyKey(propertyId, areaId)); // 1.优先缓存
if (v == null && getInstance().mCarPropertyManager.isConnected()) {
v = getInstance().mCarPropertyManager.getProperty(propertyId, areaId); // 2.缓存未命中查 CarService
}
return v;
}此方法对接 SettingsApplication.getPropertyValue(:135),是 Application 级车辆属性缓存入口。
CarConfigManager CCP 缓存策略(base/settingsVehicleLib/.../CarConfigManager.kt:78-104):
- CCP 静态配置字(出厂烧录,生命周期不变):默认走缓存
- 动态运行时属性:必须
skipCache=true跳过缓存
3.3 initConnection —— 蓝牙/热点/WiFi(:193-212)
private void initConnection() {
// 与蓝牙模块同事确认,需要在进程初始化时就初始化 BtManager,否则会导致配对异常
try { MiBluetoothUtils.getLocalBtManager(); } // 蓝牙,实测 188ms!
catch (Exception e) { MLog.e(e, "fail to init bt manager"); }
try { HotspotUtils.INSTANCE.init(mApplication); } // 热点,实测 22ms
catch (Exception e) { MLog.e(e, "fail to init hotspot"); }
try { MiCarWifiUtils.INSTANCE.init(mApplication); } // WiFi
catch (Exception e) { MLog.e(e, "fail to init wifi"); }
}注释标 27ms,但实测蓝牙单项 188ms(
LocalBluetoothManager同步初始化含反射 CNFE,白皮书 72309-73148)。这是主线程最大热点。观点冲突:注释称「必须主线程,否则黑屏」,但白皮书优化方案 C 建议挪到异步以省 ~210ms —— 需回归验证蓝牙配对稳定性。
3.4 initInAsync —— 二次派发盲区(:80-114)
不受 CountDownLatch 约束,onCreate 返回后仍在 ASYNC 线程池执行:
ThreadPoolUtils.ASYNC.execute(() -> {
LicenseMasterManager.INSTANCE.addLicenseDataChangedListener(...); // :89-95 license 变化监听
LicenseMasterManager.INSTANCE.bindLicenseMaster(mApplication); // :97 绑定 license 服务
MisDeviceSDKUtils.INSTANCE.init(); // :99 MIS 设备 SDK
// 网络共享状态检查/初始化 // :101-108
ChildSeatSignalSync.INSTANCE.sync(); // :111 儿童座椅状态同步到 ECU
});其中 license 监听块(
:84-96)有 AI(claude)生成标记(2026-05-14),先注册 listener 再 bind,避免首次 fetch 时 listener 未就绪。
3.5 Router.init —— 路由表合并(:74)
文件:settingsCommon/plugin/router/routerManager/.../Router.java:46-74
构造时反射调用编译期生成的 RouterHelper.merge() 合并路由表:
private Router() {
try {
Class clazz = Class.forName("com.android.car.settings.router.RouterHelper");
Method method = clazz.getDeclaredMethod("merge");
method.setAccessible(true);
method.invoke(clazz); // 合并路由表
} catch (Exception e) { Log.i("Router", "merge router failed"); }
}
public void init(Application application) {
initActivityLifecycle(application); // 注册 Activity/Fragment 生命周期,分发 URI
}@Module / @Modules 注解机制(SettingsApplication.java:28-35):
@Module(SettingsConstant.TAG)—— 标记模块名,同模块只注册一次@Modules({TAG, TAG_AUTOPILOT, TAG_Light, ...})—— 列举所有含RouterProvider的子模块- 编译期:注解处理器扫描
@Modules,生成RouterHelper(含merge()方法) - 启动期:
Router反射调用merge()合并所有子模块路由表
四、主线程流程图
flowchart TD A["attachBaseContext"] --> B["super.attachBaseContext<br/>mApp=this"] B --> C["onCreate"] C --> D["BaseApplication.onCreate<br/>initGlobalViewModel"] D --> E["DfxManager.init"] E --> F["checkAppMatchRom<br/>(DCD/XCD 匹配)"] F --> G["AppLifecycleTracker 注册<br/>(logUIMode 排障)"] G --> H["AutoDensityConfig.init"] H --> I["initLogging MLog"] I --> J["dispatcher.start()"] J --> K["dispatchAppStartTask"] K --> L["MainThreadStartTask.execute(主线程)"] K -.->|"并行<br/>投递ASYNC"| M["AsyncThreadStartTask<br/>见 03"] L --> L1["registerActivityLifecycleCallbacks<br/>(Intent拦截:后视镜/HUD)"] L1 --> L2["配置字块 52ms★<br/>GlobalCarPropertyManager<br/>LicenseControlMgr<br/>VehiclePermanentListener.init<br/>setConfigManager"] L2 --> L3["PreferenceVisibleStatusHelperWrapper"] L3 --> L4["initConnection 27ms★<br/>蓝牙188ms/热点22ms/WiFi"] L4 --> L5["Router.init<br/>(反射 merge 路由表)"] L5 --> L6["initInAsync<br/>→ASYNC二次派发(不受latch)"] L6 --> N["await<br/>等异步完成(最多1000ms)"] M --> N N --> O["onCreate finish"] classDef hot fill:#ffe1e1,stroke:#cc0000 class L2,L4 hot
五、主线程性能风险
| 风险 | 位置 | 实测耗时 | 说明 |
|---|---|---|---|
| 🔴 蓝牙同步初始化 | initConnection:196 | 188ms | LocalBluetoothManager 反射初始化,主线程最大热点 |
| 🔴 CarProperty 同步注册 | VehiclePermanentListener.init:66 | ~31ms(Application) | 同步 binder,Activity 阶段更严重(893ms) |
| 🟡 配置字块 | :61-68 | 52ms(注释) | 首次连接 CarService 的 IPC 开销 |
| 🟡 Router 反射 | :74 | 0ms(注释) | 反射 RouterHelper.merge,有隐藏开销 |
| 🟡 反射 CNFE 噪声 | BroadcastSourceInfoHandler | 4ms+/次 | settingslib 裁剪遗留,每次启动抛 CNFE |
优化方向(详见 05):
- 蓝牙/热点挪异步(白皮书方案 C)
- CarProperty 注册挪单线程 executor(白皮书方案 A,治本)
六、关键源码行号索引
| 组件 | 文件:行号 |
|---|---|
| SettingsApplication.onCreate | SettingsApplication.java:47-67 |
| 前置依赖段 | SettingsApplication.java:49-56 |
| AppLifecycleTracker | SettingsApplication.java:69-116 |
| getPropertyValue(缓存入口) | SettingsApplication.java:135-137 |
| initLogging | SettingsApplication.java:119-128 |
| BaseApplication.onCreate | BaseApplication.java:44-62 |
| MainThreadStartTask.execute | MainThreadStartTask.java:56-77 |
| Intent 拦截回调 | MainThreadStartTask.java:126-188 |
| 配置字块(52ms) | MainThreadStartTask.java:61-68 |
| initConnection(蓝牙/热点/WiFi) | MainThreadStartTask.java:193-212 |
| initInAsync(二次派发) | MainThreadStartTask.java:80-114 |
| VehiclePermanentListener 缓存 | VehiclePermanentListener.java:325-343 |
| CarConfigManager CCP 缓存 | CarConfigManager.kt:78-104 |
| Router.merge(反射) | Router.java:46-62 |
| checkAppMatchRom | MiCarSettingsExt.kt:81-86 |
| MiBluetoothUtils | settingsPage/micarConnectionSettings/.../bluetooth/MiBluetoothUtils.kt |
| HotspotUtils | settingsPage/micarConnectionSettings/.../hotspot/HotspotUtils.kt |
| MiCarWifiUtils | settingsPage/micarConnectionSettings/.../wifi/MiCarWifiUtils.kt |