Android ProtoLog dynamically opens related wm logging source code analysis supplement

Android ProtoLog dynamically opens related wm logging source code analysis supplement

For the previous section, it has been clear how the relevant code can be printed to logcat. In fact, protologtool is a tool that replaces all ProtoLogs in the code with specific implementations, and finally outputs conditional judgments to the Slog.
This article focuses on the relevant dynamic control process
More content qqun: 422901085 Related courses

Detailed analysis of wm logging command settings

Here you can see the relevant help of the wm logging command

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

In fact, here is mainly a difference between enable and enable-text.
enable corresponds to proto logging. This is like wms class. When winscope captures, it will write the log to the data/misc/wmtrace/ path. wm_log.winscope enable
-text corresponds to logcat. As you can see directly, this is what we often use

Now that we know the corresponding command, let’s take a look at the corresponding code output.
Before analyzing the code, we have to subdivide the command
wm logging enable-text xxxx
, indicating that this place must be called to our WindowManagerService’s 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);
    }

Here it is executed directly into the onCommand of WindowManagerShellCommand

 
    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;
            //省略
    }

Next call 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);
        }
    }

For enable and enable-text, a method setLogging is actually called:

    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;
    }

Here the shell execution part has been completed, and finally the relevant variables of the corresponding ProtoLogGroup are assigned values.

Log output part of the source code

I already knew it in the previous section

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

will become the following code

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);
}

Look here 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());
    }

It can be seen that the value set by the previous command is true, and here it can be true
and then see the corresponding print

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

The log method is called, which is
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);
        }
    }

Let's take logcat as an example to analyze

    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;
        }
    }

That means the whole process is clear.
At the same time, it should be noted that proto logging and logcat are not mutually exclusive, but do not affect each other, and can exist at the same time.

Analysis and viewing method of proto binary file

There are actually two types of methods to grab the binary of this proto:
Method 1:
Command:

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.

It is very simple to start and stop, and the final log is in the /data/misc/wmtrace/wm_log.winscope file

Method 2:
That is the winscope method we use
https://blog.csdn.net/learnframework/article/details/129432374

Viewing method after capture:
Because wm_log.winscope is a binary file, the direct text opening is actually garbled, so how to view it?
In fact, there are also 2 methods here:
1. Just directly winscope.html
insert image description here

This method is the simplest, but because it can only be used on html web pages, it is relatively unfriendly to those who want to analyze logs, and there is no other way?
Next, another
method 2 is introduced:
using the protologtool command mentioned in the previous section

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

viewer.json is /system/etc/protolog.conf.json.gz
wm_log.pb wm_log.winscope
uses a similar command: protologtool read-log --viewer-conf protolog.conf.json wm_log.winscope
then the rest is the protologtool command Where did it come from?
Unfortunately, this bin file is not found on android 13, but it has a corresponding executable 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

To execute this jar method: 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

The log is as follows:

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)

Guess you like

Origin blog.csdn.net/learnframework/article/details/130233591