一起看看StatusBarManagerService(一)

news2024/11/20 4:25:32

写在前面

工作需要涉及到这部分代码,但是我对此了解很少;边学边总结,把这部分逻辑和涉及到的知识点弄明白。该系列不确定几篇,随缘。
本篇主要介绍StatusBarManagerService与systemui之间的关联。


了解StatusBarManagerService

1. StatusBarManagerService是干什么用的?

Android系统中,三方app/系统应用/底层模块,想要与systemui交互,绝大多数要通过StatusBarManagerService去进行。这个服务名称为状态栏服务,但通过这个服务可以管理systemui的大部分组件,如状态栏、导航栏、最近任务、通控中心等。
因为在systemui源码中,谷歌在这一部分没有进行拆分,调用代码都放在StatusBar.java中去中转,导致StatusBar这个类非常臃肿。从Android U开始,谷歌对systemui状态栏部分进行MVVM改造,StatusBar更名为CentralSurfaces进行了接口化拆分,在此不多赘述感兴趣可以看下源码。

2. StatusBarManagerService是怎么生效的?
(1) StatusBarManagerService的创建

同其他ManagerService一样,StatusBarManagerService服务也是在SystemServer中被创建

private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
    ...
    StatusBarManagerService statusBar = null;
    ...
    t.traceBegin("StartStatusBarManagerService");
    try {
       statusBar = new StatusBarManagerService(context);
     if (!isWatch) {
          statusBar.publishGlobalActionsProvider();
     }
     ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar, false,
            DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);
    } catch (Throwable e) {
       reportWtf("starting StatusBarManagerService", e);
    }
    t.traceEnd();
    ...
}

StatusBarManagerService构造函数

StatusBarManagerService继承自IStatusBarService.Stub,IStatusBarService.aidl文件中声明的方法(截了一部分):

IStatusBarService

前面的方法为调用SBM常用方法,其中disable方法可以通过设置不同的flag来实现不同操作,详见:
StatusBarManager中的相关标志位

(2) StatusBarManagerService与systemui关联

systemui中有一个类,CommandQueue.java,继承IStatusBar.Stub;IStatusBar中声明的方法与前面IStatusBarService调到systemui的一致。

IStatusBar

systemui中各个模块想要接收SBM的回调都通过CommandQueue,向其注册Callback;callbak中方法声明和IStatusBar一致,只不过方法都是default空,可以根据需要选择实现。

CommandQueue.Callback

systemui在CentralSurfaces中将commandqueue注册给了StatusBarManagerService:

protected IStatusBarService mBarService;
...
@Override
public void start() {
    ...
    mBarService = IStatusBarService.Stub.asInterface(ServiceManager.getService(Context.STATUS_BAR_SERVICE));
    ...
    RegisterStatusBarResult result = null;
    try {
        result = mBarService.registerStatusBar(mCommandQueue);
    } catch (RemoteException ex) {
        ex.rethrowFromSystemServer();
    }
    ...    
}

registerStatusBar

通过registerStatusBar方法,SBMService中mBar保存了IStatusBar,即CommandQueue。


StatusBarShellCommand和CommandRegistry

我们知道可以通过adb去dump systemui的状态,例如:

adb shell dumpsys statusbar
adb shell dumpsys activity service SystemUIService

因为systemui中很多类都实现了dumpable,在dump中将关键信息打印出,以用作debug。
通过SBMService对systemui的调用需要自己编写测试app才能实现,这样操作很麻烦,能否通过adb去测试一些内容呢?

CommandQueue构造函数

CommandQueue有一个成员变量CommandRegistry:

CommandRegistry构造

CommandRegistry的registerCommand方法可以让systemui中的控件注册adb cmd命令来执行:

        commandRegistry.registerCommand("tile-service-add") { TileServiceRequestCommand() }
        commandQueue.addCallback(commandQueueCallback)
    
    
        inner class TileServiceRequestCommand : Command {
        override fun execute(pw: PrintWriter, args: List<String>) {
            val componentName: ComponentName = ComponentName.unflattenFromString(args[0])
                    ?: run {
                        Log.w(TAG, "Malformed componentName ${args[0]}")
                        return
                    }
            requestTileAdd(componentName, args[1], args[2], null) {
                Log.d(TAG, "Response: $it")
            }
        }

        override fun help(pw: PrintWriter) {
            pw.println("Usage: adb shell cmd statusbar tile-service-add " +
                    "<componentName> <appName> <label>")
        }
    }

而原生StatusBarShellCommand中预制了很多命令,以该类Android U上的完整代码来结束这篇文章吧:

/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

package com.android.server.statusbar;

import static android.app.StatusBarManager.DEFAULT_SETUP_DISABLE2_FLAGS;
import static android.app.StatusBarManager.DEFAULT_SETUP_DISABLE_FLAGS;
import static android.app.StatusBarManager.DISABLE2_NONE;
import static android.app.StatusBarManager.DISABLE_NONE;

import android.app.StatusBarManager.DisableInfo;
import android.content.ComponentName;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ShellCommand;
import android.service.quicksettings.TileService;
import android.util.Pair;

import java.io.PrintWriter;

public class StatusBarShellCommand extends ShellCommand {

    private static final IBinder sToken = new StatusBarShellCommandToken();

    private final StatusBarManagerService mInterface;
    private final Context mContext;

    public StatusBarShellCommand(StatusBarManagerService service, Context context) {
        mInterface = service;
        mContext = context;
    }

    @Override
    public int onCommand(String cmd) {
        if (cmd == null) {
            onHelp();
            return 1;
        }
        try {
            switch (cmd) {
                case "expand-notifications":
                    return runExpandNotifications();
                case "expand-settings":
                    return runExpandSettings();
                case "collapse":
                    return runCollapse();
                case "add-tile":
                    return runAddTile();
                case "remove-tile":
                    return runRemoveTile();
                case "click-tile":
                    return runClickTile();
                case "check-support":
                    final PrintWriter pw = getOutPrintWriter();
                    pw.println(String.valueOf(TileService.isQuickSettingsSupported()));
                    return 0;
                case "get-status-icons":
                    return runGetStatusIcons();
                case "disable-for-setup":
                    return runDisableForSetup();
                case "send-disable-flag":
                    return runSendDisableFlag();
                case "tracing":
                    return runTracing();
                case "run-gc":
                    return runGc();
                // Handle everything that would be handled in `handleDefaultCommand()` explicitly,
                // so the default can be to pass all args to StatusBar
                case "-h":
                case "help":
                    onHelp();
                    return 0;
                case "dump":
                    return super.handleDefaultCommands(cmd);
                default:
                    return runPassArgsToStatusBar();
            }
        } catch (RemoteException e) {
            final PrintWriter pw = getOutPrintWriter();
            pw.println("Remote exception: " + e);
        }
        return -1;
    }

    private int runAddTile() throws RemoteException {
        mInterface.addTile(ComponentName.unflattenFromString(getNextArgRequired()));
        return 0;
    }

    private int runRemoveTile() throws RemoteException {
        mInterface.remTile(ComponentName.unflattenFromString(getNextArgRequired()));
        return 0;
    }

    private int runClickTile() throws RemoteException {
        mInterface.clickTile(ComponentName.unflattenFromString(getNextArgRequired()));
        return 0;
    }

    private int runCollapse() throws RemoteException {
        mInterface.collapsePanels();
        return 0;
    }

    private int runExpandSettings() throws RemoteException {
        mInterface.expandSettingsPanel(null);
        return 0;
    }

    private int runExpandNotifications() throws RemoteException {
        mInterface.expandNotificationsPanel();
        return 0;
    }

    private int runGetStatusIcons() {
        final PrintWriter pw = getOutPrintWriter();
        for (String icon : mInterface.getStatusBarIcons()) {
            pw.println(icon);
        }
        return 0;
    }

    private int runDisableForSetup() {
        String arg = getNextArgRequired();
        String pkg = mContext.getPackageName();
        boolean disable = Boolean.parseBoolean(arg);

        if (disable) {
            mInterface.disable(DEFAULT_SETUP_DISABLE_FLAGS, sToken, pkg);
            mInterface.disable2(DEFAULT_SETUP_DISABLE2_FLAGS, sToken, pkg);
        } else {
            mInterface.disable(DISABLE_NONE, sToken, pkg);
            mInterface.disable2(DISABLE2_NONE, sToken, pkg);
        }

        return 0;
    }

    private int runSendDisableFlag() {
        String pkg = mContext.getPackageName();
        int disable1 = DISABLE_NONE;
        int disable2 = DISABLE2_NONE;

        DisableInfo info = new DisableInfo();

        String arg = getNextArg();
        while (arg != null) {
            switch (arg) {
                case "search":
                    info.setSearchDisabled(true);
                    break;
                case "home":
                    info.setNagivationHomeDisabled(true);
                    break;
                case "recents":
                    info.setRecentsDisabled(true);
                    break;
                case "notification-alerts":
                    info.setNotificationPeekingDisabled(true);
                    break;
                case "statusbar-expansion":
                    info.setStatusBarExpansionDisabled(true);
                    break;
                case "system-icons":
                    info.setSystemIconsDisabled(true);
                    break;
                case "clock":
                    info.setClockDisabled(true);
                    break;
                case "notification-icons":
                    info.setNotificationIconsDisabled(true);
                    break;
                default:
                    break;
            }

            arg = getNextArg();
        }

        Pair<Integer, Integer> flagPair = info.toFlags();

        mInterface.disable(flagPair.first, sToken, pkg);
        mInterface.disable2(flagPair.second, sToken, pkg);

        return 0;
    }

    private int runPassArgsToStatusBar() {
        mInterface.passThroughShellCommand(getAllArgs(), getOutFileDescriptor());
        return 0;
    }

    private int runTracing() {
        switch (getNextArg()) {
            case "start":
                mInterface.startTracing();
                break;
            case "stop":
                mInterface.stopTracing();
                break;
        }
        return 0;
    }

    private int runGc() {
        mInterface.runGcForTest();
        return 0;
    }

    @Override
    public void onHelp() {
        final PrintWriter pw = getOutPrintWriter();
        pw.println("Status bar commands:");
        pw.println("  help");
        pw.println("    Print this help text.");
        pw.println("");
        pw.println("  expand-notifications");
        pw.println("    Open the notifications panel.");
        pw.println("");
        pw.println("  expand-settings");
        pw.println("    Open the notifications panel and expand quick settings if present.");
        pw.println("");
        pw.println("  collapse");
        pw.println("    Collapse the notifications and settings panel.");
        pw.println("");
        pw.println("  add-tile COMPONENT");
        pw.println("    Add a TileService of the specified component");
        pw.println("");
        pw.println("  remove-tile COMPONENT");
        pw.println("    Remove a TileService of the specified component");
        pw.println("");
        pw.println("  click-tile COMPONENT");
        pw.println("    Click on a TileService of the specified component");
        pw.println("");
        pw.println("  check-support");
        pw.println("    Check if this device supports QS + APIs");
        pw.println("");
        pw.println("  get-status-icons");
        pw.println("    Print the list of status bar icons and the order they appear in");
        pw.println("");
        pw.println("  disable-for-setup DISABLE");
        pw.println("    If true, disable status bar components unsuitable for device setup");
        pw.println("");
        pw.println("  send-disable-flag FLAG...");
        pw.println("    Send zero or more disable flags (parsed individually) to StatusBarManager");
        pw.println("    Valid options:");
        pw.println("        <blank>             - equivalent to \"none\"");
        pw.println("        none                - re-enables all components");
        pw.println("        search              - disable search");
        pw.println("        home                - disable naviagation home");
        pw.println("        recents             - disable recents/overview");
        pw.println("        notification-peek   - disable notification peeking");
        pw.println("        statusbar-expansion - disable status bar expansion");
        pw.println("        system-icons        - disable system icons appearing in status bar");
        pw.println("        clock               - disable clock appearing in status bar");
        pw.println("        notification-icons  - disable notification icons from status bar");
        pw.println("");
        pw.println("  tracing (start | stop)");
        pw.println("    Start or stop SystemUI tracing");
        pw.println("");
        pw.println("  NOTE: any command not listed here will be passed through to IStatusBar");
        pw.println("");
        pw.println("  Commands implemented in SystemUI:");
        pw.flush();
        // Sending null args to systemui will print help
        mInterface.passThroughShellCommand(new String[] {}, getOutFileDescriptor());
    }

    /**
     * Token to send to StatusBarManagerService for disable* commands
     */
    private static final class StatusBarShellCommandToken extends Binder {
    }
}


写在后面

如果文章中有错误的地方,希望各位大佬们批评指正~

If you like this article, it is written by Johnny Deng.
If not, I don’t know who wrote it.

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

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

相关文章

[Android]_[初级]_[配置gradle的环境变量设置安装位置]

场景 在开发Android项目的时候, gradle是官方指定的构建工具。不同项目通过wrapper指定不同版本的gradle。随着项目越来越多&#xff0c;使用的gradle版本也增多&#xff0c;导致它以来的各种库也增加&#xff0c;系统盘空间不足&#xff0c;怎么解决&#xff1f; 说明 grad…

pyqt环境搭建

创建虚拟环境 # 用管理员身份运行 conda create --prefixE:\Python\envs\pyqt5stu python3.6 # 激活虚拟环境 conda activate E:\Python\envs\pyqt5stu # 退出虚拟环境 conda deactivate安装包 pip install PyQt5 -i https://pypi.douban.com/simple pip install PyQt5-tools…

asp.net学生宿舍管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio

一、源码特点 asp.net 学生宿舍管理系统是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为vs2010&#xff0c;数据库为sqlserver2008&#xff0c;使用c#语言 开发 asp.net学生宿舍管理系统1 应用技…

CV计算机视觉每日开源代码Paper with code速览-2023.11.8

精华置顶 墙裂推荐&#xff01;小白如何1个月系统学习CV核心知识&#xff1a;链接 点击CV计算机视觉&#xff0c;关注更多CV干货 论文已打包&#xff0c;点击进入—>下载界面 点击加入—>CV计算机视觉交流群 1.【基础网络架构】&#xff08;WACV2024&#xff09;SBCFo…

Spring Cloud学习(四)【Nacos配置管理】

文章目录 统一配置管理微服务配置拉取配置热更新多环境配置共享Nacos 集群搭建Nacos集群搭建1.集群结构图2.搭建集群2.1.初始化数据库2.2.下载nacos2.3.配置Nacos2.4.启动2.5.nginx反向代理2.6.优化 统一配置管理 Nacos 可以实现注册中心和配置管理服务 在Nacos中添加配置信息…

字符串的模式匹配(朴素模式匹配算法,KMP算法)

目录 1.朴素模式匹配算法1.定义2.算法实现3.代码实现 2.KMP算法1.优化思路2.next数组3.代码实现 3.求next数组4.KMP算法优化1.next数组的优化2.求nextval数组 1.朴素模式匹配算法 子串&#xff1a;主串的一部分&#xff0c;一定存在。 模式串&#xff1a;不一定能在主串中找到。…

【算法与数据结构】93、LeetCode复原 IP 地址

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;参照【算法与数据结构】131、LeetCode分割回文串的思路&#xff0c;需要将IP字符串进行分割&#xff0…

js 实现数字滚动效果,从 0 加到目标值,并且重复执行

js 实现数字滚动效果,从 0 加到目标值,并且重复执行 实现效果 js 方法 方法接收的参数 为目标值 const showNumberref(1999) const animateNumber (target: number) > {let current 0const increment (target - current) / (2000 / 16) // 计算每次递增的值&#xff0c…

华硕荣获“EPEAT Climate+ Champion”永续先驱称号

华硕持续深耕永续理念&#xff0c;努力提供低碳排放、高效能产品&#xff0c;并被全球电子委员会授予“EPEAT Climate Champion”称号。这一荣誉再次表明了华硕在永续管理方面的承诺&#xff0c;并凸显了华硕在追求永续发展上的决心。 华硕通过设立“科学基础减碳目标”、“再生…

lv11 嵌入式开发 ARM体系结构理论基础(异常、微架构)4

1 异常概念 处理器在正常执行程序的过程中可能会遇到一些不正常的事件发生 这时处理器就要将当前的程序暂停下来转而去处理这个异常的事件 异常事件处理完成之后再返回到被异常打断的点继续执行程序 2 异常处理机制 不同的处理器对异常的处理的流程大体相似&#xff0c…

一种ADC采样算法,中位值平均滤波+递推平均滤波

前言 在实际AD采集场景中&#xff0c;会出现周期性变化和偶然脉冲波动干扰对AD采集的影响 这里使用中位值平均滤波递推平均滤波的结合 参考前人写好的代码框架&#xff0c;也参考博主GuYH_下面这篇博客&#xff0c;在此基础上稍作修改&#xff0c;写出这篇博客&#xff0c;能…

基于超宽带技术的人员定位系统源码,spring boot+ vue+ mysql定位系统源码

​UWB定位技术源码 超宽带技术的人员定位系统源码 UWB人员定位系统是一种基于超宽带技术的人员定位系统&#xff0c;它通过发送和接收超短脉冲信号&#xff0c;在测距方面可以达到微米级精度。这种系统通常需要具备高精度的定位能力&#xff0c;通常需要达到微米级别&#xff0…

ceph-deploy bclinux aarch64 ceph 14.2.10

ssh-copy-id&#xff0c;部署机免密登录其他三台主机 所有机器硬盘配置参考如下&#xff0c;计划采用vdb作为ceph数据盘 下载ceph-deploy pip install ceph-deploy 免密登录设置主机名 hostnamectl --static set-hostname ceph-0 .. 3 配置hosts 172.17.163.105 ceph-0 172.…

局部路由守卫component守卫

局部路由守卫component守卫 component守卫&#xff08;beforeRouteEnter、beforeRouteLeave&#xff09; 代码位置&#xff1a;在路由组件中&#xff0c;代码是写在component当中的&#xff08;XXX.vue&#xff09;beforeRouteEnter、beforeRouteLeave都有三个参数&#xff1…

python Flask框架,调用MobileNetV2图像分类模型,实现前端上传图像分类

python Flask框架&#xff0c;调用MobileNetV2图像分类模型&#xff0c;实现前端上传图像分类 今天博主介绍一个图像分类的小项目 基于flask 和mobileNetV2模型的前端图像分类项目 环境配置如下&#xff1a; python版本3.7.6 安装库的版本如下&#xff1a; tensorflow 2.11.…

单挑特斯拉,华为智选车迈入第二阶段

文丨刘俊宏 编丨王一粟 华为智选车的节奏越来越快。 11月9日&#xff0c;华为跟奇瑞打造的首款C级纯电轿车智界S7发布&#xff0c;预售价为25.8万起。 在发布会上&#xff0c;华为常务董事、终端BG CEO、智能汽车解决方案BU董事长余承东采取手机以往最惯用的对标营销手法&a…

蓝桥杯算法心得——拼数(排列型回溯dfs)

大家好&#xff0c;我是晴天学长&#xff0c;排列型的dfs&#xff0c;在一些需要暴搜的题中很中很重要&#xff0c;需要的小伙伴可以关注支持一下哦&#xff01;后续会继续更新的。&#x1f4aa;&#x1f4aa;&#x1f4aa; 1) .拼数 2) .算法思路 超级递归 1.遍历数组&#…

想要和猫妹一起学Python吗?快进群吧

这是一篇2024年猫妹学Python新同学召集令&#xff0c;感兴趣的朋友可以看下。 初始Python 猫爸第一次被Python惊艳&#xff0c;是几年前的一个风格迁移程序。 国外某大学的一篇博士论文&#xff0c;为风格迁移提供了理论支撑。 下载到模型之后&#xff0c;就可以用简单的Py…

Linux的基本指令(1)

目录 快速认识的几个指令 pwd指令 mkdir指令 touch指令 cd指令 clear指令 whoami指令 ls指令 ls -l ls -la ls 目录名 ls -ld 目录名 文件 路径 路径是什么&#xff1f; 路径的形成 ​ 怎么保证路径必须有唯一性&#xff1f; ls -la隐藏文件 隐藏文件的是什…

UnRaid安装安装仓库管理系统GreaterWMS

文章目录 0、前言1、安装流程1.1、克隆GreaterWMS项目到UnRaid本地目录1.2、修改项目前后端端口1.3、修改baseurl1.4、修改Nginx.conf配置文件1.5、安装依赖插件1.5.1、Docker Compose Manager插件1.5.2、Python3环境 1.6、创建GreaterWMS容器1.6.1、为前后端启动脚本赋执行权限…