[Android14] SystemUI的启动

news2024/12/30 2:41:50

1. 什么是System UI

        SystemUI是Android系统级应用,负责反馈系统及应用状态并与用户保持大量的交互。业务主要涉及的组成部分包括状态栏(Status Bar),通知栏(Notification Panel),锁屏(Keyguard),控制中心(Quick Setting),音量调节(VolumeUI), 近期任务(Recents)等等。

图例如下所示:

2. 源码位置

package name:    com.android.systemui

SystemUI源码目录位于: framework/base/packages/SystemUI

Application位于:        frameworks\base\packages\SystemUI\SystemUIApplication

Service位于:            frameworks\base\services\java\com\android\server\

3. systemUI 启动流程

SystemServer.run()-> startOtherServices()-> startSystemUi()

SystemServer由ZygoteInit进程创建并启动

frameworks/base/services/java/com/android/server/SystemServer.java

    /**
     * The main entry point from zygote.
     */
    public static void main(String[] args) {
        new SystemServer().run();
    }



    private void run() {
    ......
    // Start services.
        try {
            t.traceBegin("StartServices");
            startBootstrapServices(t);
            startCoreServices(t);
            startOtherServices(t);  //在这里会启动startSystemUi()
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        } finally {
            t.traceEnd(); // StartServices
        }
    ......
    }


    /**
     * Starts a miscellaneous grab bag of stuff that has yet to be refactored and organized.
     */
        private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
            ......
            try {
                startSystemUi(context, windowManagerF);
            } catch (Throwable e) {
                reportWtf("starting System UI", e);
            }
            ......
        }

    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();
    }

注意看这一段 

intent.setComponent(pm.getSystemUiServiceComponent());

pm是PackageManagerInternal实例,它的getSystemUiServiceComponent()方法是一个抽象方法

frameworks/base/services/core/java/android/content/pm/PackageManagerInternal.java

    /**
     * @return The SystemUI service component name.
     */
    public abstract ComponentName getSystemUiServiceComponent();

PackageManagerService实现了该方法,如下:

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

        @Override
        public ComponentName getSystemUiServiceComponent() {
            return ComponentName.unflattenFromString(mContext.getResources().getString(
                    com.android.internal.R.string.config_systemUIServiceComponent));
        }

 com.android.internal.R.string.config_systemUIServiceComponent的值是

frameworks/base/core/res/res/values/config.xml

<!-- SystemUi service component -->
    <string name="config_systemUIServiceComponent" translatable="false"
            >com.android.systemui/com.android.systemui.SystemUIService</string>

 unflattenFromString返回的是ComponentName(“com.android.systemui”, “com.android.systemui.SystemUIService”);

unflattenFromString 具体方法如下,很简单,感兴趣的可以看看,不感兴趣的直接跳过就好,这个方法不是重点。

    /**
     * Recover a ComponentName from a String that was previously created with
     * {@link #flattenToString()}.  It splits the string at the first '/',
     * taking the part before as the package name and the part after as the
     * class name.  As a special convenience (to use, for example, when
     * parsing component names on the command line), if the '/' is immediately
     * followed by a '.' then the final class name will be the concatenation
     * of the package name with the string following the '/'.  Thus
     * "com.foo/.Blah" becomes package="com.foo" class="com.foo.Blah".
     *
     * @param str The String that was returned by flattenToString().
     * @return Returns a new ComponentName containing the package and class
     * names that were encoded in <var>str</var>
     *
     * @see #flattenToString()
     */
    public static @Nullable ComponentName unflattenFromString(@NonNull String str) {
        int sep = str.indexOf('/');
        if (sep < 0 || (sep+1) >= str.length()) {
            return null;
        }
        String pkg = str.substring(0, sep);
        String cls = str.substring(sep+1);
        if (cls.length() > 0 && cls.charAt(0) == '.') {
            cls = pkg + cls;
        }
        return new ComponentName(pkg, cls);
    }

以上代码功能为通过Intent启动了SystemUIService。

于是走到SystemUIService的onCreate()方法

frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java

    public void onCreate() {
        super.onCreate();

        // Start all of SystemUI
        ((SystemUIApplication) getApplication()).startServicesIfNeeded();
        ......
    }


    public void startServicesIfNeeded() {
        String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponents(getResources());
        startServicesIfNeeded(/* metricsPrefix= */ "StartServices", names);
    }

通过工厂模式获得SystemUI组件列表

frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
    public String[] getSystemUIServiceComponents(Resources resources) {
        return resources.getStringArray(R.array.config_systemUIServiceComponents);
    }

 列表如下:

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>

 这个列表是要传到上面的String[] names里的,作为参数,下一步执行startServicesIfNeeded(/* metricsPrefix= */ "StartServices", names);

方法如下:

大致内容就是通过反射获得上面列表的类的构造函数,然后通过构造函数创建上面那些类的实例,然后调用这些类的start方法,启动这些systemuI组件。

private void startServicesIfNeeded(String metricsPrefix, String[] services) {
        if (mServicesStarted) {
            return;
        }
        mServices = new SystemUI[services.length];

        if (!mBootCompleteCache.isBootComplete()) {
            // check to see if maybe it was already completed long before we began
            // see ActivityManagerService.finishBooting()
            if ("1".equals(SystemProperties.get("sys.boot_completed"))) {
                mBootCompleteCache.setBootComplete();
                if (DEBUG) {
                    Log.v(TAG, "BOOT_COMPLETED was already sent");
                }
            }
        }

        final DumpManager dumpManager = mRootComponent.createDumpManager();

        Log.v(TAG, "Starting SystemUI services for user " +
                Process.myUserHandle().getIdentifier() + ".");
        TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
                Trace.TRACE_TAG_APP);
        log.traceBegin(metricsPrefix);
        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(metricsPrefix + clsName);
            long ti = System.currentTimeMillis();
            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; //把实例放入到mServices数组中
            } catch (ClassNotFoundException
                    | NoSuchMethodException
                    | IllegalAccessException
                    | InstantiationException
                    | InvocationTargetException ex) {
                throw new RuntimeException(ex);
            }

            if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
            mServices[i].start(); //执行start方法
            log.traceEnd();

            // Warn if initialization of component takes too long
            ti = System.currentTimeMillis() - ti;
            if (ti > 1000) {
                Log.w(TAG, "Initialization of " + clsName + " took " + ti + " ms");
            }
            if (mBootCompleteCache.isBootComplete()) {
                mServices[i].onBootCompleted();
            }

            dumpManager.registerDumpable(mServices[i].getClass().getName(), mServices[i]);
        }
        mRootComponent.getInitController().executePostInitTasks();
        log.traceEnd();

        mServicesStarted = true;
    }

SystemUI的启动就是这样。剩下的就是启动具体组件了,例如com.android.systemui.statusbar.phone.StatusBar。

StatusBar也就是状态栏,想看状态栏怎么启动的可以跟到它的start方法,这篇就先到这里。

 

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1634033.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于H.264的RTP打包中的组合封包以及分片封包结构图简介及抓包分析

H.264视频流的RTP封装类型分析&#xff1a; 前言&#xff1a; NULL Hearder简介(结构如下)&#xff1a; ---------------|0|1|2|3|4|5|6|7|--------|F|NRI| Type |--------------- F&#xff1a;forbidden_zero_bit&#xff0c; 占1位&#xff0c;在 H.264 规范中规定了这…

RustGUI学习(iced)之小部件(四):如何使用单选框radio部件?

前言 本专栏是学习Rust的GUI库iced的合集&#xff0c;将介绍iced涉及的各个小部件分别介绍&#xff0c;最后会汇总为一个总的程序。 iced是RustGUI中比较强大的一个&#xff0c;目前处于发展中&#xff08;即版本可能会改变&#xff09;&#xff0c;本专栏基于版本0.12.1. 概述…

【酱浦菌-爬虫技术细节】解决学术堂爬虫翻页(下一页)问题

首先我们通过css选择器获取页码信息&#xff0c;这里的css选择器&#xff0c;选择的是含有a标签的所有li标签&#xff0c;代码如下&#xff1a; li html_web.css(div.pd_c_xslb_left_fenye ul li>a) for li in li:li_url li.css(a::attr(href)).get()li_num li.css(a::t…

基于FPGA的数字信号处理(6)--如何确定Verilog表达式的符号

前言 尽管signed语法的使用能带来很多便利&#xff0c;但同时也给表达式的符号确定带来了更多的不确定性。比如一个有符号数和一个无符号数的加法/乘法结果是有符号数还是无符号数&#xff1f;一个有符号数和一个无符号数的比较结果是有符号数还是无符号数&#xff1f;等等。接…

IOT病毒分析

前言&#xff1a; 最近审计报警日志&#xff0c;发现了一个IOT病毒&#xff0c;利用的是CVE-2023-1389漏洞扫描tplink&#xff0c;进行攻击&#xff0c;有点意思&#xff0c;拿出来分析下。 发现&#xff1a; 查看流量日志&#xff0c;发现了一个有问题的访问&#xff1a; 访…

【架构】后端项目如何分层及分层领域模型简化

文章目录 一. 如何分层1. 阿里规范2. 具体案例分析 二. 分层领域模型的转换1. 阿里规范2. 模型种类简化分析 三. 小结 本文描述后端项目中如何进行分层&#xff0c;以及分层领域模型简化 一. 如何分层 1. 阿里规范 阿里的编码规范中约束分层逻辑如下: 开放接口层&#xff1a…

CSS实现各种优惠券效果

一、左半圆效果 <style style"text/css">.coupon {width: 240px;height: 100px;margin-top: 15px;background-color: #ff6347;-webkit-mask: radial-gradient(circle at left center, transparent 20px, red 20px); } </style><div class"coupon…

摩根大通推出创新工具 FlowMind,引领金融自动化新变革

近日&#xff0c;摩根大通人工智能研究部推出了一款极具创新性的工具——FlowMind&#xff0c;为金融行业带来了全新的工作模式和效率提升。 FlowMind 能够自动化金融工作流程&#xff0c;在信贷审批、风险评估、合规监测等重要任务中发挥着关键作用。它利用 GPT 自动生成工作…

张鸣独到政治观,规矩与自信新解

张鸣独解规矩与自信&#xff0c;社政新影响揭秘。张鸣独到政治观&#xff0c;规矩与自信新解在当今社会政治的大背景下&#xff0c;学者张鸣的每一次公开演讲无疑都是一次思想的盛宴。最近&#xff0c;他就当前的社会政治问题提出了自己独特的观点&#xff0c;特别是他对规矩和…

【网络原理】UDP协议 | UDP报文格式 | 校验和 | UDP的特点 | 应用层的自定义格式

文章目录 一、UDP协议1.UDP的传输流程发送方接收方 2.UDP协议报文格式&#xff1a;长度受限校验和如何校验&#xff1a;CRC算法&#xff1a;循环冗余算法md5算法&#xff1a; 2.UDP的特点 二、开发中常见的自定义格式1.xml&#xff08;古老&#xff09;2.json&#xff08;最流行…

头歌:Spark任务提交

第1关&#xff1a;spark-submit提交 任务描述 相关知识 spark-submit参数 计算圆周率 编程要求 测试说明 任务描述 本关任务&#xff1a;学会将程序提交到集群上执行。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a;1.了解spark-submit的参数。2.学会提交Spar…

双目深度估计原理立体视觉

双目深度估计原理&立体视觉 0. 写在前面1. 双目估计的大致步骤2. 理想双目系统的深度估计公式推导3. 双目标定公式推导4. 极线校正理论推导 0. 写在前面 双目深度估计是通过两个相机的对同一个点的视差来得到给该点的深度。 标准系统的双目深度估计的公式推导需要满足:1)两…

按键的软件消抖

1.当出现物理情况比如单片机不小心摔了会发生灯亮的情况&#xff0c;所以我们得增加个延迟函数 2.这个错误是缺少头文件#include <intrins.h> 3. #include "reg52.h" #include <intrins.h>sbit key2 P2^0; sbit key1 P2^1; sbit ledone P3^7;voi…

稳扎稳打 部署丝滑 开源即时通讯(IM)项目OpenIM源码部署流程(linux windows mac)

背景 OpenIM包含多个关键组件&#xff0c;每个都是系统功能必不可少的一部分。具体来说&#xff0c;MongoDB 用于持久化存储&#xff1b;Redis 用作缓存&#xff1b;Kafka 用于消息队列&#xff1b;Zookeeper 用于服务发现&#xff1b;Minio 用于对象存储。这些组件的众多可能会…

用OpenCV先去除边框线,以提升OCR准确率

在OpenCV的魔力下&#xff0c;我们如魔法师般巧妙地抹去表格的边框线&#xff0c;让文字如诗如画地跃然纸上。 首先&#xff0c;我们挥动魔杖&#xff0c;将五彩斑斓的图像转化为单一的灰度世界&#xff0c;如同将一幅绚丽的油画化为水墨画&#xff0c;通过cv2.cvtColor()函数的…

【多级缓存】多级缓存OpenResty,Canal,nginx本地缓存

多级缓存 安装OpenRestyOpenResty入门OpenResty获取请求参数OpenResty向tomcat服务器发送请求 在nginx与tomcat端之间添加redis缓存Redis本地缓存缓存同步缓存同步策略基于Canal的异步通知安装Canal Canal客户端 安装OpenResty OpenResty是一个基于 Nginx的高性能 Web 平台&am…

[iOS]使用CocoaPods发布私有库

1.创建私有 Spec 仓库 首先&#xff0c;需要一个私有的 Git 仓库来存放你的 Podspec 文件&#xff0c;这个仓库用于索引你所有的私有 Pods。 在 GitHub 或其他 Git 服务上创建一个新的私有仓库&#xff0c;例如&#xff0c;名为 PrivatePodSpecs。克隆这个仓库到本地&#xf…

使用STM32CubeMX对STM32F4进行串口配置

目录 1. 配置1.1 Pin脚1.2 RCC开启外部晶振1.3 时钟1.4 串口配置 2. 代码2.1 默认生成代码2.1 开启串口中断函数2.3 接收中断2.4 接收回调函数2.5 增加Printf 的使用 1. 配置 1.1 Pin脚 1.2 RCC开启外部晶振 1.3 时钟 外部使用8MHz晶振 开启内部16MHz晶振 使用锁相环 开启最高…

机器学习:深入解析SVM的核心概念(问题与解答篇)【四、软间隔与正则化】

软间隔与正则化 问题一&#xff1a;优化目标函数是如何得到的&#xff1f;得到的过程是怎样的&#xff1f;问题二&#xff1a;拉格朗日乘子法计算详细过程问题三&#xff1a;KKT条件求解过程问题四&#xff1a;结构风险最小化&#xff08;SRM&#xff09;的原理 在前面的讨论中…

针孔相机模型原理坐标系辨析内参标定流程内参变换

针孔相机的内参标定 针孔相机原理真空相机模型图片的伸缩和裁剪变换 内参标定———非线性优化张正定标定详细原理(含公式推导)通过多张棋盘格照片完成相机的内参标定流程(C代码)其他工具箱 相机分为短焦镜头和长焦镜头&#xff0c;短焦镜头看到的视野更广阔&#xff0c;同样距…