- Android系統(tǒng)級深入開發(fā)
- 韓超 梁泉
- 4098字
- 2018-12-29 13:39:31
3.4.2 調試的方法
由于Android系統(tǒng)基于Linux,Android中的調試方式首先可以利用標準Linux的基本調試的方法,除此之外,Android中還有特定的調試方法。
1.查看系統(tǒng)進程的情況
首先可以在終端使用ps命令查看系統(tǒng)的進程。啟動Android的仿真器環(huán)境,然后使用adb shell進行連接,使用ps查看各個進程,如下所示:
# ps USER PID PPID VSIZE RSS WCHAN PC NAME root 1 0 312 220 c009b74c 0000ca4c S /init root 2 0 0 0 c004e72c 00000000 S kthreadd root 3 2 0 0 c003fdc8 00000000 S ksoftirqd/0 root 4 2 0 0 c004b2c4 00000000 S events/0 root 5 2 0 0 c004b2c4 00000000 S khelper root 6 2 0 0 c004b2c4 00000000 S suspend root 7 2 0 0 c004b2c4 00000000 S kblockd/0 root 8 2 0 0 c004b2c4 00000000 S cqueue root 9 2 0 0 c018179c 00000000 S kseriod root 10 2 0 0 c004b2c4 00000000 S kmmcd root 11 2 0 0 c006fc74 00000000 S pdflush root 12 2 0 0 c006fc74 00000000 S pdflush root 13 2 0 0 c00744e4 00000000 S kswapd0 root 14 2 0 0 c004b2c4 00000000 S aio/0 root 22 2 0 0 c017ef48 00000000 S mtdblockd root 23 2 0 0 c004b2c4 00000000 S kstriped root 24 2 0 0 c004b2c4 00000000 S hid_compat root 25 2 0 0 c004b2c4 00000000 S rpciod/0 root 26 2 0 0 c019d16c 00000000 S mmcqd root 27 1 740 220 c0158eb0 afd0d8ac S /system/bin/sh system 28 1 808 208 c01a94a4 afd0db4c S /system/bin/servicemanager root 29 1 3736 372 ffffffff afd0e1bc S /system/bin/vold root 30 1 3716 316 ffffffff afd0e1bc S /system/bin/netd root 31 1 668 184 c01b52b4 afd0e4dc S /system/bin/debuggerd radio 32 1 5392 480 ffffffff afd0e1bc S /system/bin/rild root 33 1 81940 22164 c009b74c afd0dc74 S zygote media 34 1 19508 1836 ffffffff afd0db4c S /system/bin/mediaserver bluetooth 35 1 1260 288 c009b74c afd0e98c S /system/bin/dbus-daemon root 36 1 812 236 c02181f4 afd0d8ac S /system/bin/installd keystore 37 1 1616 216 c01b52b4 afd0e4dc S /system/bin/keystore root 38 1 740 220 c003da38 afd0e7bc S /system/bin/sh root 39 1 840 280 c00b8fec afd0e90c S /system/bin/qemud root 41 1 3384 176 ffffffff 0000ecc4 S /sbin/adbd root 54 38 796 248 c02181f4 afd0d8ac S /system/bin/qemu-props system 62 33 152636 30928 ffffffff afd0db4c S system_server app_9 121 33 108964 18128 ffffffff afd0eb08 S com.android.inputmethod.latin radio 125 33 120308 19396 ffffffff afd0eb08 S com.android.phone app_27 128 33 108092 21528 ffffffff afd0eb08 S com.android.launcher system 131 33 109420 16932 ffffffff afd0eb08 S com.android.settings app_8 157 33 118524 22096 ffffffff afd0eb08 S android.process.acore app_0 182 33 116196 17064 ffffffff afd0eb08 S com.android.mms app_16 188 33 104244 17520 ffffffff afd0eb08 S android.process.media app_6 207 33 106856 18020 ffffffff afd0eb08 S com.android.email app_10 218 33 103260 16800 ffffffff afd0eb08 S com.android.bluetooth app_12 226 33 10421617020ffffffffafd0eb08Scom.android.providers.calendar app_15 240 33 103028 16900 ffffffff afd0eb08 S com.android.deskclock app_3 248 33 102408 15832 ffffffff afd0eb08 S com.android.protips app_4 255 33 105144 16748 ffffffff afd0eb08 S com.android.quicksearchbox app_13 262 33 103452 16164 ffffffff afd0eb08 S com.android.music root 268 41 740 328 c003da38 afd0e7bc S /system/bin/sh root 282 268 888 332 00000000 afd0d8ac R ps
從Android系統(tǒng)的進程中可以看到,1號和2號進程以0號進程為父進程。init是系統(tǒng)運行的第1個用戶空間進程,即Android根目下的init可執(zhí)行程序,這是一個用戶空間的進程。kthreadd是系統(tǒng)的2號進程,這是一個內核進程,其他內核進程都直接或間接以kthreadd為父進程。
系統(tǒng)的各個守護進行由init進行運行,例如Zygote、/system/bin/sh、/system/bin/mediaserver、/system/bin/adbd等,因此它們的父進程號為1,即以init為父進程。
各種文字名稱的進程表示Android應用程序的進程,例如android.process.acore、com.android.mms等進程代表的是應用程序進程,它們的父進程都是zygote。例如,在本例中它們的父進程id均為33。
本例中ps命令的進城id為282,其父進程是pid為268的/system/bin/sh,可見這個命令是從sh分支出來的,而pid為268的/system/bin/sh的父進程是pid為41的/system/bin/adbd (adb守護進程)。
使用Linux的proc文件系統(tǒng),也可以查看進程相關的信息,在/proc目錄中,包含了各個進程的信息,每個進程一個目錄,就是進程的id。
例如,查看27號進程的目錄如下所示:
# ls -l /proc/27/ dr-xr-xr-x root root 2010-08-13 03:39 task dr-x------ root root 2010-08-13 03:39 fd dr-x------ root root 2010-08-13 03:39 fdinfo dr-xr-xr-x root root 2010-08-13 03:39 net -r-------- root root 0 2010-08-13 03:39 environ -r-------- root root 0 2010-08-13 03:39 auxv -r--r--r-- root root 0 2010-08-13 03:39 status -r-------- root root 0 2010-08-13 03:39 personality -r-------- root root 0 2010-08-13 03:39 limits -rw-r--r-- root root 0 2010-08-13 03:39 sched -r--r--r-- root root 0 2010-08-13 03:38 cmdline -r--r--r-- root root 0 2010-08-13 03:34 stat -r--r--r-- root root 0 2010-08-13 03:39 statm -r--r--r-- root root 0 2010-08-13 03:39 maps -rw------- root root 0 2010-08-13 03:39 mem lrwxrwxrwx root root 2010-08-13 03:39 cwd -> / lrwxrwxrwx root root 2010-08-13 03:39 root -> / lrwxrwxrwx root root 2010-08-13 03:39 exe -> /system/bin/sh -r--r--r-- root root 0 2010-08-13 03:39 mounts -r--r--r-- root root 0 2010-08-13 03:39 mountinfo -r-------- root root 0 2010-08-13 03:39 mountstats --w------- root root 0 2010-08-13 03:39 clear_refs -r--r--r-- root root 0 2010-08-13 03:39 smaps -r-------- root root 0 2010-08-13 03:39 pagemap -r--r--r-- root root 0 2010-08-13 03:39 wchan -r--r--r-- root root 0 2010-08-13 03:39 schedstat -r--r--r-- root root 0 2010-08-13 03:39 cgroup -r--r--r-- root root 0 2010-08-13 03:39 oom_score -rw-r--r-- root root 0 2010-08-13 03:39 oom_adj -rw-r--r-- root root 0 2010-08-13 03:39 coredump_filter
在每個進程的目錄中,包含了若干個文件的子目錄,其中cmdline文件表示了這個進程所在的命令行:
# cat /proc/27/cmdline /system/bin/sh
由此可見,這個27號進程就是shell程序。查看status文件,可以獲知這個進程的一些相關信息。對27號進程的查看如下所示:
# cat /proc/27/status Name: sh # 進程名稱 State: S (sleeping) # 進程狀態(tài) Tgid: 27 # 線程組ID Pid: 27 # 進程ID PPid: 1 # 父進程ID TracerPid: 0 Uid:0 0 0 0 Gid:0 0 0 0 FDSize: 1024 Groups: VmPeak: 744 kB # 虛擬內存相關消息 VmSize: 744 kB VmLck: 0 kB VmHWM: 316 kB VmRSS: 264 kB VmData: 92 kB VmStk: 84 kB VmExe: 80 kB VmLib: 460 kB VmPTE: 12 kB Threads: 1 # 所包含的線程數(shù) SigQ: 0/768 SigPnd: 0000000000000000 ShdPnd: 0000000000000000 SigBlk: 0000000000000000 SigIgn: 0000000000284004 SigCgt: 00000000000094ea CapInh: 0000000000000000 CapPrm: fffffffffffffeff CapEff: fffffffffffffeff CapBnd: fffffffffffffeff voluntary_ctxt_switches: 38 nonvoluntary_ctxt_switches: 1
stat文件實際上包含了比status文件更多的信息,但是可讀性比較差,因此一般查看status文件。
進程目錄中的fd文件,表示了這個進程中所打開的文件的描述符。對27號進程的查看如下所示:
# ls /proc/27/fd 0 1 2 9 1023
進程目錄中的task目錄表示了這個進程所包含的子進程,也就是這個進程中所包含的線程,目錄的名稱也就是子進程的id。對27號進程的查看如下所示:
# ls /proc/27/task 27
27號進程只包含一個進程,即27號進程自己。
在Linux操作系統(tǒng)的內核的角度出發(fā),進程和線程沒有區(qū)別。在用戶空間建立的線程(例如,通過pthread建立的)在內核的情況就是一個進程,也就是上述的子進程。事實上,這些子進程的目錄結構和進程是一樣的。
對于34號進程mediaserver,情況如下所示:
# cat /proc/34/cmdline /system/bin/mediaserver # ls 34 58 59 60 61 98
除了34之外,還包含了58,59,60,61,98這4個文件夾,由此可見,mediaserver進程已經包含了若干個子進程。如果查看其status文件,也能發(fā)現(xiàn)相應信息。
2.統(tǒng)計系統(tǒng)性能消息
在Linux中有一些可以統(tǒng)計系統(tǒng)性能的方法,在Android中也有所支持。使用vmstat和top命令可以統(tǒng)計系統(tǒng)中性能的信息。
vmstat(Virtual Meomory Statistics,虛擬內存統(tǒng)計),命令報告關于內核線程、虛擬內存、磁盤、陷阱和CPU活動的統(tǒng)計信息。由vmstat命令生成的報告可以用于平衡系統(tǒng)負載活動。
vmstat的使用如下所示:
# vmstat & # procs memory system cpu r b free mapped anon slab in cs flt us ni sy id wa ir 0 0 3792 21112 50864 3724 27 66 0 1 0 1 99 0 0 0 0 3792 21112 50864 3724 22 53 0 0 0 0 99 0 0 0 0 3792 21112 50864 3724 28 63 0 1 0 2 98 0 0 1 0 1752 22168 51348 3744 94 235 4 43 0 18 39 0 0 10 1 1384 20968 52932 3760 123 555 21 60 0 38 0 2 0 11 1 1700 19340 53424 3852 366 322 8 80 0 21 0 0 0 5 0 1996 19748 53688 3800 150 337 5 82 0 17 0 0 0 4 1 1320 20584 53568 3688 154 584 15 67 0 33 0 0 0 2 1 1632 20448 53624 3500 150 422 18 66 0 33 0 1 0
vmstat的結構中幾個比較重要的值的含義如下所示。
r:在運行隊列中等待的進程數(shù)
b:在等待io的進程數(shù)
w:可以進入運行隊列但被替換的進程
free:空閑的內存(單位k)
mapped:影射的內存(單位k)
in:每秒的中斷數(shù),包括時鐘中斷
cs:每秒的環(huán)境(上下文)切換次數(shù)
us:CPU使用時間
sy:CPU系統(tǒng)使用時間
id:閑置時間
top程序主要可以檢測各個進程對CPU的消耗情況,信息將一屏一屏的階段性地打印到屏幕上。
在Android中,第1次top程序的使用如下所示:
# top & User 93%, System 6%, IOW 0%, IRQ 0% User 309 + Nice 0 + Sys 20 + Idle 0 + IOW 0 + IRQ 0 + SIRQ 0 = 329 PID CPU% S #THR VSS RSS PCY UID Name 270 82% S 17 133980K 21628K fg app_5 com.cooliris.media 62 12% S 44 152976K 25928K fg system system_server 301 3% R 1 908K 388K fg root top 4 0% S 1 0K 0K fg root events/0 5 0% S 1 0K 0K fg root khelper 6 0% S 1 0K 0K fg root suspend 7 0% S 1 0K 0K fg root kblockd/0 8 0% S 1 0K 0K fg root cqueue 9 0% S 1 0K 0K fg root kseriod 10 0% S 1 0K 0K fg root kmmcd 11 0% S 1 0K 0K fg root pdflush 12 0% S 1 0K 0K fg root pdflush 13 0% S 1 0K 0K fg root kswapd0 14 0% S 1 0K 0K fg root aio/0
top使用的第2次統(tǒng)計的內容如下所示:
User 14%, System 5%, IOW 0%, IRQ 0% User 47 + Nice 0 + Sys 18 + Idle 249 + IOW 0 + IRQ 0 + SIRQ 0 = 314 PID CPU% S #THR VSS RSS PCY UID Name 34 13% S 14 29084K 2928K fg media /system/bin/mediaserver 62 3% S 44 153040K 26532K fg system system_server 301 3% R 1 916K 404K fg root top 125 0% S 17 119236K 16508K fg radio com.android.phone 39 0% S 1 844K 336K fg root /system/bin/qemud 6 0% S 1 0K 0K fg root suspend 7 0% S 1 0K 0K fg root kblockd/0 8 0% S 1 0K 0K fg root cqueue 9 0% S 1 0K 0K fg root kseriod 10 0% S 1 0K 0K fg root kmmcd 11 0% S 1 0K 0K fg root pdflush 12 0% S 1 0K 0K fg root pdflush 13 0% S 1 0K 0K fg root kswapd0 14 0% S 1 0K 0K fg root aio/0
以上top程序統(tǒng)計的情況是,剛剛打開Gallery(3D版本)程序,因此com.cooliris. media,也就是Gallery3D的程序,這個進程占用的CPU消耗最大,同時top程序本身也占用了一些CPU消耗。然后打開了視頻播放程序,因此,/system/bin/mediaserver進程的消耗變?yōu)樽畲蟆?/p>
Andoir中還提供了dumpstat和dumpsys兩個工具,可以用于將各個進程的stat中的信息和sys文件系統(tǒng)的內容導出。這兩個工具導出的內容都較多,最好在主機端配合adb來使用,例如:
$ adb shell dumpstat | grep CPU
3.內核和驅動的調試
使用dmesg可以查看內核打印出來信息,如下所示:
# dmesg
ioctl是Android中的一個工具,用戶可以直接控制設備節(jié)點的ioctl命令,這樣可以在沒有寫程序的情況下進行一些測試工作。
ioctl的使用如下所示:
# ioctl -h ioctl [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr> -l <lenght> 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
例如,使用ioctl程序,查看framebuffer驅動的情況如下所示:
# 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 return buf: 40 01 00 00 e0 01 00 00 40 01 00 00 c0 03 00 00
linux/fb.h中定義了獲取framebuffer信息的ioctl命令FBIOGET_VSCREENINFO為0x4600,如下所示:
#define FBIOGET_VSCREENINFO 0x4600
FBIOGET_VSCREENINFO這個ioctl命令使用的結構體為struct fb_var_screeninfo,前面幾個字節(jié)的內容如下所示
struct fb_var_screeninfo { __u32 xres; /* 可見分辨率 */ __u32 yres; __u32 xres_virtual; /* 虛擬分辨率 */ __u32 yres_virtual; /* ......省略部分內容 */ }
以上的命令使用讀取了16字節(jié)的消息,得到的信息的含義為:
0x140==320 0x1E0==480 0x3C0==960
因此,表示屏幕的可見的寬為320,可見的高為480,虛擬的寬為320,虛擬的高為960,這就是雙緩沖的屏幕。
4.Android的特殊調試命令
在Android的toolbox中包含了一些非標準化的輔助命令,這些命令在Linux的shell中沒有,專門為Android系統(tǒng)所用。
netcfg是Android中的一個網絡工具,用于配置網絡,使用方法如下所示
# netcfg -h usage: netcfg [<interface> {dhcp|up|down}]
在仿真器連接網絡的情況上查看:
# netcfg lo UP 127.0.0.1 255.0.0.0 0x00000049 eth0 UP 10.0.2.15 255.255.255.0 0x00001043 tunl0 DOWN 0.0.0.0 0.0.0.0 0x00000080 gre0 DOWN 0.0.0.0 0.0.0.0 0x00000080
Service工具用于和Android一個已經啟動的Service進行通信。Service命令的使用方式如下所示:
# service -h Usage: service [-h|-?] service list service check SERVICE service call SERVICE CODE [i32 INT | s16 STR] ... Options: i32: Write the integer INT into the send parcel. s16: Write the UTF-16 string STR into the send parcel.
使用service list可以顯示系統(tǒng)已經啟動的服務,如下所示:
# service list Found 49 services: 0 phone: [com.android.internal.telephony.ITelephony] 1 iphonesubinfo: [com.android.internal.telephony.IPhoneSubInfo] 2 simphonebook: [com.android.internal.telephony.IIccPhoneBook] 3 isms: [com.android.internal.telephony.ISms] 45 media.audio_policy: [android.media.IAudioPolicyService] 46 media.camera: [android.hardware.ICameraService] 47 media.player: [android.media.IMediaPlayerService] 48 media.audio_flinger: [android.media.IAudioFlinger]
這里顯示的服務包括了Java層啟動的服務和C中啟動的服務。例如以上列出的內容中:phone就是Java層啟動的服務,media.player中就是C中啟動的服務。
使用service check查看服務的狀態(tài),如下所示:
# service check media.player Service media.player: found
使用service call調用進程的情況如下所示:
# service call media.player 3 s16 "file:///sdcard/a.mp4" Result: Parcel( 0x00000000: 00000000 40806d54 a821a0e5 73622a85 '....Tm.@..!..*bs' 0x00000010: 0000017f 00000000 00000000 '............ ') # D/MediaPlayerService( 34): Can't decode by path, use filedescriptor instead
事實上,這種調用已經調用到了MediaPlayerService中的函數(shù),因此打印出了上述的調試信息。
am命令是在控制臺中可以非常容易調試程序的工具,例如可以啟動活動、啟動服務和發(fā)送廣播等功能。am命令的基本使用方法如下所示:
# am usage: am [subcommand] [options] start an Activity: am start [-D] [-W] <INTENT> -D: enable debugging -W: wait for launch to complete start a Service: am startservice <INTENT> send a broadcast Intent: am broadcast <INTENT> start an Instrumentation: am instrument [flags] <COMPONENT> -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT) -e <NAME> <VALUE>: set argument <NAME> to <VALUE> -p <FILE>: write profiling data to <FILE> -w: wait for instrumentation to finish before returning start profiling: am profile <PROCESS> start <FILE> stop profiling: am profile <PROCESS> stop
使用am start是其中的一個功能,以INTENT作為參數(shù),INTENT使用的選項如下所示:
<INTENT> specifications include these flags: [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>] [-c <CATEGORY> [-c <CATEGORY>] ...] [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...] [--esn <EXTRA_KEY> ...] [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...] [-e|--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...] [-n <COMPONENT>] [-f <FLAGS>] [--grant-read-uri-permission] [--grant-write-uri-permission] [--debug-log-resolution] [--activity-brought-to-front] [--activity-clear-top] [--activity-clear-when-task-reset] [--activity-exclude-from-recents] [--activity-launched-from-history] [--activity-multiple-task] [--activity-no-animation] [--activity-no-history] [--activity-no-user-action] [--activity-previous-is-top] [--activity-reorder-to-front] [--activity-reset-task-if-needed] [--activity-single-top] [--receiver-registered-only] [--receiver-replace-pending] [<URI>]
使用am命令啟動計算器應用(實際是使用顯式Intent)的方式如下所示:
# am start -n com.android.calculator2/com.android.calculator2.Calculator
使用am命顯示一幅圖片(實際是使用隱式Intent)的方式如下所示:
# am start -a android.intent.action.VIEW -d file:///sdcard/a.jpg -t image/*
5.Logcat工具
logcat是Android中的一個命令行工具,可以用于得到程序的log信息。Logcat的使用方法如下所示:
logcat [options] [filterspecs]
logcat工具的具體選項如表3-2所示。
表3-2 logcat工具的選項

在Android的本地代碼中,通常具有如下的設置。
//#define LOG_NDEBUG 0 #define LOG_TAG "XXX" #include <utils/Log.h>
將#define LOG_NDEBUG 0的注釋取消,即可獲得DEBUG的調試信息,而LOG_TAG表示調試信息的前綴。
- scikit-learn Cookbook
- DBA攻堅指南:左手Oracle,右手MySQL
- The Modern C++ Challenge
- Moodle Administration Essentials
- 軟件架構設計:大型網站技術架構與業(yè)務架構融合之道
- Visual C++實例精通
- Building Mapping Applications with QGIS
- Getting Started with SQL Server 2012 Cube Development
- Windows Phone 7.5:Building Location-aware Applications
- 單片機C語言程序設計實訓100例
- ExtJS Web應用程序開發(fā)指南第2版
- Advanced UFT 12 for Test Engineers Cookbook
- HTML5+CSS3+JavaScript 從入門到項目實踐(超值版)
- Django Design Patterns and Best Practices
- Clojure Polymorphism