最近看了一个wifi, ethernet切换,状态栏图表显示的问题。记录一下追踪由于网络状态变化,SystemUI 状态栏网络图标显示的流程。
先看一下SystemUI这边:
/frameworks/base/services/java/com/android/server/SystemServer.java
/**
* Starts a miscellaneous grab bag of stuff that has yet to be refactored and organized.
*/
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
......
......
2236 // We now tell the activity manager it is okay to run third party
2237 // code. It will call back into us once it has gotten to the state
2238 // where third party code can really run (but before it has actually
2239 // started launching the initial applications), for us to complete our
2240 // initialization.
2241 mActivityManagerService.systemReady(() -> {
......
......
2276 t.traceBegin("StartSystemUI");
2277 try {
2278 startSystemUi(context, windowManagerF);
2279 } catch (Throwable e) {
2280 reportWtf("starting System UI", e);
2281 }
2282 t.traceEnd();
......
......
}
private static void startSystemUi(Context context, WindowManagerService windowManager) {
2534 PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
2535 Intent intent = new Intent();
2536 intent.setComponent(pm.getSystemUiServiceComponent());
2537 intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
2538 //Slog.d(TAG, "Starting service: " + intent);
2539 context.startServiceAsUser(intent, UserHandle.SYSTEM);
2540 windowManager.onSystemUiStarted();
}
/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java
public SystemUIService(
50 @Main Handler mainHandler,
51 DumpHandler dumpHandler,
52 BroadcastDispatcher broadcastDispatcher,
53 LogBufferFreezer logBufferFreezer) {
54 super();
55 mMainHandler = mainHandler;
56 mDumpHandler = dumpHandler;
57 mBroadcastDispatcher = broadcastDispatcher;
58 mLogBufferFreezer = logBufferFreezer;
59 }
60
61 @Override
62 public void onCreate() {
63 super.onCreate();
64
65 // Start all of SystemUI
66 ((SystemUIApplication) getApplication()).startServicesIfNeeded();
67
68 // Finish initializing dump logic
69 mLogBufferFreezer.attach(mBroadcastDispatcher);
70
71 // For debugging RescueParty
72 if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_sysui", false)) {
73 throw new RuntimeException();
74 }
75
76 if (Build.IS_DEBUGGABLE) {
77 // b/71353150 - looking for leaked binder proxies
78 BinderInternal.nSetBinderProxyCountEnabled(true);
79 BinderInternal.nSetBinderProxyCountWatermarks(1000,900);
80 BinderInternal.setBinderProxyCountCallback(
81 new BinderInternal.BinderProxyLimitListener() {
82 @Override
83 public void onLimitReached(int uid) {
84 Slog.w(SystemUIApplication.TAG,
85 "uid " + uid + " sent too many Binder proxies to uid "
86 + Process.myUid());
87 }
88 }, mMainHandler);
89 }
90
91 // Bind the dump service so we can dump extra info during a bug report
92 startServiceAsUser(
93 new Intent(getApplicationContext(), SystemUIAuxiliaryDumpService.class),
94 UserHandle.SYSTEM);
}
/**
* Makes sure that all the SystemUI services are running. If they are already running, this is a
* no-op. This is needed to conditinally start all the services, as we only need to have it in
* the main process.
* <p>This method must only be called from the main thread.</p>
*/
public void startServicesIfNeeded() {
142 String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponents(getResources());
143 startServicesIfNeeded(/* metricsPrefix= */ "StartServices", names);
}
SystemUI 要启动的所有服务都是在数组 config_systemUIServiceComponents
中定义
127 /** Returns the list of system UI components that should be started. */
128 public String[] getSystemUIServiceComponents(Resources resources) {
129 return resources.getStringArray(R.array.config_systemUIServiceComponents);
130 }
/frameworks/base/packages/SystemUI/res/values/config.xml
302 <!-- SystemUI Services: The classes of the stuff to start. -->
303 <string-array name="config_systemUIServiceComponents" translatable="false">
304 <item>com.android.systemui.util.NotificationChannels</item>
305 <item>com.android.systemui.keyguard.KeyguardViewMediator</item>
306 <item>com.android.systemui.recents.Recents</item>
307 <item>com.android.systemui.volume.VolumeUI</item>
308 <item>com.android.systemui.stackdivider.Divider</item>
309 <item>com.android.systemui.statusbar.phone.StatusBar</item>
310 <item>com.android.systemui.usb.StorageNotification</item>
311 <item>com.android.systemui.power.PowerUI</item>
312 <item>com.android.systemui.media.RingtonePlayer</item>
313 <item>com.android.systemui.keyboard.KeyboardUI</item>
314 <item>com.android.systemui.pip.PipUI</item>
315 <item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
316 <item>@string/config_systemUIVendorServiceComponent</item>
317 <item>com.android.systemui.util.leak.GarbageMonitor$Service</item>
318 <item>com.android.systemui.LatencyTester</item>
319 <item>com.android.systemui.globalactions.GlobalActionsComponent</item>
320 <item>com.android.systemui.ScreenDecorations</item>
321 <item>com.android.systemui.biometrics.AuthController</item>
322 <item>com.android.systemui.SliceBroadcastRelayHandler</item>
323 <item>com.android.systemui.SizeCompatModeActivityController</item>
324 <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
325 <item>com.android.systemui.theme.ThemeOverlayController</item>
326 <item>com.android.systemui.accessibility.WindowMagnification</item>
327 <item>com.android.systemui.accessibility.SystemActions</item>
328 <item>com.android.systemui.toast.ToastUI</item>
329 </string-array>
private void startServicesIfNeeded(String metricsPrefix, String[] services) {
159 if (mServicesStarted) {
160 return;
161 }
162 mServices = new SystemUI[services.length];
163
164 if (!mBootCompleteCache.isBootComplete()) {
165 // check to see if maybe it was already completed long before we began
166 // see ActivityManagerService.finishBooting()
167 if ("1".equals(SystemProperties.get("sys.boot_completed"))) {
168 mBootCompleteCache.setBootComplete();
169 if (DEBUG) {
170 Log.v(TAG, "BOOT_COMPLETED was already sent");
171 }
172 }
173 }
174
175 final DumpManager dumpManager = mRootComponent.createDumpManager();
176
177 Log.v(TAG, "Starting SystemUI services for user " +
178 Process.myUserHandle().getIdentifier() + ".");
179 TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
180 Trace.TRACE_TAG_APP);
181 log.traceBegin(metricsPrefix);
182 final int N = services.length;
183 for (int i = 0; i < N; i++) {
184 String clsName = services[i];
185 if (DEBUG) Log.d(TAG, "loading: " + clsName);
186 log.traceBegin(metricsPrefix + clsName);
187 long ti = System.currentTimeMillis();
188 try {
189 SystemUI obj = mComponentHelper.resolveSystemUI(clsName);
190 if (obj == null) {
191 Constructor constructor = Class.forName(clsName).getConstructor(Context.class);
192 obj = (SystemUI) constructor.newInstance(this);
193 }
194 mServices[i] = obj;
195 } catch (ClassNotFoundException
196 | NoSuchMethodException
197 | IllegalAccessException
198 | InstantiationException
199 | InvocationTargetException ex) {
200 throw new RuntimeException(ex);
201 }
202
203 if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
204 mServices[i].start();
205 log.traceEnd();
206
207 // Warn if initialization of component takes too long
208 ti = System.currentTimeMillis() - ti;
209 if (ti > 1000) {
210 Log.w(TAG, "Initialization of " + clsName + " took " + ti + " ms");
211 }
212 if (mBootCompleteCache.isBootComplete()) {
213 mServices[i].onBootCompleted();
214 }
215
216 dumpManager.registerDumpable(mServices[i].getClass().getName(), mServices[i]);
217 }
218 mRootComponent.getInitController().executePostInitTasks();
219 log.traceEnd();
220
221 mServicesStarted = true;
}
SystemBars
这个 SystemUI服务是整个System视图创建的入口类,它被启动时会调用 start()
方法,这个方法中通过下面方法创建整个SystemUI视图并添加到WindowsManager中。
createAndAddWindows(result);
public void createAndAddWindows(@Nullable RegisterStatusBarResult result) {
// 创建整个SystemUI视图
2631 makeStatusBarView(result);
// 把视图添加到Window中
2632 mNotificationShadeWindowController.attach();
2633 mStatusBarWindowController.attach();
}
关于SystemUI service和StatusBar创建,可以参考下面几个文章分析:
https://juejin.cn/post/6844904135557382158
https://juejin.cn/post/6844904135720960014
https://www.jianshu.com/p/c7098671682e
SystemUI中StatusBar的图标控制器实现类为StatusBarIconControllerImpl,其继承了StatusBarIconController的接口,用于跟踪所有图标的状态,并将对应的状态发送给注册的图标管理器(IconManagers)。当我们在StatusBar中获取到它的实例后,还会将它传给PhoneStatusBarPolicy和StatusBarSignalPolicy对象。PhoneStatusBarPolicy控制启动时装载哪些图标(蓝牙,定位等),而StatusBarSignalPolicy控制网络信号图标(移动网络,WiFi,以太网)的变化。
StatusBarSignalPolicy实现了NetworkControllerImpl.SignalCallback接口,SignalCallback接口定义在NetworkControllerImpl实现的接口NetworkController中。
/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
注册广播监听:
@VisibleForTesting
void registerListeners() {
334 for (int i = 0; i < mMobileSignalControllers.size(); i++) {
335 MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
336 mobileSignalController.registerListener();
337 }
338 if (mSubscriptionListener == null) {
339 mSubscriptionListener = new SubListener();
340 }
341 mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener);
342 mPhone.listen(mPhoneStateListener, LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
343
344 // broadcasts
345 IntentFilter filter = new IntentFilter();
346 filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
347 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
348 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
349 filter.addAction(Intent.ACTION_SIM_STATE_CHANGED);
350 filter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
351 filter.addAction(TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED);
352 filter.addAction(Intent.ACTION_SERVICE_STATE);
353 filter.addAction(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED);
354 filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
355 filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
356 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
357 filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
358 mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mReceiverHandler);
359 mListening = true;
360
361 // Initial setup of connectivity. Handled as if we had received a sticky broadcast of
362 // ConnectivityManager.CONNECTIVITY_ACTION or ConnectivityManager.INET_CONDITION_ACTION.
363 mReceiverHandler.post(this::updateConnectivity);
364
365 // Initial setup of WifiSignalController. Handled as if we had received a sticky broadcast
366 // of WifiManager.WIFI_STATE_CHANGED_ACTION or WifiManager.NETWORK_STATE_CHANGED_ACTION
367 mReceiverHandler.post(mWifiSignalController::fetchInitialState);
368
369 // Initial setup of mLastServiceState. Only run if there is no service state yet.
370 // Each MobileSignalController will also get their corresponding
371 mReceiverHandler.post(() -> {
372 if (mLastServiceState == null) {
373 mLastServiceState = mPhone.getServiceState();
374 if (mMobileSignalControllers.size() == 0) {
375 recalculateEmergency();
376 }
377 }
378 });
379
380 updateMobileControllers();
381
382 // Initial setup of emergency information. Handled as if we had received a sticky broadcast
383 // of TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED.
384 mReceiverHandler.post(this::recalculateEmergency);
}
处理广播:
public void onReceive(Context context, Intent intent) {
560 if (CHATTY) {
561 Log.d(TAG, "onReceive: intent=" + intent);
562 }
563 final String action = intent.getAction();
564 switch (action) {
565 case ConnectivityManager.CONNECTIVITY_ACTION:
566 case ConnectivityManager.INET_CONDITION_ACTION:
567 updateConnectivity();
568 break;
569 case Intent.ACTION_AIRPLANE_MODE_CHANGED:
570 refreshLocale();
571 updateAirplaneMode(false);
572 break;
573 case TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED:
574 // We are using different subs now, we might be able to make calls.
575 recalculateEmergency();
576 break;
577 case TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED:
578 // Notify every MobileSignalController so they can know whether they are the
579 // data sim or not.
580 for (int i = 0; i < mMobileSignalControllers.size(); i++) {
581 MobileSignalController controller = mMobileSignalControllers.valueAt(i);
582 controller.handleBroadcast(intent);
583 }
584 mConfig = Config.readConfig(mContext);
585 mReceiverHandler.post(this::handleConfigurationChanged);
586 break;
587 case Intent.ACTION_SIM_STATE_CHANGED:
588 // Avoid rebroadcast because SysUI is direct boot aware.
589 if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
590 break;
591 }
592 // Might have different subscriptions now.
593 updateMobileControllers();
594 break;
595 case Intent.ACTION_SERVICE_STATE:
596 mLastServiceState = ServiceState.newFromBundle(intent.getExtras());
597 if (mMobileSignalControllers.size() == 0) {
598 // If none of the subscriptions are active, we might need to recalculate
599 // emergency state.
600 recalculateEmergency();
601 }
602 break;
603 case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED:
604 mConfig = Config.readConfig(mContext);
605 mReceiverHandler.post(this::handleConfigurationChanged);
606 break;
607 default:
608 int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
609 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
610 if (SubscriptionManager.isValidSubscriptionId(subId)) {
611 if (mMobileSignalControllers.indexOfKey(subId) >= 0) {
612 mMobileSignalControllers.get(subId).handleBroadcast(intent);
613 } else {
614 // Can't find this subscription... We must be out of date.
615 updateMobileControllers();
616 }
617 } else {
//wifi状态图标处理
618 // No sub id, must be for the wifi.
619 mWifiSignalController.handleBroadcast(intent);
620 }
621 break;
622 }
}
/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
119 /**
120 * Extract wifi state directly from broadcasts about changes in wifi state.
121 */
public void handleBroadcast(Intent intent) {
123 mWifiTracker.handleBroadcast(intent);
124 mCurrentState.enabled = mWifiTracker.enabled;
125 mCurrentState.isDefault = mWifiTracker.isDefaultNetwork;
126 mCurrentState.connected = mWifiTracker.connected;
127 mCurrentState.ssid = mWifiTracker.ssid;
128 mCurrentState.rssi = mWifiTracker.rssi;
129 mCurrentState.level = mWifiTracker.level;
130 mCurrentState.statusLabel = mWifiTracker.statusLabel;
131 notifyListenersIfNecessary();
}
/frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
public void handleBroadcast(Intent intent) {
167 if (mWifiManager == null) {
168 return;
169 }
170 String action = intent.getAction();
171 if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
172 updateWifiState();
173 } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
174 updateWifiState();
175 final NetworkInfo networkInfo =
176 intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
177 connected = networkInfo != null && networkInfo.isConnected();
178 mWifiInfo = null;
179 ssid = null;
180 if (connected) {
181 mWifiInfo = mWifiManager.getConnectionInfo();
182 if (mWifiInfo != null) {
183 if (mWifiInfo.isPasspointAp() || mWifiInfo.isOsuAp()) {
184 ssid = mWifiInfo.getPasspointProviderFriendlyName();
185 } else {
186 ssid = getValidSsid(mWifiInfo);
187 }
188 updateRssi(mWifiInfo.getRssi());
189 maybeRequestNetworkScore();
190 }
191 }
192 updateStatusLabel();
193 mCallback.run();
194 } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
195 // Default to -200 as its below WifiManager.MIN_RSSI.
196 updateRssi(intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200));
197 updateStatusLabel();
198 mCallback.run();
199 }
}
/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
public void notifyListenersIfNecessary() {
161 if (isDirty()) {
162 saveLastState();
163 notifyListeners();
164 }
}
/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
80 @Override
81 public void notifyListeners(SignalCallback callback) {
82 // only show wifi in the cluster if connected or if wifi-only
83 boolean visibleWhenEnabled = mContext.getResources().getBoolean(
84 R.bool.config_showWifiIndicatorWhenEnabled);
85 boolean wifiVisible = mCurrentState.enabled && (
86 (mCurrentState.connected && mCurrentState.inetCondition == 1)
87 || !mHasMobileDataFeature || mCurrentState.isDefault
88 || visibleWhenEnabled);
89 String wifiDesc = mCurrentState.connected ? mCurrentState.ssid : null;
90 boolean ssidPresent = wifiVisible && mCurrentState.ssid != null;
91 String contentDescription = getTextIfExists(getContentDescription()).toString();
92 if (mCurrentState.inetCondition == 0) {
93 contentDescription += ("," + mContext.getString(R.string.data_connection_no_internet));
94 }
95 IconState statusIcon = new IconState(wifiVisible, getCurrentIconId(), contentDescription);
96 IconState qsIcon = new IconState(mCurrentState.connected,
97 mWifiTracker.isCaptivePortal ? R.drawable.ic_qs_wifi_disconnected
98 : getQsCurrentIconId(), contentDescription);
99 callback.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon,
100 ssidPresent && mCurrentState.activityIn, ssidPresent && mCurrentState.activityOut,
101 wifiDesc, mCurrentState.isTransient, mCurrentState.statusLabel);
102 }
/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@Override
public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
140 boolean activityIn, boolean activityOut, String description, boolean isTransient,
141 String statusLabel) {
142
143 boolean visible = statusIcon.visible && !mBlockWifi;
144 boolean in = activityIn && mActivityEnabled && visible;
145 boolean out = activityOut && mActivityEnabled && visible;
146
147 WifiIconState newState = mWifiIconState.copy();
148
149 newState.visible = visible;
150 newState.resId = statusIcon.icon;
151 newState.activityIn = in;
152 newState.activityOut = out;
153 newState.slot = mSlotWifi;
154 newState.airplaneSpacerVisible = mIsAirplaneMode;
155 newState.contentDescription = statusIcon.contentDescription;
156
157 MobileIconState first = getFirstMobileState();
158 newState.signalSpacerVisible = first != null && first.typeId != 0;
159
160 updateWifiIconWithState(newState);
161 mWifiIconState = newState;
}
private void updateWifiIconWithState(WifiIconState state) {
170 if (state.visible && state.resId > 0) {
171 mIconController.setSignalIcon(mSlotWifi, state);
172 mIconController.setIconVisibility(mSlotWifi, true);
173 } else {
174 mIconController.setIconVisibility(mSlotWifi, false);
175 }
}
通过StatusBarIconController
接口设置图标的套路都是一样的
- 获取图标名字
- 监听事件
- 通过
StatusBarIconController
相应的方法设置图标。
/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
public void onSetSignalIcon(int viewIndex, WifiIconState state) {
377 StatusBarWifiView wifiView = (StatusBarWifiView) mGroup.getChildAt(viewIndex);
378 if (wifiView != null) {
379 wifiView.applyWifiState(state);
380 }
381
382 if (mIsInDemoMode) {
383 mDemoStatusIcons.updateWifiState(state);
384 }
}
/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
public void applyWifiState(WifiIconState state) {
178 boolean requestLayout = false;
179
180 if (state == null) {
181 requestLayout = getVisibility() != View.GONE;
182 setVisibility(View.GONE);
183 mState = null;
184 } else if (mState == null) {
185 requestLayout = true;
186 mState = state.copy();
187 initViewState();
188 } else if (!mState.equals(state)) {
189 requestLayout = updateState(state.copy());
190 }
191
192 if (requestLayout) {
193 requestLayout();
194 }
}
private boolean updateState(WifiIconState state) {
198 setContentDescription(state.contentDescription);
199 if (mState.resId != state.resId && state.resId >= 0) {
200 mWifiIcon.setImageDrawable(mContext.getDrawable(state.resId));
201 }
202
203 mIn.setVisibility(state.activityIn ? View.VISIBLE : View.GONE);
204 mOut.setVisibility(state.activityOut ? View.VISIBLE : View.GONE);
205 mInoutContainer.setVisibility(
206 (state.activityIn || state.activityOut) ? View.VISIBLE : View.GONE);
207 mAirplaneSpacer.setVisibility(state.airplaneSpacerVisible ? View.VISIBLE : View.GONE);
208 mSignalSpacer.setVisibility(state.signalSpacerVisible ? View.VISIBLE : View.GONE);
209
210 boolean needsLayout = state.activityIn != mState.activityIn
211 ||state.activityOut != mState.activityOut;
212
213 if (mState.visible != state.visible) {
214 needsLayout |= true;
215 setVisibility(state.visible ? View.VISIBLE : View.GONE);
216 }
217
218 mState = state;
219 return needsLayout;
}
借用https://www.jianshu.com/p/c7098671682e文章里的图来再看下流程(图中是mobile signal和图标的更新流程)。