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





0/5 (0投票)
本文将介绍 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 调试器等。
使用 DDMS,开发者可以查看进程的堆使用情况、跟踪对象的内存分配、使用模拟器或设备的文件系统、检查线程信息、捕获方法剖析、使用网络流量工具(Android 4.0 中提供)、使用 LogCat 跟踪代码消息,以及模拟电话操作和位置。有关更多信息,请阅读 https://developer.android.com.cn/guide/developing/debugging/ddms.html。Android SDK 还提供 Hierarchy Viewer 和 layoutopt 工具,以帮助开发者调试布局问题。
Hierarchy Viewer 应用程序允许您调试和优化用户界面 (UI)。它提供了布局的视图层次结构的视觉表示(视图层次结构窗口)以及屏幕的放大视图(像素完美窗口)。
视图层次结构窗口显示构成设备或模拟器上正在运行的 Activity 的 UI 的视图对象。您可以使用它在整个视图树的上下文中查看单个视图对象。对于每个视图对象,视图层次结构窗口还会显示渲染性能数据。当您选择一个节点时,有关该视图的其他信息会显示在节点上方的一个小窗口中。当您单击节点之一时,您可以看到有关图像、视图计数和渲染时间的信息。
Pixel Perfect 是一个用于检查像素属性和根据设计图纸布局 UI 的工具。像素完美窗口显示模拟器或设备上当前可见屏幕的放大图像。在这里,您可以检查屏幕图像中单个像素的属性。您还可以使用像素完美窗口根据位图设计来帮助您布局应用程序的 UI。
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 所示。
dmtracedump 工具提供了另一种从跟踪日志文件生成图形化调用堆栈图的方法。该工具使用 Graphviz Dot 工具来创建图形输出,因此您需要在运行 dmtracedump 之前安装 Graphviz。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) 使用窗口底部的 Select other... 链接将启动器类型切换为 Standard Create Process Launcher。
9) 转到 Debugger 文件,将 Debugger type 设置为 gdbserver,将 GDB debugger 设置为 android-ndk-r8\toolchains\x86-4.4.3\prebuilt\windows\bin\i686-android-linux-gdb.exe 或 android-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) 转到 Connection 选项卡,将 Type 设置为 TCP。保持 Host name or IP address 和 Port number 的默认值(localhost d 5039)。
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 代码,此选项会很有用。
14) 现在,按常规启动您的应用程序。
15) 应用程序启动后,您可以直接通过控制台运行 ndk-gdb,或运行外部工具配置 GL2JNIActivity_GDB
,该配置将在设备上启动 GDB 服务器。GDB 服务器接收远程 GDB 客户端发送的调试命令,并在本地调试您的应用程序。
16) 打开 jni\gl_code.cpp 文件,通过双击文本编辑器的左侧边距(或右键单击并选择 Toggle breakpoint)在 setupGraphics 中设置一个断点。
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 来中断连接过程。
6) 从可用应用程序列表中选择所需的应用程序。Applications List 屏幕显示 Android 设备上安装的所有用户和系统应用程序。
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”组对应于这些核心模块中的一个,并且指标列表中的顺序取决于图形管线中核心模块的顺序。
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 所示。
UxTune 是一个用于 Android 用户交互分析和优化的工程工具。它是 pyTimeChart 工具的增强版。
UxTune 的设计特点是:
- 垂直关联:将跨层级的系统事件映射到用户级活动,例如事件、手势、帧等。
- 水平关联:关联不同系统实体之间的运行时活动,例如,一个线程触发垃圾回收。
- 基于 pyTimeChart 的可视化。
要使用 UxTune 分析响应能力,开发者需要熟悉 Android 系统的一些重要进程(在 pyTimeChart 中显示为行),即:
- InputReader 行:此行显示所有触摸事件及其触摸坐标。事件将发送到 InputDispatcher。
- InputDispatcher 行:InputDispatcher 将串行触摸事件打包,并将包发送到应用程序的 uiThread。
- uiThread 行:此行显示从 InputDispatcher 收到的包的头部触摸事件。uiThread 将根据特定操作绘制(渲染)其表面。“D”代表绘制过程。
- Surface 行:uiThread 将在绘制开始时锁定其 Surface,并在绘制完成后解锁其 Surface。“S”和“E”分别代表应用程序渲染的开始和结束。
- SurfaceFlinger 行:应用程序渲染完成后,应用程序将通知 SurfaceFlinger 进行合成和更新屏幕。“S”表示 SurfaceFlinger 开始处理应用程序请求,“E”表示合成完成(framebuffer 交换完成)。
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 显示了配置界面,开发者可以在其中为其调试目标配置工具。
在实时模式下,单击 monitor 按钮。FPS 工具将监视所有正在运行的应用程序,并将 FPS 更新到屏幕上的浮动窗口。
在测量模式下,单击 monitor 按钮。它将显示一个浮动窗口,上面写着“Click to start ...”;单击浮动窗口即可开始监视。
现在测量模式正在运行。
单击浮动窗口停止监视,它将显示结果。
单击以上列表中的每个项目以获取详细日志。
参考文献
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
相关文章与资源
要了解更多关于安卓开发者的英特尔工具,请访问英特尔® 安卓开发者专区。