65.9K
CodeProject 正在变化。 阅读更多。
Home

如何调试Android* x86应用程序及其工具

2014年6月2日

CPOL

15分钟阅读

viewsIcon

15852

本文将介绍 Android 应用程序的调试工具,旨在帮助新手开发者更快地熟悉 Android SDK 和相关工具,并在 Android x86 平台上更有效地解决缺陷。

1. 引言

我们知道,一个 Android* 开发者需要扮演多种角色:设计师、代码编写者,以及不可避免的故障排除者。代码中的错误是不可避免的,因此,无论您是否是错误的创建者,了解调试工具以及如何快速有效地查找和修复它们都至关重要。因此,有效的调试技巧是当今 Android 开发者的一项基本技能。本文将介绍 Android 应用程序的调试工具,旨在帮助新手开发者更快地熟悉 Android SDK 和相关工具,并在 Android x86 平台上更有效地解决缺陷。

2. SDK 应用调试工具

Android SDK 提供了大部分您调试应用程序所需的工具。如果您想进行单步调试代码、查看变量值和暂停应用程序执行等操作,则需要一个符合 JDWP 标准的调试器。如果您使用 Eclipse,则已包含一个符合 JDWP 标准的调试器,无需进行任何设置。如果您使用其他 IDE,则可以使用随附的调试器,并将其连接到特殊端口,以便与您设备上的应用程序虚拟机进行通信。

如果您在使用 ADT (Android development tools) 插件在 Eclipse 中开发,则可以使用内置的 Java* Debugger 和 DDMS (Dalvik Debug Monitor Server) 来调试您的应用程序。要访问调试器和 DDMS,Eclipse 会将调试器和 DDMS 功能显示为“透视图”,这些是自定义的 Eclipse 视图,根据您所在的透视图显示特定的选项卡和窗口。Eclipse 还会为您启动 ADB (Android debug bridge) 主守护程序,因此您无需手动运行它。如果您使用其他 IDE 进行调试,则可以利用 Android SDK 提供的所有调试工具,如 ADB、DDMS、Java 调试器等。

图 1. Dalvik 调试监视器服务器 (DDMS)

使用 DDMS,开发者可以查看进程的堆使用情况、跟踪对象的内存分配、使用模拟器或设备的文件系统、检查线程信息、捕获方法剖析、使用网络流量工具(Android 4.0 中提供)、使用 LogCat 跟踪代码消息,以及模拟电话操作和位置。有关更多信息,请阅读 https://developer.android.com.cn/guide/developing/debugging/ddms.html。Android SDK 还提供 Hierarchy Viewer 和 layoutopt 工具,以帮助开发者调试布局问题。

Hierarchy Viewer 应用程序允许您调试和优化用户界面 (UI)。它提供了布局的视图层次结构的视觉表示(视图层次结构窗口)以及屏幕的放大视图(像素完美窗口)。

图 2. Hierarchy Viewer

视图层次结构窗口显示构成设备或模拟器上正在运行的 Activity 的 UI 的视图对象。您可以使用它在整个视图树的上下文中查看单个视图对象。对于每个视图对象,视图层次结构窗口还会显示渲染性能数据。当您选择一个节点时,有关该视图的其他信息会显示在节点上方的一个小窗口中。当您单击节点之一时,您可以看到有关图像、视图计数和渲染时间的信息。

图 3. 视图对象信息窗口

Pixel Perfect 是一个用于检查像素属性和根据设计图纸布局 UI 的工具。像素完美窗口显示模拟器或设备上当前可见屏幕的放大图像。在这里,您可以检查屏幕图像中单个像素的属性。您还可以使用像素完美窗口根据位图设计来帮助您布局应用程序的 UI。

图 4. Pixel Perfect 窗口

layoutopt 工具允许您分析定义应用程序 UI 的 XML 文件,以查找视图层次结构中的低效率。要运行该工具,请打开终端并在 SDK tools/ 目录中运行 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 是一个图形化查看器,用于查看您使用 Debug 类创建的执行日志,以记录代码中的跟踪信息。Traceview 可以帮助您调试应用程序并剖析其性能。Traceview 会加载日志文件,并在一个窗口中显示其数据,该窗口在两个面板中可视化您的应用程序,如图 5 和图 6 所示。

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

图 6. 剖析面板提供了在方法中花费的所有时间的摘要。

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++ 源文件中插入断点。由于 ADT 插件管理 Android 调试桥的调试,Java 断点开箱即用。CDT 则不是如此,它当然不是 Android 感知的。因此,除非我们将 CDT 配置为使用 NDK 的 GDB,而 NDK 的 GDB 又需要绑定到原生 Android 应用程序才能调试它,否则插入断点将不起作用。调试器支持在 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 中手动设置,请检查其值是否设置为 debug(而不是 release),或者干脆将其删除。

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:此文件直接从您的设备检索。它是一个系统可执行文件,在系统启动时启动,并被 fork 以启动新应用程序。GBD 需要此参考文件来查找其标记。在某些方面,它是您应用程序的二进制入口点。
  • libc.so:此文件也从您的设备检索。它是 Android 的标准 C 库(通常称为 bionic),GDB 用于跟踪运行时创建的所有原生线程。

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

6) 在 Eclipse 主菜单中,转到 Run | Debug Configurations...,并在 C/C++ application 项下创建一个新的 Debug 配置,命名为 GL2JNIActivityDefault。此配置将启动您计算机上的 GDB 客户端并连接到设备上运行的 GDB 服务器。

7) 在 Main 选项卡中,将 Project 设置为您自己的项目目录,将 C/C++ application 指向 obj\local\ x86\app_process(您可以使用 Browse 按钮;可以使用绝对路径或相对路径)。

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

8) 使用窗口底部的 Select other... 链接将启动器类型切换为 Standard Create Process Launcher。

图 9. 选择首选启动器

9) 转到 Debugger 文件,将 Debugger type 设置为 gdbserver,将 GDB debugger 设置为 android-ndk-r8\toolchains\x86-4.4.3\prebuilt\windows\bin\i686-android-linux-gdb.exeandroid-ndk-r8\toolchains\arm-linux-androideabi-4.4.3\prebuilt\linux-x86\bin\arm-linux-androideabi-gdb(用于 arm),将 GDB command file 指向位于 \obj\local\x86 或 obj\local\armeabi\(用于 arm)的 gdb2.setup 文件(您可以使用绝对路径或相对路径)。

图 10. 调试器设置面板

10) 转到 Connection 选项卡,将 Type 设置为 TCP。保持 Host name or IP address 和 Port number 的默认值(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 选项卡中,将 Location 指向我们修改过的 android-ndk-r8 中的 ndk-gdb。将 Working directory 设置为您的应用程序目录位置。
可选地,设置 Arguments 文本框。

  • verbose:详细查看 Eclipse 控制台中发生的情况。
  • force:自动终止任何之前的会话。
  • start:让 GDB 服务器启动应用程序,而不是在应用程序启动后附加到它。如果您只调试原生代码而不是 Java 代码,此选项会很有用。

图 12. 外部工具配置

14) 现在,按常规启动您的应用程序。

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

16) 打开 jni\gl_code.cpp 文件,通过双击文本编辑器的左侧边距(或右键单击并选择 Toggle breakpoint)在 setupGraphics 中设置一个断点。

图 13. 断点设置

17) 最后,启动 GL2JNIActivity Default C/C++ 应用程序配置以启动 GDB 客户端。它通过套接字连接将调试命令从 Eclipse CDT 中继到 GDB 服务器。从开发者的角度来看,这几乎就像调试本地应用程序一样。

还有一些专门用于调试图形性能的工具,Intel® GPA System Analyzer 是 Intel® Graphics Performance Analyzers (Intel® GPA) 中的一员,它新增了对基于 Intel 的 Android 设备的支持,旨在帮助应用程序和驱动程序工程师优化他们的 OpenGL* ES 工作负载。

本节将介绍如何通过 USB 连接配置和使用 Intel GPA 与您的 Android 设备。连接到 Android 设备时,Intel GPA System Analyzer 提供 OpenGL ES API、CPU 和 GPU 性能指标,还提供多个图形管线状态覆盖,以帮助您分析 OpenGL ES 应用程序性能。

要在基于 Android x86 的设备上使用 Intel GPA System Analyzer,您需要查阅文档中的目标机器和固件/版本。

要开始收集指标,您需要在客户端系统上安装 Intel GPA System Analyzer 并将其连接到目标设备。

1) 在 Windows*/Linux* 客户端机器上安装 Intel GPA 2012 R3。

2) 启动 Intel GPA System Analyzer。

3) 确保 Android 设备已通过 USB 线连接到客户端系统。

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

5) 找到要连接的设备,然后单击 Connect。Intel GPA System Analyzer 会将所需组件复制到目标设备,并生成已安装应用程序的列表。您可以通过单击 Stop 来中断连接过程。

图 14. 选择已连接设备

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

图 15. 应用程序列表

7) 应用程序将启动,您将在 Intel GPA System Analyzer 窗口中看到其数据。

8) 要切换到其他应用程序,请单击 Back。请注意,正在运行的应用程序将被强制关闭。

9) 要切换到其他目标设备,请单击 Back。
PowerVR 图形架构由以下核心模块组成,这些模块将提交的 3D 应用程序数据转换为渲染图像:Tile Accelerator (TA)、Image Synthesis Processor (ISP) 和 Texture & Shading Processor (TSP)。Intel GPA 指标中的“GPU”组对应于这些核心模块中的一个,并且指标列表中的顺序取决于图形管线中核心模块的顺序。

图 16. Intel GPA System Analyzer 窗口

Perf 是 Linux 中一个非常有用的工具(自 2.6.30 起),可用于硬件和软件相关的性能分析。虽然 Android 构建在 Linux 之上,但 Android 并不像许多其他组件和库那样包含 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 将在绘制开始时锁定其 Surface,并在绘制完成后解锁其 Surface。“S”和“E”分别代表应用程序渲染的开始和结束。
  5. SurfaceFlinger 行:应用程序渲染完成后,应用程序将通知 SurfaceFlinger 进行合成和更新屏幕。“S”表示 SurfaceFlinger 开始处理应用程序请求,“E”表示合成完成(framebuffer 交换完成)。

图 19. UxTune 分析窗口

Meter-FPS 是一个用于测量系统 FPS 值的工具,它会截获图形处理路径以获取每帧的日志,包括最大帧时间、帧时间方差、#long-time-frames 和帧丢弃率等其他指标。FPS 监视器有两种模式。实时模式 (Real Time Pattern) 会实时显示所有运行应用程序的 FPS。测量模式 (Measure Pattern) 会在用户定义的开始和停止时间段内测量 FPS 和其他参数。使用此工具时,设备应已 root。
设置环境
setprop debug.graphic_log 1
stop zygote
start zygote

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

20. Meter-FPS 配置

在实时模式下,单击 monitor 按钮。FPS 工具将监视所有正在运行的应用程序,并将 FPS 更新到屏幕上的浮动窗口。

图 21. Meter-FPS 实时模式

在测量模式下,单击 monitor 按钮。它将显示一个浮动窗口,上面写着“Click to start ...”;单击浮动窗口即可开始监视。

图 22. Meter-FPS 测量模式-1

现在测量模式正在运行。

图 23. Meter-FPS 测量模式-1

单击浮动窗口停止监视,它将显示结果。

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

单击以上列表中的每个项目以获取详细日志。

图 25. Meter-FPS 分析详细日志

参考文献

https://developer.android.com.cn/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

相关文章与资源

要了解更多关于安卓开发者的英特尔工具,请访问英特尔® 安卓开发者专区

© . All rights reserved.