Android7 SystemUI 源码解析(二)启动流程深度解析

系列导航一:全景概览与架构设计 | 二:启动流程深度解析(本文) | 三:StatusBar 状态栏 | 四:NavigationBar 导航栏 | 五:通知系统 | 六:QuickSettings | 七:Keyguard 锁屏 | 八:Recents 与其他子系统


一、概述

SystemUI 是系统启动过程中第一个用户肉眼可见的应用------开机后看到的锁屏界面、状态栏、导航栏都由它负责。理解 SystemUI 的启动流程,是深入掌握其内部机制的第一步。

整个启动链路可以概括为三个阶段:

复制代码
阶段一:SystemServer 启动 SystemUIService
  → 阶段二:SystemUIService 初始化 SystemUIApplication
    → 阶段三:SystemUIApplication 按 SERVICES 数组逐个加载子模块

本文将以 AOSP7 源码为基准,逐层追踪这一完整链路。

二、阶段一:SystemServer 中的启动入口

2.1 SystemServer 的 run() 方法

SystemServer 是 Android 系统的核心进程,负责启动所有 Java 层系统服务。run() 方法按阶段依次启动各类服务,SystemUI 的启动入口就在其中的 startOtherServices() 里。

源码路径frameworks/base/services/java/com/android/server/SystemServer.java

java 复制代码
public final class SystemServer {
    public static void main(String[] args) {
        new SystemServer().run();
    }

    private void run() {
        // ... 初始化 Looper、加载本地库 ...
        // 创建系统 Context
        createSystemContext();
        // 启动引导服务
        startBootstrapServices();
        // 启动核心服务(AMS、WMS、PMS 等)
        startCoreServices();
        // 启动其他服务:SystemUI 正是在这里、在 AMS 的 systemReady 回调中被启动
        startOtherServices();
        // 进入消息循环
        Looper.loop();
    }
}

关键设计startOtherServices() 只是把所有服务"启动起来",SystemUI 并不是在这里直接拉起,而是等到 AMS 发出 systemReady 回调时才真正启动,以保证 AMS / WMS 等核心服务已就绪。

2.2 startOtherServices() 中的 SystemUI 启动

SystemUI 的启动发生在 startOtherServices() 方法中,在 AMS 的 systemReady() 回调里执行。回调内部用 try/catch 包裹,并用 Trace 标记出这段耗时,启动 SystemUI 的调用就藏在这段 run() 里。

源码路径frameworks/base/services/java/com/android/server/SystemServer.java

java 复制代码
public final class SystemServer {
    // ...
    private void startOtherServices() {
        // ... 启动大量系统服务 ...

        mActivityManagerService.systemReady(new Runnable() {
            @Override
            public void run() {
                Slog.i(TAG, "Making services ready");
                // ... 进入 PHASE_ACTIVITY_MANAGER_READY、启动各项 systemReady ...

                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartSystemUI");
                try {
                    startSystemUi(context);   // 启动 SystemUI
                } catch (Throwable e) {
                    reportWtf("starting System UI", e);
                }
                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
                // ... 继续把其它服务置为 ready ...
            }
        });
    }
}

2.3 startSystemUi() 方法详解

startSystemUi() 是一个 static final 方法,它构造一个显式 Intent 指定 SystemUIService 组件,再以 SYSTEM 用户身份启动它。

源码路径frameworks/base/services/java/com/android/server/SystemServer.java

java 复制代码
public final class SystemServer {
    // ...
    static final void startSystemUi(Context context) {
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.android.systemui",
                    "com.android.systemui.SystemUIService"));
        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
        context.startServiceAsUser(intent, UserHandle.SYSTEM);
    }
}

关键设计 :这里用 startServiceAsUserUserHandle.SYSTEM 身份、显式指定 com.android.systemui.SystemUIService 组件来启动 SystemUI。SystemUI 本身是 Service 而非 Activity,运行在独立进程里(由 AndroidManifest.xmlandroid:process 决定)。

三、阶段二:SystemUIService 的初始化

3.1 SystemUIService 的 onCreate()

SystemUIService 本身几乎没有逻辑,onCreate() 只做一件事:把真正的启动逻辑委托给 SystemUIApplicationstartServicesIfNeeded()

源码路径frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java

java 复制代码
public class SystemUIService extends Service {

    @Override
    public void onCreate() {
        super.onCreate();
        ((SystemUIApplication) getApplication()).startServicesIfNeeded();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

关键设计SystemUIService 没有重写 onStartCommand(),启动动作全部发生在 onCreate() 中------它把 this 强转为 SystemUIApplication 并调用 startServicesIfNeeded(),真正的子模块加载逻辑都在 Application 那一层。

3.2 SystemUI 的 AndroidManifest 配置

xml 复制代码
<!-- frameworks/base/packages/SystemUI/AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.systemui"
    coreApp="true"
    android:sharedUserId="android.uid.system">  <!-- ★ 系统 UID -->
    
    <application
        android:name=".SystemUIApplication"
        android:persistent="true"                <!-- ★ 持续运行 -->
        android:process="com.android.systemui"   <!-- ★ 独立进程 -->
        ...>
        
        <service
            android:name="SystemUIService"
            android:exported="true"
            .../>
    </application>
</manifest>

下面三个属性决定了 SystemUI 能以系统身份、独立进程、常驻方式运行:

属性 含义
android:sharedUserId android.uid.system 系统级权限
android:persistent true 进程被杀后自动重启
android:process com.android.systemui 独立的进程空间

四、阶段三:SystemUIApplication 加载子模块

4.1 startServicesIfNeeded() 方法

startServicesIfNeeded() 是启动子模块的核心循环:遍历组件数组,逐个实例化并注入上下文,然后调用每个模块的 start()。注意它并不从资源里读字符串数组,而是遍历一个硬编码的 Class<?>[]

源码路径frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java

java 复制代码
public class SystemUIApplication extends Application {
    private final Class<?>[] SERVICES = new Class[] { /* 见 4.2 节 */ };
    private final SystemUI[] mServices = new SystemUI[SERVICES.length];
    private boolean mServicesStarted;
    private boolean mBootCompleted;
    private final Map<Class<?>, Object> mComponents = new HashMap<>();

    public void startServicesIfNeeded() {
        startServicesIfNeeded(SERVICES);
    }

    private void startServicesIfNeeded(Class<?>[] services) {
        if (mServicesStarted) {
            return;
        }
        // ... 检查 sys.boot_completed 判断是否已经开机完成 ...
        final int N = services.length;
        for (int i = 0; i < N; i++) {
            Class<?> cl = services[i];
            try {
                Object newService = SystemUIFactory.getInstance().createInstance(cl);
                mServices[i] = (SystemUI) ((newService == null) ? cl.newInstance() : newService);
            } catch (IllegalAccessException ex) {
                throw new RuntimeException(ex);
            } catch (InstantiationException ex) {
                throw new RuntimeException(ex);
            }
            mServices[i].mContext = this;
            mServices[i].mComponents = mComponents;
            mServices[i].start();
            if (mBootCompleted) {
                mServices[i].onBootCompleted();
            }
        }
        mServicesStarted = true;
    }
}

关键设计 :实例化优先走 SystemUIFactory.getInstance().createInstance(cl),只有当工厂返回 null 时才回退到 cl.newInstance(),并非纯反射 Class.forName(name)。启动顺序即数组顺序,且若系统已 BOOT_COMPLETED 会顺带调用 onBootCompleted()

4.2 硬编码的 SERVICES 组件数组

SystemUI 的"启动清单"并不是资源里的字符串数组,而是一个硬编码在 SystemUIApplication 里的 Class<?>[] SERVICES,数组顺序即启动顺序:

源码路径frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java

java 复制代码
public class SystemUIApplication extends Application {
    private final Class<?>[] SERVICES = new Class[] {
            com.android.systemui.tuner.TunerService.class,
            com.android.systemui.keyguard.KeyguardViewMediator.class,
            com.android.systemui.recents.Recents.class,
            com.android.systemui.volume.VolumeUI.class,
            Divider.class,
            com.android.systemui.statusbar.SystemBars.class,
            com.android.systemui.usb.StorageNotification.class,
            com.android.systemui.power.PowerUI.class,
            com.android.systemui.media.RingtonePlayer.class,
            com.android.systemui.keyboard.KeyboardUI.class,
            com.android.systemui.tv.pip.PipUI.class,
            com.android.systemui.shortcut.ShortcutKeyDispatcher.class,
            com.android.systemui.VendorServices.class
    };
}

关键设计 :调整子模块的启动顺序,需要直接改这个 Class<?>[] SERVICES 数组,而 SERVICES.length 也决定了 mServices 数组的大小。

4.3 SystemUI 基类

所有子模块都继承自 SystemUI 基类。它声明了 mContextmComponents 两个共享字段,以及抽象的 start() 和若干可选回调,startServicesIfNeeded() 循环里注入的正是这两个字段。

源码路径frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUI.java

java 复制代码
public abstract class SystemUI {
    public Context mContext;
    public Map<Class<?>, Object> mComponents;

    public abstract void start();

    protected void onConfigurationChanged(Configuration newConfig) {
    }

    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    }

    protected void onBootCompleted() {
    }

    // ... getComponent / putComponent 依赖注入辅助方法 ...
}

关键设计 :这是一个典型的模板方法模式 ------基类定义字段与生命周期框架,子类只需实现 start() 完成各自初始化;mComponents 是模块间共享的依赖容器,onBootCompleted() 则在系统完成开机后统一回调。

五、启动时序图

复制代码
SystemServer            SystemUIService       SystemUIApplication       各子模块 (SERVICES[i])
    |                          |                       |                        |
    |--startSystemUi()-------->|                       |                        |
    |  (startServiceAsUser)    |                       |                        |
    |                          |--onCreate()---------->|                        |
    |                          |                       |                        |
    |                          |   startServicesIfNeeded()                     |
    |                          |                       |                        |
    |                          |        遍历 Class<?>[] SERVICES:               |
    |                          |                       |                        |
    |                          |  SystemUIFactory.createInstance / cl.newInstance
    |                          |                       |                        |
    |                          |              mServices[i].start()------------->|
    |                          |                       |                        |
    |                          |                       |   TunerService        |
    |                          |                       |   KeyguardViewMediator|
    |                          |                       |   Recents             |
    |                          |                       |   SystemBars          |
    |                          |                       |   PowerUI ...         |
    |                          |                       |                        |
    |                          |<-----启动完成-----------|                        |
    |                          |                       |                        |

六、启动顺序的重要影响

6.1 为什么 TunerService 和 KeyguardViewMediator 排在前面?

TunerServiceSERVICES 数组的第一个元素,负责调参/调试相关的早期初始化;紧随其后的 KeyguardViewMediator 负责锁屏窗口,是开机后最先需要呈现给用户界面的模块之一,因此需要在更靠后的 SystemBars 之前就位。

6.2 为什么 SystemBars 在中间?

SystemBars 负责创建状态栏和导航栏窗口,它排在 KeyguardViewMediatorRecentsVolumeUIDivider 之后,等这些依赖基础窗口的模块就绪后再构建状态栏/导航栏窗口,避免早期模块引用到尚未创建的状态栏。

6.3 为什么 VendorServices 在最后?

VendorServices 是设备厂商的扩展入口,放在最后确保所有 AOSP 标准模块都已初始化完成。

七、启动流程中的关键日志

在调试 SystemUI 启动问题时,可以关注以下日志标签:

bash 复制代码
# 查看 SystemServer 启动 SystemUI 的日志
adb logcat | grep "SystemServer"

# 查看 SystemUI 各模块启动日志
adb logcat | grep "SystemUIService"
adb logcat | grep "SystemUIApplication"

# 查看具体模块的启动状态
adb logcat | grep "PhoneStatusBar"
adb logcat | grep "KeyguardViewMediator"
adb logcat | grep "SystemBars"

八、小结

本文梳理了 SystemUI 从 SystemServer 到各个子模块的完整启动链路:

  1. SystemServer.startSystemUi() → 以 Service 形式启动 SystemUIService
  2. SystemUIService.onCreate() → 委托给 SystemUIApplication.startServicesIfNeeded()
  3. SystemUIApplication → 遍历硬编码的 Class<?>[] SERVICES,通过 SystemUIFactory(回退 newInstance())逐一实例化并调用 start()

关键设计思想

  • 统一入口 :所有子模块由 SystemUIApplicationSERVICES 数组顺序统一拉起
  • 统一基类 :所有子模块继承 SystemUI,统一生命周期管理
  • 依赖注入mComponents 容器 + SystemUIFactory 管理模块间的依赖关系
  • 独立进程:SystemUI 拥有独立进程空间,与系统服务通过 Binder 通信

下一篇我们将深入 SystemUI 的核心枢纽------StatusBar 状态栏 ,从 PhoneStatusBarmakeStatusBarView() 开始,逐一拆解状态栏窗口的创建、图标管理和下拉手势处理。


下一篇:AOSP7 SystemUI 源码解析(三):StatusBar 状态栏源码分析

相关推荐
2501_916007471 小时前
苹果商店iOS应用上架费用全面解析:开发者计划与审核费用计算
android·ios·小程序·https·uni-app·iphone·webview
Android打工仔1 小时前
Kotlin 协程源码解析:协程是如何切换线程的?
android·kotlin
mmsx1 小时前
Android GIS系列 内存加锁、SQLite 开事务:矢量数据集双层并发设计
android·性能优化·app
Godikov1 小时前
没有 adb 怎么排查接口问题?给 OkHttp 加一个"永不炸"的文件日志拦截器
android
邪修king2 小时前
Re:Linux 系统篇(三十四):进程间通信开篇Chapter1 —— 匿名管道 pipe 深度拆解与代码实战
android·linux·运维·开发语言
AFinalStone2 小时前
Android7 SystemUI 源码解析(一)全景概览与架构设计
android·systemui
2501_916008893 小时前
如何实现iOS App代码混淆:SwiftShield使用指南
android·ios·小程序·https·uni-app·iphone·webview
恋猫de小郭3 小时前
AndroidX 新增 Security State ,支持可编程的系统安全状态查询
android·前端·flutter
AFinalStone4 小时前
Android7 SystemUI 源码解析(六)QuickSettings快捷设置面板
android·systemui