调试 Android* x86 应用程序的方法以及要使用的工具

1.简介

众所周知,Android* 开发人员头顶许多称呼:设计员、程序猿等,并且通常会不可避免地被称为故障检修工。代码中的错误无法避免,因此无论您是否一开始就造成错误,了解调试工具以及如何迅速而有效地跟踪并解决错误都很重要。鉴于此,如今的 Android 开发人员必须掌握有效的调试技巧。本文提供了 Android 应用程序调试工具的简单教学,用于帮助 Android SDK 以及相关工具的新手迅速入门,并在 Android x86 平台上更有效地解决故障。

2.SDK 应用程序调试工具

Android SDK 提供了试应用程序所需的大多数工具。如果希望进行诸如单步调试代码、查看变量值以及暂停执行应用程序的操作,则需要兼容 JDWP 的调试程序。如果使用 Eclipse,则已附带兼容 JDWP 的调试程序,无需设置。如果使用其它 IDE,则可使用其附带的调试程序并将调试程序与特殊端口连接,使其可以和您设备上的应用程序虚拟机通信。

如果使用 ADT(Android 开发工具)插件在 Eclipse 中进行开发,则可使用内置的 Java* 调试程序并结合 DDMS(Dalvik 调试监测程序服务器)来调试应用程序。为了便于访问调试程序和 DDMS,Eclipse 以视图形式显示调试程序和 DDMS 功能,这些都是自定义的 Eclipse 视图,根据您所在的视图显示特定选项卡和窗口。Eclipse 还可负责为您启动ADB (Android Debug Bridge) 主机守护程序,从而无需手动运行该工具。如果使用其他 IDE 进行调试,则可使用 Android SDK 提供的所有调试工具,例如 ADB、DDMS、Java 调试程序等。

图 1. Dalvik 调试监测程序服务器

借助 DDMS,开发人员可查看进程的堆区使用情况、跟踪对象的内存分配、使用模拟器或设备的文件系统、检查线程信息、获取方法配置、使用网络流量工具(在 Android 4.0 中提供)、使用 LogCat 跟踪代码信息以及模拟手机操作和位置。如欲了解更多信息,请参阅 http://developer.android.com/guide/developing/debugging/ddms.html。Android SDK 还提供 Hierarchy Viewer(层级观察器)和 layoutopt(布局优化分析工具)帮助开发人员调试布局问题。

Hierarchy Viewer 应用程序可让您调试并优化您的用户界面 (UI)。它以可视方式呈现布局的视图层级(View Hierarchy 口),提供放大的显示视图(Pixel Perfect 窗口)。

图 2. Hierarchy Viewer(层级查看器)

View Hierarchy窗口显示形成您设备上或模拟器上运行的活动的 UI 的视图对象。您可以用它在整个视图树的上下文中查看各个视图对象。对于每个视图对象,View Hierarchy 窗口还显示渲染性能数据。在选择节点时,视图的额外信息出现在节点上方的小窗口中。 在单击其中一个节点时,可看到有关图像、视图计数和渲染时间的信息。

图 3. 查看对象信息窗口

Pixel Perfect 是一个工具,用于检查像素属性并通过设计图排布用户界面。Pixel Perfect 窗口显示模拟器或设备上可见的屏幕的放大图像。在该窗口中,可检查屏幕图像中各个像素的属性。也可使用 Pixel Perfect 窗口根据位图设计帮助排布应用程序的用户界面。

图 4. Pixel Perfect 窗口

layoutopt 工具可让您分析 XML 文件,该文件定义应用程序的用户界面以查找视图层级中的不当之处。要运行工具,可打开终端并从 SDK 工具/目录启动 layoutopt <xmlfiles>。<xmlfiles> 变量是以空格分隔的要分析的资源的列表,可以是未编译的资源 xml 文件或这些文件的目录。工具会加载指定的 XML 文件并根据一组预定义的规则分析它们的定义和层级。 下面是来自工具的输出示例:

$ layoutopt samples/ samples/compound.xml 7:23 The root-level <FrameLayout/> can be replaced with <merge/> 11:21 This LinearLayout layout or its FrameLayout parent is useless samples/simple.xml 7:7 The root-level <FrameLayout/> can be replaced with <merge/> samples/too_deep.xml -1:-1 This layout has too many nested layouts: 13 levels, it should have <= 10! 20:81 This LinearLayout layout or its LinearLayout parent is useless 24:79 This LinearLayout layout or its LinearLayout parent is useless 28:77 This LinearLayout layout or its LinearLayout parent is useless 32:75 This LinearLayout layout or its LinearLayout parent is useless 36:73 This LinearLayout layout or its LinearLayout parent is useless 40:71 This LinearLayout layout or its LinearLayout parent is useless 44:69 This LinearLayout layout or its LinearLayout parent is useless 48:67 This LinearLayout layout or its LinearLayout parent is useless 52:65 This LinearLayout layout or its LinearLayout parent is useless 56:63 This LinearLayout layout or its LinearLayout parent is useless samples/too_many.xml 7:413 The root-level <FrameLayout/> can be replaced with <merge/> -1:-1 This layout has too many views: 81 views, it should have <= 80! samples/useless.xml 7:19 The root-level <FrameLayout/> can be replaced with <merge/> 11:17 This LinearLayout layout or its FrameLayout parent is useless

 

Traceview 是执行日志的图形化查看器,这些日志在您使用调试类记录代码中的跟踪信息时创建。Traceview 可帮助您调试应用程序并概述其性能。Traceview 可加载日志文件并在窗口中显示其数据,该窗口如图 5 和图 6 所示以两个面板将您的应用程序可视化:

 

图 5. 时间轴面板描述每个线程和方法何时开始和停止

图 6. Profile(概要)面板提供方法中花费的所有时间的摘要。

dmtracedump 是一种工具,为您提供一种备选方式,用于从跟踪日志文件生成图形调用栈图。该工具使用 Graphviz Dot 实用程序创建图形化输出,因此您需要在运行 dmtracedump 之前安装 Graphviz。dmtracedump 工具以树图形式生成调用堆栈数据,每个调用表示为一个节点。它使用箭头显示调用流程(从父节点至子节点)。图 7 显示了 dmtracedump 输出的一个示例。

图 7. dmtracedump

3.NDK 应用程序调试工具

由于 Android NDK 基于 GCC 工具链,Android NDK 包含 GDB、GNU 调试程序,因而可让您启动、暂停、检查和修改程序。在 Android 设备上,GDB 配置为客户端/服务器模式,在嵌入式设备上这种配置更为常见。程序在设备上作为服务器和远程客户端运行。开发人员的工作站与其连接,并发送与本地应用程序相似的调试命令。GDB 本身是一个命令行实用程序,如果手动使用会显得较为繁琐。幸好 GDB 可由大多数 IDE 尤其是 CDT 处理。从而可直接使用 Eclipse 来添加断点并检查程序,但前提是先正确配置它!

通过单击文本编辑器的左端,Eclipse 确实可方便地用 Java 和 C/C++ 源文件插入断点。Java 断点借助 ADT 插件可以立即使用,该插件管理通过 Android Debug Bridge 进行的调试。但对 CDT 并非如此,CDT 并不能感知 Android。因此,插入断点将不会有作用,除非我们配置 CDT 以使用 NDK 的 GDB,GDB 本身需要绑定至原生应用程序以对其进行调试。 在 NDK 版本中改善了对调试程序的支持(例如,之前不能调试纯原生线程)。尽管 NDK 越来越适用,但 NDK R5(甚至包括 R7)还很不完善。但是,它仍然有用处! 现在让我们了解下如何调试原生应用程序。

首先通过以下步骤在我们的应用程序中启用调试模式:
1)有一步操作很重要,但也很容易被忽略,那就是在 Android 项目中激活调试标记。该操作在应用程序清单 AndroidManifest.xml 中完成。请勿忘记对原生代码使用适用的 SDK 版本:

<?xml version="1.0" encoding="utf-8"?> <manifest ...> <uses-sdk android:minSdkVersion="10"/> <application ... android:debuggable="true"> ...

 

2)在清单中启用调试标记会自动以原生代码激活调试模式。但是,APP_OPTIM 标记也控制着调试模式。如果已在 Android.mk 中手动设置它,则检查是否已设置其值以进行调试(并不发布)或直接删除它:

APP_OPTIM := debug

 

 

3)现在让我们配置将连接至设备的 GDB 客户端。重新编译项目并插入设备或启动模拟器。运行然后离开应用程序。确保加载应用程序并且其 PID 可用。可通过使用以下命令(在 Windows 中使用 Cygwin)监听进程来检查它:

$ adb shell ps |grep gl2jni

 

 

应该会返回一行:

app_75 13178 1378 201108 68672 ffffffff 80118883 S com.android.gl2jni

 

 

4)打开终端窗口并转到项目目录。运行 ndk-gdb 命令(位于 Android NDK 文件夹,例如 android-ndk-r8\):

$ ndk-gdb

 

 

该命令不会返回消息,但是会在 obj\local\x86 目录创建三个文件(对于 arm 设备目录为 obj\local\armeabi):

 

  • gdb.setup:这是为 GDB 客户端生成的配置文件。
  • app_process:该文件直接从您的设备检索。其为系统可执行文件,在系统启动时启动,并可形成分支,启动新的应用程序。GBD 需要该参考文件来查找其标记。在某些方面,其为您的应用程序的二进制输入点。
  • libc.so:该文件也可直接从您的设备检索。其为 GDB 使用的 Android 标准 C 库(通常称为 bionic),用于保持跟踪运行时期间创建的所有原生线程。

5)在您的项目目录中,复制 obj\local\x86\gdb.setup 并将其命名为 gdb2.setup。打开它并删除请求 GDB 客户端连接至运行于设备上的 GDB 服务器的以下行(将由 Eclipse 自身执行):
target remote :5039

6在 Eclipse 主菜单中,转至“Run(运行)| Debug Configurations(调试配置)...”,并在名为 GL2JNIActivityDefault 的 C/C++ 应用程序项目中创建新的调试配置。该配置将在您的计算机上启动 GDB 客户端并连接至设备上运行的 GDB 服务器。

7在 Main(主菜单)选项卡中,使用浏览按钮,将项目设置为自己的项目目录,将 C/C++ 应用程序设置为指向 obj\local\ x86\app_process(可以使用绝对或相对路径)。

图 8. 为 C/C++ 应用程序调试配置

8使用窗口底部的链接“Select other(选择其他)...”,将启动程序类型切换为“Standard Create Process Launcher(标准创建进程启动程序)”:

图 9. 选择首选启动程序

9转至调试程序文件并设置调试程序类型为 gdbserver,将 GDB 调试程序设置为 android-ndk-r8\toolchains\x86-4.4.3\prebuilt\windows\bin\i686-android-linux-gdb.exe 或针对 arm 平台设置为 android-ndk-r8\toolchains\arm-linux-androideabi-4.4.3\prebuilt\linux-x86\bin\arm-linux-androideabi-gdb,针对 arm 平台将 GDB 命令文件需求设置为指向位于 \obj\local\x86 或 obj\local\armeabi\ 中的 gdb2.setup 文件(使用绝对或相对路径均可)。

图 10. 调试程序设置面板

10转至 Connection(连接)选项卡并将类型设置为 TCP。主机名、IP 地址和端口号 (localhost d 5039) 都保留默认值。

图 11. 调试程序设置面板上的链接设置

11现在让我们配置 Eclipse 以在设备上运行 GDB 服务器。复制 android-ndk-r8\ndk-gdb 并用文本编辑器打开它。查找以下行:
$GDBCLIENT -x `native_path $GDBSETUP`

由于 GDB 客户端将由 Eclipse 本身运行,因此对其进行注释:

#$GDBCLIENT -x `native_path $GDBSETUP`

12在 Eclipse 主菜单中,转到“Run(运行)| External Tools(外部工具)| External Tools Configurations(外部工具
配置)...”,并创建新配置 GL2JNIActivity_GDB。
该配置将在设备上启动 GDB 服务器。

13在 Main(主菜单)选项卡上,将位置设置为指向 android-ndk-r8 中我们修改过的 ndk-gdb。 将工作目录设置为您的应用程序目录位置
也可设置 Arguments(变量)文本框:

  • Verbose:详细查看 Eclipse 控制台中发生了什么。
  • Force:自动终止之前所有会话。
  • start:让 GDB 服务器启动应用程序,而不是在应用程序启动之后连接至应用程序。该选项在您仅调试原生代码而非 Java 代码时有用。

图 12. 外部工具配置

14现在,和往常一样启动应用程序。

15一旦应用程序启动,就可直接通过控制台启动 ndk-gdb 或启动外部工具配置 GL2JNIActivity_GDB,该配置将启动设备上的 GDB 服务器。GDB 服务器接收远程 GDB 客户端发送的调试命令,并在本地调试您的应用程序。

16打开 jni\gl_code.cpp 并通过双击文本编辑器的左端在 setupGraphics 中设置断点(或右键单击并选择 Toggle breakpoint(切换断点))。

图 13. 断点设置

17最后启动 GL2JNIActivity 默认 C/C++ 应用程序配置启动 GDB 客户端。它会通过套接字连接将调试命令从 Eclipse CDT 中继至 GDB 服务器。从开发人员的观点来看,这与调试本地应用程序很相似。

也有一些专用工具用于调试图形性能,例如 Intel® GPA System Analyzer 为英特尔® 图形性能分析器(英特尔® GPA)之一,新增加了对于英特尔架构 Android 设备的支持,并且专供应用程序和驱动程序工程师优化其 OpenGL* ES 工作量。

该部分提供的信息涉及如何配置英特尔 GPA 并通过 USB 连接将其用于您的 Android 设备。在连接至 Android 设备时,英特尔 GPA System Analyzer 提供 OpenGL ES API、CPU 和 GPU 性能标准,并通过提供多个图形管线状态重写以帮助分析 OpenGL ES 应用程序性能。

要在基于 Android x86 的设备上使用英特尔 GPA System Analyzer,需要从文档检查目标机器和固件/版本。

要开始收集标准,需要在客户端系统上安装英特尔 GPA System Analyzer 并将其连接至目标设备:

1在 Windows*/Linux* 客户端机器上安装英特尔 GPA 2012 R3。

2启动英特尔 GPA System Analyzer。

3确保 Android 设备通过 USB 电缆连接至客户端系统。

4在客户端系统检测目标设备时,最多等待 10 秒。发现的设备会出现在对话框窗口中。目标设备的列表会每隔 5 到 6 秒刷新一次。

5查找要连接的设备并单击“Connect(连接)”。英特尔 GPA System Analyzer 会将所需的组件复制到目标设备并生成已安装应用程序的列表。可通过单击“Stop(停止)”中断连接进程。

图 14. 选择互联设备

6从可用应用程序列表中选择所需的应用程序。“Application List(应用程序列表)”屏幕显示所有用户以及 Android 设备上安装的所有系统应用程序。

图 15. 应用列表

7将会启动应用程序并且您将在英特尔 GPA System Analyzer 窗口中看到其数据。

8要切换至不同应用程序,单击“Back(返回)”。请注意,将强制关闭正在运行的应用程序。

9要切换至不同目标,单击“Back(返回)”。
PowerVR 显卡架构由以下核心模块构成,这些模块可将提交的 3D 应用程序数据转换为渲染的图形:Tile Accelerator (TA)、Image Synthesis Processor (ISP) 以及 Texture & Shading Processor (TSP)。“GPU” 组中的英特尔 GPA 标准对应这些核心模块之一,“Metrics List(标准列表)”中标准的顺序取决于图形管线中核心模块的顺序。

图 16. Intel GPA System Analyzer 窗口

Perf 是自 Linux 版本 2.6.30 起 Linux 中很有用的一个工具,可同时用于与硬件和软件相关的性能分析。尽管 Android 基于 Linux 构建,但和不包含其他 Linux 组件和库一样,它也不包含 perf。您必须将静态构建的 perf 推送至其中。如果您已有该工具,只需将其置于 /system/bin/ 下,就可有效发挥其作用。有关 perf 的简短说明、基本用法和教程,可访问 https://perf.wiki.kernel.org/index.php/Main_Page
借助 traceview,开发人员可获取 Java 代码的性能信息;借助 perf,开发人员可获取有关原生和系统级代码的性能信息,如图 17 中所示。

图 17. 性能统计数据

图 18. 函数调用栈

UxTune 是一个工程工具,用于 Android 用户交互分析和优化。它是一种增强的 pyTimeChart 工具。
UxTune 设计特性包括:

  • 垂直相关:将跨层的系统事件映射至用户级别活动,例如事件、手势、帧等。
  • 水平相关:将不同系统实体间的运行时活动(例如一个线程触发垃圾回收)关联。
  • 基于 pyTimeChart 的可视化。

要使用 UxTune 分析响应能力,开发人员需要熟悉 Android 系统的某些重要进程(在 pyTimeChart 中显示为行),即:

  1. InputReader 行:该行以触摸坐标显示所有触摸事件。事件将发送至 InputDispatcher。
  2. InputDispatcher 行:InputDispatcher 将把连续的触摸事件打包,并将该包发送至应用程序的 uiThread。
  3. uiThread 行:该行显示从 InputDispatcher 收到的包的主要触摸事件。uiThread 将根据特定操作绘制(渲染)其表面。 “D” 表示绘制进程。
  4. Surface 行:uiThread 在绘制开始时锁定其表面,并在绘制完成后解锁表面。“S” 和 “E” 表示应用程序渲染的开始和结束。
  5. SurfaceFlinger 行:在完成应用程序渲染后,应用程序将通知 SurfaceFlinger 合成并更新屏幕。“S” 表示 SurfaceFlinger 开始处理应用程序请求,而 “E” 表示合成完成(帧缓冲区交换完成)。

图 19. UxTune 分析窗口

Meter-FPS 是一个工具,用于测量系统的 FPS 值,它会截取显卡处理路径以获得每帧的记录,还包含其他标准,例如最大帧时间、帧时间变化、#长时帧和掉帧率。fps 监控器有两种模式。Real Time Pattern(实时模式)可实时显示所有正在运行的应用程序的 fps。Measure Pattern(测量模式)可在用户定义的启动和停止时间测量 fps 和其他参数。要使用该工具,必须取得设备最高权限。
设置环境:
setprop debug.graphic_log 1
stop zygote
start zygote

图 20 显示了配置界面,开发人员可在其中为调试目标配置工具。

20. Meter-FPS 配置

在 Real Time(实时)模式中单击监控器按钮。fps 工具将监控所有正在运行的应用程序,并在屏幕上的浮动窗口中更新 fps。

图 21. Meter-FPS 实时模式

在 Measure(测量)模式中单击监控器按钮。将显示一个浮动窗口,其中显示“Click to start(单击以开始)...”;单击浮动窗口开始监控。

图 22. Meter-FPS 实时模式 1

现在测量模式正在运行:

图 23. Meter-FPS 实时模式 1

单击浮动窗口停止监控;其将显示结果:

图 24. Meter-FPS 分析结果列表

单击上面列表中的每个项目以获取详细记录:

图 25. Meter-FPS 分析详细记录

参考:

http://developer.android.com/guide/developing/debugging/index.html
http://www.eclipse.org/sequoyah/documentation/native_debug.php
http://mhandroid.wordpress.com/2011/01/23/using-eclipse-for-android-cc-development/
http://mhandroid.wordpress.com/2011/01/23/using-eclipse-for-android-cc-debugging/
http://packages.python.org/pytimechart/userguide.html
https://perf.wiki.kernel.org/index.php/Main_Page

相关文章与资源:

关于作者

Xiaodong Wang 是英特尔软件及服务事业部的应用工程师。 他专注于采用 Android 操作系统的基于英特尔的平台的 ISV。 Xiaodong 提供技术支持的 PRC Plus 项目(Android 平板电脑 ISV 启用)成功启用了前 50 个 NDK 应用程序作为技术接口。最近 Xiaodong 参与了英特尔的数个创新项目,并在开发过程中扮演重要角色。尤其是其中一个项目被选为英特尔信息技术峰会的演示项目,而 Xiaodong 成功地提供了技术支持。 在加入英特尔之前,Xiaodong 在 MediaTek 进行有关框架和应用程序开发的工作。Xiaodong 是北京大学硕士,并在作为访问学者在新加坡南洋大学进行研究期间,在《IEEE 计算机汇刊》上发表了一篇技术论文。他感兴趣的领域为移动互联网技术(例如 LBS、NFC AR 等)以及创新设计。

 

声明

 

本文件中包含关于英特尔产品的信息。本文件不构成对任何知识产权的授权,包括明示的、暗示的,也无论是基于禁止反言的原则或其他。英特尔不承担任何其他责任。英特尔在此作出免责声明:本文件不构成英特尔关于其产品的使用和/或销售的任何明示或暗示的保证,包括不就其产品的(i)对某一特定用途的适用性、(ii)适销性以及(iii)对任何专利、版权或其他知识产权的侵害的承担任何责任或作出任何担保。

除非经过英特尔的书面同意认可,英特尔的产品无意被设计用于或被用于以下应用:即在这样的应用中可因英特尔产品的故障而导致人身伤亡。

英特尔有权随时更改产品的规格和描述,恕不另行通知。设计者不应信赖任何英特产品所不具有的特性,设计者亦不应信赖任何标有保留权利摂或未定义摂说明或特性描述。对此,英特尔保留将来对其进行定义的权利,同时,英特尔不应为因其日后更改该等说明或特性描述而产生的冲突和不相容承担任何责任。此处提供的信息可随时更改,恕不另行通知。请勿根据本文件提供的信息完成一项产品设计。

本文件所描述的产品可能包含使其与宣称的规格不符的设计缺陷或失误。这些缺陷或失误已收录于勘误表中,可索取获得。

在发出订单之前,请联系当地的英特尔营业部或分销商以获取最新的产品规格。

如欲获得本文涉及的带编号文档的副本或其他英特尔文献,可致电 1-800-548-4725,或访问: http://www.intel.com/design/literature.htm
性能测试中使用的软件和工作负载可能仅在英特尔® 微处理器上针对性能进行了优化。诸如SYSmark和MobileMark等测试均系基于特定计算机系统、硬件、软件、操作系统及功能。上述任何要素的变动都有可能导致测试结果的变化。请参考其他信息及性能测试(包括结合其他产品使用时的运行性能)以对目标产品进行全面评估。
对本文件中包含的软件源代码的提供均依据相关软件许可而做出,任何对该等源代码的使用和复制均应按照相关软件许可的条款执行。英特尔和 Intel 标识是英特尔在美国和/或其他国家的商标。
英特尔公司 © 2012 年版权所有。所有权保留。
* 其他的名称和品牌可能是其他所有者的资产。