android 常规log、dump、winscope常见抓取方法

1,214 阅读7分钟

ProtoLog开关

在代码中我们经常看见ProtoLog打印的log,如下:

ProtoLog.i(WM_DEBUG_ANIM, "Animation start delayed for %s", mAnimatable);

这种log正常情况不会显示,因此我们需要打开开关,其格式为: adb shell wm logging enable-text [代码中对应的TAG] 我们这段代码的TAG是WM_DEBUG_ANIM,因此通过命令adb shell wm logging enable-text WM_DEBUG_ANIM打开log开关

另一种情况

ProtoLog.v(WM_SHELL_TASK_ORG, "Task info changed taskId=%d", taskInfo.taskId);

wmshell的log比较特殊,其在SystemUI进程,如果我们直接运行adb shell wm logging enable-text WM_SHELL_TASK_ORG会报错,打印如下:

Loaded 749 log definitions from /system/etc/protolog.conf.json.gz
No IProtoLogGroup named WM_SHELL_TASK_ORG
Not handled, please use `adb shell dumpsys activity service SystemUIService WMShell` if you are looking for ProtoLog in WMShell

根据提示我们打开log adb shell dumpsys activity service SystemUIService WMShell protolog enable WM_SHELL_TASK_ORG

logcat抓取log

# 抓取普通的andorid log
adb shell logcat > log.txt
# 仅抓取events log
adb shell logcat -b events > log.txt
# 抓取所有类型log
adb shell logcat -b all > log.txt

# 根据关键字抓取log,-i可以忽略大小,-e可以添加多条关键字,如下:
adb shell logcat -b events | grep -ie "关键log1" -ie "关键log2"> log.txt

events.log中对应代码查找

events log对应代码的规律是: events log开头的字段,比如wm_xxx 则对应的代码可以通过 grep 抓取 writeWmxxx 找出是在哪里打印的该events log

例如: 应用走到onresume生命周期的log wm_on_resume_called: [223605563,com.tencent.mm.ui.LauncherUI,RESUME_ACTIVITY,10]

EventLogTags.writeWmOnResumeCalled(mIdent, getComponentName().getClassName(), reason);

通知cancel的log notification_canceled: [0|com.tencent.mm|40|null|10218,8,19980,19980,7720,-1,-1,NULL]

EventLogTags.writeNotificationCanceled(canceledKey, reason,
                r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
                rank, count, listenerName);

使用winscope

手机要处于root状态才能使用

  • 使用手机自带的winscope 在手机设置里面,找到开发者选项->快捷设置开发者图块->打开 “ Winscope跟踪 ” 打开后复现问题,最后再关闭这个开关,就表示抓取完成 导出文件adb pull /data/misc/wmtrace 把导出文件在源码路径的android-13.0.0_r6/prebuilts/misc/common/winscope/winscope.html打开即可

  • 使用脚本抓取winscope(推荐) 附链接: winscope-t
    winscope-u winscope-v winscope-t和winscope-u均可离线使用,但是V的版本却不行,需要进行以下操作 1.需要用npm安装http-server npm install -g http-server 2.安装完成后运行http-server,进入下面任意一个ip即可在这里插入图片描述

    下载后,连接手机,直接运行脚本中的./run.sh,或者python3 winscope_proxy.py 在这里插入图片描述 START TRACE: 可以持续dump window和SurfaceFlinger信息,一般适用于闪黑场景,复现之前按下,复现后停止即可。 DMUP STATE: 相当于就是抓取一次 dumpsys windowdumpsys SurfaceFlinger

  • android 15之后离线抓取winscope方法

    # SurfaceFlinger
    # 开启
    adb shell perfetto --out /data/misc/perfetto-traces/winscope-proxy-trace.perfetto-trace --txt --config /data/misc/perfetto-configs/winscope-proxy-trace.conf --detach=WINSCOPE-PROXY-TRACING-SESSION
    # 停止
    adb shell perfetto --attach=WINSCOPE-PROXY-TRACING-SESSION --stop
    # 导出
    adb pull /data/misc/perfetto-traces/winscope-proxy-trace.perfetto-trace 
    
    # 有些设备可能没有winscope-proxy-trace.conf这类conf文件,可以尝试使用Android 15之前的方法
    adb shell su root service call Surface Flinger 1025 i32 1
    adb shell su root service call Surface Flinger 1025 i32 0
    adb pull /data/misc/wmtrace/layers_trace.pb 
    
    # window(window的抓取方法在Android15没有变化)
    # 开启
    adb shell cmd window tracing start
    # 停止
    adb shell cmd window tracing stop
    # 导出
    adb pull /data/misc/wmtrace/wm_trace.winscope
    

    手机里的 /data/misc/perfetto-configs/中不一定都是以winscope-proxy-trace.conf命名,比如:

    /data/misc/perfetto-configs # ls                                                                               
    winscope-proxy.surfaceflinger.conf  
    

    运行指令也可能报错

    adb shell perfetto --out /data/misc/perfetto-traces/winscope-proxy-trace.perfetto-trace --txt --config /data/misc/perfetto-configs/winscope-proxy.surfaceflinger.conf  --detach=WINSCOPE-PROXY-TRACING-SESSION      
    [191.423]     perfetto_cmd.cc:794 TraceConfig's write_into_file must be true when using --detach    
    

    这里提示需要write_into_file为true设置这个时候就需要我们修改脚本 在原始脚本的脚本的基础上修改即可

    vi /data/misc/perfetto-configs/winscope-proxy.surfaceflinger.conf                                       
    data_sources: {                                                                                                         
        config {                                                                                                            
            name: "android.surfaceflinger.layers"                                                                           
            surfaceflinger_layers_config: {                                                                                 
                mode: MODE_ACTIVE                                                                                           
                trace_flags: TRACE_FLAG_INPUT                                                                               
                trace_flags: TRACE_FLAG_COMPOSITION                                                                                     
                trace_flags: TRACE_FLAG_HWC                                                                                             
                trace_flags: TRACE_FLAG_BUFFERS                                                                                         
            }                                                                                                               
        }                                                                                                                   
    } 
    # 添加代码解决
    write_into_file: true
    
  • Android 16 winscope 本地尝试 Android 16 winscope当前无法离线使用,依赖nodejs

    构建方法(需要在当前AOSP目录下构建)

    1.安装nodejs https://nodejs.org/zh-cn/download

    2.在aosp/development/tools/winscope目录下运行,npm run build:prod,等项目构建完成

    运行方式

    1.在winscope目录下运行npm run start或者npx serve dist -p 8080(不带-p端口参数默认为3000)

    2.在winscope/src/adb目录下运行 python3 winscope_proxy.py

    注:python版本要在3.10以上,npx serve distnpm run start更为简单,根据个人使用习惯选择即可。

  • winscope中的Transactions

    在这里插入图片描述 这里layer是114,找到Transactions中的114,查看对应layer的Transactions 在这里插入图片描述 TX ID表示当前Transactions的ID,PID是谁做的这个Transactions操作,LAYER/DISP ID就是图层ID(与前面SF相对应)。

常见dump命令

adb shell dumpsys SurfaceFlinger > ./dump/SurfaceFlinger.txt
adb shell dumpsys window -a > ./dump/window.txt
adb shell dumpsys activity activities > ./dump/activities.txt
adb shell dumpsys activity top > ./dump/top_activity.txt
adb shell dumpsys activity containers > ./dump/containers.txt
adb shell dumpsys input > ./dump/input.txt

查找dump命令的方法

代码路径:frameworks/base/core/java/android/content/Context.java 这个代码里面有很多serviceName

    @StringDef(suffix = { "_SERVICE" }, value = {
            POWER_SERVICE,
            //@hide: POWER_STATS_SERVICE,
            WINDOW_SERVICE,
            LAYOUT_INFLATER_SERVICE,
            ACCOUNT_SERVICE,
            ACTIVITY_SERVICE,
            ALARM_SERVICE,
            NOTIFICATION_SERVICE,
            ACCESSIBILITY_SERVICE,
            CAPTIONING_SERVICE,
            KEYGUARD_SERVICE,
            LOCATION_SERVICE,
            HEALTHCONNECT_SERVICE,
            //@hide: COUNTRY_DETECTOR,
            SEARCH_SERVICE,
            SENSOR_SERVICE,
            SENSOR_PRIVACY_SERVICE,
            STORAGE_SERVICE,
            STORAGE_STATS_SERVICE,
            WALLPAPER_SERVICE,
            VIBRATOR_MANAGER_SERVICE,
            VIBRATOR_SERVICE,
            //@hide: STATUS_BAR_SERVICE,
            CONNECTIVITY_SERVICE,
            PAC_PROXY_SERVICE,
            VCN_MANAGEMENT_SERVICE,
            //@hide: IP_MEMORY_STORE_SERVICE,
            IPSEC_SERVICE,
            VPN_MANAGEMENT_SERVICE,
            TEST_NETWORK_SERVICE,
            //@hide: UPDATE_LOCK_SERVICE,
            //@hide: NETWORKMANAGEMENT_SERVICE,
            NETWORK_STATS_SERVICE,
            //@hide: NETWORK_POLICY_SERVICE,
            WIFI_SERVICE,
            WIFI_AWARE_SERVICE,
            WIFI_P2P_SERVICE,
            WIFI_SCANNING_SERVICE,
            //@hide: LOWPAN_SERVICE,
            //@hide: WIFI_RTT_SERVICE,
            //@hide: ETHERNET_SERVICE,
            WIFI_RTT_RANGING_SERVICE,
            NSD_SERVICE,
            AUDIO_SERVICE,
            AUDIO_DEVICE_VOLUME_SERVICE,
            AUTH_SERVICE,
            FINGERPRINT_SERVICE,
            //@hide: FACE_SERVICE,
            BIOMETRIC_SERVICE,
            MEDIA_ROUTER_SERVICE,
            TELEPHONY_SERVICE,
            TELEPHONY_SUBSCRIPTION_SERVICE,
            CARRIER_CONFIG_SERVICE,
            EUICC_SERVICE,
            //@hide: MMS_SERVICE,
            TELECOM_SERVICE,
            CLIPBOARD_SERVICE,
            INPUT_METHOD_SERVICE,
            TEXT_SERVICES_MANAGER_SERVICE,
            TEXT_CLASSIFICATION_SERVICE,
            APPWIDGET_SERVICE,
            //@hide: VOICE_INTERACTION_MANAGER_SERVICE,
            //@hide: BACKUP_SERVICE,
            REBOOT_READINESS_SERVICE,
            ROLLBACK_SERVICE,
            DROPBOX_SERVICE,
            //@hide: DEVICE_IDLE_CONTROLLER,
            //@hide: POWER_WHITELIST_MANAGER,
            DEVICE_POLICY_SERVICE,
            UI_MODE_SERVICE,
            DOWNLOAD_SERVICE,
            NFC_SERVICE,
            BLUETOOTH_SERVICE,
            //@hide: SIP_SERVICE,
            USB_SERVICE,
            LAUNCHER_APPS_SERVICE,
            //@hide: SERIAL_SERVICE,
            //@hide: HDMI_CONTROL_SERVICE,
            INPUT_SERVICE,
            DISPLAY_SERVICE,
            //@hide COLOR_DISPLAY_SERVICE,
            USER_SERVICE,
            RESTRICTIONS_SERVICE,
            APP_OPS_SERVICE,
            ROLE_SERVICE,
            //@hide ROLE_CONTROLLER_SERVICE,
            CAMERA_SERVICE,
            //@hide: PLATFORM_COMPAT_SERVICE,
            //@hide: PLATFORM_COMPAT_NATIVE_SERVICE,
            PRINT_SERVICE,
            CONSUMER_IR_SERVICE,
            //@hide: TRUST_SERVICE,
            TV_INTERACTIVE_APP_SERVICE,
            TV_INPUT_SERVICE,
            //@hide: TV_TUNER_RESOURCE_MGR_SERVICE,
            //@hide: NETWORK_SCORE_SERVICE,
            USAGE_STATS_SERVICE,
            MEDIA_SESSION_SERVICE,
            MEDIA_COMMUNICATION_SERVICE,
            BATTERY_SERVICE,
            JOB_SCHEDULER_SERVICE,
            //@hide: PERSISTENT_DATA_BLOCK_SERVICE,
            //@hide: OEM_LOCK_SERVICE,
            MEDIA_PROJECTION_SERVICE,
            MIDI_SERVICE,
            RADIO_SERVICE,
            HARDWARE_PROPERTIES_SERVICE,
            //@hide: SOUND_TRIGGER_SERVICE,
            SHORTCUT_SERVICE,
            //@hide: CONTEXTHUB_SERVICE,
            SYSTEM_HEALTH_SERVICE,
            //@hide: INCIDENT_SERVICE,
            //@hide: INCIDENT_COMPANION_SERVICE,
            //@hide: STATS_COMPANION_SERVICE,
            COMPANION_DEVICE_SERVICE,
            VIRTUAL_DEVICE_SERVICE,
            CROSS_PROFILE_APPS_SERVICE,
            //@hide: SYSTEM_UPDATE_SERVICE,
            //@hide: TIME_DETECTOR_SERVICE,
            //@hide: TIME_ZONE_DETECTOR_SERVICE,
            PERMISSION_SERVICE,
            LIGHTS_SERVICE,
            LOCALE_SERVICE,
            //@hide: PEOPLE_SERVICE,
            //@hide: DEVICE_STATE_SERVICE,
            //@hide: SPEECH_RECOGNITION_SERVICE,
            UWB_SERVICE,
            MEDIA_METRICS_SERVICE,
            //@hide: ATTESTATION_VERIFICATION_SERVICE,
            //@hide: SAFETY_CENTER_SERVICE,
            DISPLAY_HASH_SERVICE,
            CREDENTIAL_SERVICE,
            DEVICE_LOCK_SERVICE,
            VIRTUALIZATION_SERVICE,
            GRAMMATICAL_INFLECTION_SERVICE,

    })

我们只需要根据这些常量找到对应的名称即可,比如输入法:

    /**
     * Use with {@link #getSystemService(String)} to retrieve a
     * {@link android.view.inputmethod.InputMethodManager} for accessing input
     * methods.
     *
     * @see #getSystemService(String)
     */
    public static final String INPUT_METHOD_SERVICE = "input_method";

我们可以看到,其实就是通过getSystemService方法中调用的字符常量,我们要dump输入法服务相关的命令就是adb shell dumpsys input_method

如果我们想知道这个dump的方法具体在哪,会有哪些打印,则只需通过对应Mananger找到对应的ManagerService即可。 比如,我们这里以输入法为例,那么其对应的就是InputMethodManagerService,在这个里面就有对应的dump方法: 代码路径:frameworks/base/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java

void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
            final SimpleDateFormat dataFormat =
                    new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);

            for (int i = 0; i < mEntries.length; ++i) {
                final Entry entry = mEntries[(i + mNextIndex) % mEntries.length];
                if (entry == null) {
                    continue;
                }
                pw.print(prefix);
                pw.println("SoftInputShowHideHistory #" + entry.mSequenceNumber + ":");

                pw.print(prefix);
                pw.println(" time=" + dataFormat.format(new Date(entry.mWallTime))
                        + " (timestamp=" + entry.mTimestamp + ")");

                pw.print(prefix);
                pw.print(" reason=" + InputMethodDebug.softInputDisplayReasonToString(
                        entry.mReason));
                pw.println(" inFullscreenMode=" + entry.mInFullscreenMode);

                pw.print(prefix);
                pw.println(" requestClient=" + entry.mClientState);

                pw.print(prefix);
                pw.println(" focusedWindowName=" + entry.mFocusedWindowName);

                pw.print(prefix);
                pw.println(" requestWindowName=" + entry.mRequestWindowName);

                pw.print(prefix);
                pw.println(" imeControlTargetName=" + entry.mImeControlTargetName);

                pw.print(prefix);
                pw.println(" imeTargetNameFromWm=" + entry.mImeTargetNameFromWm);

                pw.print(prefix);
                pw.print(" editorInfo: ");
                pw.print(" inputType=" + entry.mEditorInfo.inputType);
                pw.print(" privateImeOptions=" + entry.mEditorInfo.privateImeOptions);
                pw.println(" fieldId (viewId)=" + entry.mEditorInfo.fieldId);

                pw.print(prefix);
                pw.println(" focusedWindowSoftInputMode=" + InputMethodDebug.softInputModeToString(
                        entry.mFocusedWindowSoftInputMode));
            }
        }
    }

有些命令是带参数的,比如:adb shell dumpsys activity top 可以加上-h来查看所有的命令,如:adb shell dumpsys activity -h 打印结果如下:

Activity manager dump options:
  [-a] [-c] [-p PACKAGE] [-h] [WHAT] ...
  WHAT may be one of:
    a[ctivities]: activity stack state
    r[recents]: recent activities state
    b[roadcasts] [PACKAGE_NAME] [history [-s]]: broadcast state
    broadcast-stats [PACKAGE_NAME]: aggregated broadcast statistics
    i[ntents] [PACKAGE_NAME]: pending intent state
    p[rocesses] [PACKAGE_NAME]: process state
    o[om]: out of memory management
    perm[issions]: URI permission grant state
    prov[iders] [COMP_SPEC ...]: content provider state
    provider [COMP_SPEC]: provider client-side state
    s[ervices] [COMP_SPEC ...]: service state
    allowed-associations: current package association restrictions
    as[sociations]: tracked app associations
    exit-info [PACKAGE_NAME]: historical process exit information
    lmk: stats on low memory killer
    lru: raw LRU process list
    binder-proxies: stats on binder objects and IPCs
    settings: currently applied config settings
    service [COMP_SPEC]: service client-side state
    package [PACKAGE_NAME]: all state related to given package
    all: dump all activities
    top: dump the top activity
    users: user state
  WHAT may also be a COMP_SPEC to dump activities.
  COMP_SPEC may be a component name (com.foo/.myApp),
    a partial substring in a component name, a
    hex object identifier.
  -a: include all available server state.
  -c: include client state.
  -p: limit output to given package.
  -d: limit output to given display.
  --checkin: output checkin format, resetting data.
  --C: output checkin format, not resetting data.
  --proto: output dump in protocol buffer format.
  --dump-dumpable: dump just the DUMPABLE-related state of an activity. Use the --list-dumpables option to list the supported DUMPABLEs
  --list-dumpables: show the available dumpables in an activity