一 SystemUI 概述
SystemUI
全称System User Interface
,直译过来便是体系级用户交互界面,在 Android 体系中由SystemUI
担任统一管理整个体系层的 UI,它是一个体系级使用程序(APK),源码在/frameworks/base/packages/
目录下。
1.1 SystemUI
Android – Phone中SystemUI
从源码量看便是一个适当杂乱的程序,常见的如:状态栏、音讯中心、近期使命、截屏以及一系列功用都是在SystemUI
中实现的。
源码方位:/frameworks/base/packages/SystemUI
常见 UI
组件有(包含但不限于,完整列表能够检查 SystemUI
服务组件列表)
- 状态栏
StatusBar
- 导航栏
NavigationBar
- 告诉栏
NotificationPanel
- 快捷按键栏
QSPanel
- 最近使命
Recent
- 键盘锁
Keyguard
原生 Android
体系中 SystemUI
大概是这样
1.2 CarSystemUI
Android-AutoMotive
中的SystemUI
相对手机中要简略不少,现在商用车载体系中几乎必备的顶部状态栏、音讯中心、底部导航栏在原生的Android
体系中都现已实现了。
源码方位:frameworks/base/packages/CarSystemUI
虽然CarSystemUI
与SystemUI
的源码方位不同,但是二者实际上是复用联系。经过阅读CarSystemUI
的 Android.bp 文件能够发现CarSystemUI
在编译时把SystemUI
以静态库的办法引进进来了。
android.bp 源码方位:/frameworks/base/packages/CarSystemUI/Android.bp
android_library {
name: "CarSystemUI-core",
...
static_libs: [
"SystemUI-core",
"SystemUIPluginLib",
"SystemUISharedLib",
"SystemUI-tags",
"SystemUI-proto",
...
],
...
}
二 SystemUI 发动流程
System UI
的发动大致可分为以下两个流程:
- 在
Framework
中发动SystemUIService
- 在
SystemUIService
中发动SystemUI
所需的各种组件
阐明:本文源码剖析基于版别:android-12.0.0_r3
2.1 Framework 中的流程
SystemUI
是体系使用,所以它也是一个 APK,有入口 Application
,只不过它是由 system_server
进程直接发动的。
关于SystemServer
,它是 Android framework 中要害体系的服务,由 Android 体系最核心的进程Zygote
fork 生成,进程名为system_server
。常见的ActivityManagerService
、PackageManagerService
、WindowManageService
都是由SystemServer
发动的。
SystemServer 源码路径:/frameworks/base/services/java/com/android/server/SystemServer.java
第一步:SystemServer
的 main()
办法中调用 SystemServer.run()
,run()
中调用startOtherServices()
public static void main(String[] args) {
new SystemServer().run();
}
private void run() {
... ...
// Start services.
try {
startBootstrapServices(t);
startCoreServices(t);
startOtherServices(t); //SystemServer在startOtherServices()被发动
}
... ...
}
第二步:startOtherServices()
中经过AMS
的回调办法ready()
,然后调用startSystemUi()
mActivityManagerService.systemReady(() -> {
... ...
try {
startSystemUi(context, windowManagerF);
} catch (Throwable e) {
reportWtf("starting System UI", e);
}
... ...
,t);
第三步:startSystemUi()
中能够看出,SystemUI
实质便是一个Service
,经过PM
获取到的Component
是com.android.systemui/.SystemUIService
,然后经过调用context.startServiceAsUser()
完结对SystemUIService
的发动。
private static void startSystemUi(Context context, WindowManagerService windowManager) {
PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
Intent intent = new Intent();
intent.setComponent(pm.getSystemUiServiceComponent());
intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
//Slog.d(TAG, "Starting service: " + intent);
context.startServiceAsUser(intent, UserHandle.SYSTEM);
windowManager.onSystemUiStarted();
}
第四步:SystemUIService
依附于SystemUI
使用,所以SystemUIService
发动前需求完结SystemUI
整个使用的发动,其流程也便是使用常见的冷发动流程,这儿展开讲一下:
-
SystemUI 使用发动流程
context
中的startServiceAsUser()
是一个笼统办法,详细实现在ContextImpl.java
里。实现办法startServiceCommon()
中,经过ActivityManager.getService()
就会走到AMS
中,终究在AMS
来发动SystemUIService
。
@Override
public ComponentName startServiceAsUser(Intent service, UserHandle user) {
return startServiceCommon(service, false, user);
}
@Override
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
ComponentName cn = ActivityManager.getService().startService( //在AMS中开启Service
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
getOpPackageName(), getAttributionTag(), user.getIdentifier());
... ...
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
接下来进入AMS
,一探究竟:
AMS 源码路径:/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
在AMS
的startService()
办法里,会经过一系列内部流程,调用到bringUpServiceLocked()
办法。
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage,
String callingFeatureId, int userId)
throws TransactionTooLargeException {
... ...
try {
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
requireForeground, callingPackage, callingFeatureId, userId); // 内部调用到 startServiceLocked()
}
... ...
}
}
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType, int callingPid, int callingUid, boolean fgRequired, String callingPackage,
@Nullable String callingFeatureId, final int userId,
boolean allowBackgroundActivityStarts) throws TransactionTooLargeException {
... ...
if (caller != null) {
// 这儿记录app的进程信息
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
... ...
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting); //内部调用到startServiceInnerLocked()
... ...
return cmp;
}
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r, boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
... ...
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false); //调用到bringUpServiceLocked()
if (error != null) {
return new ComponentName("!!", error);
}
... ...
return r.name;
}
持续调用了bringUpServiceLocked()
办法,
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg, boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
... ...
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid + " app=" + app);
//假如service进程存在
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
//发动service
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortInstanceName, e);
}
}
}
... ...
// 假如不存在此进程
if (app == null && !permissionsReviewRequired) {
// 发动运转的线程
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, isolated, false)) == null) {
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": process is bad";
Slog.w(TAG, msg);
bringDownServiceLocked(r);
return msg;
}
}
... ...
return null;
}
这个办法做了两件事:
- 假如
SystemUIService
所属进程现已存在,则直接调用realStartServiceLocked()
。 - 假如
SystemUIService
所属进程不存在,则履行startProcessLocked()
办法创立进程,经过层层调用,终究也会走到realStartServiceLocked()
中:
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
... ...
try {
... ...
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
app.getReportedProcState());
r.postNotification();
created = true;
}
}
这个办法内部调用了app.thread.scheduleCreateService()
,而app.thread
是一个IApplicationThread
类型的,他的实现是ActivityThread
的一个内部类ApplicationThread
,而这个类正好实现了IApplicationThread.Stub
,在ApplicationThread
类中,找到对应的调用办法:
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
sendMessage(H.CREATE_SERVICE, s);
}
能够看出,是发送一个音讯给Handler
,这个Handler
是ActivityThread
的内部类H
public void handleMessage(Message msg) {
switch (msg.what) {
... ...
case CREATE_SERVICE:
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
("serviceCreate: " + String.valueOf(msg.obj)));
}
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
... ...
}
}
终究调用了handleCreateService()
办法:
private void handleCreateService(CreateServiceData data) {
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
//创立service的context
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
//创立Application
Application app = packageInfo.makeApplication(false, mInstrumentation);
//获取类加载器
java.lang.ClassLoader cl = packageInfo.getClassLoader();
//加载service实例
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
// Service resources must be initialized with the same loaders as the application
// context.
context.getResources().addLoaders(
app.getResources().getLoaders().toArray(new ResourcesLoader[0]));
context.setOuterContext(service);
//初始化service
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
//调用service的onCreate办法
service.onCreate();
mServices.put(data.token, service);
try {
//经过serviceDoneExecuting告知AMS,service现已发动完结
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to create service " + data.info.name
+ ": " + e.toString(), e);
}
}
}
这个办法首要做了以下几件事:
- 首要,创立上下文
- 创立
SystemUIApplication
,获取类加载器 - 加载
SystemUIService
实例,初始化SystemUIService
, 调用onCreate()
办法 - 终究告诉
AMS
,SystemUIService
发动完结。
到这儿SystemUIService
现已发动完结。
第五步: 前面在SystemUIApplication
创立成功后会回调内部的OnCreate()
办法,在OnCreate()
中办法注册了一个开机播送,当接收到开机播送后会调用SystemUI
的onBootCompleted()
办法来告诉每个子模块 Android 体系现已完结开机。
@Override
public void onCreate() {
super.onCreate();
Log.v(TAG, "SystemUIApplication created.");
// 设置所有服务承继的使用程序主题。
// 请注意,在清单中设置使用程序主题仅适用于activity。这儿是让Service保持与主题设置同步。
setTheme(R.style.Theme_SystemUI);
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 (mBootCompleteCache.isBootComplete()) return;
if (DEBUG) Log.v(TAG, "BOOT_COMPLETED received");
unregisterReceiver(this);
mBootCompleteCache.setBootComplete();
if (mServicesStarted) {
final int N = mServices.length;
for (int i = 0; i < N; i++) {
mServices[i].onBootCompleted(); //告诉SystemUI子模块
}
}
}
}, bootCompletedFilter);
...
} else {
// 咱们不需求为正在履行某些使命的子进程发动服务。
...
}
}
2.2 SystemUI 中的流程
第六步:SystemUIService
初始化完结后会调用onCreate()
办法,onCreate()
中调用了SystemUIApplication
中的startServiceIfNeeded()
办法完结SystemUI
子模块的初始化。
SystemUIService 源码方位:/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java
public class SystemUIService extends Service {
... ...
@Override
public void onCreate() {
super.onCreate();
// Start all of SystemUI
((SystemUIApplication) getApplication()).startServicesIfNeeded(); //调用startServicesIfNeeded()
... ...
}
}
第七步: 在SystemUIApplication
的startServicesIfNeeded()
办法中,经过SystemUIFactory
获取到装备在config.xml
中每个子模块的className
。
SystemUIApplication 源码方位:/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
// SystemUIApplication
public void startServicesIfNeeded() {
String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponents(getResources());
startServicesIfNeeded("StartServices", names);
}
// SystemUIFactory
/** Returns the list of system UI components that should be started. */
public String[] getSystemUIServiceComponents(Resources resources) {
return resources.getStringArray(R.array.config_systemUIServiceComponents);
}
config.xml 方位:/frameworks/base/packages/SystemUI/res/values/config.xml
<!-- SystemUI Services: The classes of the stuff to start. -->
<string-array name="config_systemUIServiceComponents" translatable="false">
<item>com.android.systemui.util.NotificationChannels</item>
<item>com.android.systemui.keyguard.KeyguardViewMediator</item>
<item>com.android.systemui.recents.Recents</item>
<item>com.android.systemui.volume.VolumeUI</item>
<item>com.android.systemui.stackdivider.Divider</item>
<item>com.android.systemui.statusbar.phone.StatusBar</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.biometrics.AuthController</item>
<item>com.android.systemui.SliceBroadcastRelayHandler</item>
<item>com.android.systemui.SizeCompatModeActivityController</item>
<item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
<item>com.android.systemui.theme.ThemeOverlayController</item>
<item>com.android.systemui.accessibility.WindowMagnification</item>
<item>com.android.systemui.accessibility.SystemActions</item>
<item>com.android.systemui.toast.ToastUI</item>
</string-array>
第八步: 在startServicesIfNeeded()
中经过反射完结了每个SystemUI
组件的创立,然后再调用各个SystemUI
的onStart()
办法来持续履行子模块的初始化。
private SystemUI[] mServices;
private void startServicesIfNeeded(String metricsPrefix, 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];
if (DEBUG) Log.d(TAG, "loading: " + clsName);
try {
SystemUI obj = mComponentHelper.resolveSystemUI(clsName);
if (obj == null) {
Constructor constructor = Class.forName(clsName).getConstructor(Context.class);
obj = (SystemUI) constructor.newInstance(this);
}
mServices[i] = obj;
} catch (ClassNotFoundException
| NoSuchMethodException
| IllegalAccessException
| InstantiationException
| InvocationTargetException ex) {
throw new RuntimeException(ex);
}
if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
// 调用各个子模块的start()
mServices[i].start();
// 初次发动时,这儿始终为false,不会被调用
if (mBootCompleteCache.isBootComplete()) {
mServices[i].onBootCompleted();
}
}
mServicesStarted = true;
}
这儿的SystemUI
是一个笼统类,状态栏、近期使命等等模块都是承继自SystemUI
,经过这种办法能够很大程度上简化杂乱的SystemUI
程序中各个子模块创立办法,一起咱们能够经过装备资源的办法动态加载需求的SystemUI
模块。
SystemUI
的源码如下,办法根本都能见名知意,就不再介绍了。
public abstract class SystemUI implements Dumpable {
protected final Context mContext;
public SystemUI(Context context) {
mContext = context;
}
public abstract void start();
protected void onConfigurationChanged(Configuration newConfig) {
}
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
}
protected void onBootCompleted() {
}
2.3 CarSystemUI 的发动流程
前文说到CarSystemUI
复用了手机SystemUI
的代码,所以CarSystemUI
的发动流程和SystemUI
的是完全一致的。
但CarSystemUI
中需求的功用与SystemUI
中也有部分差异,那么是这些差异化的功用是怎么引进并完结初始化?以及一些手机的SystemUI
才需求的功用是怎么去除的呢?
其实很简略,在SystemUI
的发动流程中咱们得知,各个子模块的 className 是经过SystemUIFactory
的getSystemUIServiceComponents()
获取到的,那么只需承继SystemUIFactory
并重写getSystemUIServiceComponents()
就能够了。
public class CarSystemUIFactory extends SystemUIFactory {
@Override
protected SystemUIRootComponent buildSystemUIRootComponent(Context context) {
return DaggerCarSystemUIRootComponent.builder()
.contextHolder(new ContextHolder(context))
.build();
}
@Override
public String[] getSystemUIServiceComponents(Resources resources) {
Set<String> names = new HashSet<>();
// 先引进systemUI中的components
for (String s : super.getSystemUIServiceComponents(resources)) {
names.add(s);
}
// 再移除CarsystemUI不需求的components
for (String s : resources.getStringArray(R.array.config_systemUIServiceComponentsExclude)) {
names.remove(s);
}
// 终究再增加CarsystemUI特有的components
for (String s : resources.getStringArray(R.array.config_systemUIServiceComponentsInclude)) {
names.add(s);
}
String[] finalNames = new String[names.size()];
names.toArray(finalNames);
return finalNames;
}
}
<!-- 需求移除的Components. -->
<string-array name="config_systemUIServiceComponentsExclude" translatable="false">
<item>com.android.systemui.recents.Recents</item>
<item>com.android.systemui.volume.VolumeUI</item>
<item>com.android.systemui.stackdivider.Divider</item>
<item>com.android.systemui.statusbar.phone.StatusBar</item>
<item>com.android.systemui.keyboard.KeyboardUI</item>
<item>com.android.systemui.pip.PipUI</item>
<item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
<item>com.android.systemui.LatencyTester</item>
<item>com.android.systemui.globalactions.GlobalActionsComponent</item>
<item>com.android.systemui.SliceBroadcastRelayHandler</item>
<item>com.android.systemui.statusbar.notification.InstantAppNotifier</item>
<item>com.android.systemui.accessibility.WindowMagnification</item>
<item>com.android.systemui.accessibility.SystemActions</item>
</string-array>
<!-- 新增的Components. -->
<string-array name="config_systemUIServiceComponentsInclude" translatable="false">
<item>com.android.systemui.car.navigationbar.CarNavigationBar</item>
<item>com.android.systemui.car.voicerecognition.ConnectedDeviceVoiceRecognitionNotifier</item>
<item>com.android.systemui.car.window.SystemUIOverlayWindowManager</item>
<item>com.android.systemui.car.volume.VolumeUI</item>
</string-array>
经过以上办法,就完结了CarSystemUI
子模块的替换。
2.4 小结
总结一下,SystemUI
的大致发动流程能够归纳如下:
SystemUI
是一个 persistent
使用,它由操作体系发动,首要流程为
-
Android
体系在开机后会创立system_server
进程,它会发动各种体系所需求的服务,其中就包括SystemUIService
。 -
SystemUIService
发动后进入到使用层SystemUI
中,在SystemUIApplication
它首要会初始化监听ACTION_BOOT_COMPLETED
等告诉,待体系完结发动后会告诉各个组件onBootCompleted
。 - 在进入
SystemUIService
中仍然履行的SystemUIApplication
中的startServicesIfNeeded()
办法发动SystemUI
中的子模块。 - 终究的服务发动逻辑都是在
SystemUIApplication
里边,而且都保存在mServices
数组中。
三 总结
SystemUI
在原生的车载 Android 体系是一个较为杂乱的模块,本文首要介绍了SystemUI
和CarSystemUI
的功用、源码结构及发动时序,希望能帮到从事SystemUI
开发的同学。