SystemUI 在Android 系统中是非常重要的部分,SystemUI 是一个系统APK,代码位置在 frameworks/base/packages/SystemUI/
. 从代码位置也可以看出SystemUI 非常重要, SystemUI 源码很庞大, 需要一点一点的分析。
这篇文章主要介绍SystemUI 启动过程
如何启动SystemUI
SystemUI 启动是在 SystemServer
中 startOtherServices
方法中开始的 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
这个变量, windowManagerF
是WindowManagerService
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();
}
这里主要是做了两件事
- 启动
SystemUIService
- 绑定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();
}
mPolicy
是 PhoneWindowManager
的实现
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 方法时, 最终会调用到 SystemUIInitializerFactory
中 createFromConfigNoAssert
方法中创建一个 SystemUIInitializerImpl
的实例, 然后给mSysUIComponent
变量赋值, 这里注意一下 mSysUIComponent
是在 SystemUIInitializer
中init
时候创建的 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
下面在回头看一下SystemUIApplication
中 startServicesIfNeeded
方法的重载方法
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()
方法。到此启动完成。