[Android14] SystemUI的启动

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方法,这篇就先到这里。

 

 

 

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Babylon.js和Three.js的区别

Babylon.js和Three.js都是基于WebGL的3D图形库&#xff0c;它们使得开发者能够在网页上创建和展示3D内容。尽管它们的目标相似&#xff0c;但在设计理念、功能集、性能和社区支持等方面存在一些差异。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢…

SpringCloud引入SpringBoot Admin

Spring Boot Admin可以监控和管理Spring Boot&#xff0c;能够将 Actuator 中的信息进行界面化的展示&#xff0c;也可以监控所有 Spring Boot 应用的健康状况&#xff0c;提供警报功能。 1. 创建SpringBoot工程 2. 引入相关依赖 <dependency><groupId>com.alib…

MinIO分布式文件系统介绍

1、不同存储方式的对比&#xff1a; 2、 分布式文件系统对比 3、MinIO的特点 MinIO特点 数据保护&#xff1a;Minio使用Minio Erasure Code&#xff08;纠删码&#xff09;来防止硬件故障。即便损坏一半以上的driver&#xff0c;但是仍然可以从中恢复。 高性能&#xff1a;作…

PID算法学习

PID算法介绍 在过程控制中&#xff0c;按偏差的比例&#xff08;P&#xff09;、积分&#xff08;I&#xff09;和微分&#xff08;D&#xff09;进行控制的PID控制器&#xff08;亦称PID调节器&#xff09;是应用最为广泛的一种自动控制器。它具有原理简单&#xff0c;易于实…

冯唐成事心法笔记 —— 知世

系列文章目录 冯唐成事心法笔记 —— 知己 冯唐成事心法笔记 —— 知人 冯唐成事心法笔记 —— 知世 冯唐成事心法笔记 —— 知智慧 文章目录 系列文章目录PART 3 知世 成事者的自我修养怎样做一个讨人喜欢的人第一&#xff0c;诚心第二&#xff0c;虚心 如何正确看待别人的评…

MQTTX工具获取及使用

工具获取地址&#xff1a;百度网盘 请输入提取码 新建连接 订阅主题

Redis分布式锁手动实现

Redis分布式锁手动实现 java中锁机制 在 Java 中&#xff0c;锁是用来同步并发访问共享资源的机制。它确保了在一个时间点&#xff0c;只有一个线程可以执行某个代码块或方法&#xff0c;从而防止了数据的不一致和竞态条件。Java 提供了多种锁机制&#xff0c;包括内置锁&…

全国各地级市财政收入支出明细统计数据2003-2022年

01、数据简介 全国各地级市财政统计主要是按地级市财政支出和财政收入两项统计&#xff0c;反映地区财政资金形成、分配以及使用情况的统计&#xff0c;​是由地区各地级市统计局统计公布&#xff0c;是加强财政资金管理使用的依据&#xff0c;研究国民收入分配和再分配的重要…

山东省2024年首版次测试报告具体的要求是什么?

山东省首版次测试报告的具体要求可能会根据每年的政策调整、行业变化以及申报的具体产品而有所不同。但一般而言&#xff0c;山东省首版次测试报告需要满足以下一些基本要求和标准&#xff1a; 1.完整性&#xff1a;测试报告应涵盖所有关键的测试环节&#xff0c;包括但不限于测…

张小泉签约实在智能,用实在Agent打造自动化高

在不少老杭州人的童年记忆里&#xff0c;妈妈裁剪衣服、料理食材、修剪各种物品&#xff0c;用的都是张小泉刀剪。 近日&#xff0c;实在智能与“刀剪第一股”张小泉&#xff08;股票代码&#xff1a;301055.SZ&#xff09;正式达成合作&#xff0c;实在Agent数字员工助力张小…

AM解调 FPGA(寻找复刻电赛电赛D题的)

设计平台 Quartus II10.3mif产生工具modelsimSE &#xff08;仿真用&#xff09; DDS&#xff08;直接数字式频率合成器&#xff09; 从前面的内容可知&#xff0c;我们需要产生一个载波&#xff0c;并且在仿真时&#xff0c;我们还需要一个较低频率的正弦波信号来充当我们的…

划重点:用这个技巧,抖音粉丝涨不停!

在这个信息爆炸的时代&#xff0c;如何在抖音上脱颖而出&#xff0c;吸引大量粉丝&#xff0c;成为了每一个创作者心中的痛。你是否曾经在发布作品后焦急等待评论&#xff0c;期待着每一次互动&#xff1f;如果你有这样的困扰&#xff0c;那么这篇文章将为你打开一扇新的大门&a…

【Claude 3 Opus】Claude 3 Opus 模型正式上线抢先体验

文章目录 1. Claude 3 Opus介绍2. Claude 3 Opus 支持的应用场景3. 申请Claude 3 Opus访问4. Claude 3 Opus初体验5. 『云上探索实验室』Bedrock 体验又更新啦6. 参考链接 1. Claude 3 Opus介绍 近期&#xff0c;亚马逊云宣布 Anthropic 的 Claude 3 Opus 模型已在 Amazon Bed…

大数据分析与应用实验(黑龙江大学)

实验一 Hadoop伪分布式实验环境搭建与WordCount程序 一、实验目的 1、学习搭建Hadoop伪分布式实验环境 2、在伪分布式实验环境下运行WordCount程序 二、实验内容 1、搭建Hadoop伪分布式实验环境&#xff0c;并安装Eclipse。 2、在Eclipse环境下&#xff0c;编写并执行Wor…

【JVM】从i++到JVM栈帧

【JVM】从i到JVM栈帧 本篇博客将用两个代码例子&#xff0c;简单认识一下JVM与栈帧结构以及其作用 从i与i说起 先不急着看i和i&#xff0c;我们来看看JVM虚拟机&#xff08;请看VCR.JPG&#xff09; 我们初学JAVA的时候一定都听到过JAVA“跨平台”的特性&#xff0c;也就是…

西瓜书学习——线性判别分析

文章目录 定义LDA的具体步骤1. 计算类内散布矩阵&#xff08;Within-Class Scatter Matrix&#xff09;2. 计算类间散布矩阵&#xff08;Between-Class Scatter Matrix&#xff09;3. 求解最佳投影向量4. 数据投影5. 分类 定义 线性判别分析&#xff08;Linear Discriminant A…

安装svn网络有问题怎么办?

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

【C++进阶之路】C++11(下) —— 线程库

序言 本篇文章主要是填之前C11留下的坑以及了解与熟悉线程库&#xff0c;有读者感兴趣之前的内容的话可见「C进阶之路」专栏中标题为「C11」的内容&#xff0c;废话不多说&#xff0c;先来概括一下本文的内容&#xff0c;首先我们会从历史的角度分别谈及Linux以及Windows下的线…

JetBrains GoLand v2024.1 激活版 (Go语言集成开发IDE)

前言 JetBrains GoLand是一款专门为Go语言开发人员构建的跨平台的集成开发环境。动态错误检测和修复建议、快速安全重构、智能代码完成、无效代码检测和文档提示可以帮助新手和有经验的Go开发人员高效地创建可靠的代码。GoLand还支持JavaScript&#xff0c;TypeScript&#xf…

AIX7环境上一次艰难的Oracle打补丁经历

系统环境 AIX &#xff1a;7200-05-03-2148 Oracle&#xff1a;11.2.0.4 PSU: 11.2.0.4.201020&#xff08;31718723&#xff09; perl:5.28 问题一&#xff1a;AUTO patch #/u01/app/11.2.0/grid/OPatch/opatch auto /tmp/31718723 错误信息如下&#xff1a;匹配mos 2516761.1…