SystemUI-StatusBar啟動過程簡單分析
SystemUI的啟動
SystemUI本質(zhì)上是一個app爆雹,在系統(tǒng)中對應的源碼路徑為:
frameworks/base/packages/SystemUI
在源碼中編譯后會生成
out/target/product/product_name/system/priv-app/SystemUI/SystemUI.apk夯缺。
在system/priv-app下意味著SystemUI開機就會被安裝,SystemUI并不是自己啟動的捣域,它是在SystemServer進程創(chuàng)建過程中被開啟的,SystemServer進程啟動時會啟動各種系統(tǒng)服務(如AMS、PMS等)SystemUI的啟動就在這一流程中酝惧,下面以源碼中流程代碼來分析這一啟動過程:
以下源碼基于MT2712 MR2004 Android9.0版本源碼,流程代碼中省略了一些內(nèi)容
platform/frameworks/base/services/java/com/android/server/SystemServer.java
public final class SystemServer {
....
// SystemServer進程啟動入口
public static void main(String[] args) {
new SystemServer().run();
}
private void run() {
....
// 啟動各種系統(tǒng)服務
try {
startBootstrapServices();
startCoreServices();
// SystemUI的啟動在其他服務的啟動過程中
startOtherServices();
SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
....
} finally {
traceEnd();
}
....
// Loop forever.
Looper.loop();
}
....
private void startOtherServices() {
....
final WindowManagerService windowManagerF1 = wm;
traceBeginAndSlog("StartSystemUI");
try {
// 啟動SystemUI入口
startSystemUi(context, windowManagerF1);
} 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);
context.startServiceAsUser(intent, UserHandle.SYSTEM);
windowManager.onSystemUiStarted();
}
}
通過最后調(diào)用到的startSystemUi可以看出伯诬,最后通過創(chuàng)建Intent晚唇,啟動SystemUIService。
SystemUI的加載
這里進入frameworks/basepackages/SystemUI/src/com/android/systemui/SystemUIService.java源碼中查看啟動后執(zhí)行了什么
public class SystemUIService extends Service {
@Override
public void onCreate() {
super.onCreate();
((SystemUIApplication) getApplication()).startServicesIfNeeded();
....
}
}
在onCreate中獲取了SystemUIApplication并調(diào)用了其startServicesIfNeeded方法
platform/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
public class SystemUIApplication extends Application implements SysUiServiceProvider {
....
public void startServicesIfNeeded() {
String[] names = getResources().getStringArray(R.array.config_systemUIServiceComponents);
startServicesIfNeeded(names);
}
private void startServicesIfNeeded(String[] services) {
if (mServicesStarted) {
return;
}
mServices = new SystemUI[services.length];
....
final int N = services.length;
for (int i = 0; i < N; i++) {
String clsName = services[i];
....
Class cls;
try {
// 通過反射調(diào)組件類啟動
cls = Class.forName(clsName);
mServices[i] = (SystemUI) cls.newInstance();
} catch(ClassNotFoundException ex){
throw new RuntimeException(ex);
} 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;
}
}
在方法內(nèi)創(chuàng)建了一個字符數(shù)組names盗似,讀取res/values/config.xml文件中定義的數(shù)組config_systemUIServiceComponents里面包含了各種SystemUI的各個組件和服務類的完整路徑哩陕,之后通過循環(huán)和反射調(diào)用各個組件的start方法,并將它們放入一個SystemUI數(shù)組管理赫舒;
<string-array name="config_systemUIServiceComponents" translatable="false">
<item>com.android.systemui.Dependency</item>
<item>com.android.systemui.Dependency</item>
<item>com.android.systemui.util.NotificationChannels</item>
<item>com.android.systemui.statusbar.CommandQueue$CommandQueueStart</item>
<item>com.android.systemui.keyguard.KeyguardViewMediator</item>
<item>com.android.systemui.SystemBars</item>
<item>com.android.systemui.volume.VolumeUI</item>
<item>com.android.systemui.usb.StorageNotification</item>
<item>com.android.systemui.power.PowerUI</item>
<item>com.android.systemui.media.RingtonePlayer</item>
<item>com.android.systemui.keyboard.KeyboardUI</item>
<item>com.android.systemui.pip.PipUI</item>
<item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
<item>@string/config_systemUIVendorServiceComponent</item>
<item>com.android.systemui.util.leak.GarbageMonitor$Service</item>
<item>com.android.systemui.LatencyTester</item>
<item>com.android.systemui.globalactions.GlobalActionsComponent</item>
<item>com.android.systemui.ScreenDecorations</item>
<item>com.android.systemui.fingerprint.FingerprintDialogImpl</item>
<item>com.android.systemui.SliceBroadcastRelayHandler</item>
</string-array>
這里分析以com.android.systemui.SystemBars為主悍及。
StatusBars的加載
platform/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemBars.java
public class SystemBars extends SystemUI {
....
@Override
public void start() {
createStatusBarFromConfig();
}
....
private void createStatusBarFromConfig() {
// 讀取res/values/config.xml獲取config_statusBarComponent屬性
// 這里讀到的時com.android.systemui.statusbar.phone.StatusBar
final String clsName = mContext.getString(R.string.config_statusBarComponent);
....
Class<?> cls = null;
try {
cls = mContext.getClassLoader().loadClass(clsName);
} catch (Throwable t) {
throw andLog("Error loading status bar component: " + clsName, t);
}
try {
mStatusBar = (SystemUI) cls.newInstance();
} catch (Throwable t) {
throw andLog("Error creating status bar component: " + clsName, t);
}
mStatusBar.mContext = mContext;
mStatusBar.mComponents = mComponents;
mStatusBar.start();
}
}
這里與上衣過程類似,也是從config.xml文件中讀取一個完整路徑接癌,然后通過反射調(diào)用其start方法心赶,這里調(diào)用到StatusBar.java類的start方法。
platform/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
public class StatusBar extends SystemUI implements DemoMode,
DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener,
OnHeadsUpChangedListener, CommandQueue.Callbacks, ZenModeController.Callback,
ColorExtractor.OnColorsChangedListener, ConfigurationListener, NotificationPresenter {
....
protected StatusBarWindowView mStatusBarWindow;
protected StatusBarWindowManager mStatusBarWindowManager;
@Override
public void start() {
....
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mDisplay = mWindowManager.getDefaultDisplay();
updateDisplaySize();
....
// 1.這里開始加載StatusBar布局并添加到界面上
createAndAddWindows();
....
}
public void createAndAddWindows() {
// 2
addStatusBarWindow();
}
private void addStatusBarWindow() {
// 3.構(gòu)造SatusBarView
makeStatusBarView();
....
// 6.將mStatusBarWindow加載到系統(tǒng)界面上
// getStatusBarHeight()對應的高度值在下方的updateResources()內(nèi)進行加載
mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
}
protected void makeStatusBarView() {
....
updateResources();//包含一些狀態(tài)欄高度等資源的加載
....
// 4.通過inflate將布局加載給mStatusBarWindow
inflateStatusBarWindow();
// 5.將CollapsedStatusBarFragment加載進mStatusBarWindow扔涧,對應的就是顯示在頂部的狀態(tài)欄
FragmentHostManager.get(mStatusBarWindow)
.addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
CollapsedStatusBarFragment statusBarFragment =
(CollapsedStatusBarFragment) fragment;
statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);
mStatusBarView = (PhoneStatusBarView) fragment.getView();
// mStatusBarView的一些設置
....
setAreThereNotifications();
checkBarModes();
}).getFragmentManager()
.beginTransaction()
.replace(R.id.status_bar_container, new CollapsedStatusBarFragment(),
CollapsedStatusBarFragment.TAG)
.commit();
....
}
protected void inflateStatusBarWindow(Context context) {
mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
R.layout.super_status_bar, null);
}
}
針對StatusBar园担,當我們調(diào)用StatusBar的start方法后届谈,我們會加載狀態(tài)欄的一些資源(如高度),之后通過inflate將super_status_bar.xml對應的布局加載給mStatusBarWindow對象弯汰;
在super_status_bar.xml布局文件中有一個status_bar_container的FrameLayout艰山,之后會被用來放置CollapsedStatusBarFragment,這里存放了眾多的狀態(tài)欄View。這一步完成后就會將將mStatusBarWindow加載到系統(tǒng)界面上
StatusBar加載到系統(tǒng)界面
StatusBar通過StatusBarWindowManager.add加載到系統(tǒng)界面上咏闪,具體的源碼如下:
platform/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
/**
* 將狀態(tài)欄視圖添加到WindowMangager曙搬。
*
* @param statusBarView
* @param barHeight 折疊狀態(tài)下狀態(tài)欄高度
*/
public void add(View statusBarView, int barHeight) {
mWindowManager.getDefaultDisplay().getSize(mPoint);
int navigationbarWidth = getNavigationBarWidth();
mLp = new WindowManager.LayoutParams(
mPoint.x - navigationbarWidth,
barHeight,
navigationbarWidth,
0,
WindowManager.LayoutParams.TYPE_STATUS_BAR,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
PixelFormat.TRANSLUCENT);
mLp.token = new Binder();
mLp.gravity = Gravity.TOP;
mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
mLp.setTitle("StatusBar");
mLp.packageName = mContext.getPackageName();
mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
mStatusBarView = statusBarView;
mBarHeight = barHeight;
mWindowManager.addView(mStatusBarView, mLp);
mLpChanged = new WindowManager.LayoutParams();
mLpChanged.copyFrom(mLp);
}
這里傳入的mStatusBarWindow就通過WindowManager加載到相應的位置上了。
CollapsedStatusBarFragment擴展學習記錄
這里展示CollapsedStatusBarFragment的兩個生命周期鸽嫂。這里包含了布局和顯示內(nèi)容的加載
frameworks/base纵装、packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
public class CollapsedStatusBarFragment extends Fragment implements CommandQueue.Callbacks {
....
private PhoneStatusBarView mStatusBar;
private KeyguardMonitor mKeyguardMonitor;
private NetworkController mNetworkController;
private StatusBar mStatusBarComponent;
....
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
Bundle savedInstanceState) {
// 加載布局status_bar.xml
return inflater.inflate(R.layout.status_bar, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mStatusBar = (PhoneStatusBarView) view;
if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_PANEL_STATE)) {
mStatusBar.go(savedInstanceState.getInt(EXTRA_PANEL_STATE));
}
mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons));
mDarkIconManager.setShouldLog(true);
Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);
// 用來顯示狀態(tài)欄圖標的區(qū)域((藍牙、wifi据某、VPN橡娄、網(wǎng)卡、SIM卡信號癣籽、飛行模式等) 電池)
mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area);
mClockView = mStatusBar.findViewById(R.id.clock);
showSystemIconArea(false);
showClock(false);
initEmergencyCryptkeeperText();
initOperatorName();
}
}
CollapsedStatusBarFragment內(nèi)還有一些Notification相關的內(nèi)容挽唉,之后有時間再
graph LR
A-->B
繼續(xù)分析。