Android14 SystemUI 启动过程

134 阅读6分钟

SystemUI 在Android 系统中是非常重要的部分,SystemUI 是一个系统APK,代码位置在 frameworks/base/packages/SystemUI/ . 从代码位置也可以看出SystemUI 非常重要, SystemUI 源码很庞大, 需要一点一点的分析。

这篇文章主要介绍SystemUI 启动过程

如何启动SystemUI

SystemUI 启动是在 SystemServerstartOtherServices 方法中开始的 frameworks/base/services/java/com/android/server/SystemServer.java

t.traceBegin("StartSystemUI");
    try {
        startSystemUi(context, windowManagerF);
    } catch (Throwable e) {
        reportWtf("starting System UI", e);
    }
    t.traceEnd();

这里需要注意一下 windowManagerF 这个变量, windowManagerFWindowManagerService

private static void startSystemUi(Context context, WindowManagerService windowManager) {
        PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
        Intent intent = new Intent();
        intent.setComponent(pm.getSystemUiServiceComponent());
        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
        //Slog.d(TAG, "Starting service: " + intent);
        context.startServiceAsUser(intent, UserHandle.SYSTEM);
        windowManager.onSystemUiStarted();
    }

这里主要是做了两件事

  1. 启动SystemUIService
  2. 绑定WMS绑定KeyguardService

看一下是如何启动SystemUIService frameworks/base/services/core/java/com/android/server/pm/PackageManagerInternalBase.java

public final ComponentName getSystemUiServiceComponent() {
        return ComponentName.unflattenFromString(getContext().getResources().getString(
                com.android.internal.R.string.config_systemUIServiceComponent));
    }

这里是通过config 中获取 config_systemUIServiceComponent 对应启动的SystemUI 中对应的服务的,看一下config中具体内容 frameworks/base/core/res/res/values/config.xml

<string name="config_systemUIServiceComponent" translatable="false"
                >com.android.systemui/com.android.systemui.SystemUIService</string>

从config 文件中可以看到启动了SystemUIService 服务

简单在看一下绑定WMS绑定KeyguardService 过程,这里不详细分析

通过 windowManager.onSystemUiStarted(); 触发 frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

public void onSystemUiStarted() {
        mPolicy.onSystemUiStarted();
    }

mPolicyPhoneWindowManager 的实现 frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

public void onSystemUiStarted() {
        bindKeyguard();
    }

    private void bindKeyguard() {
        synchronized (mLock) {
            if (mKeyguardBound) {
                return;
            }
            mKeyguardBound = true;
        }
        mKeyguardDelegate.bindService(mContext);
    }

mKeyguardDelegate 实现类是 KeyguardServiceDelegate frameworks/base/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java

public void bindService(Context context) {
        Intent intent = new Intent();
        final Resources resources = context.getApplicationContext().getResources();

        final ComponentName keyguardComponent = ComponentName.unflattenFromString(
                resources.getString(com.android.internal.R.string.config_keyguardComponent));
        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
        intent.setComponent(keyguardComponent);

        if (!context.bindServiceAsUser(intent, mKeyguardConnection,
                Context.BIND_AUTO_CREATE, mHandler, UserHandle.SYSTEM)) {
            mKeyguardState.showing = false;
            mKeyguardState.secure = false;
            synchronized (mKeyguardState) {
                mKeyguardState.deviceHasKeyguard = false;
            }
        } else {
            if (DEBUG) Log.v(TAG, "*** Keyguard started");
        }

        final DreamManagerInternal dreamManager =
                LocalServices.getService(DreamManagerInternal.class);

        dreamManager.registerDreamManagerStateListener(mDreamManagerStateListener);
    }

从代码中发现这里面绑定的Service 也是通过config 中 config_keyguardComponent 获取要绑定哪个服务的, 看一下config中具体内容 frameworks/base/core/res/res/values/config.xml

<string name="config_keyguardComponent" translatable="false"
                >com.android.systemui/com.android.systemui.keyguard.KeyguardService</string>

通过config 文件内容可以知道这里绑定的服务是KeyguardService

到此SystemServer 分析完毕

SystemUI 启动

这里需要注意一下SystemUI 的AndroidManifest.xml文件 application

<application
            android:name=".SystemUIApplication"
            android:persistent="true"
            android:allowClearUserData="false"
            android:backupAgent=".backup.BackupHelper"
            android:killAfterRestore="false"
            android:hardwareAccelerated="true"
            android:label="@string/app_label"
            android:icon="@drawable/android14_patch_adaptive"
            android:process="com.android.systemui"
            android:supportsRtl="true"
            android:theme="@style/Theme.SystemUI"
            android:defaultToDeviceProtectedStorage="true"
            android:directBootAware="true"
            tools:replace="android:appComponentFactory"
            android:appComponentFactory=".SystemUIAppComponentFactory">

发现在 的AndroidManifest 中配置了appComponentFactory ,这个不在这里展开, 在应用启动的时候会先调用 这个配置进行一些初始化 看一下SystemUIAppComponentFactory 这个实现 frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java

/**
 * Starts up SystemUI using the AOSP {@link SystemUIInitializerImpl}.
 *
 * This initializer relies on reflection to start everything up and should be considered deprecated.
 * Instead, create your own {@link SystemUIAppComponentFactoryBase}, specify it in your
 * AndroidManifest.xml and construct your own {@link SystemUIInitializer} directly.
 *
 * @deprecated Define your own SystemUIAppComponentFactoryBase implementation and use that. This
 *             implementation may be changed or removed in future releases.
 */
@Deprecated
public class SystemUIAppComponentFactory extends SystemUIAppComponentFactoryBase {
    @Override
    protected SystemUIInitializer createSystemUIInitializer(Context context) {
        return SystemUIInitializerFactory.createWithContext(context);
    }
}

这里需要注意一下注释, 这个在后面的版本可能被废弃 frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIInitializerFactory.kt 看一下SystemUIAppComponentFactoryBase的主要实现 frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt 先看两个接口:

fun interface ContextAvailableCallback {
    fun onContextAvailable(context: Context): SystemUIInitializer
}


interface ContextInitializer {
    fun setContextAvailableCallback(callback: ContextAvailableCallback)
}

定义了一个方法callback 接口, 一个上下文实现类的接口, 后面会详细介绍, 这里只要记得有这样一组接口定义

下面分段看一下,

protected abstract fun createSystemUIInitializer(context: Context): SystemUIInitializer

private fun createSystemUIInitializerInternal(context: Context): SystemUIInitializer {
    return systemUIInitializer ?: run {
        val initializer = createSystemUIInitializer(context.applicationContext)
        try {
            initializer.init(false)
        } catch (exception: ExecutionException) {
            throw RuntimeException("Failed to initialize SysUI", exception)
        } catch (exception: InterruptedException) {
            throw RuntimeException("Failed to initialize SysUI", exception)
        }
        initializer.sysUIComponent.inject(
            this@SystemUIAppComponentFactoryBase
        )

        systemUIInitializer = initializer
        return initializer
    }
}

override fun instantiateApplicationCompat(cl: ClassLoader, className: String): Application {
    val app = super.instantiateApplicationCompat(cl, className)
    if (app !is ContextInitializer) {
        throw RuntimeException("App must implement ContextInitializer")
    } else {
        app.setContextAvailableCallback { context ->
            createSystemUIInitializerInternal(context)
        }
    }

    return app
    }

在APP 初始化Application时会调用instantiateApplicationCompat 方法, 通过上面代码猜测SystemUIApplication 中实现了ContextInitializer 接口, 向SystemUIApplication 设置了一个Callback , 当Callback 调用时会调用createSystemUIInitializerInternal 方法回调抽象方法createSystemUIInitializer创建一个 SystemUIInitializer 实现类, 并且初始化

下面看一下初始化的时候都做了什么 frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java

public void init(boolean fromTest) throws ExecutionException, InterruptedException {
        mRootComponent = getGlobalRootComponentBuilder()
                .context(mContext)
                .instrumentationTest(fromTest)
                .build();

        mInitializationChecker = mRootComponent.getInitializationChecker();
        boolean initializeComponents = mInitializationChecker.initializeComponents();

        // Stand up WMComponent
        setupWmComponent(mContext);

        // And finally, retrieve whatever SysUI needs from WMShell and build SysUI.
        SysUIComponent.Builder builder = mRootComponent.getSysUIComponent();
        if (initializeComponents) {
            // Only initialize when not starting from tests since this currently initializes some
            // components that shouldn't be run in the test environment
            builder = prepareSysUIComponentBuilder(builder, mWMComponent)
                    .setShell(mWMComponent.getShell())
                    .setPip(mWMComponent.getPip())
                    .setSplitScreen(mWMComponent.getSplitScreen())
                    .setOneHanded(mWMComponent.getOneHanded())
                    .setBubbles(mWMComponent.getBubbles())
                    .setTaskViewFactory(mWMComponent.getTaskViewFactory())
                    .setTransitions(mWMComponent.getTransitions())
                    .setKeyguardTransitions(mWMComponent.getKeyguardTransitions())
                    .setStartingSurface(mWMComponent.getStartingSurface())
                    .setDisplayAreaHelper(mWMComponent.getDisplayAreaHelper())
                    .setRecentTasks(mWMComponent.getRecentTasks())
                    .setBackAnimation(mWMComponent.getBackAnimation())
                    .setDesktopMode(mWMComponent.getDesktopMode());

            // Only initialize when not starting from tests since this currently initializes some
            // components that shouldn't be run in the test environment
            mWMComponent.init();
        } else {
            // TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option
            // is separating this logic into newly creating SystemUITestsFactory.
            builder = prepareSysUIComponentBuilder(builder, mWMComponent)
                    .setShell(new ShellInterface() {})
                    .setPip(Optional.ofNullable(null))
                    .setSplitScreen(Optional.ofNullable(null))
                    .setOneHanded(Optional.ofNullable(null))
                    .setBubbles(Optional.ofNullable(null))
                    .setTaskViewFactory(Optional.ofNullable(null))
                    .setTransitions(new ShellTransitions() {})
                    .setKeyguardTransitions(new KeyguardTransitions() {})
                    .setDisplayAreaHelper(Optional.ofNullable(null))
                    .setStartingSurface(Optional.ofNullable(null))
                    .setRecentTasks(Optional.ofNullable(null))
                    .setBackAnimation(Optional.ofNullable(null))
                    .setDesktopMode(Optional.ofNullable(null));
        }
        mSysUIComponent = builder.build();
        if (initializeComponents) {
            mSysUIComponent.init();
        }

        // Every other part of our codebase currently relies on Dependency, so we
        // really need to ensure the Dependency gets initialized early on.
        Dependency dependency = mSysUIComponent.createDependency();
        dependency.start();
    }

在初始化的时候主要是实例化mSysUIComponent 变量, 这里需要重点关注mSysUIComponent 这个变量。

最后下面看一下 SystemUIApplication 类继承关系, 发现 SystemUIApplication 确实实现了 SystemUIAppComponentFactory.ContextInitializer frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java

public class SystemUIApplication extends Application implements
        SystemUIAppComponentFactory.ContextInitializer {
}

下面看一下在SystemUIApplication中什么时候调用的Callback 进行初始化的。

public void setContextAvailableCallback(SystemUIAppComponentFactory.ContextAvailableCallback callback) {
    mContextAvailableCallback = callback;
}

public void onCreate() {
    mInitializer = mContextAvailableCallback.onContextAvailable(this);
    mSysUIComponent = mInitializer.getSysUIComponent();
}

onCreate 会掉Callback 方法时, 最终会调用到 SystemUIInitializerFactorycreateFromConfigNoAssert 方法中创建一个 SystemUIInitializerImpl 的实例, 然后给mSysUIComponent变量赋值, 这里注意一下 mSysUIComponent 是在 SystemUIInitializerinit时候创建的 mSysUIComponent, 这个很关键,后面会再次用到

object SystemUIInitializerFactory {
    @JvmStatic
    @VisibleForTesting
    fun createFromConfigNoAssert(context: Context): SystemUIInitializer {
        return initializer ?: run {
            val className = context.getString(R.string.config_systemUIFactoryComponent)
            if (className.isEmpty()) {
                throw RuntimeException("No SystemUIFactory component configured")
            }
            try {
                val cls = context.classLoader.loadClass(className)
                val constructor = cls.getConstructor(Context::class.java)
                (constructor.newInstance(context) as SystemUIInitializer).apply {
                    initializer = this
                }
            } catch (t: Throwable) {
                Log.w(TAG, "Error creating SystemUIInitializer component: $className", t)
                throw t
            }
        }
    }
}

通过读取config 文件中 config_systemUIFactoryComponent 值,然后通过反射的方式创建对象,下面看一下 config_systemUIFactoryComponent 内容 frameworks/base/packages/SystemUI/res/values/config.xml

<!-- SystemUIFactory component -->
<string name="config_systemUIFactoryComponent" translatable="false">com.android.systemui.SystemUIInitializerImpl</string>

SystemUIInitializerImpl 的实现 frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIInitializerImpl.kt

class SystemUIInitializerImpl(context: Context) : SystemUIInitializer(context) {
    override fun getGlobalRootComponentBuilder(): GlobalRootComponent.Builder {
        return DaggerReferenceGlobalRootComponent.builder()
    }
}

这里主要是返回一个注入的builder , 这里需要知道DaggerReferenceGlobalRootComponent 对应的实现是 ReferenceGlobalRootComponent 到这里初始化基本完成。

下面需要看最关键的地方SystemUiService frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java

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

发现在SystemUiService中又调用到了SystemUIApplication 中,下面看一下 startServicesIfNeeded()

public void startServicesIfNeeded() {
    final String vendorComponent = mInitializer.getVendorComponent(getResources());

    Map<Class<?>, Provider<CoreStartable>> sortedStartables = new TreeMap<>(
            Comparator.comparing(Class::getName));
    sortedStartables.putAll(mSysUIComponent.getStartables());
    sortedStartables.putAll(mSysUIComponent.getPerUserStartables());
    startServicesIfNeeded(
            sortedStartables, "StartServices", vendorComponent);
}

注意到getStartables()getPerUserStartables() 两个方法, 都是用来获取CoreStartable组件的映射,区别在于getStartables()返回的是全局的组件,getPerllserStartables()返回的是每个用户特有的组件。

通过Dagger2框架实现的依赖注入策略,它允许自动发现和注入所有实现了特定接口(这里是CoreStartable 的类,并将它们组织到一个Map集合中。当调用getStartables()方法时,你会得到一个包含所有CoreStartable实现类的提供者的Map。

简单看一下 SysUIComponent frameworks/base/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java

@SysUISingleton
@Subcomponent(modules = {
        DefaultComponentBinder.class,
        DependencyProvider.class,
        NotificationInsetsModule.class,
        QsFrameTranslateModule.class,
        SystemUIBinder.class,
        SystemUIModule.class,
        SystemUICoreStartableModule.class,
        ReferenceSystemUIModule.class})
public interface SysUIComponent {

    /**
     * Returns {@link CoreStartable}s that should be started with the application.
     */
    Map<Class<?>, Provider<CoreStartable>> getStartables();

    /**
     * Returns {@link CoreStartable}s that should be started for every user.
     */
    @PerUser Map<Class<?>, Provider<CoreStartable>> getPerUserStartables();

}

发现上面代码modules中有SystemUICoreStartableModule, 这个module 是对CoreStartable实现的注入类 frameworks/base/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt

下面在回头看一下SystemUIApplicationstartServicesIfNeeded 方法的重载方法

private void startServicesIfNeeded(
        Map<Class<?>, Provider<CoreStartable>> startables,
        String metricsPrefix,
        String vendorComponent) {
   // 省略掉部分代码

    int i = 0;
    for (Map.Entry<Class<?>, Provider<CoreStartable>> entry : startables.entrySet()) {
        String clsName = entry.getKey().getName();
        int j = i;  // Copied to make lambda happy.
        timeInitialization(
                clsName,
                () -> mServices[j] = startStartable(clsName, entry.getValue()),
                log,
                metricsPrefix);
        i++;
    }
    // 省略掉部分代码

}

private static void timeInitialization(String clsName, Runnable init, TimingsTraceLog log,
        String metricsPrefix) {
    long ti = System.currentTimeMillis();
    log.traceBegin(metricsPrefix + " " + clsName);
    init.run();
    log.traceEnd();

    // Warn if initialization of component takes too long
    ti = System.currentTimeMillis() - ti;
    if (ti > 1000) {
        Log.w(TAG, "Initialization of " + clsName + " took " + ti + " ms");
    }
}

private static CoreStartable startStartable(String clsName, Provider<CoreStartable> provider) {
    if (DEBUG) Log.d(TAG, "loading: " + clsName);
    if (Trace.isEnabled()) {
        Trace.traceBegin(
                Trace.TRACE_TAG_APP, "Provider<" + clsName + ">.get()");
    }
    CoreStartable startable = provider.get();
    Trace.endSection();
    return startStartable(startable);
}

private static CoreStartable startStartable(CoreStartable startable) {
    if (DEBUG) Log.d(TAG, "running: " + startable);
    if (Trace.isEnabled()) {
        Trace.traceBegin(
                Trace.TRACE_TAG_APP, startable.getClass().getSimpleName() + ".start()");
    }
    startable.start();
    Trace.endSection();

    return startable;
}

通过上面代码可以知道最终会调用 CoreStartable 实现类中 start() 方法。到此启动完成。