SystemUI分析
简介
SystemUI是一个持续的进程,为系统提供UI,作为Android系统的核心应用,SystemUI负责反馈系统及应用状态并与用户保持大量的交付。
SystemUI的路径
代码位置在
frameworks\base\packages\SystemUI
apk安装目录
system/priv-app/SystemUI
不同手机的SystemUI可能有所不同,比如小米手机的安装目录就是system/priv-app/MiuiSystemUI
功能划分
- StatusBar(状态栏):通知消息提示和状态展示
- NavigationBar(导航栏):返回,HOME,Recent
- KeyGuard(键盘锁):锁屏模块
- Recents:近期应用管理,以堆叠的形式展示
- Notification Panel(通知面板):展示系统或应用的通知内容,提供快速系统设置开关
- Volume:展示或控制音量的变化:媒体、铃音、通知、通话音量
- ScreenShot(截屏):长按电源键+音量下键后截屏,用以展示截取的屏幕照片/内容
- PowerUI:主要处理和Power相关的事件。
- RingtonePlayer:铃音播放
- StackDivider:控制管理分屏
- PipUI:画中画管理(Android7.0)
SystemUI启动流程分析
SystemUI的启动是由SystemServer开始。SystemServer由Zygote fork生成的,进程名为system_server,system_server是framework的核心服务。Zygote启动过程中会调用startSystemServer()。SystemUI的启动是从SystemUI的main方法开始。大致流程如下
frameworks/base/services/java/com/android/server/SystemServer.java
/**
* The main entry point from zygote.
*/
public static void main(String[] args) {
new SystemServer().run();
}
private void run() {
/*
*省略代码
*/
// Start services.
try {
traceBeginAndSlog("StartServices");
startBootstrapServices();
startCoreServices();
startOtherServices(); //systemUI在这个里面启动
SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
traceEnd();
}
}
/**
* Starts a miscellaneous grab bag of stuff that has yet to be refactored
* and organized.
*/
private void startOtherServices() {
... //省略大概1000行
mActivityManagerService.systemReady(() -> {
Slog.i(TAG, "Making services ready");
...
traceBeginAndSlog("StartSystemUI");
try {
startSystemUi(context, windowManagerF);
} catch (Throwable e) {
reportWtf("starting System UI", e);
}
...
}
}
static final void startSystemUi(Context context, WindowManagerService windowManager) {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.systemui",
"com.android.systemui.SystemUIService"));
intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
//Slog.d(TAG, "Starting service: " + intent);
context.startServiceAsUser(intent, UserHandle.SYSTEM);
windowManager.onSystemUiStarted();
}
SystemUI的run会启动各种重要的服务,在startOtherServices方法中启动SystemUI()。在startOtherServices()中,通过调用AMS的systemReady()方法通知AMS准备就绪。systemReady()拥有一个名为goingCallback的Runnable实例作为参数,当AMS完成对systemReady()的处理后将会回调这一Runnable的run()方法。startSystemUi这个方法主要是启动com.android.systemui.SystemUIService这个服务,但是需要注意的是,这时候SystemUI还没启动成功,因为startOtherService()方法都还没有执行完毕。所以暂时还不会发送ACTION_BOOT_COMPLETE广播,该广播是在AMS中的finishBooting()中发送的。(该广播在我们SystemUIService中有做监听,用来判断是否完成系统启动)。
frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java
@Override
37 public void onCreate() {
38 super.onCreate();
39 ((SystemUIApplication) getApplication()).startServicesIfNeeded();
40
41 // For debugging RescueParty
42 if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_sysui", false)) {
43 throw new RuntimeException();
44 }
45
46 if (Build.IS_DEBUGGABLE) {
47 // b/71353150 - looking for leaked binder proxies
48 BinderInternal.nSetBinderProxyCountEnabled(true);
49 BinderInternal.nSetBinderProxyCountWatermarks(1000,900);
50 BinderInternal.setBinderProxyCountCallback(
51 new BinderInternal.BinderProxyLimitListener() {
52 @Override
53 public void onLimitReached(int uid) {
54 Slog.w(SystemUIApplication.TAG,
55 "uid " + uid + " sent too many Binder proxies to uid "
56 + Process.myUid());
57 }
58 }, Dependency.get(Dependency.MAIN_HANDLER));
59 }
60 }
这里面的核心代码就只有一行
((SystemUIApplication) getApplication()).startServicesIfNeeded();
这里需要说明一下Service和Application的创建先后
(1)实例Service;
(2)实例Application;
(3)Application实例执行onCreate方法;
(4)Service实例执行onCrate方法。
所以在SystemUI启动过程中,SystemUIApplication.java的onCreate方法先于SystemUIService.java的oncreate方法。
@Override
62 public void onCreate() {
63 super.onCreate();
64 // Set the application theme that is inherited by all services. Note that setting the
65 // application theme in the manifest does only work for activities. Keep this in sync with
66 // the theme set there. 设置主题
67 setTheme(R.style.Theme_SystemUI);
68 //android 7.0以后引入,方便定制
69 SystemUIFactory.createFromConfig(this);
70 //判断是系统还是切换到其它用户
71 if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
72 IntentFilter bootCompletedFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
73 bootCompletedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
74 registerReceiver(new BroadcastReceiver() {
75 @Override
76 public void onReceive(Context context, Intent intent) {
77 if (mBootCompleted) return;
78
79 if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");
80 unregisterReceiver(this);
81 mBootCompleted = true;
82 if (mServicesStarted) { //该变量表示SystemUIService是否已经启动了
83 final int N = mServices.length;
84 for (int i = 0; i < N; i++) {
85 mServices[i].onBootCompleted();
86 }
87 }
88
89
90 }
91 }, bootCompletedFilter);
92
93 IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
94 registerReceiver(new BroadcastReceiver() {
95 @Override
96 public void onReceive(Context context, Intent intent) {
97 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
98 if (!mBootCompleted) return;
99 // Update names of SystemUi notification channels
100 NotificationChannels.createAll(context);
101 }
102 }
103 }, localeChangedFilter);
104 } else {
105 // We don't need to startServices for sub-process that is doing some tasks.
106 // (screenshots, sweetsweetdesserts or tuner ..)
107 String processName = ActivityThread.currentProcessName();
108 ApplicationInfo info = getApplicationInfo();
109 if (processName != null && processName.startsWith(info.processName + ":")) {
110 return;
111 }
112 // For a secondary user, boot-completed will never be called because it has already
113 // been broadcasted on startup for the primary SystemUI process. Instead, for
114 // components which require the SystemUI component to be initialized per-user, we
115 // start those components now for the current non-system user.
//非系统用户
116 startSecondaryUserServicesIfNeeded();
117 }
118 }
119
在Application的oncreate中会区分系统用户和非系统用户来区分流程。如果是系统用户会接收两个广播Intent.ACTION_BOOT_COMPLETED和Intent.ACTION_LOCALE_CHANGED。 Intent.ACTION_BOOT_COMPLETED是监听开机启动,从android 7.0以后,android提供FBE加密方式(https://source.android.google.cn/security/encryption/file-based),在这种情况下,要等到系统启动并锁屏界面解锁后,在进入到桌面过程中,系统才会发送该广播,所以接收该广播的处理逻辑比较延后,SystemUIService启动完后才接收到该广播,所以startServicesIfNeeded方法会先执行,开机广播只会处理一次,就会注销该广播,以后就不会再接收了。mService[]数组存储的是SystemUI的子服务,当整个系统启动完成后,这里面的每个子服务都会执行onBootCompleted()方法,让各个子服务知道系统启动完成了,开始执行任务。
Intent.ACTION_LOCALE_CHANGED广播是用于监听设备当前区域设置已更改时发出的广播,简单来说就是修改语言时发出的广播(暂时不知道其它动作是否也会发送该广播)。
startSecondaryUserServicesIfNeeded
只会发生在系统启动之后。
/**
133 * Ensures that all the Secondary user SystemUI services are running. If they are already
134 * running, this is a no-op. This is needed to conditinally start all the services, as we only
135 * need to have it in the main process.
136 * <p>This method must only be called from the main thread.</p>
137 */
138 void startSecondaryUserServicesIfNeeded() {
139 String[] names =
140 getResources().getStringArray(R.array.config_systemUIServiceComponentsPerUser);//需要启动的服务
141 startServicesIfNeeded(names);
142 }
config_systemUIServiceComponentsPerUser在frameworks/base/packages/SystemUI/res/values/config.xml中,需要说明的是,Android9.0才引入这种模式,之前版本都是通过数组直接写在代码中。
<!-- SystemUI Services (per user): The classes of the stuff to start for each user. This is a subset of the config_systemUIServiceComponents -->
359 <string-array name="config_systemUIServiceComponentsPerUser" translatable="false">
360 <item>com.android.systemui.Dependency</item> //一种静态依赖项
361 <item>com.android.systemui.util.NotificationChannels</item> //通知
362 <item>com.android.systemui.recents.Recents</item> //多任务
363 </string-array>
再看一下
/**
121 * Makes sure that all the SystemUI services are running. If they are already running, this is a
122 * no-op. This is needed to conditinally start all the services, as we only need to have it in
123 * the main process.
124 * <p>This method must only be called from the main thread.</p>
125 */
126
127 public void startServicesIfNeeded() {
128 String[] names = getResources().getStringArray(R.array.config_systemUIServiceComponents);
129 startServicesIfNeeded(names);
130 }
需要启动以下服务
<!-- SystemUI Services: The classes of the stuff to start. -->
331 <string-array name="config_systemUIServiceComponents" translatable="false">
332 <item>com.android.systemui.Dependency</item>
333 <item>com.android.systemui.util.NotificationChannels</item>
334 <item>com.android.systemui.statusbar.CommandQueue$CommandQueueStart</item>
335 <item>com.android.systemui.keyguard.KeyguardViewMediator</item>
336 <item>com.android.systemui.recents.Recents</item>
337 <item>com.android.systemui.volume.VolumeUI</item>
338 <item>com.android.systemui.stackdivider.Divider</item>
339 <item>com.android.systemui.SystemBars</item>
340 <item>com.android.systemui.usb.StorageNotification</item>
341 <item>com.android.systemui.power.PowerUI</item>
342 <item>com.android.systemui.media.RingtonePlayer</item>
343 <item>com.android.systemui.keyboard.KeyboardUI</item>
344 <item>com.android.systemui.pip.PipUI</item>
345 <item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
346 <item>@string/config_systemUIVendorServiceComponent</item>
347 <item>com.android.systemui.util.leak.GarbageMonitor$Service</item>
348 <item>com.android.systemui.LatencyTester</item>
349 <item>com.android.systemui.globalactions.GlobalActionsComponent</item>
350 <item>com.android.systemui.ScreenDecorations</item>
351 <item>com.android.systemui.fingerprint.FingerprintDialogImpl</item>
352 <item>com.android.systemui.SliceBroadcastRelayHandler</item>
353 </string-array>
最终是在
private void startServicesIfNeeded(String[] services) {
145 if (mServicesStarted) { //如果SystemUI已经启动就返回
146 return;
147 }
148 mServices = new SystemUI[services.length];
149
150 if (!mBootCompleted) {
151 // check to see if maybe it was already completed long before we began
152 // see ActivityManagerService.finishBooting()
153 if ("1".equals(SystemProperties.get("sys.boot_completed"))) {
154 mBootCompleted = true;
155 if (DEBUG) Log.v(TAG, "BOOT_COMPLETED was already sent");
156 }
157 }
158
159 Log.v(TAG, "Starting SystemUI services for user " +
160 Process.myUserHandle().getIdentifier() + ".");
161 TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
162 Trace.TRACE_TAG_APP);
163 log.traceBegin("StartServices");
164 final int N = services.length;
165 for (int i = 0; i < N; i++) {
166 String clsName = services[i];
167 if (DEBUG) Log.d(TAG, "loading: " + clsName);
168 log.traceBegin("StartServices" + clsName);
169 long ti = System.currentTimeMillis();
170 Class cls;
171 try {
172 cls = Class.forName(clsName);
173 mServices[i] = (SystemUI) cls.newInstance();
174 } catch(ClassNotFoundException ex){
175 throw new RuntimeException(ex);
176 } catch (IllegalAccessException ex) {
177 throw new RuntimeException(ex);
178 } catch (InstantiationException ex) {
179 throw new RuntimeException(ex);
180 }
181
182 mServices[i].mContext = this;
183 mServices[i].mComponents = mComponents;
184 if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
185 mServices[i].start(); //启动子服务
186 log.traceEnd();
187
188 // Warn if initialization of component takes too long
189 ti = System.currentTimeMillis() - ti;
190 if (ti > 1000) {
191 Log.w(TAG, "Initialization of " + cls.getName() + " took " + ti + " ms");
192 }
193 if (mBootCompleted) { //如果已经启动完成
194 mServices[i].onBootCompleted();
195 }
196 }
197 log.traceEnd();
198 Dependency.get(PluginManager.class).addPluginListener(
199 new PluginListener<OverlayPlugin>() {
200 private ArraySet<OverlayPlugin> mOverlays;
201
202 @Override
203 public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {
204 StatusBar statusBar = getComponent(StatusBar.class);
205 if (statusBar != null) {
206 plugin.setup(statusBar.getStatusBarWindow(),
207 statusBar.getNavigationBarView());
208 }
209 // Lazy init.
210 if (mOverlays == null) mOverlays = new ArraySet<>();
211 if (plugin.holdStatusBarOpen()) {
212 mOverlays.add(plugin);
213 Dependency.get(StatusBarWindowManager.class).setStateListener(b ->
214 mOverlays.forEach(o -> o.setCollapseDesired(b)));
215 Dependency.get(StatusBarWindowManager.class).setForcePluginOpen(
216 mOverlays.size() != 0);
217
218 }
219 }
220
221 @Override
222 public void onPluginDisconnected(OverlayPlugin plugin) {
223 mOverlays.remove(plugin);
224 Dependency.get(StatusBarWindowManager.class).setForcePluginOpen(
225 mOverlays.size() != 0);
226 }
227 }, OverlayPlugin.class, true /* Allow multiple plugins */);
228
229 mServicesStarted = true;
230 }
这里主要通过反射的方式将前面的各个子服务实例化,并执行对这些对象中的start方法,来启动这些服务。
至此,SystemUI的启动分析完成,后面分析单个功能。
本文地址:https://blog.csdn.net/u011164827/article/details/102998091