4. SystemUI 项目结构分析:关键注入点识别与服务组件
SystemUI 作为一个独立 APK 运行在系统进程中,其内部模块高度复杂,依赖关系盘根错节。正确识别 Dagger 注入的“关键入口点”与“核心服务组件”,是后续改造与扩展的基石。
4.1 项目结构概览
SystemUI 的源码位于 frameworks/base/packages/SystemUI/,核心业务逻辑集中在 src/com/android/systemui/。从依赖注入的视角,可将包结构划分为三层:
| 层次 | 典型包名 | 职责 |
|---|---|---|
| 全局注入层 | di | 定义顶级 Component、Module 及作用域注解 |
| 功能注入层 | statusbar, navigationbar, qs | 各子功能模块的 Subcomponent 与绑定声明 |
| 服务组件层 | plugins, shared, util | 被注入的 Service/Controller/Helper 实现 |
关键原则:所有模块的
@Module 最终都必须汇总到 SystemUIxModule(或类似聚合模块),再注入到 SysUIComponent 中。新增功能时,检查是否完成此“注册”链条。
4.2 Dagger 注入体系的全局布局
SystemUI 的 Dagger 基础设施主要依赖以下注解与基类:
- @SysUISingleton —— 自定义作用域,等价于
@Singleton,确保对象在 SystemUI 进程内唯一。 - @SysUIComponent —— 唯一的全局顶级
@Component,负责实例化所有@SysUISingleton对象。 - @Binds / @Provides —— 分别在抽象 Module 与静态 Module 中声明绑定。
- 核心入口类
SystemUIApplication—— 在onCreate()中调用DaggerSysUIComponent.create(),启动 DI 容器。
4.3 关键注入点识别
以下 5 个注入点构成 SystemUI 的“骨架”,无论定制任何功能,都必须先确认它们的存在与配置:
| 序号 | 注入点 | 所在文件 / 注解 | 注入时机 |
|---|---|---|---|
| 1 | SysUIComponent | SysUIComponent.java @Component(modules={…}) | App 启动时 |
| 2 | StatusBar | StatusBar.java @Inject 构造器 | 系统准备完成后 |
| 3 | NavigationBarComponent | NavigationBarComponent.java @Subcomponent | 导航栏创建时 |
| 4 | NotificationPanelView | NotificationPanelView.java @Inject 字段/构造器 | 布局 inflate 时 |
| 5 | GlobalActionsComponent | GlobalActionsComponent.java @Binds 接口绑定 | 长按电源键触发时 |
识别技巧:搜索
@Inject 所在类的 create() 或 get() 调用点,找到对应的 Subcomponent.Builder,即可反推出该注入点所在的上层 Component。通常会在 DaggerSysUIComponent 生成的实现类中找到。
4.4 核心服务组件及其注入关系
SystemUI 内部存在大量长时间运行的 Service 与 Controller,它们通过 DI 汇集到 UI 层。以下是 5 个最重要的服务组件:
- CommandQueue —— 接收系统服务(WMS/NMS)的 IPC 回调,触发 StatusBar 状态更新。
- NotificationListener —— 监听 NotificationManagerService 的通知变化,驱动通知面板的增删改。
- DozeServiceHost —— 管理息屏显示(Ambient Display)与唤醒逻辑。
- BatteryController —— 提供电量/充电状态数据,注入到 QS 与状态栏图标。
- ThemeOverlayController —— 负责动态主题(如 monet)的切换与同步。
这些服务组件通常注入了 Context、Looper(主线程或 BG 线程)、以及 DumpManager,以便在 adb shell dumpsys 输出诊断信息。
// 典型的服务组件注入构造器示例 (伪代码)
@SysUISingleton
public class BatteryControllerImpl implements BatteryController {
private final Context context;
private final Handler bgHandler;
private final DumpManager dumpManager;
@Inject
public BatteryControllerImpl(
Context context,
@BgLooper Looper bgLooper,
DumpManager dumpManager) {
this.context = context;
this.bgHandler = new Handler(bgLooper);
this.dumpManager = dumpManager;
dumpManager.registerDumpable("BatteryController", this);
}
}
4.5 SVG:SystemUI 依赖注入架构总览
4.6 调试与验证方法
- Dagger 注解处理器输出:编译后查看
build/generated/source/apt/下的DaggerSysUIComponent.java,确认所有子组件与模块是否自动生成。 - 注入点断点:在
SystemUIApplication.onCreate()中DaggerSysUIComponent.create()处设断点,逐层展开可看到全部已注册的@Provides方法。 - 运行时分析:执行
adb shell dumpsys activity service com.android.systemui/.SystemUIService,观察有注入字段的服务是否正常填充。
常见错误:忘记将新增的
@Module 加入 SysUIComponent 的 modules 数组,导致编译时提示“找不到依赖”。解决方案:逐一检查 SystemUIxModule 中的模块列表,确保新增模块已添加。
4.7 避坑指南:注入点选择与作用域配平
| 场景 | 推荐注入点 | 作用域 | 理由 |
|---|---|---|---|
| 全局单例服务 | SysUIComponent | @SysUISingleton | 进程内唯一,省内存 |
| UI 控制器 | 对应 Subcomponent | @ActivityScoped / @ViewScoped | 随组件销毁释放 |
| 动态插件 | PluginComponent | 无 | 插件生命周期独立 |
| 工具类无状态 | @Provides + @Reusable | @Reusable | 允许缓存,不强制单例 |