Android ProtoLog动态开启相关wm logging源码分析补充

news2025/1/26 15:34:19

Android ProtoLog动态开启相关wm logging源码分析补充

针对上一节已经清楚了相关的代码中怎么可以打印到logcat中,其实本质上还就是protologtool这个工具对代码中的所有ProtoLog进行了相关的替换成了具体实现,最后会条件判断输出到Slog中
本文就重点来看看相关动态控制过程
更多内容qqun:422901085 相关课程

wm logging 命令设置详细分析

这里可以看看wm logging命令的相关帮助

NX563J:/ # wm logging -h
Unknown command
Window manager logging options:
	//启动抓取proto logging
  start: Start proto logging 
  //停止抓取proto logging
  stop: Stop proto logging 
  //允许proto logging的输出针对对应group(
  enable [group...]: Enable proto logging for given groups 
  //禁止proto logging的输出针对对应group
  disable [group...]: Disable proto logging for given groups
  //允许locat的输出针对对应group
  enable-text [group...]: Enable logcat logging for given groups
  //禁止locat的输出针对对应group
  disable-text [group...]: Disable logcat logging for given groups
Not handled, please use `adb shell dumpsys activity service SystemUIService WMShell` if you are looking for ProtoLog in WMShell

这里其实主要是enable和enable-text的一个区别
enable对应是proto logging这个就是像wms课程时候winscope抓取会把日志写入到data/misc/wmtrace/路径下wm_log.winscope
enable-text对应就是logcat可以直接看到的,这个也就是我们经常用的

知道对应的命令了,这里来看看对应的代码输出
分析代码之前我们得细分这个命令
wm logging enable-text xxxx
说明这个地方肯定是调用到我们WindowManagerService的onShellCommand

    @Override
    public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
            String[] args, ShellCallback callback, ResultReceiver result) {
        new WindowManagerShellCommand(this).exec(this, in, out, err, args, callback, result);
    }

这里直接执行到了WindowManagerShellCommand的onCommand中

 
    public int onCommand(String cmd) {
        if (cmd == null) {
            return handleDefaultCommands(cmd);
        }
        final PrintWriter pw = getOutPrintWriter();
        try {
            switch (cmd) {
                //省略
                case "logging":
                    String[] args = peekRemainingArgs();
                    int result = ProtoLogImpl.getSingleInstance().onShellCommand(this);
                    //省略
                    return result;
            //省略
    }

接下来调用到了ProtoLogImpl.getSingleInstance().onShellCommand

public int onShellCommand(ShellCommand shell) {
        PrintWriter pw = shell.getOutPrintWriter();
        String cmd = shell.getNextArg();
        if (cmd == null) {
            return unknownCommand(pw);
        }
        ArrayList<String> args = new ArrayList<>();
        String arg;
        while ((arg = shell.getNextArg()) != null) {
            args.add(arg);
        }
        String[] groups = args.toArray(new String[args.size()]);
        switch (cmd) {
            case "start":
                startProtoLog(pw);
                return 0;
            case "stop":
                stopProtoLog(pw, true);
                return 0;
            case "status":
                logAndPrintln(pw, getStatus());
                return 0;
            case "enable":
                return setLogging(false, true, pw, groups);
            case "enable-text":
                mViewerConfig.loadViewerConfig(pw, mViewerConfigFilename);
                return setLogging(true, true, pw, groups);
            case "disable":
                return setLogging(false, false, pw, groups);
            case "disable-text":
                return setLogging(true, false, pw, groups);
            default:
                return unknownCommand(pw);
        }
    }

针对enable和enable-text其实也都是调用了一个方法setLogging:

    protected int setLogging(boolean setTextLogging, boolean value, PrintWriter pw,
            String... groups) {
        for (int i = 0; i < groups.length; i++) {
            String group = groups[i];
            IProtoLogGroup g = LOG_GROUPS.get(group);
            //根据传递进来的group进行遍历出对应的IProtoLogGroup
            if (g != null) {
                if (setTextLogging) {//如果是logcat输出
                    g.setLogToLogcat(value);
                } else {//只是输出到proto文件
                    g.setLogToProto(value);
                }
            } else { //没有遍历到就宣告失败
                logAndPrintln(pw, "No IProtoLogGroup named " + group);
                return -1;
            }
        }
        sCacheUpdater.run();
        return 0;
    }
frameworks/base/core/java/com/android/internal/protolog/ProtoLogGroup.java
    @Override
    public void setLogToLogcat(boolean logToLogcat) {
        this.mLogToLogcat = logToLogcat;//只是有个赋值而以
    }
 @Override
    public void setLogToProto(boolean logToProto) {
        this.mLogToProto = logToProto;
    }

这里shell执行部分就已经完成了,最终就是吧对应的ProtoLogGroup的相关变量赋值了

日志输出部分源码

前一节已经知道了

ProtoLog.x(ProtoLogGroup.GROUP_NAME, "Format string %d %s", value1, value2);

会变成如下代码

if (ProtoLogImpl.isEnabled(GROUP_NAME)) {
    int protoLogParam0 = value1;
    String protoLogParam1 = String.valueOf(value2);
    ProtoLogImpl.x(ProtoLogGroup.GROUP_NAME, 123456, 0b0100, "Format string %d %s or null", protoLogParam0, protoLogParam1);
}

这里看看ProtoLogImpl.isEnabled(GROUP_NAME)

  /** Returns true iff logging is enabled for the given {@code IProtoLogGroup}. */
    public static boolean isEnabled(IProtoLogGroup group) {
        return group.isLogToLogcat()
                || (group.isLogToProto() && getSingleInstance().isProtoEnabled());
    }

可以看出就是前面命令设置的值为true了这里就可以为true
再看对应的打印

   public static void w(IProtoLogGroup group, int messageHash, int paramsMask,
            @Nullable String messageString,
            Object... args) {
        getSingleInstance().log(LogLevel.WARN, group, messageHash, paramsMask, messageString, args);
    }
    

调用到了log方法,它是
frameworks/base/core/java/com/android/internal/protolog/BaseProtoLogImpl.java

 @VisibleForTesting
    public void log(LogLevel level, IProtoLogGroup group, int messageHash, int paramsMask,
            @Nullable String messageString, Object[] args) {
        if (group.isLogToProto()) {//判断是否属于输出到proto
            logToProto(messageHash, paramsMask, args);
        }
        if (group.isLogToLogcat()) {//判断是否属于输出到logcat
            logToLogcat(group.getTag(), level, messageHash, messageString, args);
        }
    }

下面只以logcat为例分析一下

    private void logToLogcat(String tag, LogLevel level, int messageHash,
            @Nullable String messageString, Object[] args) {
   //省略
        passToLogcat(tag, level, message);
    }
/**
     * SLog wrapper.
     */
    @VisibleForTesting
    public void passToLogcat(String tag, LogLevel level, String message) {
        switch (level) {
            case DEBUG:
                Slog.d(tag, message);//最后调用到了Slog
                break;
            case VERBOSE:
                Slog.v(tag, message);
                break;
            case INFO:
                Slog.i(tag, message);
                break;
            case WARN:
                Slog.w(tag, message);
                break;
            case ERROR:
                Slog.e(tag, message);
                break;
            case WTF:
                Slog.wtf(tag, message);
                break;
        }
    }

那相当于整个流程清晰了
同时要注意一下:proto logging和logcat其实不是互斥,而是互不影响,而且可以同时存在

proto二进制文件的解析查看方法

抓取这个proto的二进制其实又2类方法:
方法1:
命令:

NX563J:/ # test@test:~/wmtrace/nx563$ adb shell wm logging start                                           
Start logging to /data/misc/wmtrace/wm_log.winscope.
test@test:~/wmtrace/nx563$ adb shell wm logging stop 
Stop logging to /data/misc/wmtrace/wm_log.winscope. Waiting for log to flush.
Log written to /data/misc/wmtrace/wm_log.winscope.

很简单start开始和stop结束,最后日志在 /data/misc/wmtrace/wm_log.winscope文件中

方法2:
那就是我们使用的winscope方法
https://blog.csdn.net/learnframework/article/details/129432374

抓取之后查看方法:
因为wm_log.winscope属于二进制文件,直接文本打开其实乱码,那么怎么查看呢?
其实这里也有2中方法:
1、就是直接winscope.html即可以
在这里插入图片描述

这种方式最简单,但是因为只能在html网页,相对来说对想日志分析的还是不那么友好,又没有其他方法?
接下来就介绍另一种
方法2:
使用上一节提到的protologtool命令

 Command: read-log --viewer-conf <viewer.json> <wm_log.pb>

viewer.json就是/system/etc/protolog.conf.json.gz
wm_log.pb wm_log.winscope
即使用类似命令:protologtool read-log --viewer-conf protolog.conf.json wm_log.winscope
那么剩下就是protologtool命令哪里来的?
遗憾是android 13上面没有找到这个bin文件,但是它有对应可以执行的jar

java_binary_host {
    name: "protologtool",
    manifest: "manifest.txt",
    static_libs: [
        "protologtool-lib",
    ],
}

test@test:~/aosp/out$ find -name  protologtool.jar
./soong/.intermediates/frameworks/base/tools/protologtool/protologtool/linux_glibc_common/combined/protologtool.jar

要执行这个jar方法:java -jar protologtool.jar

test@test:~/aosp/out/soong/.intermediates/frameworks/base/tools/protologtool/protologtool/linux_glibc_common/combined$ java -jar protologtool.jar read-log --view
er-conf ~/wmtrace/protolog.conf.json ~/wmtrace/nx563/wmtrace/wm_log.winscope  > ~/1-wm_log.txt

日志如下:

03-04 09:06:45.953 INFO WindowManager: >>> OPEN TRANSACTION animate
03-04 09:06:45.958 INFO WindowManager: <<< CLOSE TRANSACTION animate
03-04 09:06:47.190 INFO WindowManager: Relayout Window{ce1f2d7 u0 StatusBar}: oldVis=0 newVis=0. java.lang.RuntimeException
03-04 09:06:47.191 INFO WindowManager: OUT SURFACE Surface(name=StatusBar)/@0x46c3092: copied
03-04 09:06:47.193 DEBUG WindowManager: InsetsSource updateVisibility for ITYPE_IME, serverVisible: false clientVisible: false
03-04 09:06:47.193 DEBUG WindowManager: InsetsSource updateVisibility for ITYPE_TOP_TAPPABLE_ELEMENT, serverVisible: true clientVisible: true
03-04 09:06:47.193 DEBUG WindowManager: InsetsSource updateVisibility for ITYPE_TOP_MANDATORY_GESTURES, serverVisible: true clientVisible: true
03-04 09:06:47.193 DEBUG WindowManager: InsetsSource updateVisibility for ITYPE_STATUS_BAR, serverVisible: true clientVisible: true
03-04 09:06:47.193 DEBUG WindowManager: handleNotObscuredLocked w: Window{41477bf u0 ScreenDecorOverlayBottom}, w.mHasSurface: false, w.isOnScreen(): false, w.isDisplayedLw(): false, w.mAttrs.userActivityTimeout: -1
03-04 09:06:47.194 DEBUG WindowManager: handleNotObscuredLocked w: Window{b45a65c u0 ScreenDecorOverlay}, w.mHasSurface: false, w.isOnScreen(): false, w.isDisplayedLw(): false, w.mAttrs.userActivityTimeout: -1
03-04 09:06:47.194 DEBUG WindowManager: handleNotObscuredLocked w: Window{66460ee u0 pip-dismiss-overlay}, w.mHasSurface: false, w.isOnScreen(): false, w.isDisplayedLw(): false, w.mAttrs.userActivityTimeout: -1
03-04 09:06:47.194 DEBUG WindowManager: handleNotObscuredLocked w: Window{e44117e u0 NotificationShade}, w.mHasSurface: true, w.isOnScreen(): true, w.isDisplayedLw(): true, w.mAttrs.userActivityTimeout: -1
03-04 09:06:47.194 DEBUG WindowManager: handleNotObscuredLocked w: Window{ce1f2d7 u0 StatusBar}, w.mHasSurface: true, w.isOnScreen(): true, w.isDisplayedLw(): true, w.mAttrs.userActivityTimeout: -1
03-04 09:06:47.194 DEBUG WindowManager: handleNotObscuredLocked w: Window{13ab3d9 u0 ShellDropTarget}, w.mHasSurface: false, w.isOnScreen(): false, w.isDisplayedLw(): false, w.mAttrs.userActivityTimeout: -1
03-04 09:06:47.194 DEBUG WindowManager: handleNotObscuredLocked w: Window{d0a84ad u0 InputMethod}, w.mHasSurface: false, w.isOnScreen(): false, w.isDisplayedLw(): false, w.mAttrs.userActivityTimeout: -1
03-04 09:06:47.194 DEBUG WindowManager: handleNotObscuredLocked w: Window{cd7897f u0 com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher}, w.mHasSurface: true, w.isOnScreen(): true, w.isDisplayedLw(): true, w.mAttrs.userActivityTimeout: -1
03-04 09:06:47.195 DEBUG WindowManager: handleNotObscuredLocked w: Window{1b1cf58 u0 com.android.settings/com.android.settings.SubSettings}, w.mHasSurface: false, w.isOnScreen(): false, w.isDisplayedLw(): false, w.mAttrs.userActivityTimeout: -1
03-04 09:06:47.195 DEBUG WindowManager: handleNotObscuredLocked w: Window{b350833 u0 com.android.settings/com.android.settings.SubSettings}, w.mHasSurface: false, w.isOnScreen(): false, w.isDisplayedLw(): false, w.mAttrs.userActivityTimeout: -1
03-04 09:06:47.195 DEBUG WindowManager: handleNotObscuredLocked w: Window{88c7bc6 u0 com.android.settings/com.android.settings.SubSettings}, w.mHasSurface: false, w.isOnScreen(): false, w.isDisplayedLw(): false, w.mAttrs.userActivityTimeout: -1
03-04 09:06:47.195 DEBUG WindowManager: handleNotObscuredLocked w: Window{e7b31e4 u0 com.android.settings/com.android.settings.Settings}, w.mHasSurface: false, w.isOnScreen(): false, w.isDisplayedLw(): false, w.mAttrs.userActivityTimeout: -1
03-04 09:06:47.195 DEBUG WindowManager: handleNotObscuredLocked w: Window{6ea66a3 u0 com.android.systemui.wallpapers.ImageWallpaper}, w.mHasSurface: true, w.isOnScreen(): true, w.isDisplayedLw(): true, w.mAttrs.userActivityTimeout: -1
03-04 09:06:47.208 INFO WindowManager: enableScreenIfNeededLocked: mDisplayEnabled=true mForceDisplayEnabled=false mShowingBootMessages=false mSystemBooted=true. java.lang.RuntimeException: here
03-04 09:06:47.209 VERBOSE WindowManager: ActivityRecord{cfb41da u0 com.android.launcher3/.uioverrides.QuickstepLauncher} t148} is requesting orientation 5 (SCREEN_ORIENTATION_NOSENSOR)
03-04 09:06:47.209 VERBOSE WindowManager: Task{f56c100 #148 type=home I=com.android.launcher3/.uioverrides.QuickstepLauncher} is requesting orientation 5 (SCREEN_ORIENTATION_NOSENSOR)
03-04 09:06:47.209 VERBOSE WindowManager: Task{c7e1a66 #1 type=home} is requesting orientation 5 (SCREEN_ORIENTATION_NOSENSOR)

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

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

相关文章

【池化方法】多示例学习池化(MIL pooling)公式与代码

一般的池化方法包括最大池化、平均池化、自适应池化与随机池化&#xff0c;这几天意外看到了多示例学习池化&#xff0c;感觉挺有意思的&#xff0c;记录一下。   论文   代码 1. 多示例学习&#xff08;Multiple instance learning&#xff0c;MIL&#xff09; 经典深度学…

梯度下降算法原理详解及MATLAB程序代码(最简单)

模型就是线性规划及线性规划的对偶理论&#xff0c;单纯形法以及它的实际应用&#xff1a;整数规划及其解法(分支定界法、割平面法匈牙利算法Q)&#xff0c;目标规划&#xff0c;非线性规划动态规划、决策分析等等。 其它的一些优化算法。比如说一维搜索里面的黄金分割法、加步…

PostMan笔记(二)发送请求

1. 发送请求功能介绍 Postman是一款流行的API开发工具&#xff0c;它可以让开发人员更方便地测试、调试和使用API。其中&#xff0c;发送请求功能是Postman最为重要和基础的功能之一。 在Postman中&#xff0c;发送请求功能主要包括以下几个步骤&#xff1a; 选择请求方法&am…

数据分析时,进行数据建模该如何筛选关键特征?

1.为什么要做关键特征筛选&#xff1f; 在数据量与日俱增的时代&#xff0c;我们收集到的数据越来越多&#xff0c;能运用到数据分析挖掘的数据也逐渐丰富起来&#xff0c;但同时&#xff0c;我们也面临着如何从庞大的数据中筛选出与我们业务息息相关的数据。&#xff08;大背景…

Java的对象克隆

本节我们会讨论 Cloneable 接口&#xff0c;这个接口指示一个类提供了一个安全的 clone() 方法。 Object 类提供的 clone() 方法是 “浅拷贝”&#xff0c;并没有克隆对象中引用的其他对象&#xff0c;原对象和克隆的对象仍然会共享一些信息。深拷贝指的是&#xff1a;在对象中…

微服务---一篇学完SpringCloud

SpringCloud 1.认识微服务 随着互联网行业的发展&#xff0c;对服务的要求也越来越高&#xff0c;服务架构也从单体架构逐渐演变为现在流行的微服务架构。这些架构之间有怎样的差别呢&#xff1f; 1.0.学习目标 了解微服务架构的优缺点 1.1.单体架构 单体架构&#xff1a…

java企业级信息系统开发学习笔记06基于xml配置方式使用Spring MVC

文章目录 一、学习目标二、Spring MVC概述1、MVC架构2、Spirng MVC3、使用Spring MVC的两种方式 三、基于xml配置与注解的方式使用Spring MVC&#xff08;一&#xff09;创建Maven项目&#xff08;二&#xff09;添加相关依赖&#xff08;三&#xff09;给项目添加Web功能&…

SpringMVC表格提交中文乱码和配置logback

最佳解决方案还是使用Spring提供的过滤器&#xff0c;将其配置到WEB.XML文件中&#xff1a; <filter><filter-name>characterEncodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class&g…

nginx部署VUE项目

前言 目前公司的前端代码基本都是部署在nginx下&#xff0c;特此来记录一下 开发环境&#xff1a;window10 nginx环境搭建&#xff08;参考下方文章&#xff09; window环境安装 mac环境安装 本地我将nginx放置于F盘 前端项目打包 一个nginx服务下可能会放置多个前端包&…

echarts 折线图

Echarts 常用各类图表模板配置 注意&#xff1a; 这里主要就是基于各类图表&#xff0c;更多的使用 Echarts 的各类配置项&#xff1b; 以下代码都可以复制到 Echarts 官网&#xff0c;直接预览&#xff1b; 图标模板目录Echarts 常用各类图表模板配置一、简洁折线图二、环形图…

结构体的存储

由于要想知道结构体的大小&#xff0c;了解结构体是如何存储在内存中的 我们需要先了解一个知识点&#xff1a; 结构体内存对齐 1. 第一个成员在与结构体变量偏移量为0的地址处 (偏移量是某个字节相较于起始存储空间的相差字节数 例如第一个字节的偏移量是0&#xff0c;第二个…

一套专业的C#医院体检管理系统源码 PEIS体检报告管理系统源码 C/S医院PEIS系统源码

医院PEIS体检管理系统源码&#xff0c;有源码&#xff0c;有演示&#xff0c;自主研发&#xff0c;官方正版授权&#xff01; 开发语言&#xff1a;C# 开发工具&#xff1a;VS2013版本起 后端框架&#xff1a;winform 数 据 库&#xff1a;oracle 12c 医院体检系统主要特点…

人大金仓亮相2023CHITEC,五大看点不容错过

近日&#xff0c;由中国卫生信息与健康医疗大数据学会和《中国卫生信息管理杂志》社联合举办的2023&#xff08;17th&#xff09;中国卫生信息技术/健康医疗大数据应用交流大会暨软硬件与健康医疗产品展览会&#xff08;2023 CHITEC&#xff09;在安徽合肥顺利召开。 作为数据库…

【DAY38】BOM/VUE初步学习

pageXOffset 设置或返回当前页面相对于窗口显示区左上角的 X 位置。 pageYOffset 设置或返回当前页面相对于窗口显示区左上角的 Y 位置。 screenLeft&#xff0c;screenTop&#xff0c;screenX&#xff0c;screenY 声明了窗口的左上角在屏幕上的的 x 坐标和 y 坐标。IE、Safari…

JavaScript历史

JavaScript历史 参考视频1 1990年&#xff0c;第一个终端显示网页被蒂姆博士创造出来&#xff0c;表现为超链接跳转、无图的特点。文本格式定义、文本传输协议即应用层协议&#xff0c;解析显示引擎是关键。1993年&#xff0c;随着人们对视觉效果的要求逐渐变高&#xff0c;马…

Https详解

文章目录 一. 什么是 Https1. "加密"是什么?2. 对称加密3. 非对称加密4. "中间人攻击" 二. 引入证书理解签名黑客能否伪造证书?黑客能否替换公钥?黑客能否篡改签名?如何查看证书? 一. 什么是 Https https 就是 http 安全层(SSL)–> 用来加密的协…

黑马在线教育数仓实战6

6. 意向用户主题看板_增量流程 6.1 数据采集(拉链表) 7. hive的索引 ​ 索引的作用: 加快查询的效率 为什么索引可以提升查询效率呢? hive索引是在 分区 分桶优化基础上, 又提供一种新的优化手段, 如果分区 和分桶受限, 可以尝试使用索引的方式来优化处理 hive提供了三种索…

VMware ESXi 8.0U1 macOS Unlocker OEM BIOS (标准版和厂商定制版)

ESXi 8.0U1 标准版&#xff0c;Dell HPE 联想 浪潮 定制版 请访问原文链接&#xff1a; https://sysin.org/blog/vmware-esxi-8-u1-oem/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org 2023-04-18, VMware vSphere 8.0U1 发布…

家用洗地机实用吗?家用洗地机款式推荐

要说现在家居清洁用什么单品更省心&#xff0c;洗地机必须要算一项。虽然这在国际上也不是什么新鲜的概念了&#xff0c;但是在国内兴起也只是这几年的事&#xff0c;关于家用洗地机什么牌子最好之类的问题也是很多人都比较关心的问题。我个人也是不喜欢做家务的&#xff0c;家…

C++算法:排序、查找

排序 排序是一个非常经典的问题&#xff0c;它以一定的顺序对一个数组&#xff08;或一个列表&#xff09;中的项进行重新排序 有许多不同的排序算法&#xff0c;每个都有其自身的优点和局限性。 时间复杂度&#xff1a;对排序数据的总的操作次数。反映当n变化时&#xff0c;操…