[android]使用jdb调试android应用程序

简介:
觉得eclipse太过臃肿,或者机器资源有限,不妨试试用jdb命令行中调试java程序。先要确保adb工作正常,用adb jdwp列出支持JDPW的进程ID。
835
$ adb jdwp:
876
873
879
926
956
989
999
1010
1022

用adb shell ps查看进程的信息。 
system 835 793 208564 29768 ffffffff afe0c57c S system_server
radio 873 793 112816 21252 ffffffff afe0d674 S com.android.phone
app_8 876 793 98044 17336 ffffffff afe0d674 S android.process.media
app_7 879 793 123780 28452 ffffffff afe0d674 S android.process.acore
app_0 926 793 104916 18372 ffffffff afe0d674 S com.google.process.gapps
app_11 956 793 96008 16392 ffffffff afe0d674 S com.android.alarmclock
app_16 989 793 105304 16772 ffffffff afe0d674 S com.android.mms
app_23 999 793 96324 15552 ffffffff afe0d674 S org.broncho.powermonitor
app_19 1010 793 98492 16044 ffffffff afe0d674 S com.android.setupwizard
app_7 1022 793 106708 19204 ffffffff afe0d674 S com.android.inputmethod.pinyin



确定要调试的进程ID之后,建立网络数据转发关系。 
假设这里要调试进程873。
adb forward tcp:9000 jdwp:873


设置jdb源代码路径,这里设置了android系统内的JAVA路径,如果调试自己的应用程序 ,可以加在后面。 
export ANDROID_SRC=/broncho/cupcake/dev
export ANDROID_SRC_PATH=$ANDROID_SRC/frameworks/base/opengl/java:$ANDROID_SRC/frameworks/base/awt/java:$ANDROID_SRC/frameworks/base/core/java:$ANDROID_SRC/frameworks/base/location/java:$ANDROID_SRC/frameworks/base/sax/java:$ANDROID_SRC/frameworks/base/graphics/java:$ANDROID_SRC/frameworks/base/telephony/java:$ANDROID_SRC/frameworks/base/services/java:$ANDROID_SRC/frameworks/base/media/java:$ANDROID_SRC/frameworks/base/wifi/java:$ANDROID_SRC/frameworks/base/im/java:$ANDROID_SRC/dalvik/libcore/suncompat/src/main/java:$ANDROID_SRC/dalvik/libcore/nio_char/src/main/java:$ANDROID_SRC/dalvik/libcore/nio_char/src/main/java/java:$ANDROID_SRC/dalvik/libcore/security-kernel/src/main/java:$ANDROID_SRC/dalvik/libcore/security-kernel/src/main/java/java:$ANDROID_SRC/dalvik/libcore/security/src/main/java:$ANDROID_SRC/dalvik/libcore/security/src/main/java/java:$ANDROID_SRC/dalvik/libcore/archive/src/main/java:$ANDROID_SRC/dalvik/libcore/archive/src/main/java/java:$ANDROID_SRC/dalvik/libcore/awt-kernel/src/main/java:$ANDROID_SRC/dalvik/libcore/awt-kernel/src/main/java/java:$ANDROID_SRC/dalvik/libcore/luni/src/main/java:$ANDROID_SRC/dalvik/libcore/luni/src/main/java/java:$ANDROID_SRC/dalvik/libcore/math/src/main/java:$ANDROID_SRC/dalvik/libcore/math/src/main/java/java:$ANDROID_SRC/dalvik/libcore/x-net/src/main/java:$ANDROID_SRC/dalvik/libcore/openssl/src/main/java:$ANDROID_SRC/dalvik/libcore/dalvik/src/main/java:$ANDROID_SRC/dalvik/libcore/auth/src/main/java:$ANDROID_SRC/dalvik/libcore/concurrent/src/main/java:$ANDROID_SRC/dalvik/libcore/concurrent/src/main/java/java:$ANDROID_SRC/dalvik/libcore/sql/src/main/java:$ANDROID_SRC/dalvik/libcore/sql/src/main/java/java:$ANDROID_SRC/dalvik/libcore/prefs/src/main/java:$ANDROID_SRC/dalvik/libcore/prefs/src/main/java/java:$ANDROID_SRC/dalvik/libcore/xml/src/main/java:$ANDROID_SRC/dalvik/libcore/text/src/main/java:$ANDROID_SRC/dalvik/libcore/text/src/main/java/java:$ANDROID_SRC/dalvik/libcore/luni-kernel/src/main/java:$ANDROID_SRC/dalvik/libcore/luni-kernel/src/main/java/java:$ANDROID_SRC/dalvik/libcore/regex/src/main/java:$ANDROID_SRC/dalvik/libcore/regex/src/main/java/java:$ANDROID_SRC/dalvik/libcore/nio/src/main/java:$ANDROID_SRC/dalvik/libcore/nio/src/main/java/java:$ANDROID_SRC/dalvik/libcore/json/src/main/java:$ANDROID_SRC/dalvik/libcore/crypto/src/main/java:$ANDROID_SRC/dalvik/libcore/icu/src/main/java:$ANDROID_SRC/dalvik/libcore/annotation/src/main/java:$ANDROID_SRC/dalvik/libcore/annotation/src/main/java/java:$ANDROID_SRC/dalvik/libcore/junit/src/main/java:$ANDROID_SRC/dalvik/libcore/logging/src/main/java:$ANDROID_SRC/dalvik/libcore/logging/src/main/java/java:$ANDROID_SRC/dalvik/libcore-disabled/instrument/src/main/java:$ANDROID_SRC/dalvik/libcore-disabled/instrument/src/main/java/java:$ANDROID_SRC/dalvik/libcore-disabled/sound/src/main/java



启动jdb
jdb -sourcepath $ANDROID_SRC_PATH -attach localhost:9000


这里的端口号9000,是由前面的tcp:9000决定。然后就可以使用jdb的各种调试命令了。方便起见可以使用jdbshell。 

附: 
jdb/jdbshell基本调试技巧: 

jdbshell兼容所有jdb命令,只是另外加了些命令缩写、记录历史、命令自动补全和命令行编辑等功能。 

1.用threads查询所有线程: 
命令: 
threads


结果显示示例:
组 system:
(java.lang.Thread)0xc14360d1e8 <7> Signal Catcher 条件正在等待
(java.lang.Thread)0xc142850040 <5> HeapWorker 条件正在等待
组 main:
(java.lang.Thread)0xc140018e50 <3> main 条件正在等待
(java.lang.Thread)0xc143767c78 <59> Binder Thread #16 正在运行
(java.lang.Thread)0xc143744d48 <57> Binder Thread #15 正在运行
(java.lang.Thread)0xc143757458 <51> Binder Thread #14 正在运行
(java.lang.Thread)0xc14374ab88 <55> Binder Thread #13 正在运行
(java.lang.Thread)0xc14376d698 <53> Binder Thread #12 正在运行
(java.lang.Thread)0xc143615478 <45> Binder Thread #11 正在运行
(java.lang.Thread)0xc1437317b0 <49> Binder Thread #10 正在运行
(java.lang.Thread)0xc1436e8c38 <47> Binder Thread #9 正在运行
(java.lang.Thread)0xc14374eb50 <43> Binder Thread #8 正在运行
(java.lang.Thread)0xc1437000e0 <41> Binder Thread #7 正在运行
(android.os.HandlerThread)0xc1436dd9d0 <37> ContactsAsyncWorker 条件正在等待
(java.lang.Thread)0xc143681fb8 <35> Binder Thread #6 正在运行
(java.lang.Thread)0xc143681ef8 <33> Binder Thread #5 正在运行
(java.lang.Thread)0xc143659170 <31> Stk App Service 条件正在等待
(java.lang.Thread)0xc14368bc88 <29> Binder Thread #4 正在运行
(java.lang.Thread)0xc14368ad00 <27> Binder Thread #3 正在运行
(android.os.HandlerThread)0xc1436597a0 <25> AsyncQueryWorker 条件正在等待
(android.os.HandlerThread)0xc143656c00 <23> Stk Icon Loader 条件正在等待
(android.os.HandlerThread)0xc143656580 <21> RilMessageDecoder 条件正在等待
(android.os.HandlerThread)0xc1436560a0 <19> Stk Telephony service 条件正在等待
(java.lang.Thread)0xc143643c70 <17> RILReceiver 正在运行
(android.os.HandlerThread)0xc143641858 <15> RILSender 条件正在等待
(java.lang.Thread)0xc14360ee08 <13> Binder Thread #2 正在运行
(java.lang.Thread)0xc14360df90 <11> Binder Thread #1 正在运行


2.选择你感兴趣的线程。 
命令: 
thread 0xc1436dd9d0



结果显示示例:
<37> ContactsAsyncWorker[1]



和gdb不同的是,这里使用线程的ID,而不是线程的序号。这个问题让我折腾了好久,问了好几个做JAVA的朋友,原来他们都不用jdb。 

3.暂停线程。 
命令: 
suspend 0xc1436dd9d0



4.显示调用堆栈。 
命令:
wherei


结果显示示例: 
[1] java.lang.Object.wait (本机方法)
[2] java.lang.Object.wait (Object.java:288), pc = 3
[3] android.os.MessageQueue.next (MessageQueue.java:148), pc = 153
[4] android.os.Looper.loop (Looper.java:110), pc = 8
[5] android.os.HandlerThread.run (HandlerThread.java:60), pc = 28


5.切换调用堆栈的frame: 

命令: 
up [n 帧] – 向上移动线程的堆栈 
down [n 帧] – 向下移动线程的堆栈 

和gdb不同的时,这里指定的是要切换的frame与当前frame的偏移,而不是frame的索引。 

结果显示示例:
<37> ContactsAsyncWorker[1] up
<37> ContactsAsyncWorker[2]


6.设置断点 

命令: 
stop at <类>:<行号> 或
stop in <类>.<方法名>[(参数类型,...)]


结果显示示例:
> stop at com.android.phone.SimContacts$ImportAllThread:124
设置 断点 com.android.phone.SimContacts$ImportAllThread:124



7.显示某个类的信息。有时要在嵌套类里设置断点,这个命令可能有帮助。 
命令: 
class <类 ID> – 显示已命名的类的详细信息 

结果显示示例:
>class com.android.phone.SimContacts
类:com.android.phone.SimContacts
扩展: com.android.phone.ADNList
嵌套: com.android.phone.SimContacts$ImportAllThread


8.继续运行 
命令: 
step – 执行当前行
step up – 执行到当前方法返回到其调用程序
stepi – 执行当前指令
next – 跳过一行(跨过调用)
cont – 从断点处继续执行


9.清除断点 
命令:
clear <类 ID>.<方法>[(参数类型,...)] – 清除方法中的断点
clear <类 ID>:<行> – 清除行中的断点
clear – 列出断点


10.查看源代码 
命令: 
list [line number|method] – 输出源代码 

11.jdbshell命令缩写 
command alias:
c — cont
l — list
n — next
r — run
s — step
si — stepi
f — step up
bt — wherei

目录
相关文章
|
3天前
|
Android开发
Android应用实例(一)之---有道辞典VZ.0
Android应用实例(一)之---有道辞典VZ.0
10 2
|
12天前
|
移动开发 Java Android开发
构建高效Android应用:Kotlin协程的实践之路
【4月更文挑战第30天】在移动开发领域,随着用户需求的不断增长和设备性能的持续提升,实现流畅且高效的用户体验已成为开发者的首要任务。针对Android平台,Kotlin协程作为一种新兴的异步编程解决方案,以其轻量级线程管理和简洁的代码逻辑受到广泛关注。本文将深入探讨Kotlin协程的概念、优势以及在实际Android应用中的运用,通过实例演示如何利用协程提升应用性能和响应能力,为开发者提供一条构建更高效Android应用的实践路径。
|
1天前
|
移动开发 API Android开发
构建高效Android应用:Kotlin协程的实践指南
【5月更文挑战第11天】 在移动开发领域,性能优化和资源管理是至关重要的。特别地,对于Android开发者来说,合理利用Kotlin协程可以极大地改善应用的响应性和稳定性。本文将深入探讨Kotlin协程在Android中的实际应用,包括它们如何简化异步编程模型、提高UI线程的响应性,以及减少内存消耗。我们将通过具体案例分析,了解如何在实际项目中有效地使用协程,从而帮助开发者构建更加高效的Android应用程序。
|
2天前
|
开发工具 Android开发 Windows
Android应用] 问题2:ERROR: unknown virtual device name:
Android应用] 问题2:ERROR: unknown virtual device name:
|
2天前
|
XML JSON API
转Android上基于JSON的数据交互应用
转Android上基于JSON的数据交互应用
|
4天前
|
安全 Java Android开发
构建高效Android应用:采用Kotlin进行内存优化的策略
【5月更文挑战第8天】 在移动开发领域,性能优化一直是开发者关注的焦点。特别是对于Android应用而言,合理管理内存资源是确保应用流畅运行的关键因素之一。近年来,Kotlin作为官方推荐的开发语言,以其简洁、安全和互操作性的特点受到开发者青睐。本文将深入探讨利用Kotlin语言特性,通过具体策略对Android应用的内存使用进行优化,旨在帮助开发者提高应用性能,减少内存消耗,避免常见的内存泄漏问题。
8 0
|
5天前
|
Shell Android开发
Android Activity重写dump方法实现通过adb调试代码
Android Activity重写dump方法实现通过adb调试代码
11 0
|
5天前
|
移动开发 数据库 Android开发
构建高效Android应用:Kotlin协程的全面应用
【5月更文挑战第7天】 在移动开发领域,性能优化与流畅的用户体验是至关重要的。随着Kotlin语言的流行,其并发神器——协程,已成为提升Android应用性能的重要工具。本文将深入探讨如何在Android项目中利用Kotlin协程进行异步编程、网络请求和数据库操作,以及如何通过协程简化代码结构,增强应用的响应性和稳定性。我们的目标是为开发者提供一套实用的协程使用模式和最佳实践,以便构建更加高效的Android应用。
21 3
|
5天前
|
移动开发 数据库 Android开发
构建高效Android应用:Kotlin与协程的完美结合
【5月更文挑战第7天】 在移动开发领域,性能优化和资源管理始终是核心议题。随着Kotlin语言的普及,其提供的协程特性为Android开发者带来了异步编程的新范式。本文将深入探讨如何通过Kotlin协程来优化Android应用的性能,实现流畅的用户体验,并减少资源消耗。我们将分析协程的核心概念,并通过实际案例演示其在Android开发中的应用场景和优势。
|
8天前
|
移动开发 前端开发 Android开发
构建高效Android应用:探究Kotlin协程的优势
【5月更文挑战第4天】 在移动开发领域,尤其是对于Android开发者而言,编写响应迅速且高效的应用程序至关重要。Kotlin作为一种现代的编程语言,其提供的协程特性为异步编程带来了革命性的改变。本文将深入探讨Kotlin协程在Android开发中的应用优势,并通过实例代码展示如何利用协程简化异步任务处理,提高应用性能和用户体验。