SystemUI 主要模塊
- StatusBar:通知消息提示和狀態展現
- NavigationBar:返回,HOME,Recent
- KeyGuard:鎖屏模塊可以看做單獨的應用,提供基本的手機個人隱私保護
- Recents:近期應用管理,以堆疊棧的形式展現。
- Notification Panel:展示系統或應用通知內容。提供快速系統設置開關。
- Volume:來用展示或控制音量的變化:媒體音量、鈴聲音量與鬧鐘音量
- 截屏界面:長按電源鍵+音量下鍵后截屏,用以展示截取的屏幕照片/內容
- PowerUI:主要處理和Power相關的事件,比如省電模式切換、電池電量變化和開關屏事件等。
- RingtonePlayer:鈴聲播放
- StackDivider:控制管理分屏
- PipUI:提供對于畫中畫模式的管理
簡單的說下 SystemUI 的啟動過程
由init進程->Zygote進程->SystemServer進程。
那init進程又是怎么起來的?當你按下電源鍵,系統上電,從固定地址開始加載固化在ROM的Bootloader代碼到RAM中并執行,Bootloader引導程序負責將系統OS拉起。當系統OS被拉起,并完成一些列初始化和系統設置后,就會首先在系統文件中尋找“init”文件并啟動這個咱們用戶空間的第一個進程。
image
SystemUI
每個模塊的公共方法 所以系統抽取了 SystemUI 公共類
- 處理各自模塊的初始化
- 處理系統的狀態變化
- 執行dump
- 系統啟動完成時,要處理相應邏輯
// SystemUI
public abstract class SystemUI implements SysUiServiceProvider {
public Context mContext;
public Map<Class<?>, Object> mComponents;
// 完成初始化操作
public abstract void start();
// 是處理系統狀態變化的回調,這里的狀態變化包括:時區變更,
// 字體大小變更,輸入模式變更,屏幕大小變更,屏幕方向變更等。
protected void onConfigurationChanged(Configuration newConfig) {
}
// dump方法用來將模塊的內部狀態dump到輸出流中,這個方法主要是輔助
// 調試所用。開發者可以在開發過程中,通過adb shell執行dump來了解系統的內部狀態。
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
}
// 系統啟動完成的回調方法
protected void onBootCompleted() {
}
@SuppressWarnings("unchecked")
public <T> T getComponent(Class<T> interfaceType) {
return (T) (mComponents != null ? mComponents.get(interfaceType) : null);
}
public <T, C extends T> void putComponent(Class<T> interfaceType, C component) {
if (mComponents != null) {
mComponents.put(interfaceType, component);
}
}
public static void overrideNotificationAppName(Context context, Notification.Builder n,
boolean system) {
final Bundle extras = new Bundle();
String appName = system
? context.getString(com.android.internal.R.string.notification_app_name_system)
: context.getString(com.android.internal.R.string.notification_app_name_settings);
extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, appName);
n.addExtras(extras);
}
public interface Injector extends Function<Context, SystemUI> {
}
}
除了截屏服務,提及模塊均繼承抽象類SystemUI并在應用啟動時被分別初始化。從這種角度來看,SystemUI應用更像是這些功能模塊的容器。
SystemUIApplication
從 AndroidManifest.XML 中可以看到
<application
android:name=".SystemUIApplication"
android:persistent="true"
android:allowClearUserData="false"
android:allowBackup="false"
android:hardwareAccelerated="true"
android:label="@string/app_label"
android:icon="@drawable/icon"
android:process="com.android.systemui"
android:supportsRtl="true"
android:theme="@style/Theme.SystemUI"
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true"
android:appComponentFactory="androidx.core.app.CoreComponentFactory">
<!-- Keep theme in sync with SystemUIApplication.onCreate().
所以我們去康康 SystemUIApplication 的 Oncreate
方法
@Override
public void onCreate() {
super.onCreate();
// Set the application theme that is inherited by all services. Note that setting the
// application theme in the manifest does only work for activities. Keep this in sync with
// the theme set there.
setTheme(R.style.Theme_SystemUI);
SystemUIFactory.createFromConfig(this);
// 這里有設置一個廣播 但是只接受一次
if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
IntentFilter bootCompletedFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
bootCompletedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
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 {
···
startSecondaryUserServicesIfNeeded();
}
}
/**
* Ensures that all the Secondary user 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>
*/
void startSecondaryUserServicesIfNeeded() {
String[] names =
getResources().getStringArray(R.array.config_systemUIServiceComponentsPerUser);
startServicesIfNeeded(names);
}
private void startServicesIfNeeded(String[] services) {
if (mServicesStarted) {
return;
}
mServices = new SystemUI[services.length];
···
Log.v(TAG, "Starting SystemUI services for user " +
Process.myUserHandle().getIdentifier() + ".");
TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
Trace.TRACE_TAG_APP);
log.traceBegin("StartServices");
final int N = services.length;
for (int i = 0; i < N; i++) {
···
mServices[i].mContext = this;
mServices[i].mComponents = mComponents;
if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
// 這里可以看到啟動了每個 Service
mServices[i].start();
···
}
···
}
到這里SystemUI的啟動流程就完了
如有錯誤歡迎指出 共同學習 共同進步哈~
本文轉自 https://juejin.cn/post/6844904180365131784,如有侵權,請聯系刪除。