第二集SystemUI的启动

本文深入分析了Android5.1版本中SystemUI的架构与启动过程,详细介绍了SystemUI所包含的各个功能模块及其启动流程。通过阅读本文,读者可以了解到SystemUI在Android系统中的作用及其实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android 5.1 SystemUI 家的事系列片

第二集SystemUI的启动



什么是SystemUI

SystemUI是什么?我们从2个层面来看;

用户层面,即显示效果

  • status bar 和 navigation bar
    图一
    这里写图片描述

图中红色框框标示出的即为SystemUI显示的范围,上方的我们称之为status bar即状态栏,其height一般为25dpi,width为屏幕的宽度;下方的为navigation bar即导航栏,其height为48dpi,width为屏幕的宽度;

  • expand panel
    图二
    这里写图片描述
    expand panel即我们常说的下拉面板;如图中红色框框所示;其UI 显示以及下拉,缩回的动画都在SystemUI的实现;
    当我们收到notification时,例如插拔sdcard,在expand panel中会有通知显示,其显示的UI也由SystemUI 控制;

开发层面,即源码

SystemUI的源码位于android源码/frameworks/base/package/SystemUI
分析frameworks/base/package/SystemUI/Android.mk文件

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

LOCAL_SRC_FILES := $(call all-java-files-under, src) \
    src/com/android/systemui/EventLogTags.logtags

LOCAL_STATIC_JAVA_LIBRARIES := Keyguard
LOCAL_JAVA_LIBRARIES := telephony-common

LOCAL_PACKAGE_NAME := SystemUI
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := true

LOCAL_PROGUARD_FLAG_FILES := proguard.flags

LOCAL_RESOURCE_DIR := \
    frameworks/base/packages/Keyguard/res \
    $(LOCAL_PATH)/res
LOCAL_AAPT_FLAGS := --auto-add-overlay --extra-packages com.android.keyguard

include $(BUILD_PACKAGE)

include $(call all-makefiles-under,$(LOCAL_PATH))

其实SystemUI就是一个APP,没有Activity的。用platform key签名,拥有system权限的系统app;
编译后,其apk文件在out/target/product/productname/system/priv-app/SystemUI/SystemUI.apk

  • SystemUI的管辖地带说明

1.status bar中显示的例如时钟,SIM卡信号,3G信号,wifi信号,蓝牙,等等,都归SystemUI控制;

2.navigation bar中涉及到3个重要的按钮,back button,home button以及recent app button;这些控制都在SystemUI中;

3.wallpaper,即在图一看到的绿色背景,称之为静态壁纸,归SystemUI管控;但是出去红色框框之外的,壁纸之上的,都是home的管辖地带了;

插播一段小花絮
这里为什么一定要提到SystemUI的管辖地带,因为很多人在解决Android bug时,分不清楚,哪个是SystemUI的,哪个是home的;很容易弄混,导致了分析问题时,连方向都找错了;
例如,点击图一中的Gallery button,无法进入Gallery,有人会认为SystemUI有问题引起的。其实问题有可能在home,但一定不在SystemUI,,这个锅SystemUI不背;
例如,wallpaper不显示了,背景为黑色的,问题应该在SystemUI, 但一定不在home;

SystemUI的架构

分析的起点

分析或者学习一个功能,总的来说先从架构图入手,纵观全局;然后再从流程图推进,逐步了解细节;
那么针对Android app,或者framework层的功能;它的入手也是从架构图开始,但有2个重要的文件,一定是要先看的,一个是Android.mk,一个是AndroidManifest.xml;

Android.mk决定了当前参与此功能的编译code涉及了哪些,编译出来的是个什么鬼;是个jar包,apk还是so库,还是可执行文件;所以会读mk文件,是行走android 源码的基本技能之一;

AndroidManifest.xml在apk中特有,从它可以知道,该app运行的起始activity会是谁,app中涉及到了哪些activity,service,broadcast;APP具备哪些权限,等等;

可以说读懂以上2个文件,是分析Apk的源头;

SystemUI类图

SystemUI 功能类图分析
图三
这里写图片描述
这个图标识除了SystemUI中管控的七大功能:

  • SystemBars
  • KerguardViewMediator
  • Recents
  • VolumeUI
  • StorageNotification
  • PowerUI
  • RingtonePlayer

这些功能具体做了哪些事情,后续分集讲解;

SystemUIService是SystemUI得以运行的总起点,它去找SystemUIApplication将七大功能都运行起来;所以说它们二者开始了SystemUI的启动;具体流程看第三节—SystemUI的启动

SystemUI的启动

startSystemUi

SystemUI是随着Android系统的启动而启动的;正如我们所熟知的,Android系统运行的第一个进程为zygote,然后启动了init进程,接着就是SystemServer了;SystemServer负责将Android系统的各大Service运行起来,例如负责App运行的ActivityManagerService,负责APP安装,解析,卸载的PackageManagerService,负责Window窗口绘画管理的WindowManagerService,等等;SystemUI也是在SystemServer中启动的;
具体code如下:

static final void startSystemUi(Context context) {
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.android.systemui",                   "com.android.systemui.SystemUIService"));
        //Slog.d(TAG, "Starting service: " + intent);
        context.startServiceAsUser(intent, UserHandle.OWNER);
    }

我们看到SystemUI的启动其实就是启动了一个常规的Android四大组件之一Service—- SystemUIService;
startSystemUi又是由谁调用的呢?

mActivityManagerService.systemReady(new Runnable() {
            @Override
            public void run() {
                Slog.i(TAG, "Making services ready");
                ...
                try {
                    startSystemUi(context);
                } catch (Throwable e) {
                    reportWtf("starting System UI", e);
                }

我们看到在AcitivityManagerService运行成功之后,调用了startSystemUi函数;

SystemUI 各大功能的创建

在SystemServer中执行了startSystemUi之后,就会运行到SystemUI中的SystemUIService onCreate函数,那么接下来做了哪些事情呢?

这里写图片描述
step 1 onCreate
属于系统调用,先调用Application的onCreate

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.systemui_theme);

        IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
        filter.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();
                    }
                }
            }
        }, filter);
    }

step 1的关键是注册了一个静态广播,防止各大功能的onBootCompleted没有被调用;这样说可能大家有些迷糊,先放着,继续往下看;
step 2 onCreate
也是系统调用,注意step 1 和step 2 都是来自Android 对Service启动的生命周期控制;

public void onCreate() {
        super.onCreate();
        ((SystemUIApplication) getApplication()).startServicesIfNeeded();
    }

step 2 很简单,就是回调到SystemUIApplication中的startServicesIfNeeded()函数中
step3 startServicesIfNeeded

public void startServicesIfNeeded() {
        if (mServicesStarted) {
            return;
        }

        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.");
        final int N = SERVICES.length;
        for (int i=0; i<N; i++) {
            Class<?> cl = SERVICES[i];
            if (DEBUG) Log.d(TAG, "loading: " + cl);
            try {
                mServices[i] = (SystemUI)cl.newInstance();
            } 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();

            if (mBootCompleted) {
                mServices[i].onBootCompleted();
            }
        }
        mServicesStarted = true;
    }

SystemUIApplication当中有2个比较重要的控制变量:
private boolean mServicesStarted;
private boolean mBootCompleted;
初始化的值均为false;
mServicesStarted为true表示SystemUIService运行起来了,该变量的目的是方式new 出多个SystemUI对象;

mBootCompleted为true表示Android系统已经运行完全,具体的指标有系统发出boot completed广播或者sys.boot_completed属性值为1;因为SystemUI中有些功能必须在系统运行完全之后才能执行;

这里相当于将SystemUI旗下的功能,分成了2个阶段初始化,start函数执行在boot completed之前,而onBootCompelted执行在boot completed之后;为什么要分2个阶段初始化?是因为功能需求,在早起的Android 3.X的系统中,SystemUI并没有这样的初始化区分;

功能总结变量:
private final SystemUI[] mServices = new SystemUI[SERVICES.length];
在step 3中,各个功能new出的实例都存放在mServices中;

Class<?> cl = SERVICES[i];
 mServices[i] = (SystemUI)cl.newInstance();

SERVICE 列出了,当前有哪些功能:

private final Class<?>[] SERVICES = new Class[] {
            com.android.systemui.keyguard.KeyguardViewMediator.class,
            com.android.systemui.recent.Recents.class,
            com.android.systemui.volume.VolumeUI.class,
       com.android.systemui.statusbar.SystemBars.class,
    com.android.systemui.usb.StorageNotification.class,
            com.android.systemui.power.PowerUI.class,
       com.android.systemui.media.RingtonePlayer.class
    };

这就是我们在图三种看到7个功能;
回过头来看step 1中注册的静态广播
在step 3 中的最后几步,如果此时mBootCompleted的值为false,也就是说,此时系统还没有运行完全,那么各大功能的onBootcompleted就不会被调用;此时广播就发挥效用了;当系统发出boot commpelted的广播时,在onReceive中就会执行各个功能的onBootCompleted函数了;
严谨的编程思维就是这样的,而且我们可以看到onReceive中,最先执行的是unregisterReceiver,将广播注销;这也是我们经常忽略的部分,值得学习

总结

SystemUIService的开始运行,启动了SystemUI的运作;后续会绘画status bar,navigation bar,expand panel,接收notification等等;后续会陆续分析;

从SystemUI的架构图中,我们看出SystemUI的架构设计得很好;所有的功能都继承自abstract class SystemUI;启动也列举到 SERVICES中,如果我们想要在SystemUI中增加新的功能,很简单,自己写一个继承自SystemUI 的类即可;如果想要删除某个功能,也很简单,在SERVICES中将其移除即可;体现了架构设计的灵活性;

上一集:第一集 缘分的起点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值