SystemUI模块总结

2023-10-27

SystemUI模块总结

1,SystemUI路径

SystemUI被放在

framework/base/packages/apps/SystemUI

在该目录的二级目录src/com/android下可看到SystemUI和Keyguard两个目录

SystemUI
Keyguard

由此可见如今将锁屏界面也整合在SystemUI中

2,SystemUI所需权限

从清单文件中可以发现 SystemUI需要建立以下开通权限用以监听开机广播,读写内存和访问所有用户存储状态,监听物理硬件,控制AM,WM,屏保,
锁屏,recent事件,wifi的展示,截屏,快捷设置入口等

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Used to read storage for all users -->
<uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

<uses-permission android:name="android.permission.INJECT_EVENTS" />
<uses-permission android:name="android.permission.DUMP" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />

<uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
<uses-permission android:name="android.permission.STATUS_BAR" />
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
<uses-permission android:name="android.permission.REMOTE_AUDIO_PLAYBACK" />

<uses-permission android:name="android.permission.MANAGE_USERS" />
<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />


。。。。。。


<uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS" />

3,SystemUI启动流程

SystemUI启动分为两部分
1)Service部分

代码路径:

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

开机后系统会首先启动SystemServer,SystemServer启动后才会带动其他一系列系统服务的启动,也包括SystemUI的启动

    public static void main(String[] args) {
    new SystemServer().run();
}

在SystemUI的main方法中启用了 SystemServer().run();run方法中主要做了以下操作

traceBeginAndSlog("StartServices");
        startBootstrapServices();
        startCoreServices();
        startOtherServices();

而在run()方法中做了startBootstrapServices(),startCoreServices(),startOtherServices()三个操作
而在startOtherServices()中做了startSystemUi(context, windowManagerF)的方法

	traceBeginAndSlog("StartSystemUI");
    	try {
            startSystemUi(context, windowManagerF);
        } catch (Throwable e) {
            reportWtf("starting System UI", e);
        }
        traceEnd();

startSystemUi具体实现如下,用Intent启动了SystemUIService

    static final void startSystemUi(Context context, WindowManagerService windowManager) {
    Intent intent = new Intent();
    intent.setComponent(new ComponentName("com.android.systemui",
                "com.android.systemui.SystemUIService"));
    intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
    //Slog.d(TAG, "Starting service: " + intent);
    context.startServiceAsUser(intent, UserHandle.SYSTEM);
    windowManager.onSystemUiStarted();
	}
2)SystemUI部分

接下来就走到了SystemUIService中,我们看一下SystemUIService中的onCreat方法

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

可知在SystemUIService中启动了SystemUIApplication中的startServicesIfNeeded()方法

public void startServicesIfNeeded() {
    startServicesIfNeeded(SERVICES);
}

其中SERVICES是一组所有用户共用的SystemUI服务,如下

    private final Class<?>[] SERVICES = new Class[] {

        Dependency.class,         //SystemUI的依赖项

        NotificationChannels.class,  //展示系统或应用通知内容

        CommandQueue.CommandQueueStart.class,   //StatusBar的扩展类

        KeyguardViewMediator.class,  //协调与keyguard相关的请求

        Recents.class, //近期应用管理

        VolumeUI.class,  //来用展示或控制音量的变化:媒体音量、铃声音量与闹钟音量

        Divider.class,  //控制堆栈的服务

        SystemBars.class,  //通知栏

        StorageNotification.class,  //存储设备管理

        PowerUI.class,   //主要处理和Power相关的事件,比如省电模式切换、电池电量变化和开关屏事件等

        RingtonePlayer.class,   //铃声播放

        KeyboardUI.class,   //键盘界面

        PipUI.class,   //画中画

        ShortcutKeyDispatcher.class,  //系统组件快捷方式

        VendorServices.class,  //厂商定制的服务

        GarbageMonitor.Service.class, //垃圾监视服务

        LatencyTester.class,  //debug测试

        GlobalActionsComponent.class,  //全局控制

        RoundedCorners.class,  //圆角切割
};

下面看看在SystemUIApplication是如何启动这一系列服务的

   private void startServicesIfNeeded(Class<?>[] services) {
    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 for user " +
            Process.myUserHandle().getIdentifier() + ".");
    TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
            Trace.TRACE_TAG_APP);



    log.traceBegin("StartServices");

    final int N = services.length;       //获取启动服务列表的长度

    for (int i = 0; i < N; i++) {
        Class<?> cl = services[i];
        if (DEBUG) Log.d(TAG, "loading: " + cl);
        log.traceBegin("StartServices" + cl.getSimpleName());
        long ti = System.currentTimeMillis();
        try {
				/*通过SystemUI创建相应的单例*/
            Object newService = SystemUIFactory.getInstance().createInstance(cl);
            mServices[i] = (SystemUI) ((newService == null) ? cl.newInstance() : newService);
        } 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();  //依次启动相应的服务
        log.traceEnd();

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

上面的代码的逻辑首先获取SERVICE数组中的class名,然后分别实例化他们,最后调用start接口统一启动,因此,每一个UI元素都必须继承自SystemUI这个抽象类,并且重载其中的start方法。

3,SystemUI主要模块

StatusBar:通知消息提示和状态展现

NavigationBar:返回,HOME,Recent

KeyGuard:锁屏模块可以看做单独的应用,提供基本的手机个人隐私保护

Recents:近期应用管理,以堆叠栈的形式展现。

Notification Panel:展示系统或应用通知内容。提供快速系统设置开关。

VolumeUI:来用展示或控制音量的变化:媒体音量、铃声音量与闹钟音量

截屏界面:长按电源键+音量下键后截屏,用以展示截取的屏幕照片/内容

PowerUI:主要处理和Power相关的事件,比如省电模式切换、电池电量变化和开关屏事件等。

RingtonePlayer:铃声播放

StackDivider:控制管理分屏

PipUI:提供对于画中画模式的管理

SystemBar的启动过程

由上文可知SystemBar存在于SystemUIApplication的services集合中,因此在mServices[i].start()时,SystemBars也同时被启动了
下面看一下SystemBar服务,SystemBar继承SystemUI抽象类

public class SystemBars extends SystemUI {
private static final String TAG = "SystemBars";
private static final boolean DEBUG = false;
private static final int WAIT_FOR_BARS_TO_DIE = 500;

// in-process fallback implementation, per the product config
private SystemUI mStatusBar;

@Override
public void start() {
    if (DEBUG) Log.d(TAG, "start");
    createStatusBarFromConfig();
}

由此可见在SystemUI的start方法中只执行了一个createStatusBarFromConfig()创建了staturbar,SystemBar只是作了一个中间过程
再来看一下createStatusBarFromConfig()方法

private void createStatusBarFromConfig() {
    if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");
    final String clsName = mContext.getString(R.string.config_statusBarComponent);
    if (clsName == null || clsName.length() == 0) {
        throw andLog("No status bar component configured", null);
    }
    Class<?> cls = null;
    try {
        cls = mContext.getClassLoader().loadClass(clsName);
    } catch (Throwable t) {
        throw andLog("Error loading status bar component: " + clsName, t);
    }
    try {
        mStatusBar = (SystemUI) cls.newInstance();
    } catch (Throwable t) {
        throw andLog("Error creating status bar component: " + clsName, t);
    }
    mStatusBar.mContext = mContext;
    mStatusBar.mComponents = mComponents;
    mStatusBar.start();
    if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName());
}

同样也是调用了statusbar中的start方法,再来看一下statusbar中的start方法

@Override
public void start() {   
...
//这里面进行了StatusBar中各个组件的初始化
mBarService = IStatusBarService.Stub.asInterface(
        ServiceManager.getService(Context.STATUS_BAR_SERVICE));
...
try {
    /* 经过一系列对象的创建与初始化后,开始向StatusBarService进行注册。这里涉及跨进程操作,
              因而传递的参数都是继承自Parcelable的 */
    mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,
            fullscreenStackBounds, dockedStackBounds);
} ...

createAndAddWindows();  //这里才是真正将Status Bar显示出来的地方

StarusBarService通过Context.STATUS_BAR_SERVICE启动,这个服务在SystemServer中注册,先看一下SystemServer中的代码

if (!disableSystemUI) {
   traceBeginAndSlog("StartStatusBarManagerService");
   try {
       statusBar = new StatusBarManagerService(context, wm);
       ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
   } catch (Throwable e) {
       reportWtf("starting StatusBarManagerService", e);  //原来StatusBarManagerService这个家伙注册的
   }
   traceEnd();
}

接下来进一步分析StatusBarManagerService的实现,首先看下其中的registerStatusBar中的代码:

StatusBarManagerService代码路径:

framework/base/services/core/java/com/android/server/statusbar/StatusBarManagerService.java

不在之前的SystemUI的路径中

 @Override
public void registerStatusBar(IStatusBar bar, List<String> iconSlots,
        List<StatusBarIcon> iconList, int switches[], List<IBinder> binders,
        Rect fullscreenStackBounds, Rect dockedStackBounds) {
    enforceStatusBarService();

    Slog.i(TAG, "registerStatusBar bar=" + bar);
    mBar = bar;
    try {
        mBar.asBinder().linkToDeath(new DeathRecipient() {
            @Override
            public void binderDied() {
                mBar = null;
                notifyBarAttachChanged();
            }
        }, 0);
    } catch (RemoteException e) {
    }
    notifyBarAttachChanged();
    synchronized (mIcons) {        //复制icon列表
        for (String slot : mIcons.keySet()) {
            iconSlots.add(slot);
            iconList.add(mIcons.get(slot));
        }
    }
    synchronized (mLock) {
        switches[0] = gatherDisableActionsLocked(mCurrentUserId, 1);
        switches[1] = mSystemUiVisibility;
        switches[2] = mMenuVisible ? 1 : 0;
        switches[3] = mImeWindowVis;
        switches[4] = mImeBackDisposition;
        switches[5] = mShowImeSwitcher ? 1 : 0;
        switches[6] = gatherDisableActionsLocked(mCurrentUserId, 2);
        switches[7] = mFullscreenStackSysUiVisibility;
        switches[8] = mDockedStackSysUiVisibility;
        binders.add(mImeToken);
        fullscreenStackBounds.set(mFullscreenStackBounds);
        dockedStackBounds.set(mDockedStackBounds);
    }
}

从上面的代码看,registerStatusBar的作用主要是:一,为新启动的SystemUI应用赋予当前系统的真实值(比如有多少需要显示的图标);二,通过mBar记录istatusBar对象,它在SystemUI中对应的是CommandQueue。
下面是整理的流程图,大家可以参考一下

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SystemUI模块总结 的相关文章

  • android edittext中的字符映射

    我想让我的编辑文本就像我写字符 g 时一样 它是相关的映射自定义字符应该写成印地语中的 我认为应该有字符映射 但没有知识任何人都可以帮助我 怎么做 其他应用程序https play google com store apps details
  • Android短音的正确播放方法?

    我正在创建一个应用程序 屏幕上将有多个图像 这些图像将是按钮 点击时会播放短促的声音 我对此进行了研究 只能找到我当前用来播放声音的方法 这似乎根本没有响应 我希望声音能够快速播放并且能够响应多次快速点击 我不确定这在 Android 中是
  • Cheesesquare:enterAlways 会产生错误的布局

    Adding enterAlways到 Cheesesquare 演示的滚动标志
  • Xamarin Android Webview Javascript

    我正在尝试通过 Xamarin for Android 创建一个移动应用程序 它有一个显示网站的 WebView 问题是正常按钮会触发 但 javascript 事件不会触发 我已经启用了 Javascript 但没有运气 如何在 Andr
  • AdapterContextMenuInfo 始终为 null

    我尝试通过 android 开发文档中的书来做到这一点 this didn t create a menu i don t know why registerForContextMenu getListView setListAdapter
  • 如何正确释放Android MediaPlayer

    我正在尝试向我的 Android 应用程序添加一个按钮 当点击该按钮时它会播放 MP3 我已经让它工作了 但没有办法释放 mediaPlayer 对象 因此即使在我离开活动后它仍然会继续播放 如果我在react 方法之外初始化MediaPl
  • 将现有 VARCHAR 列与 Room 结合使用

    我正在尝试将现有的数据库与 Android Room 一起使用 但是 我的一个表有一个 VARCHAR 列 Room 似乎只支持 TEXT 不支持 VARCHAR 而且 sqlite 不允许修改列类型 那么 有没有办法使用Room中现有的带
  • 以编程方式将文本颜色设置为主要 Android 文本视图

    如何设置我的文本颜色TextView to android textColorPrimary以编程方式 我已经尝试了下面的代码 但它将 textColorPrimary 和 textColorPrimary Inverse 的文本颜色始终设
  • 在 Cordova 应用程序中获取额外功能

    我们有两个 Android 应用程序 一个使用本机 Java 实现 另一个使用 Ionic 编写 Ionic 应用程序启动我的应用程序 这是使用灯插件 https github com lampaa com lampa startapp 我
  • Android:后台Activity可以执行代码吗?

    后台的活动是否被视为 正在运行 并且可以执行代码 还是处于挂起状态 他们暂停了 活动生命周期 http developer android com reference android app Activity html ActivityLi
  • 使用片段时应用程序崩溃

    我正在处理碎片和 我的代码中有一个我找不到的问题 logcat 指向我的一个片段中的这段代码 Override public View onCreateView LayoutInflater inflater ViewGroup conta
  • 对于一个单元格,RecyclerView onBindViewHolder 调用次数过多

    我正在将 RecyclerView 与 GridLayoutManager 一起使用 对于网格中的每个项目 我需要调用 REST api 来检索数据 然后 从远程异步获取数据后 我使用 UIL 加载 显示图像 一切似乎都很好 但我发现 on
  • Mipmap 与可绘制文件夹[重复]

    这个问题在这里已经有答案了 我正在使用 Android Studio 1 1 Preview 1 我注意到 当我创建一个新项目时 我得到以下层次结构 不同 DPI 的 Mipmap 文件夹 不再有不同 DPI 的可绘制文件夹 我应该将所有资
  • Android 如何将总天数准确更改为年、月、日?

    我正在做一个应用程序 该应用程序与根据给定的生日日期输入获取一个人的年龄有关 为此 我从下面的代码中获取从该日期到当前日期的总天数 String strThatDay 1991 05 10 SimpleDateFormat formatte
  • 没有用于警告的设置器/字段 Firebase 数据库检索数据填充列表视图

    我只是想将 Firebase 数据库中的数据填充到我的列表视图中 日志显示正在检索数据 但适配器不会将值设置为列表中单个列表项中的文本 它只说 没有二传手 场地插入值 这让我觉得我的设置器没有正确制作 但 Android Studio 自动
  • 插件“Android Bundle Support”不兼容

    大家好 自从上次更新以来 当我启动 android studio 时 我遇到了一个非常奇怪的错误 我有这个错误 插件错误 插件 Android Bundle Support 不兼容 直到构建 AI 195 SNAPSHOT 我在网上找不到任
  • 问题:为什么React Native Video不能全屏播放视频?

    我正在react native 0 57 7 中为android和ios创建一个应用程序并使用反应本机视频 https github com react native community react native video播放上传到的视频
  • 通过电子邮件发送文本文件附件

    我正在尝试附加一个文本文件以便通过电子邮件发送 但每当我打开电子邮件应用程序时 它都会说该文件不存在 请帮助 Intent i new Intent Intent ACTION SEND i setType text plain i put
  • CamcorderProfile.videoCodec 返回错误值

    根据docs https developer android com reference android media CamcorderProfile html 您可以使用CamcorderProfile获取设备默认视频编解码格式 然后将其
  • 错误:(23, 13) 无法解决:com.google.android.gms:play-services:11.2.0“安装存储库和同步项目”不起作用

    我正在尝试在我的 Android 应用程序中获取位置并更新到服务器 这是我的 Gradle 代码 我在这里包含了compile com google android gms play services 11 2 0 这条线是从文档中 htt

随机推荐

  • DMRS在5G NR各种物理信道上的配置

    笔者在微信公众号GiveMe5G定期发布学习文章 更多更及时 欢迎订阅和分享 文章下方有二维码 本篇文章旨在介绍DMRS DeModulation Reference Signal 在5G中 DMRS广泛存在于各个重要的物理信道当中 如下行
  • MMdetection的Proposal原理和代码解析

    一 算法原理 接受N级score bbox pred anchor和image shape作为输入 通过anchor和框的偏移 bbox pred 得到proposal 然后对这些proposal做NMS 最后选出前num个 二 执行步骤
  • golang 组成树形格式

    该封装受到前端 js filter函数的启发看着特别简洁 一 封装一个函数 比较简单就是循环根据传入的 回调函数 进行过滤组成新的数组返回 func Filter T any arr T f func item T bool list T
  • 震动传感器介绍及实战(中断)

    项目要求 利用震动传感器实现点灯效果 当传感器察觉震动 led灯亮 否则不亮 接线及引脚 传感器信号引脚DO接PA4 led1灯的引脚接PB8 所以中断的信号源就是PA4引脚 配置STM32 PB8设置成output 输出给led 打开使能
  • 红黑树结构算法原理与代码解析

    红黑树 Red Black Tree 平衡二叉B树 是一种自平衡二叉查找树 是在计算机科学中用到的一种数据结构 典型的用途是实现关联数组 典型的普通顺序数组结构的增 删 查效率都是O n 但是红黑树进行读写操作时的效率可以稳定在O log
  • JAVA笔记

    目录 模板模式的理解 使用模板模式的例子 整合工厂模式 模板模式的理解 模板模式简单理解就是创建一个抽象父类作为模板 可以分两部分 一部分是定义了所有子类都需要执行的公共方法 这样就不用在每个子类中重复写相同代码 另一部分就是强制规定每个子
  • php面试题之四——PHP面向对象(基础部分)

    1 写出 php 的 public protected private 三种访问控制模式的区别 新浪网技术部 public 公有 任何地方都可以访问 protected 继承 只能在本类或子类中访问 在其它地方不允许访问 private 私
  • (Oracle技能篇) oracle数据库分页查询和各大数据库的分页查询

    1 oracle数据库分页 select from select a rownum rc from 表名 where rownum lt endrow a where a rc gt startrow 2 DB2数据库分页 Select f
  • 堆与栈的区别详细总结

    常见的数据结构 数组 栈 队列 链表 树 图 散列表 哈希表 堆与栈的区别 堆 队列优先 先进先出 FIFO firstinfirstout 栈 先进后出 FILO First In Last Out 一般情况下 如果有人把堆栈合起来说 那
  • js浏览器回到顶部方法_js 返回顶部按钮

    要求 当鼠标从顶部滚动后 显示返回顶部按钮 点击按钮 页面平滑滚动到顶部 按钮隐藏 1 css scrollTop position fixed bottom 20px right 20px height 0px width 45px li
  • [ Android实战 ] 开机时通过广播启动应用,但是很长时间才能接收到,如何解决?

    Android实战 开机时通过广播启动应用 但是很长时间才能接收到 如何解决 背景 测试 发送广播流程 广播分发流程 解决方案 思考 系统层面 应用层面 总结 转载请注明出处 我的博客 背景 前段时间在做一个项目 在适配客户应用的过程中发现
  • jmeter自动调试系统接口配置流程

    1 起因 最近测试的同事需要用jmeter工具压测一下我们项目的接口 因为接口中有token或者加密登录密码等逻辑 有的地方需要从上一步接口中拿到结果作为下一步的参数 进行传递 因为涉及的有点麻烦 就帮测试看了下这个工具 顺便记录一下 帮助
  • Markdown 实现页内跳转

    Markdown 实现页内跳转 在使用 Markdown 做一些论文笔记或者说写文档时 通常会出现这样一种情况 我们在文档的某个地方定义了一个 t a b l e o
  • 数据库的多表查询操作-查询只选修了1门课程的学生,显示学号、姓名、课程名。

    文章目录 前言 一 建立数据库和表 二 数据库展示 2 查询只选修了1门课程的学生 显示学号 姓名 课程名 总结 前言 在我看来数据库真的是一个神奇的东西 不但里面的只是点很深刻 而且对于我们学习起来还是有一定的压力的 关于数据的知识 我感
  • 【CSAPP】背景知识-调用者保存寄存器与被调用者保存寄存器

    1 调用者保存与被调用者保存 函数A调用了函数B 寄存器rbx在函数B中被修改了 逻辑上 rbx内容在调用函数B的前后应该保持一致 解决这个问题有两个策略 1 在函数A在调用函数B之前提前保存寄存器 rbx的内容 执行完函数B之后再恢复 r
  • 顶会常见的 python matplotlib 双Y轴柱状图

    效果图 代码如下 import matplotlib pyplot as plt import numpy as np plt rc font family Times New Roman x data 1 2 3 ax data 16 2
  • flex布局flex取值以及align-self、align-content、align-items的区别

    flex取值 flex是 flex grow flex shrink flex basis 的缩写 flex取值 flex grow flex shrink flex basis 默认值 0 1 auto none 0 0 auto aut
  • libevent库学习(1)

    一 初识 1 libevent介绍 Libevent 是一个用C语言编写的 轻量级的开源高性能事件通知库 主要有以下几个亮点 事件驱动 event driven 高性能 轻量级 专注于网络 不如 ACE 那么臃肿庞大 源代码相当精炼 易读
  • 计算机efs加密,EFS加密

    EFS Encrypting File System 加密文件系统 是Windows 2000 XP所特有的一个实用功能 对于NTFS卷上的文件和数据 都可以直接被操作系统加密保存 在很大程度上提高了数据的安全性 EFS加密简介 语音 EF
  • SystemUI模块总结

    SystemUI模块总结 1 SystemUI路径 SystemUI被放在 framework base packages apps SystemUI 在该目录的二级目录src com android下可看到SystemUI和Keyguar