dumpstate log的一些总结

dumpState log在Android开发中是解决问题的重要途径之一,这篇文章记录我关于dumpstate的学习总结。

一、dumpstate的结构

dumpstate文件一般有几十万行的log,要从这么多log中找出想要的关键信息,如果不掌握一定的技巧,俨然大海捞针。先从总体上了解dumpstate的结构,以至于不会迷失在log海当中。随手抓了一个dumpstate,大概如下

 

二、dumpstate解析

对于三星型号,电话盘输入*#9900#进入以下界面

这个界面的代码在android\vendor\samsung\packages\apps\MSP\FactoryTest\ServiceModeApp\src\com\sec\android\app\servicemodeapp\app\SysDump.java

这里只分析点击第三项RUN DUMPSTATE/LOGCAT为例,实际运行的主要代码是

Runtime.getRuntime().exec("bugreport >/data/log/dumpstate_sysdump_time.log");

这里运行了bugreport程序,并将结果重定位到log文件中,这个log文件就是我们所说的dumpstate log了

 

bugreport的代码位于android\frameworks\native\cmds\bugreport\Bugreport.c

dumpstate的代码位于android\frameworks\native\cmds\dumpstate\Dumpstate.c

在bugreport中,先启动dumpstate的service

 

/* start the dumpstate service */
    property_set("ctl.start", "dumpstate");

然后通过linux socket的方式,在bugreport和dumpstate两个进程间建立通讯。

 

Bugreport Client端

 

s = socket_local_client("dumpstate",
                             ANDROID_SOCKET_NAMESPACE_RESERVED,
                             SOCK_STREAM);

 

 

Dumpstate Server端

 

redirect_to_socket(stdout, "dumpstate");
void redirect_to_socket(FILE *redirect, const char *service) {
    int s = android_get_control_socket(service);
    if (s < 0) {
        fprintf(stderr, "android_get_control_socket(%s): %s\n", service, strerror(errno));
        exit(1);
    }
    if (listen(s, 4) < 0) {//监听是否有client连接
        fprintf(stderr, "listen(control socket): %s\n", strerror(errno));
        exit(1);
    }

    struct sockaddr addr;
    socklen_t alen = sizeof(addr);
    int fd = accept(s, &addr, &alen);
    if (fd < 0) {
        fprintf(stderr, "accept(control socket): %s\n", strerror(errno));
        exit(1);
    }

    fflush(redirect);
    dup2(fd, fileno(redirect));
    close(fd);
}

这样dumpstate的结果就输出到stdout中,然后再重定位到log文件中,所以dumpstate.c这个程序才是重点。

 

从main函数进来,整个dump过程分五个过程,DumpState、ProcLibRank、ShowmapAll、DumpsysAll、DumpsysOther,分别调用的函数是dumpstate、proc_lib_rank、do_showmap_all、dumpsys_all、dumpsys_other

 

1. DumpState

 

    printf("========================================================\n");
    printf("== dumpstate: %s\n", date);
    printf("========================================================\n");

 

------ UPTIME (uptime) ------

打印系统当前运行了多长时间等信息

run_command("UPTIME", 10, "uptime", NULL);

uptime: 开机运行了多长时间

idle time:所有CPU休眠的总时间

 

------ MEMORY INFO (/proc/meminfo) ------

输出结果和cat /proc/meminfo的结果相同,proc系统反映了linux运行时的信息

 

dump_file("MEMORY INFO", "/proc/meminfo");

 

------ CPU CORE INFO ------

 

实际上输出的和cat下面等信息相同

 

    "/sys/devices/system/cpu/offline",
    "/sys/devices/system/cpu/online",
    "/sys/devices/system/cpu/possible",
    "/sys/devices/system/cpu/cpu0/rq-stats/cpu_normalized_load",
    "/sys/devices/system/cpu/cpu0/rq-stats/run_queue_avg",
    "/sys/devices/system/cpu/cpu0/rq-stats/run_queue_poll_ms"

 

 

 

------ CPU INFO (top -n 1 -d 1 -m 30 -t) ------

实际上是运行top命令

 

------ VIRTUAL MEMORY STATS (/proc/vmstat) ------

显示虚拟内存的信息,cat /proc/vmstat

 

------ VMALLOC INFO (/proc/vmallocinfo) ------

vmalloc内存分配信息,cat /proc/vmallocinfo

 

------ SLAB INFO (/proc/slabinfo) ------

slab分配器信息,cat /proc/slabinfo

 

------ ZONEINFO (/proc/zoneinfo) ------

内存域信息,cat /proc/zoneinfo

 

------ PAGETYPEINFO (/proc/pagetypeinfo) ------

cat /proc/pagetypeinfo

 

------ BUDDYINFO (/proc/buddyinfo) ------

伙伴系统信息, cat /proc/buddyinfo

 

------ KERNEL WAKELOCKS (/proc/wakelocks) ------

内核唤醒锁信息, cat /proc/wakelocks

 

------ KERNEL WAKE SOURCES (/d/wakeup_sources: 1970-01-01 08:00:00) ------

查看所有的wake_lock,cat /sys/kernel/debug/wakeup_sources

 

------ KERNEL CPUFREQ (/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state) ------

记录了CPU从开机以来在每个频率下的运行时间,cat /sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state

 

------ KERNEL BLUEDROID (/d/bluedroid) ------

蓝牙协议信息,cat /sys/kernel/debug/bluedroid

 

------ PROCESSES (ps -P --abi) ------

进程信息,相当于ps命令的输出结果

 

------ KERNEL LOG (dmesg) ------

显示系统启动时的kernel log,相当于dmesg命令的输出结果

 

------ UART LOG (/sys/kernel/debug/ipc_logging/uart_log/log) ------

相当于cat /sys/kernel/debug/ipc_logging/uart_log/log

 

------ USB LOG (/proc/usblog) ------

相当于cat /proc/usblog

 

**********************************************************************************************************************************************************

------ SYSTEM LOG (logcat -v threadtime -d *:v) ------

相当于命令logcat -v threadtime -d *:v 的输出结果

 

------ EVENT LOG (logcat -b events -v threadtime -d *:v) ------

相当于logcat -b events -v threadtime -d *:v 的输出结果

 

------ RADIO LOG (logcat -b radio -v threadtime -d *:v) ------

相当于logcat -b radio -v threadtime -d *:v 的输出结果

 

logcat -b表示请求不同的缓冲区(main、radio、events、system、crash、kernel),默认为-b main -b system,所以SYSTEM LOG包含了main缓冲区的和system缓冲区的,关于缓冲区,看下面的介绍。-v <format>设置log的打印格式(brief process tag thread raw time threadtime long color usec printable)。-d表示只读不阻塞。<tag>[:priority]是logcat的过滤器,*:v表示打出所有tag的log,级别为verbose

 

Log把日志保存到缓冲区,Logcat从缓冲区读取并查看。

Log工具

要打印一句log,通过这样的方法,Log.i("csf", "log test");

Log源码在android\frameworks\base\core\java\android\util\Log.java,看Log.i的实现

 

public static int i(String tag, String msg) {
        return println_native(LOG_ID_MAIN, INFO, tag, msg);
    }

 

在native层实现,android\frameworks\base\core\jni\android_util_Log.cpp

static jint android_util_Log_println_native(JNIEnv* env, jobject clazz,
        jint bufID, jint priority, jstring tagObj, jstring msgObj)
{
    const char* tag = NULL;
    const char* msg = NULL;

    if (msgObj == NULL) {
        jniThrowNullPointerException(env, "println needs a message");
        return -1;
    }

    if (bufID < 0 || bufID >= LOG_ID_MAX) {
        jniThrowNullPointerException(env, "bad bufID");
        return -1;
    }

    if (tagObj != NULL)
        tag = env->GetStringUTFChars(tagObj, NULL);
    msg = env->GetStringUTFChars(msgObj, NULL);

    int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);

    if (tag != NULL)
        env->ReleaseStringUTFChars(tagObj, tag);
    env->ReleaseStringUTFChars(msgObj, msg);

    return res;
}

真面目还藏在__android_log_buf_write()函数中,这个函数在android\system\core\liblog\logd_write.c中

通过分析,总结出下面,具体请查看源码

通过Log.d、Log.i、Log.v等输出的log保存在/dev/log/main这个缓冲区中,一般app用这种方式打log
通过Rlog.d、Rlog.v、Rlog.i等输出的log保存在/dev/log/radio这个缓冲区中,一般射频、SIM、telephony模块用这个比较多

通过Slog.d、Slog.v、Slog.i等输出的log保存在/dev/log/system这个缓冲区中,很多framework的log都用Slog

通过EventLog.writeEvent输出的log保存在/dev/log/events这个缓冲区中,一般用在framework模块中

Logcat工具

logcat的源码位于/android/system/core/logcat中

当运行logcat -v threadtime -d *:v 这样的命令时,便会启动logcat进入main函数,这里就会根据传入的参数读取不同缓冲区的内容

threadtime输入的格式如下

 

        case FORMAT_THREADTIME:
            len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
                "%s %5d %5d %c %-8s: ", timeBuf,
                entry->pid, entry->tid, priChar, entry->tag);
            strcpy(suffixBuf + suffixLen, "\n");
            ++suffixLen;
            break;

比如:

 

Time                             PID     TID  priority               Tag                           Message

05-25 15:48:17.318  1603  3061 V WindowOrientationListener: OrientationSensorJudge.getProposedRotation, Rotation: 0

**********************************************************************************************************************************************************

 

**********************************************************************************************************************************************************

------ LIST OF OPEN FILES (/system/xbin/su root lsof) ------

列出当前系统打开的文件,相当于命令/system/xbin/su root lsof,输出结果如下

COMMAND     PID       USER   FD      TYPE             DEVICE  SIZE/OFF       NODE NAME

zygote      518       root  mem       ???              00:04         0      11702 /dev/ashmem/dalvik-main

 

COMMAND:进程名称

PID:进程号

USER:进程所有者

FD:文件描述符,应用程序通过文件描述符识别该文件

TYPE:文件类型,如DIR、REG等

DEVICE:指定磁盘的名称

SIZE:文件的大小

NODE:索引节点(文件在磁盘上的标识)

NAME:打开文件的确切名称

**********************************************************************************************************************************************************

 

------ BLOCKED PROCESS WAIT-CHANNELS ------

列出系统上所有睡眠的线程的名称和函数名,如

tid                                                           睡眠的函数

6051       Binder_3                      binder_thread_read

 

 

------ VM TRACES JUST NOW (/data/anr/traces.txt.bugreport: 2016-05-25 15:49:20) ------

 

------ VM TRACES AT LAST ANR (/data/anr/traces.txt: 2016-05-25 15:49:20) ------

 

虚拟机相关信息,收集虚拟机和native的堆栈信息,这里需要root user权限

/proc目录下存在很多以数字命名的目录,这些数字其实就是进程号,每创建一个进程,/proc就会新建一个以进程号命名的目录,以下两个命令大概就是遍历每个进程,并获取backtrace,具体的实现是dump_backtrace_to_file()这个函数,源码位于/android/system/core/libcutils/Debugger.c

 

 

TOMBSTONE,当android发生crash时,会产生一个叫做Tombstone的文件,tombstone包含了进程crash时的重要信息,该文件位于/data/tombstone_xx下,每发生一次crash,xx递增一次,如果没有,则打印出

*** NO TOMBSTONES to dump in /data/tombstones

 

 

网络相关信息

------ NETWORK DEV INFO (/proc/net/dev) ------

相当于cat /proc/net/dev,输出结果如下

 

Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
 wlan0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0

receive表示收包,Transmit表示发包。bytes表示收发的字节数,packets表示收发正确的包数,errs表示收发错误的包数,drop表示收发丢弃的包数

 

 

------ NETWORK MCAST INFO (/proc/net/dev_mcast) ------

------ QTAGUID NETWORK INTERFACES INFO (/proc/net/xt_qtaguid/iface_stat_all) ------

------ QTAGUID NETWORK INTERFACES INFO (xt) (/proc/net/xt_qtaguid/iface_stat_fmt) ------

------ QTAGUID CTRL INFO (/proc/net/xt_qtaguid/ctrl) ------

------ QTAGUID STATS INFO (/proc/net/xt_qtaguid/stats) ------

 

------ LAST KMSG (/proc/last_kmsg) ------

系统重启前的kernel log,相当于cat /proc/last_kmsg或者cat /sys/fs/pstore/console-ramoops,必须系统重启才存在这个log,这里也可以看出系统重启的原因

 

------ POWER ON INFO (/proc/boot_stat) ------

开机后一些重要事件的时间戳

 

------ POWER OFF INFO (/data/log/poweroff_info.txt) ------

------ POWER RESET INFO (/data/log/powerreset_info.txt) ------

------ POWER OFF RESET REASON (/data/log/power_off_reset_reason.txt) ------

------ POWER OFF RESET REASON BACKUP (/data/log/power_off_reset_reason_backup.txt) ------

 

------ NETWORK INTERFACES (ip link) ------

网络设备运行状态

 

------ IPv4 ADDRESSES (ip -4 addr show) ------

------ IPv6 ADDRESSES (ip -6 addr show) ------

------ IP ADDR (ip addr) ------

------ IP RULES (ip rule show) ------

------ IP RULES v6 (ip -6 rule show) ------

IPV4和IPV6相关信息

 

------ TZBSP QSEE LOG (cat /d/tzdbg/qsee_log) ------

------ TZBSP LOG (cat /d/tzdbg/log) ------

高通相关的log?

 

------ INTERRUPTS (1) (/proc/interrupts) ------

------ INTERRUPTS (2) (/proc/interrupts) ------

列出系统当前的中断信息

 

------ SYSTEM PROPERTIES ------

列出系统所有属性的键值对

 

------ FILESYSTEMS & FREE SPACE (df) ------

磁盘容量信息

 

------ PROC FILESYSTEMS (/proc/filesystems) ------

当前内核支持的文件系统

 

------ PACKAGE LIST (/system/xbin/su root cat /data/system/packages.list) ------

所有包的信息

 

------ PACKAGE USAGE LIST (/data/system/package-usage.list: 2016-05-25 15:23:02) ------

------ USAGE HISTORY BACKUP (/data/system/usage-history.xml.backup) ------

 

------ BACKLIGHTS ------

背光信息

 

------ BINDER FAILED TRANSACTION LOG (/sys/kernel/debug/binder/failed_transaction_log) ------

------ BINDER TRANSACTION LOG (/sys/kernel/debug/binder/transaction_log) ------

------ BINDER TRANSACTIONS (/sys/kernel/debug/binder/transactions) ------

------ BINDER STATS (/sys/kernel/debug/binder/stats) ------

binder通信信息

 

========================================================
== Board
========================================================

板级信息

 

------ BACKGROUND BYTES (/proc/sys/vm/dirty_background_bytes) ------

------ BACKGROUND RATIO (/proc/sys/vm/dirty_background_ratio) ------

------ BACKGROUND BYTES (/proc/sys/vm/dirty_bytes) ------

------ DIRTY RATIO (/proc/sys/vm/dirty_ratio) ------

------ SCHEDULER (/sys/block/mmcblk0/queue/scheduler) ------

------ SLICE IDLE (/sys/block/mmcblk0/queue/iosched/slice_idle) ------

------ MAX SECTORS (/sys/block/mmcblk0/queue/max_sectors_kb) ------

------ READ AHEAD (/sys/block/mmcblk0/queue/read_ahead_kb) ------

------ CID (/sys/block/mmcblk0/device/cid) ------

------ CLK SCALING (/sys/devices/msm_sdcc.1/mmc_host/mmc0/clk_scaling/enable) ------

------ CSD (/sys/block/mmcblk0/device/csd) ------

------ CAPS (/sys/block/mmcblk0/device/caps) ------

------ CAPS2 (/sys/block/mmcblk0/device/caps2) ------

------ FILESYSTEMS (/proc/filesystems) ------

这些都是System Memory Info

 

------ Partitions (/proc/partitions) ------

分区信息

 

2. ProcLibRank

========================================================
== Procrank/Librank: Android Framework Services
========================================================

实际上运行的是两个命令procrank和librank

 

procrank从高到低顺序列出进程的内存使用情况

 

------ PROCRANK (procrank) ------
  PID       Vss      Rss      Pss      Uss     Swap  cmdline
  562   123948K   33748K   26013K   25192K     916K  /system/bin/mm-qcamera-daemon

VSS >= RSS >= PSS >= USS

 

VSS:Virtual Set Size,虚拟耗用内存,包含共享库占用的内存,是单个进程全部可访问的地址空间

RSS:Resident Set Size,实际使用物理内存,包含共享库占用的内存,是单个进程实际占用的内存大小,对于单个共享库,无论多少个进程使用,实际该共享库只会装入内存一次。

PSS:Proportional Set Size,实际使用的物理内存,比例分配共享库占用的内存

USS:Unique Set Size,进程独自占用的物理内存,不包含共享库占用的内存,USS是一个非常有用的数字,因为它揭示了运行一个特定进程的真实的内存增量大小。如果进程被终止,USS就是实际被返还给系统的内存大小。

USS是针对某个进程是否有内存泄露,进行检测的最佳数字。怀疑是否有内存泄露可以查看这个值是否一直有增加。
 

3. ShowmapAll

查看每个进程的内存使用信息,实际是运行showmap pid号的命令

 

4. DumpsysAll

========================================================
== DUMPSYS: Android Framework Services
========================================================

查看FrameWork所有service的信息,实际上运行的是dumpsys serviceName

比如:

dumpsys account列出所有账户

dumpsys activity activity的相关信息

dumpsys的代码在android\frameworks\native\cmds\dumpsys\dumpsys.cpp

从源码实现中看,是遍历所有的service,然后调用service->dump()方法,比如查看EmailService的栈

EmailContent$Account.dumpAccountInfo(Context) line: 7597
EmailSyncServiceLogger.dumpAllAccountInfo(Context, PrintWriter) line: 768
EmailService.dump(FileDescriptor, PrintWriter, String[]) line: 395
ActivityThread.handleDumpService(ActivityThread$DumpComponentInfo) line: 3655

 

5. DumpsysOther

dumpsys activity all -> 所有task和task上activity,activity的view Hierachy

dumpsys activity service all ->所有app service的信息

具体参考源码dumpstate.cpp的dumpsys_other()函数

 

三、一些关键字

1、广播相关信息

ACTIVITY MANAGER BROADCAST STATE (dumpsys activity broadcasts)

Registered Receivers 列出系统中所有动态注册的广播接收者ReceiverList,该结构包含一些Intent filter,比如下面的log

 

  * ReceiverList{27d9778 18700 system/1000/u0 local:com.android.server.AlarmManagerService$UninstallReceiver@86fd5ea,7c790db}
    app=18700:system/1000 pid=18700 uid=1000 user=0
    Filter #0: BroadcastFilter{2703e51}
      Action: "android.intent.action.PACKAGE_REMOVED"
      Action: "android.intent.action.PACKAGE_RESTARTED"
      Action: "android.intent.action.PACKAGE_DATA_CLEARED"
      Action: "android.intent.action.QUERY_PACKAGE_RESTART"
      Scheme: "package"
      AutoVerify=false
    Filter #1: BroadcastFilter{6d66b6}
      Action: "android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE"
      Action: "android.intent.action.USER_STOPPED"
      Action: "android.intent.action.UID_REMOVED"
      AutoVerify=false

 

存在Filter #0 和 Filter #1,说明UninstallReceiver这个receiver动态注册了两次,两次注册的filter分别有所不同,过滤的action有所不同,查看AlaramManagerService.java的源码后也确实如此

 

public UninstallReceiver() {
            IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
            filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
            filter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
            filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
            filter.addDataScheme("package");
            getContext().registerReceiver(this, filter);
             // Register for events related to sdcard installation.
            IntentFilter sdFilter = new IntentFilter();
            sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
            sdFilter.addAction(Intent.ACTION_USER_STOPPED);
            sdFilter.addAction(Intent.ACTION_UID_REMOVED);
            getContext().registerReceiver(this, sdFilter);
        }

 

 

 

 

Historical Broadcast foreground 列出位于前台的历史广播

Historical Broadcast background 列出位于后台的历史广播

经常可以查看广播从哪里发出。

2、虚拟机信息

Dalvik Thread

3、查看系统登录了哪些账号

DUMP OF SERVICE account:

属于dumpstate的第四个阶段的DumpsysAll中的dumpsys account

4、等待的intent的状态

ACTIVITY MANAGER PENDING INTENTS (dumpsys activity intents)

5、所有所有注册的broadcastReceiver及其filter、action的信息

ACTIVITY MANAGER BROADCAST STATE (dumpsys activity broadcasts)

6、显示所有content providers信息

ACTIVITY MANAGER CONTENT PROVIDERS (dumpsys activity providers)

7、当前active状态的service信息

ACTIVITY MANAGER SERVICES (dumpsys activity services)

上述4、5、6、7都是发生在dumpsys activity的过程中

8、查看CPU最近的使用情况

DUMP OF SERVICE cpuinfo:

9、查看系统上db的相关情况,app的数据库最近的操作情况

DUMP OF SERVICE dbinfo

10、查看当前的notification,每个NotificationRecord记录一个通知

DUMP OF SERVICE notification

11、查看某个包的信息,包名是AndroidManifest.xml中的包名

Package [com.samsung.android.email.provider]

这里也可以查看app的版本

12、查看是否发生了ANR

WINDOW MANAGER LAST ANR (dumpsys window lastanr)

13、查看data是否连接的信息

DUMP OF SERVICE connectivity

14、查看email service的相关信息

SERVICE com.samsung.android.email.provider/com.samsung.android.email.sync.service.EmailService

SERVICE com.samsung.android.email.provider/com.samsung.android.email.sync.exchange.ExchangeService

15、查看Email是否收到新邮件,更新badge

11-16 14:50:54.314: D/BadgeCache(12920): 1. updateBadgeCounts: com.samsung.android.email.provider = 2,2表示badge的数量

16、查看手机芯片

Chip Name

17、手机使用的网络

Network: China Telecom

18、Debug Level : 1

19、语言Current Lang Name : English (US)

20、查看是哪里启动当前activity,可查看event log

如查到当前activity的event log:am_create_activity

可查看前面am_on_stop_called,am_destroy_activity,am_finish_activity,am_pause_activity,便可以推断出是哪里启动当前activity

21、查看每个进程的流量消耗

------ QTAGUID STATS INFO (/proc/net/xt_qtaguid/stats) ------
idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets


  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值