SystemUI是系统最重要的一个APK,它属于persistent app,什么是persistent app呢?简单的来说就是,具有系统签名,并且在AndroidMainfest中声明persistent=true,如果是使用flag来匹配查找的话:ApplicationInfo.FLAG_PERSISTENT。目前系统具有这类app还有com.mediatek.ims(短信),com.android.phone(电话)。这类的app是在android系统环境准备完成之后启动,比launcher和开机向导启动还早。具体的流程,可以看我之前写的:ActivityManagerService启动之旅(一)
可能大家都知道SystemUI的重要,那SystemUI有哪些功能呢?导航栏,状态栏,通知栏,近期列表。这个可能是大家比较熟悉的功能,但是其实System所具有的功能远远不止这些。如下:
有一点需要说明一下,Android 10之后近期列表的显示被移到Launcher app里面了。在Launcher3的一个 类中TouchInteractionService.java IBinder mMyBinder = new IOverviewProxy.Stub() 通过AIDL的方法与systemUI通信。本文的还是以Android 9.0作为研究对象,所以近期列表还是在SystemUI中。
今后的几章会围绕SystemUI的启动流程、状态栏的加载显示流程,导航栏的加载显示流程,通知栏的加载显示流程以及近期列表的加载显示流程,这五个方面对SystemUI的研究,至于其他,电源UI,锁屏等有时间再研究。
如果不讲SystemUI的里面的服务的话,单单讲SystemUI的启动是非常简单的。
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();
}
启动是不是很简单,startServiceAsUser方法启动SystemUIService。而startSystemUi函数是在什么时候调用呢?
mActivityManagerService.systemReady(() -> {
....................
....................
traceBeginAndSlog("StartSystemUI");
try {
startSystemUi(context, windowManagerF);
} catch (Throwable e) {
reportWtf("starting System UI", e);
}
在ActvityManagerService调用systemReady函数中有这行代码 if (goingCallback != null) goingCallback.run();当执行到这句话就会执行上面{}里面的代码。
public class SystemUIService extends Service {
@Override
public void onCreate() {
super.onCreate();
((SystemUIApplication) getApplication()).startServicesIfNeeded();
// For debugging RescueParty
if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_sysui", false)) {
throw new RuntimeException();
}
if (Build.IS_DEBUGGABLE) {
// b/71353150 - looking for leaked binder proxies
BinderInternal.nSetBinderProxyCountEnabled(true);
BinderInternal.nSetBinderProxyCountWatermarks(1000,900);
BinderInternal.setBinderProxyCountCallback(
new BinderInternal.BinderProxyLimitListener() {
@Override
public void onLimitReached(int uid) {
Slog.w(SystemUIApplication.TAG,
"uid " + uid + " sent too many Binder proxies to uid "
+ Process.myUid());
}
}, Dependency.get(Dependency.MAIN_HANDLER));
}
}
从上面代码看就是一个service,在oncreate中启动SystemUIApplication.startServicesIfNeeded方法。
public class SystemUIApplication extends Application implements SysUiServiceProvider {
public static final String TAG = "SystemUIService";
private static final boolean DEBUG = false;
/**
* Hold a reference on the stuff we start.
*/
private SystemUI[] mServices;
private boolean mServicesStarted;
private boolean mBootCompleted;
private final Map, Object> mComponents = new HashMap<>();
@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);
//正常情况下SystemUI是有SystemServer启动的,Process.myUserHandle()=UserHandle.SYSTEM
if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
IntentFilter bootCompletedFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
bootCompletedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);//优先接受开机广播
//接收开机广播,并且启动所有继承SystemUI的类的onBootCompleted方法。
//继承systemUI的类有哪些?
//config 里面有一个数组config_systemUIServiceComponents里面罗列了继承systeUI的类
/*
- com.android.systemui.Dependency
- com.android.systemui.util.NotificationChannels
- com.android.systemui.statusbar.CommandQueue$CommandQueueStart
- com.android.systemui.keyguard.KeyguardViewMediator
- com.android.systemui.recents.Recents
- com.android.systemui.volume.VolumeUI
- com.android.systemui.stackdivider.Divider
- com.android.systemui.SystemBars
- com.android.systemui.usb.StorageNotification
- com.android.systemui.power.PowerUI
- com.android.systemui.media.RingtonePlayer
- com.android.systemui.keyboard.KeyboardUI
- com.android.systemui.pip.PipUI
- com.android.systemui.shortcut.ShortcutKeyDispatcher
- @string/config_systemUIVendorServiceComponent
//com.android.systemui.VendorServices
- com.android.systemui.util.leak.GarbageMonitor$Service
- com.android.systemui.LatencyTester
- com.android.systemui.globalactions.GlobalActionsComponent
- com.android.systemui.ScreenDecorations
- com.android.systemui.fingerprint.FingerprintDialogImpl
- com.android.systemui.SliceBroadcas
*/
registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (StatusBar.SYSTEMUI_START_DEBUG) Log.i(StatusBar.TAG_XIAO, "BOOT_COMPLETED received");
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 {
// We don't need to startServices for sub-process that is doing some tasks.
// (screenshots, sweetsweetdesserts or tuner ..)
String processName = ActivityThread.currentProcessName();
ApplicationInfo info = getApplicationInfo();
if (processName != null && processName.startsWith(info.processName + ":")) {
return;
}
// For a secondary user, boot-completed will never be called because it has already
// been broadcasted on startup for the primary SystemUI process. Instead, for
// components which require the SystemUI component to be initialized per-user, we
// start those components now for the current non-system user.
startSecondaryUserServicesIfNeeded();
}
//@along add
registerReceiver(new LauncherReceiver(), new IntentFilter("android.intent.action.INST_LAUNCHER"));
}
/**
* 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.
*
This method must only be called from the main thread.
*/
public void startServicesIfNeeded() {
String[] names = getResources().getStringArray(R.array.config_systemUIServiceComponents);
startServicesIfNeeded(names);
}
/**
* 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.
* This method must only be called from the main thread.
*/
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];
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() + ".");
TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
Trace.TRACE_TAG_APP);
log.traceBegin("StartServices");
final int N = services.length;
for (int i = 0; i < N; i++) {
String clsName = services[i];
if (DEBUG) Log.d(TAG, "loading: " + clsName);
log.traceBegin("StartServices" + clsName);
long ti = System.currentTimeMillis();
Class cls;
try {
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;
if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
mServices[i].start();//启动继承SystemUI的类。具体有哪些类可以查看config 里面有一个数组config_systemUIServiceComponents
log.traceEnd();
// Warn if initialization of component takes too long
ti = System.currentTimeMillis() - ti;
if (ti > 1000) {
Log.w(TAG, "Initialization of " + cls.getName() + " took " + ti + " ms");
}
if (mBootCompleted) {
mServices[i].onBootCompleted();
}
}
log.traceEnd();
Dependency.get(PluginManager.class).addPluginListener(
new PluginListener() {
private ArraySet mOverlays;
@Override
public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {
StatusBar statusBar = getComponent(StatusBar.class);
Log.i(StatusBar.TAG_XIAO,"SystemUIApplication onPluginConnected plugin "+ plugin+",pluginContext:"+pluginContext);
if (statusBar != null) {
plugin.setup(statusBar.getStatusBarWindow(),
statusBar.getNavigationBarView());
}
// Lazy init.
if (mOverlays == null) mOverlays = new ArraySet<>();
if (plugin.holdStatusBarOpen()) {
mOverlays.add(plugin);
Dependency.get(StatusBarWindowManager.class).setStateListener(b ->
mOverlays.forEach(o -> o.setCollapseDesired(b)));
Dependency.get(StatusBarWindowManager.class).setForcePluginOpen(
mOverlays.size() != 0);
}
}
@Override
public void onPluginDisconnected(OverlayPlugin plugin) {
Log.i(StatusBar.TAG_XIAO,"SystemUIApplication onPluginDisconnected plugin "+ plugin);
mOverlays.remove(plugin);
Dependency.get(StatusBarWindowManager.class).setForcePluginOpen(
mOverlays.size() != 0);
}
}, OverlayPlugin.class, true /* Allow multiple plugins */);
mServicesStarted = true;//systemui servcie启动完成
}
从上面的代码来看就是加载一堆服务,这些服务都定义在config_systemUIServiceComponents,这些类都有一个特点就是继承SystemUI类。到这里SystemUI就算加载完成,之后的就是每个服务快的加载流程。所以回顾代码看是不是很简单