> 文章列表 > Android ProtoLog动态开启相关wm logging源码分析补充

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

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

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 loggingstart: Start proto logging //停止抓取proto loggingstop: Stop proto logging //允许proto logging的输出针对对应group(enable [group...]: Enable proto logging for given groups //禁止proto logging的输出针对对应groupdisable [group...]: Disable proto logging for given groups//允许locat的输出针对对应groupenable-text [group...]: Enable logcat logging for given groups//禁止locat的输出针对对应groupdisable-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

    @Overridepublic 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进行遍历出对应的IProtoLogGroupif (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@Overridepublic void setLogToLogcat(boolean logToLogcat) {this.mLogToLogcat = logToLogcat;//只是有个赋值而以}@Overridepublic 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

 @VisibleForTestingpublic void log(LogLevel level, IProtoLogGroup group, int messageHash, int paramsMask,@Nullable String messageString, Object[] args) {if (group.isLogToProto()) {//判断是否属于输出到protologToProto(messageHash, paramsMask, args);}if (group.isLogToLogcat()) {//判断是否属于输出到logcatlogToLogcat(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.*/@VisibleForTestingpublic void passToLogcat(String tag, LogLevel level, String message) {switch (level) {case DEBUG:Slog.d(tag, message);//最后调用到了Slogbreak;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)