一 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 大概是这样

Android 车载使用开发攻略 - SystemUI

1.2 CarSystemUI

Android-AutoMotive中的SystemUI相对手机中要简略不少,现在商用车载体系中几乎必备的顶部状态栏、音讯中心、底部导航栏在原生的Android体系中都现已实现了。

源码方位:frameworks/base/packages/CarSystemUI

Android 车载使用开发攻略 - SystemUI

虽然CarSystemUISystemUI的源码方位不同,但是二者实际上是复用联系。经过阅读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 体系最核心的进程Zygotefork 生成,进程名为system_server。常见的ActivityManagerServicePackageManagerServiceWindowManageService都是由SystemServer发动的。

SystemServer 源码路径:/frameworks/base/services/java/com/android/server/SystemServer.java

第一步:SystemServermain() 办法中调用 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获取到的Componentcom.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

AMSstartService()办法里,会经过一系列内部流程,调用到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;
}

这个办法做了两件事:

  1. 假如SystemUIService所属进程现已存在,则直接调用realStartServiceLocked()
  2. 假如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,这个HandlerActivityThread的内部类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);
        }
    }
}

这个办法首要做了以下几件事:

  1. 首要,创立上下文
  2. 创立SystemUIApplication,获取类加载器
  3. 加载SystemUIService实例,初始化SystemUIService, 调用onCreate()办法
  4. 终究告诉AMSSystemUIService发动完结。

到这儿SystemUIService现已发动完结。

第五步: 前面在SystemUIApplication创立成功后会回调内部的OnCreate()办法,在OnCreate()中办法注册了一个开机播送,当接收到开机播送后会调用SystemUIonBootCompleted()办法来告诉每个子模块 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()
        ... ...
    }
}

第七步:SystemUIApplicationstartServicesIfNeeded()办法中,经过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组件的创立,然后再调用各个SystemUIonStart()办法来持续履行子模块的初始化。

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 是经过SystemUIFactorygetSystemUIServiceComponents()获取到的,那么只需承继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的大致发动流程能够归纳如下:

Android 车载使用开发攻略 - SystemUI

SystemUI 是一个 persistent 使用,它由操作体系发动,首要流程为

  • Android 体系在开机后会创立 system_server 进程,它会发动各种体系所需求的服务,其中就包括 SystemUIService
  • SystemUIService 发动后进入到使用层 SystemUI 中,在 SystemUIApplication 它首要会初始化监听ACTION_BOOT_COMPLETED 等告诉,待体系完结发动后会告诉各个组件 onBootCompleted
  • 在进入 SystemUIService 中仍然履行的 SystemUIApplication 中的startServicesIfNeeded() 办法发动 SystemUI 中的子模块。
  • 终究的服务发动逻辑都是在 SystemUIApplication 里边,而且都保存在 mServices 数组中。

三 总结

SystemUI在原生的车载 Android 体系是一个较为杂乱的模块,本文首要介绍了SystemUICarSystemUI的功用、源码结构及发动时序,希望能帮到从事SystemUI开发的同学。

四 参阅文档

Android 车载使用开发与剖析(12) – SystemUI (一)