Android 系统的调试方法有哪些?(此篇分析基础为Android 7.1.1系统源码)
偌大的Android系统中,出bug是难免的,对于开发者而言出bug不可怕,关键是要知道如何debug。此篇总结下Android系统常用的调试方法。
由于Android 系统基于 Linux 实现,在系统中可以使用 Linux 中标准的方法进行调试。在Android系统中有一个类似于 Linux 中 busybox 一样的工具集 toybox 。常用的通用 Linux 的调试方法主要包括以下几个:
以我安装了Android 7.1.1 系统的 Nexus5手机而言,基本是toybox和toolbox工具集中的命令
hammerhead:/system/bin # ls -al|grep toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 acpi -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 arp -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 base64 -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 basename -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 blockdev -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 bzcat -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 cal -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 cat -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 chattr -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 chcon -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 chgrp -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 chmod -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 chown -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 chroot -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 chrt -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 cksum -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 clear -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 cmp -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 comm -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 cp -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 cpio -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 cut -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 date -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 df -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 diff -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 dirname -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 dmesg -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 dos2unix -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 du -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 echo -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 env -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 expand -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 expr -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 fallocate -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 false -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 fdisk -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 file -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 find -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 flock -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 free -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 freeramdisk -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 fsfreeze -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 fstype -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 ftpget -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 ftpput -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 getenforce -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 getfattr -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 getprop -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 groups -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 head -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 help -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 host -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 hostname -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 hwclock -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 id -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 ifconfig -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 inotifyd -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 insmod -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 install -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 ionice -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 iorenice -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 kill -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 killall -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 ln -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 load_policy -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 logname -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 losetup -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 ls -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 lsattr -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 lsmod -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 lsof -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 lspci -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 lsusb -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 makedevs -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 md5sum -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 mkdir -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 mkfifo -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 mknod -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 mkswap -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 mktemp -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 modinfo -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 more -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 mount -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 mountpoint -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 mv -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 nbd-client -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 nc -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 netcat -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 netstat -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 nice -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 nl -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 nohup -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 nproc -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 od -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 partprobe -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 paste -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 patch -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 pgrep -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 pidof -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 pivot_root -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 pkill -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 pmap -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 printenv -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 printf -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 pwd -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 pwdx -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 readahead -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 readlink -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 realpath -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 renice -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 reset -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 resize -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 restorecon -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 rev -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 rfkill -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 rm -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 rmdir -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 rmmod -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 route -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 runcon -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 sed -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 seq -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 setenforce -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 setfattr -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 setprop -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 setsid -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 sha1sum -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 sha224sum -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 sha256sum -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 sha384sum -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 sha512sum -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 sleep -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 sort -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 split -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 stat -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 strings -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 swapoff -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 swapon -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 sync -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 sysctl -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 tac -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 tail -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 tar -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 taskset -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 tee -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 telnet -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 test -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 time -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 timeout -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 touch -> toybox
-rwxr-xr-x 1 root shell 358624 2022-05-17 17:39 toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 tr -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 traceroute -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 true -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 truncate -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 tty -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 tunctl -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 ulimit -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 umount -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 uname -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 uniq -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 unix2dos -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 uptime -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 usleep -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 vconfig -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 vmstat -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 watch -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 wc -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 which -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 whoami -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 xargs -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 xxd -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 xzcat -> toybox
lrwxr-xr-x 1 root shell 6 2022-05-17 17:39 yes -> toybox
hammerhead:/system/bin # ls -al|grep toolbox
lrwxr-xr-x 1 root shell 7 2022-05-16 19:11 dd -> toolbox
lrwxr-xr-x 1 root shell 7 2022-05-16 19:11 getevent -> toolbox
lrwxr-xr-x 1 root shell 7 2022-05-16 19:11 iftop -> toolbox
lrwxr-xr-x 1 root shell 7 2022-05-16 19:11 ioctl -> toolbox
lrwxr-xr-x 1 root shell 7 2022-05-16 19:11 log -> toolbox
lrwxr-xr-x 1 root shell 7 2022-05-16 19:11 nandread -> toolbox
lrwxr-xr-x 1 root shell 7 2022-05-16 19:11 newfs_msdos -> toolbox
lrwxr-xr-x 1 root shell 7 2022-05-16 19:11 prlimit -> toolbox
lrwxr-xr-x 1 root shell 7 2022-05-16 19:11 ps -> toolbox
lrwxr-xr-x 1 root shell 7 2022-05-16 19:11 restart -> toolbox
lrwxr-xr-x 1 root shell 7 2022-05-16 19:11 sendevent -> toolbox
lrwxr-xr-x 1 root shell 7 2022-05-16 19:11 start -> toolbox
lrwxr-xr-x 1 root shell 7 2022-05-16 19:11 stop -> toolbox
-rwxr-xr-x 1 root shell 88960 2022-05-16 19:11 toolbox
lrwxr-xr-x 1 root shell 7 2022-05-16 19:11 top -> toolbox
如:ps、mount、umount、lsmod、kill等命令。
如:ifconfig、netstat、rouute、iftopd等命令。
Linux 系统设备文件位于 /dev/ 目录中,设备相关的信息位于 /sys 文件系统中。这些文件内容都是当前设备信息的反映,通过他们可以得知很多系统状态。
如:vmstat、top等命令。
vmstat (Virtual Meomory Statistics,虚拟内存统计),命令报告关于内核线程、虚拟内存磁盘、陷阱和 CPU 活动的统计信息。由 vmstat 命令生成的报告可以用于平衡系统负载活动。vmstat 在运行过程中,会定期打出一行的内容,表示系统当前的运行状态:
hammerhead:/system/bin # vmstat
procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
r b swpd free buff cache si so bi bo in cs us sy id wa
2 0 0 591988 34120 526384 0 0 3 2 0 35 0 0 99 0
top 命令表示列出系统最耗资源的进程,主要可以检测各个进程对 CPU 的消耗情况,信息将一屏一屏的阶段性地打印到终端上。打印出的信息中,VSS (Virtual Set Size) 表示进程使用的虚拟内存,RSS(Resident Set Size) 表示进程使用的物理内存。
hammerhead:/system/bin # top
User 3%, System 10%, IOW 0%, IRQ 0%
User 1 + Nice 0 + Sys 3 + Idle 25 + IOW 0 + IRQ 0 + SIRQ 0 = 29
PID USER PR NI CPU% S #THR VSS RSS PCY Name
19907 root 20 0 27% R 1 4560K 1552K fg top
1462 root 13 -7 3% S 7 11380K 1444K fg /system/bin/mpdecision
3 root 20 0 0% S 1 0K 0K fg ksoftirqd/0
7 root 0 -20 0% D 1 0K 0K fg kworker/u:0H
8 root RT 0 0% S 1 0K 0K fg migration/0
13 root 0 -20 0% S 1 0K 0K fg khelper
14 root 0 -20 0% S 1 0K 0K fg netns
18 root 0 -20 0% S 1 0K 0K fg modem_notifier
......
在Android 中 gdb 调试的方法和标准的 Linux 相同,主机运行 gdb 调试程序,目标机运行 gdbserver。需要找到某种主机到目标机的连接方式。例如,在目标系统使用网络的 adb情况下,adb 默认使用 5555 端口,可以将其他端口给 gdb 使用。
hammerhead:/system/bin # ls gdbserver -al
-rwxr-xr-x 1 root shell 596484 2022-05-16 19:11 gdbserver
hammerhead:/system/bin # ./gdbserver
Usage: gdbserver [OPTIONS] COMM PROG [ARGS ...]
gdbserver [OPTIONS] --attach COMM PID
gdbserver [OPTIONS] --multi COMM
COMM may either be a tty device (for serial debugging),
HOST:PORT to listen for a TCP connection, or '-' or 'stdio' to use
stdin/stdout of gdbserver.
PROG is the executable program. ARGS are arguments passed to inferior.
PID is the process ID to attach to, when --attach is specified.
Operating modes:
--attach Attach to running process PID.
--multi Start server without a specific program, and
only quit when explicitly commanded.
--once Exit after the first connection has closed.
--help Print this message and then exit.
--version Display version information and exit.
Other options:
--wrapper WRAPPER -- Run WRAPPER to start new programs.
--disable-randomization
Run PROG with address space randomization disabled.
--no-disable-randomization
Don't disable address space randomization when
starting PROG.
Debug options:
--debug Enable general debugging output.
--debug-format=opt1[,opt2,...]
Specify extra content in debugging output.
Options:
all
none
timestamp
--remote-debug Enable remote protocol debugging output.
--disable-packet=opt1[,opt2,...]
Disable support for RSP packets or features.
Options:
vCont, Tthread, qC, qfThreadInfo and
threads (disable all threading packets).
For more information, consult the GDB manual (available as on-line
info or a printed manual).
gdbserver 的使用方式有两种,一种是命令行启动一个应用,另一种是连接(attach)到个已经运行进程上。COMM 表示连接的类型,可以使用一个TTY 设备或者 HOST:PORT 格式的 TCP 网络连接。与标准的 gdb 使用相同,需要对所调试的代码以 -g 的方式进行编译和连接,表示生成调试版本。
Android 主机系统使用 gdb 可以通过系统的封装进行:
source build/envsetup.sh
gdbclient <port> <pid>
例如,通常按照如下的方式来进行使用,将自动启动目标机的 gdbserver
gdbclient :5039 1
Android 中本地代码 log 使用统一的方式。头文件是 system/core/include/cutils/log.h,实际上 libutils 的 Log.h 包含了 log.h。
在 Android 的纯 C 代码中,通常使用如下的方式加入 log:
//#define LOG_NDEBUG 0
#define LOG_TAG "XXX" //Log的前缀
#include //包含C工具库的头文件
在 Android 的 C++ 代码中,通常使用如下的方式加入 log:
//#define LOG_NDEBUG 0
#define LOG TAG "XXX" //Log 的前缀
#include //包含 C++工具库的头文件
将 #define LOG_NDEBUG 0 的注释取消,即可获得 DEBUG 的调试信息,而 LOGT_AG表示调试信息的前缀。LOGV()、LOGD()、LOGI()、LOGW() 和 LOGE() 表示 5 个不同的 log 级别。
使用logcat命令
hammerhead:/system/bin # logcat --help
Usage: logcat [options] [filterspecs]
options include:
-s Set default filter to silent. Equivalent to filterspec '*:S'
-f <file>, --file=<file> Log to file. Default is stdout
-r <kbytes>, --rotate-kbytes=<kbytes>
Rotate log every kbytes. Requires -f option
-n <count>, --rotate-count=<count>
Sets max number of rotated logs to <count>, default 4
-v <format>, --format=<format>
Sets the log print format, where <format> is:
brief color epoch long monotonic printable process raw
tag thread threadtime time uid usec UTC year zone
-D, --dividers Print dividers between each log buffer
-c, --clear Clear (flush) the entire log and exit
if Log to File specified, clear fileset instead
-d Dump the log and then exit (don't block)
-e , --regex=
Only print lines where the log message matches
where is a regular expression
-m , --max-count=
Quit after printing lines. This is meant to be
paired with --regex, but will work on its own.
--print Paired with --regex and --max-count to let content bypass
regex filter but still stop at number of matches.
-t Print only the most recent lines (implies -d)
-t ' <time>' Print most recent lines since specified time (implies -d)
-T Print only the most recent lines (does not imply -d)
-T ' <time>' Print most recent lines since specified time (not imply -d)
count is pure numerical, time is 'MM-DD hh:mm:ss.mmm...'
'YYYY-MM-DD hh:mm:ss.mmm...' or 'sssss.mmm...' format
-g, --buffer-size Get the size of the ring buffer.
-G , --buffer-size=
Set size of log ring buffer, may suffix with K or M.
-L, -last Dump logs from prior to last reboot
-b , --buffer= Request alternate ring buffer, ' main',
'system', 'radio', 'events', 'crash', 'default' or 'all'.
Multiple -b parameters or comma separated list of buffers are
allowed. Buffers interleaved. Default -b main,system,crash.
-B, --binary Output the log in binary.
-S, --statistics Output statistics.
-p, --prune Print prune white and ~black list. Service is specified as
UID, UID/PID or /PID. Weighed for quicker pruning if prefix
with ~, otherwise weighed for longevity if unadorned. All
other pruning activity is oldest first. Special case ~!
represents an automatic quicker pruning for the noisiest
UID as determined by the current statistics.
-C colored output
-P '<list> ...', --prune='<list> ...'
Set prune white and ~black list, using same format as
listed above. Must be quoted.
--pid= Only prints logs from the given pid.
--wrap Sleep for 2 hours or when buffer about to wrap whichever
comes first. Improves efficiency of polling by providing
an about-to-wrap wakeup.
filterspecs are a series of
[:priority]
where is a log component tag (or * for all) and priority is:
V Verbose (default for )
D Debug (default for ' *')
I Info
W Warn
E Error
F Fatal
S Silent (suppress all output)
'*' by itself means '*:D' and by itself means :V.
If no ' *' filterspec or -s on command line, all filter defaults to '*:V'.
eg: '*:S <tag>' prints only , ' <tag>:S' suppresses all <tag> log messages.
If not specified on the command line, filterspec is set from ANDROID_LOG_TAGS.
If not specified with -v on command line, format is set from ANDROID_PRINTF_LOG
or defaults to "threadtime"
在Android 有一些用于调试非标准化的辅助手段,不是 Linux 的 shell 标准的内容,而是 Android 系统特有的内容。
Android 中还提供了 dumpstate、dumpsys、bugreport 等几个工具,用于查看系统各个方面的信息。
hammerhead:/system/bin # ioctl -h
ioctl [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr>
-l <length> Length of io buffer
-a <argsize> Size of each argument (1-8)
-r Open device in read only mode
-d Direct argument (no iobuffer)
-h Print help
hammerhead:/system/bin # ioctl -l 16 -r /dev/graphics/fb0 0x4600
sending ioctl 0x4600 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 to /dev/graphics/fb0
return buf: 38 04 00 00 80 07 00 00 38 04 00 00 00 0f 00 00
使用 ioctl 程序,查看 framebuffer 驱动的情况。linux/fb.h 头文件中定义了获取 framebufer 信息的 ioctl 命令FBIOGET_VSCREENINFO 为 0x4600,并且 FBIOGET_VSCREENINFO 这个 ioctl 命令使用的结构体为 struct fb_var_screeninf,前面几个字节的内容如下所示:struct fb_var_screeninfo {
__u32 xres; /*可见分辨率*/
__u32 yres;
__u32 xres_virtual; /*虚拟分辨率 */
__u32 yres_virtual;
......
}
以上的命令使用读取了 16 字节的消息,得到的信息表示屏幕可见的宽为 1080(0x438)可见的高为 1920 (0x780),虚拟的宽为 1080 (0x438),虚拟的高为 3840(0xf00),这就是双缓冲的屏幕。参考此篇:Android 系统的分区和文件系统(5)- Android Framework层上的工具和命令
系统调用相关的调试工具。
import android.util.Log;
如:am、pm、dalvikvm等命令,注意 dalvikvm 与前两者的区别。参考此篇:Android 系统的分区和文件系统(5)- Android Framework层上的工具和命令
Android 的 Java 代码中有一些特殊的调试方法。调试的基础实际上是利用 Dalvik 虚拟机提供的特殊机制,让外部的程序与之进行交互。
android.os 包中的 Debug 是一个与调试相关的类。Debug 类中有众多的 get 函数用于获得系统的各种信息。例如,线程相关信息,统计内存等。源码位置:Frameworks/base/core/java/android/os/Debug.java,Debug 类中一些常用的方法如下所示:
// 获得 Java 虚拟机相关的内存信息:空闲数目,空闲大小,垃圾回收调用次数,类数目
public static int getGlobalFreedCount() {...}
public static int getGlobalFreedSize() {...}
public static int getGlobalGcInvocationCount() {...}
public static int getLoadedClassCount() {...}
// 获取本地堆内存信息
public static native long getNativeHeapAllocatedSize();
public static native long getNativeHeapSize();
public static native long getNativeHeapFreeSize();
//获得线程的信息,线程的数目和大小
public static int getThreadAllocCount() {...}
public static int getThreadAllocSize() {...}
与上述方法相对应的是一系列 resetXXX() 方法,用于重设上述相关的信息。不过上面这些方法都已经是@Deprecated的了,另有一个比较高级的方法如下所示:
public static native void getMemoryInfo(MemoryInfo memoryInfo);
Debug.MemoryInfo 是一个静态的类,这个类当中包含了一些公共的域。它们表示了当前进程内存映射的信息。
场景分为3 种:虚拟机 (dalvik)、本地 (native) 和其他 (other);
内存类型分为3种:Pss 表示实际使用的物理内存(Proportional Set Size),PrivateDirty 表示私有的脏页, SharedDirty 表示共享脏页。
Debug.InstructionCount 是另外一个子类,用于计算程序中执行的指令数目和方法数目。简单的示例如下:
import android.os.Debug;
import android.os.Debug.InstructionCount;
Debug.InstructionCount icount = new Debug.InstructionCount();
icount.resetAndstart();
//执行实际的工作
if (icount.collect()) { // 返回 boolean 类型,表示是否采集到
icount.globalTotal(); // 指令(Instruction)执行的总数
icount.globalMethodInvocations(); // 方法(Method)执行的总数
}
由于具体方法和指令消耗的资源并不能严格按照“数目”衡量。在一般情况下,InstructionCount 仅仅用于粗略统计一个程序耗费 CPU 的情况。
Debug 执行的精确度比较高,在代码中加入 Debug 类之后,可以实时获得当前进程运行情况的信息。
Dalvik 虚拟机具有特殊信号处理器,因此对任何 Android 中的 Java 进程发送的一些信号,具有特殊的含义,可以用来调试应用程序。
Debug 类的一个主要功能是获取 Android Java 代码运行过程中的跟踪文件。得到跟踪文件之后,可以进一步通过文件分析代码运行的资源占用率等信息。
import android.os.Debug;
android.os.Debug.startMethodTracing("/data/trace/test"); // test,trace
/* ...需要剖析的内容... */
android.os.Debug.stopMethodTracing();
在 startMethodTracing() 和 stopMethodTracing() 之间运行的代码,就是被跟踪文件提供运行信息的部分。其中 startMethodTracing() 的参数是输出跟踪文件的路径,如果不加路径,默认的路径就是 /sdcard/ 。如果增加了类似 /data/trace/ 根式的目录,则要求这个目录应用程序可以写。运行后将在目录中生成后缀名为 trace 的文件,例如 test.trace 文件。
将跟踪文件 (*.trace) 导入到主机,可以使用 Android 中提供的 traceview 工具分析其内容。
HProf 工具用于对内存的剖析 (Heap Profile),实际上包含了部分内存和 CPU 的运行的信息。Debug 类具有如下的方法用于获得 HProf 文件:
public static void dumpHprofData(String fileName) throws IOException {
VMDebug.dumpHprofData(fileName);
}
在代码中,通常需要加入如下的内容来获得HProf:
import android.os.Debug;
import java.io.IOException;
try {
android.os.Debug.dumpHprofData(“/data/hprof/test.hprof”}
catch (IOException ioe) {//异常处理}
}
test.hprof 文件就是执行后的输出结果。这个文件不能被直接处理,需要使用 Android 中的 hprod-conv 工具将其转化,方法如下所示:
hprof-conv test.hprof out.hprof
获得 out.hprof 文件之后,可以使用 Java 中一种名称为 MAT(Memory Analyzer Tool) 的工具来进行分析。MAT 工具可以直接列出值得怀疑的问题(Problem Suspect)。
libcore/dalvik/src/main/java/dalvik/system/SamplingProfiler.java,至少Android7 已经没有了
StrictMode 可以检查应用程序主线程(UI线程)中的意外,并引起开发者的注意,以此让开发者修复它们。例如:耗费时间较多的磁盘读/写、网络访问等。
StrictMode 是 android.os 包中的一个类。打开了 StrictMode 的检测功能之后,如果程序中有违反策略的操作,程序运行时就会提示开发者。StrictMode 负责两个方面的策略,一个是线程方面的策略,一个是虚拟机(vm)方面的策略。类中主要包含以下几个静态的方法:
public static void enableDefaults()
public static ThreadPolicy getThreadPolicy()
public static void setThreadPolicy(final ThreadPolicy policy)
public static VmPolicy getVmPolicy()
public static void setVmPolicy(final VmPolicy policy)
enableDefaults() 表示使用默认的严格模式策略,所有违反策略的情况使用 Log 来进行记录。StrictMode.ThreadPolicy 和 StrictMode.VmPolicy 是 StrictMode 的两个子类,分别用于表示线程和虚拟机两个方面的策略。它们都使用其中的 build 子类来构建。StrictMode.ThreadPolicy 的 build 子类的主要方法如下所示:
public StrictMode.ThreadPolicy.Builder detectAll() //所有的
public StrictMode.ThreadPolicy.Builder permitAll()
public StrictMode.ThreadPolicy.Builder detectDiskReads() //磁盘读
public StrictMode.ThreadPolicy.Builder permitDiskReads()
public StrictMode.ThreadPolicy.Builder detectDiskWrites() //磁盘写
public StrictMode.ThreadPolicy.Builder permitDiskWrites()
public StrictMode.ThreadPolicy.Builder detectNetwork() //网络访问
public StrictMode.ThreadPolicy.Builder permitNetwork()
detect 和 permit 二者对应,前者表示进行检测,如果情况发生就会有所反应,后者表示允许所有,对情况不做出反应。操作分成磁盘读、磁盘写和网络访问,all 表示所有的。如果实施了检测,出现违反规则情况,将造成的结果,也称为“处罚 (penalty)”。几个方法用于设置违反规则造成的结果,如下所示:
public StrictMode.ThreadPolicy.Builder penaltyLog() //在Log中提示
public StrictMode.ThreadPolicy.Builder penaltyDialog() //在对话框提示
public StrictMode.ThreadPolicy.Builder penaltyDropBox() //在DropBox提示
public StrictMode.ThreadPolicy.Builder penaltyDeath() //让程序崩溃
一个程序设置线程策略可以如下所示:
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
.detectAl1().penaltyLog().build(); //检测所有,使用Log提示
StrictMode.setThreadPolicy(policy);
StrictMode.VmPolicy 的 build 子类的主要方法如下所示:
public StrictMode.VmPolicy.Builder detectAll()
public StrictMode.VmPolicy.Builder detectLeakedSqlliteObjects()
主要针对了使用 SQLiteCursor 等数据库的对象,并且使用完成还没有关闭的情况。StrictMode.VmPolicy 的 build 子类的几个处罚和 StrictMode.ThreadPolicy 中类似。一个程序设置虚拟机策略可以如下所示:
StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder()
.detectAll().penaltyLog().build(); //检测所有,使用Log提示
StrictMode.setVmPolicy(policy);
StrictMode 的设置通常在 Application、Activity 或者其他组件的 onCreate() 方法中进行设置。这种设置应该仅限于开发者调试的模式。StrictMode 的提示是在尽量严格的情况下对程序中可能出现的问题的一种提示,并不表示所有违反规则的情况都需要修正。当进行发布的时候,不应该使用任何的严格模式限定。
StrictMode 的原理主要是在 Java 框架层代码中加入了检查机制。如果使用 JNI 操作磁盘和访问网络,则不在StrictMode 的检查范围中。此外,如果通过 Binder 进行远程调用,也不在 StrictMode 的检查范围中。
用于APP动态调试,此工具在AndroidStudio安装后的SDK/tools中。
HierarchyViewer 的含义为层级查看器,查看的对象是 View 树的层次结构。HierarchyViewerh 还可以列出 Layout-View(布局到视图)的属性和层次关系。