質問
Androidシステムのデバッグ方法にはどのようなものがありますか? (この分析は Android 7.1.1 システムのソース コードに基づいています)
概要
巨大な Android システムでは、バグは避けられません。開発者にとって、バグはひどいものではありません。重要なのは、デバッグ方法を知ることです。この記事では、Android システムの一般的なデバッグ方法をまとめました。
1 ネイティブ部分のデバッグ
1.1 Linux の標準的なデバッグ方法
Android システムは Linux をベースに実装されているため、システムのデバッグには Linux の標準的な方法を使用できます。Androidシステムには、Linuxのbusyboxに似たツールセットtoyboxがあります。一般的に使用される一般的な Linux のデバッグ方法には、主に次のようなものがあります。
- システムツール
- ネットワーク関連ツール
- /dev/device ファイルと /sys/pseudo-filesystem
- システムパフォーマンスツール
- gdbのデバッグ
Android 7.1.1 システムがインストールされている私の Nexus5 携帯電話に関しては、基本的にはおもちゃ箱とツールボックスのツールセットのコマンドです
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
1.1.1 システムツール
例: ps、mount、umount、lsmod、kill、その他のコマンド。
1.1.2 ネットワーク関連ツール
例: ifconfig、netstat、rouute、iftopd、その他のコマンド。
1.1.3 /dev/device ファイルと /sys/pseudo-ファイル システム
Linux システムのデバイス ファイルは /dev/ ディレクトリにあり、デバイス関連の情報は /sys ファイル システムにあります。これらのファイルの内容は現在のデバイス情報を反映しており、これを通じてシステムのさまざまなステータスを知ることができます。
1.1.4 システムパフォーマンスツール
例: vmstat、top、その他のコマンド。
vmstat (仮想メモリ統計) コマンドは、カーネル スレッド、仮想メモリ ディスク、トラップ、および CPU アクティビティに関する統計を報告します。vmstat コマンドによって生成されたレポートは、システム負荷アクティビティのバランスをとるために使用できます。vmstat の実行プロセス中に、システムの現在の実行ステータスを示すコンテンツ行が定期的に出力されます。
- r: 実行キューで待機しているプロセスの数。
- b: 待機中のプロセスの数。
- w: 置き換えられる実行キューに入ることができるプロセス。
- free: 空きメモリ (ユニット k)。
- マップ済み: マップされたメモリ (ユニット k)。
- in: クロック割り込みを含む、1 秒あたりの割り込み数。
- cs: 1 秒あたりの環境 (コンテキスト) スイッチの数。
- us: CPU 使用時間。
- sy: CPU システム使用時間。
- ID: アイドル時間。
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
......
1.1.5 gdbのデバッグ
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 の使用方法は 2 つあり、1 つはコマンド ラインからアプリケーションを起動する方法、もう 1 つは既に実行中のプロセスに接続 (アタッチ) する方法です。COMM は接続のタイプを示し、TTY デバイスまたは HOST:PORT 形式の TCP ネットワーク接続を使用できます。標準の gdb と同様に、デバッグするコードはコンパイルして -g モードで接続する必要があります。これは、デバッグ バージョンを生成することを意味します。
Android ホスト システムは、システム パッケージを通じて gdb を使用して次のことを行うことができます。
source build/envsetup.sh
gdbclient <port> <pid>
たとえば、通常は次のように使用されます。これにより、ターゲットマシンの gdbserver が自動的に起動されます。
gdbclient :5039 1
1.2 ログの利用方法
1.2.1 ログの書き込み
Android のローカル コード ログは統一された方法を使用します。ヘッダー ファイルは system/core/include/cutils/log.h で、実際には libutils の Log.h に log.h が含まれています。
Android の純粋な C コードでは、通常、ログは次の方法で追加されます。
//#define LOG_NDEBUG 0
#define LOG_TAG "XXX" //Log的前缀
#include <cutils/log.h> //包含C工具库的头文件
Android C++ コードでは、通常、ログは次の方法で追加されます。
//#define LOG_NDEBUG 0
#define LOG TAG "XXX" //Log 的前缀
#include <utils/Log.h> //包含 C++工具库的头文件
DEBUG デバッグ情報を取得するには #define LOG_NDEBUG 0 のコメントを解除します。LOGT_AG はデバッグ情報のプレフィックスを表します。LOGV()、LOGD()、LOGI()、LOGW()、および LOGE() は 5 つの異なるログ レベルを表します。
1.2.2 ログの表示
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 <expr>, --regex=<expr>
Only print lines where the log message matches <expr>
where <expr> is a regular expression
-m <count>, --max-count=<count>
Quit after printing <count> 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 <count> Print only the most recent <count> lines (implies -d)
-t '<time>' Print most recent lines since specified time (implies -d)
-T <count> Print only the most recent <count> 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 <size>, --buffer-size=<size>
Set size of log ring buffer, may suffix with K or M.
-L, -last Dump logs from prior to last reboot
-b <buffer>, --buffer=<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=<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
<tag>[:priority]
where <tag> is a log component tag (or * for all) and priority is:
V Verbose (default for <tag>)
D Debug (default for '*')
I Info
W Warn
E Error
F Fatal
S Silent (suppress all output)
'*' by itself means '*:D' and <tag> by itself means <tag>:V.
If no '*' filterspec or -s on command line, all filter defaults to '*:V'.
eg: '*:S <tag>' prints only <tag>, '<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"
1.3 Android 固有のデバッグ方法
Android にはデバッグ用の非標準の補助手段がいくつかあります。これらは Linux シェルの標準コンテンツではなく、Android システムの固有コンテンツです。
1.3.1 いくつかの個別ツール
- netcfg
netcfg は、主にネットワーク インターフェイス、つまりネットワーク デバイスをアップリンク、ダウンリンク、または DHCP (ネットワーク アドレスを動的に取得) として設定できます。 - vdc
vold の補助ツール。 - ndc netd
の補助ツール。 - sdcard
sdcard ツールは、デバイスに SD カードをエミュレートさせるために使用されます。
1.3.2 システム情報取得ツール
Android には、システムのさまざまな側面に関する情報を表示するための、dumpstate、dumpsys、bugreport などのいくつかのツールも提供されています。
- dumpstate ツールは、sys ファイル システムにアクセスして他のツールを呼び出すことにより、システム デバイスの状態をエクスポートするために使用されます。
- dumpsys ツールはシステム サービスのさまざまな側面に関する情報をエクスポートしますが、出力コンテンツも比較的大きくなります。
- bugreport ツールは同様の機能を提供し、実際には dumpstate ツールを呼び出します。
1.3.3 ツールボックス内の特殊ツール
- setprop/getprop
システム プロパティ値を設定または取得します。 - start/stop
は、init プロセスでサービスを開始または停止するために使用されます。これら 2 つのツールの本質は、init プロセスによって処理される ctl.start.<service name> プロパティと ctl.stop.<service name> プロパティを設定することです。 - ioctl
ユーザーはデバイス ノードの ioctl コマンドを直接制御できるため、プログラムを作成せずに一部のテスト作業を実行できます。
ioctl プログラムを使用して、フレームバッファ ドライバのステータスを確認します。フレームバッファ情報を取得するための ioctl コマンド FBIOGET_VSCREENINFO は、linux/fb.h ヘッダー ファイルで 0x4600 として定義されており、ioctl コマンド FBIOGET_VSCREENINFO で使用される構造体は struct fb_var_screeninf であり、最初の数バイトの内容は次のとおりです。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
上記のコマンドは 16 バイトのメッセージを読み取り、取得した情報は、画面の可視幅が 1080 (0x438)、可視高さは 1920 (0x780)、仮想幅は 1080 (0x438)、仮想高さは 1080 (0x438) であることを示します。は 3840 ( 0xf00)、これはダブルバッファ画面です。struct fb_var_screeninfo { __u32 xres; /*可见分辨率*/ __u32 yres; __u32 xres_virtual; /*虚拟分辨率 */ __u32 yres_virtual; ...... }
1.3.4 サービスツール
この記事を参照してください: Android システム パーティションとファイル システム (5) - Android Framework レイヤーのツールとコマンド
1.3.5 straceツール
システムコール関連のデバッグツール。
2 Java パーツのデバッグ
2.1 Java でのログインの使用
import android.util.Log;
2.2 Java レイヤー用のコマンドライン ツール
am、pm、dalvikvm およびその他のコマンドなど、dalvikvm と前の 2 つのコマンドの違いに注意してください。この記事を参照してください: Android システム パーティションとファイル システム (5) - Android Framework レイヤーのツールとコマンド
2.3 コード内容に関するデバッグ
Android の Java コードには、特別なデバッグ方法がいくつかあります。デバッグの基本は、実際には、Dalvik 仮想マシンが提供する特別なメカニズムを使用して、外部プログラムが Dalvik 仮想マシンと対話できるようにすることです。
2.3.1 基本的なデバッグ
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 は、いくつかのパブリック フィールドを含む静的クラスです。これらは、現在のプロセスのメモリ マップに関する情報を表します。
シーンは仮想マシン (dalvik)、ローカル (ネイティブ)、その他 (other) の 3 つのタイプに分けられ、メモリ
タイプは 3 つのタイプに分けられます: Pss は実際に使用される物理メモリ (比例セット サイズ) を示し、PrivateDirty はプライベート ダーティを示しますページ、SharedDirty 共有ダーティ ページを示します。
Debug.structsCount は、プログラム内で実行される命令とメソッドの数をカウントするもう 1 つのサブクラスです。簡単な例は次のとおりです。
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)执行的总数
}
特定のメソッドや命令によって消費されるリソースを厳密に「数値」で測定することはできないためです。一般に、struct はプログラムの CPU 消費量を大まかにカウントするためにのみ使用されます。
デバッグ実行の精度は比較的高く、コードに Debug クラスを追加すると、現在のプロセスの実行状況に関するリアルタイムの情報を取得できます。
Dalvik 仮想マシンには特別なシグナル ハンドラーがあるため、Android の Java プロセスによって送信されるいくつかのシグナルは特別な意味を持ち、アプリケーションのデバッグに使用できます。
- SIGQUIT シグナルを送信します (3): /data/misc/anr/ トレース情報を生成します。
- SIGUSR1 シグナルを送信します (10): リソースをリサイクルします (GC)。
2.3.2 プログラムの追跡
Debug クラスの主な機能の 1 つは、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/ のようなルート ディレクトリを追加する場合は、このディレクトリがアプリケーションによって書き込み可能である必要があります。実行後、test.trace ファイルなど、接尾辞がtrace のファイルがディレクトリに生成されます。
トレース ファイル (*.trace) をホストにインポートし、Android で提供される Traceview ツールを使用してその内容を分析します。
2.3.3 Hprof 分析
HProf ツールはメモリ (ヒープ プロファイル) を分析するために使用されます。これには、実際には一部のメモリと 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 ツールは、疑わしい問題 (問題の疑い) を直接リストできます。
2.3.4 サンプリングプロファイラ
libcore/dalvik/src/main/java/dalvik/system/SamplingProfiler.java、少なくとも Android7 はなくなっています
2.3.5 厳密モードのチェック
StrictMode は、アプリケーションのメイン スレッド (UI スレッド) で例外をチェックし、開発者に通知して修正できるようにします。例: 時間のかかるディスクの読み取り/書き込み、ネットワーク アクセスなど。
StrictMode は、android.os パッケージ内のクラスです。StrictMode の検出機能をオンにすると、プログラム内でポリシーに違反する操作があった場合、プログラムの実行時に開発者にプロンプトが表示されます。StrictMode は 2 つの戦略を担当します。1 つはスレッド戦略、もう 1 つは仮想マシン (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() は、デフォルトの厳密モード ポリシーが使用され、ポリシーのすべての違反がログを使用して記録されることを示します。StrictMode.ThreadPolicy と StrictMode.VmPolicy は StrictMode の 2 つのサブクラスで、それぞれスレッドと仮想マシンのポリシーを表すために使用されます。これらはすべて、ビルド サブクラスの 1 つを使用してビルドされます。StrictMode.ThreadPolicy のビルド サブクラスのメイン メソッドは次のとおりです。
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()
検知と許可は対応しており、前者は事態が発生した場合に検知して対応することを意味し、後者はすべてを許可して事態に対応しないことを意味します。操作はディスク読み取り、ディスク書き込み、ネットワーク アクセスに分かれており、すべてはすべてを意味します。検知が実施されルール違反があった場合には「ペナルティ(ペナルティ)」とも呼ばれる結果が発生します。ルール違反の結果を設定するには、次のようないくつかのメソッドが使用されます。
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 のビルド サブクラスのメイン メソッドは次のとおりです。
public StrictMode.VmPolicy.Builder detectAll()
public StrictMode.VmPolicy.Builder detectLeakedSqlliteObjects()
主に SQLiteCursor などのデータベース オブジェクトの使用を目的としており、使用が終了していない状況です。StrictMode.VmPolicy のビルド サブクラスのいくつかのペナルティは、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 検査の範囲には含まれません。
2.4 DDMS ツール
このツールは APP の動的デバッグに使用され、AndroidStudio のインストール後に SDK/ツールに含まれています。
2.5 階層ビューアツール
HierarchyViewer の意味は階層ビューアであり、表示されるオブジェクトは View ツリーの階層構造です。HierarchyViewerh は、Layout-View (レイアウトからビュー) の属性と階層関係をリストすることもできます。