??團隊博客: 汽車電子社區(qū)
一、簡介
??在Android系統(tǒng)中SystemUI是一個系統(tǒng)級的APP,它提供了系統(tǒng)的用戶界面,由system_server進程啟動。SystemUI本身不屬于system_server進程,它是一個獨立的進程。它的HMI包括了狀態(tài)欄、導(dǎo)航欄、通知欄、鎖屏、近期任務(wù)等等。
??SystemServer是一個由Zogyte進程啟動的程序,它負責啟動和管理Android系統(tǒng)中的各種核心服務(wù)。 例如:ActivityManagerService和PackageManagerService,這些服務(wù)也都運行在system_server進程中,為Android系統(tǒng)提供各種功能和接口,供應(yīng)用程序和其他服務(wù)調(diào)用。我們常說的Android Framework其實就是由這些Service組成的。
二、功能介紹
??這部分將主要介紹那些對我們定制自己的SystemUI時有參考價值的模塊。
??1. 狀態(tài)欄
???? StatusBar,負責顯示時間,電量,信號,通知等狀態(tài)信息。 ??2. 導(dǎo)航欄
????NavigationBar,顯示返回,主頁,最近任務(wù)等按鈕。在車載Android中,我們多數(shù)時候會稱為Dock欄(DockBar)。一般負責顯示車控、主頁、藍牙電話等常用功能的快捷控制和入口。
??3. 通知欄
????NotificationPanel,顯示、控制通知的界面。實際的車載項目中通知欄往往會和【消息中心】合并成一個獨立的APP。 ??4. 快捷控制
????QuickSettings,這個面板可以讓用戶快速地調(diào)整一些常用的設(shè)置,例如亮度、飛行模式、藍牙等。QS面板有多種狀態(tài),包括初級展開面板(Quick Quick Settings,QQS)和完整QS面板(Quick Settings,QS)。用戶可以通過下拉通知欄來打開或關(guān)閉QS面板。 ??5. 其他功能
????一些系統(tǒng)級的對話框、彈窗、動畫、屏保等,這些內(nèi)容相對比較簡單,不再介紹了。而鎖屏、媒體控制等一些功能,車載SystemUI開發(fā)時涉及的不多,也同樣不再介紹。
三、SystemUI 啟動流程
??當Android系統(tǒng)啟動完成后,system_server進程會通過ActivityManagerService啟動一個名為com.android.systemui.SystemUIService的服務(wù),這個服務(wù)是SystemUI的入口類,它繼承了Service類。
SystemServer的源碼位置:/frameworks/base/services/java/com/android/server/SystemServer.java
mActivityManagerService.systemReady(() -> {
Slog.i(TAG, "Making services ready");
//...
t.traceBegin("StartSystemUI");
try {
startSystemUi(context, windowManagerF);
} catch (Throwable e) {
reportWtf("starting System UI", e);
}
t.traceEnd();
}, t);
??從這里我們可以看出,SystemUI本質(zhì)就是一個Service,通過Pm獲取到的Component是com.android.systemui/.SystemUIService。startSystemUi代碼細節(jié)如下:
private static 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的啟動流程,接下來我們繼續(xù)看SystemUI是如何初始化的。
四、SystemUI 初始化流程
??SystemUI的初始化流程分為以下幾步:
4.1、Application初始化
SystemUIApplication源碼位置:/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
??在SystemUI啟動后,首先會調(diào)用Application的onCreate方法,并在onCreate方法中對SystemUI進行初始化。這里我把它分為四個部分的內(nèi)容。
??1、第一部分內(nèi)容不多,主要是通過Dagger拿到SystemUI中的一些創(chuàng)建好的組件,同時設(shè)定一些調(diào)試工具。
public void onCreate() {
super.onCreate();
Log.v(TAG, "SystemUIApplication created.");
// This line is used to setup Dagger's dependency injection and should be kept at the
// top of this method.
// TimingsTraceLog 是一個用于跟蹤代碼執(zhí)行時間的工具類,它可以在traceview中看到。
TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
Trace.TRACE_TAG_APP);
log.traceBegin("DependencyInjection");
// 此行用于設(shè)置Dagger的依賴注入,并應(yīng)保持在onrecate方法的頂部。
mContextAvailableCallback.onContextAvailable(this);
log.traceEnd();
mLocalHandler = new LocalHandler();
// 設(shè)置所有服務(wù)繼承的應(yīng)用程序主題。請注意,
// 僅在清單中設(shè)置應(yīng)用程序主題僅適用于活動。請將其與在那里設(shè)置的主題同步。
setTheme(R.style.Theme_SystemUI);
}
??2、首先判斷當前進程是否屬于系統(tǒng)用戶。然后根據(jù)SF GPU上下文優(yōu)先級設(shè)置設(shè)定SystemUI的渲染器的上下文優(yōu)先級,最后開啟SystemServer的binder調(diào)用trace跟蹤。
public void onCreate() {
// 判斷當前進程是否是系統(tǒng)進程。如果是系統(tǒng)進程,那么就注冊 BOOT_COMPLETED 廣播接收器。
if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
// 創(chuàng)建 BOOT_COMPLETED 廣播接收器的意圖過濾器。
IntentFilter bootCompletedFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
bootCompletedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
}
}
??ThreadedRenderer可以簡單理解為一個渲染器,它可以在后臺線程中渲染視圖層次結(jié)構(gòu)。優(yōu)先級越高,渲染速度越快。
??Process.myUserHandle()可以獲取當前進程的用戶類型。如果是從事移動端APP開發(fā),很少會涉及Android系統(tǒng)的多用戶機制。但是由于汽車是一種具有共享屬性的工具,會存在多個家庭成員使用一輛車的情況,所以Android多用戶在車載Android開發(fā)中較為常見。
??當我們在系統(tǒng)設(shè)置中的「系統(tǒng)」「多用戶」添加一個新用戶并切換到這個新用戶時,實際上會再啟動一個SystemUI進程,新的SystemUI進程的用戶ID會從U1X開始,原始的SystemUI的用戶ID則始終是U0。
??3、第三部分注冊監(jiān)聽開機廣播,并在SystemUIService啟動后,再通知SystemUI中的其它組件「系統(tǒng)啟動完成」。
public void onCreate() {
registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (mBootCompleted) return;
if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");
unregisterReceiver(this);
mBootCompleted = true;
if (mServicesStarted) {
final int N = mServices.length;
for (int i = 0; i < N; i++) {
mServices[i].onBootCompleted();
}
}
}
}, bootCompletedFilter);
IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
if (!mBootCompleted) return;
// Update names of SystemUi notification channels
NotificationChannels.createAll(context);
}
}
}, localeChangedFilter);
} else {
/* 第四部分 */
}
}
??4、第四部分如果當前用戶非系統(tǒng)用戶那么調(diào)用startSecondaryUserServicesIfNeeded方法。
// 我們不需要為正在執(zhí)行某些任務(wù)的子進程初始化組件。例如:截圖進程等
String processName = ActivityThread.currentProcessName();
ApplicationInfo info = getApplicationInfo();
if (processName != null && processName.startsWith(info.processName + ":")) {
return;
}
// 對于第二個用戶,boot-completed永遠不會被調(diào)用,因為它已經(jīng)在啟動時為主SystemUI進程廣播了
// 對于需要每個用戶初始化SystemUI組件的組件,我們現(xiàn)在為當前非系統(tǒng)用戶啟動這些組件。
startSecondaryUserServicesIfNeeded();
??在這里插入代碼片`startSecondaryUserServicesIfNeeded方法也是通過startServicesIfNeeded方法來初始化SystemUI中的功能組件。具體是如何初始化,我們之后再來分析。
void startSecondaryUserServicesIfNeeded() {
String[] names =
getResources().getStringArray(R.array.config_systemUIServiceComponentsPerUser);
startServicesIfNeeded(names);
}
??到這里,我們簡單總結(jié)一下SystemUIApplication中其實最主要的工作,其實只有兩個:
????1.、在系統(tǒng)用戶空間中監(jiān)聽開機廣播,并通知SystemUI的功能組件。
????2、在非系統(tǒng)用戶空間中,直接初始化SystemUI的功能組件。
4.2、啟動 SystemUIService
??當Application完成初始化之后,緊接著,SystemUIService就會被啟動。
SystemUIService源碼位置:/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java
??SystemUIService在onCreate()方法中會調(diào)用((SystemUIApplication) getApplication()).startServicesIfNeeded()方法。文章來源:http://www.zghlxwxcb.cn/news/detail-806623.html
@Override
public void onCreate() {
super.onCreate();
// Start all of SystemUI
((SystemUIApplication) getApplication()).startServicesIfNeeded();
...
}
??這里可能有個疑問:為什么不把startServicesIfNeeded的相關(guān)邏輯寫在Service中,非要寫到Application中?
??是因為,當前用戶不是系統(tǒng)用戶時,startSecondaryUserServicesIfNeeded也需要去調(diào)用startServicesIfNeeded方法進行組件初始化,所以干脆把所有的初始化邏輯都寫到Application中了。文章來源地址http://www.zghlxwxcb.cn/news/detail-806623.html
private void startServicesIfNeeded(String[] services) {
if (mServicesStarted) {
return;
}
mServices = new SystemUI[services.length];
if (!mBootCompleted) {
// check to see if maybe it was already completed long before we began
// see ActivityManagerService.finishBooting()
if ("1".equals(SystemProperties.get("sys.boot_completed"))) {
mBootCompleted = true;
if (DEBUG) {
Log.v(TAG, "BOOT_COMPLETED was already sent");
}
}
}
Log.v(TAG, "Starting SystemUI services for user " +
Process.myUserHandle().getIdentifier() + ".");
Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
Message msg = mLocalHandler.obtainMessage();
msg.obj = services;
msg.arg1 = services.length;
msg.arg2 = 0;
msg.what = EVENT_START_SERVICE;
msg.sendToTarget();
}
到了這里,關(guān)于Android SystemUI梳理的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!