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

Intel® Atom™ 平台上的 Android* 应用程序开发和优化

2013 年 12 月 9 日

CPOL

16分钟阅读

viewsIcon

18233

本文档详细介绍了在 Intel Atom 平台上开发和移植 Android 应用程序的方法,并讨论了使用 Android Native Development Kit (NDK) 开发应用程序和优化性能的最佳实践。

访问 Intel® Android 开发者专区

摘要

本文档详细介绍了在 Intel Atom 平台上开发和移植 Android 应用程序的方法,并讨论了使用 Android Native Development Kit (NDK) 开发应用程序和优化性能的最佳实践。Android 开发者可以参考本文档来为 Intel 架构构建高质量的应用程序。

1. Android 应用分类

Android 应用程序可分为两类,如图 1 所示。

  • Dalvik 应用程序包含 Java* 代码,仅使用 Android 官方 SDK API 以及必要的资源文件(如 XML 和 PNG),并编译成 APK 文件。
  • Android NDK 应用程序包含 Java 代码和资源文件,以及 C/C++ 源代码,有时还包括汇编代码。所有原生代码都编译成动态链接库(.so 文件),然后通过 JNI 机制由主程序中的 Java 代码调用。

图 1:两种 Android 应用程序类型

2. Android Native Development Kit (NDK)

2.1 简介

Android Native Development Kit (NDK) 是 Android SDK 的配套工具。NDK 是开发 Android 应用程序的强大工具,因为它能够:

  • 使用原生代码构建性能关键部分。在使用 Java 代码时,Java 源代码需要通过虚拟机解释成机器语言。相比之下,原生代码在执行前直接编译并优化成二进制文件。通过恰当使用原生代码,您可以在应用程序中构建高性能代码,例如硬件视频编码和解码、图形处理以及算术运算。
  • 重用旧的原生代码。C/C++ 代码可以编译成动态库,并通过 JNI 机制由 Java 代码调用。

2.2 工具概述

在开发过程中,您可以使用 Intel® Hardware Execution Manager (HAXM) 来提高 Android 模拟器的性能。HAXM 是一个硬件辅助虚拟化引擎(Hypervisor),它利用 Intel® Virtualization Technology (Intel® VT) 来加速在主机上模拟 Android 应用程序。结合 Intel 提供的 Android x86 模拟器镜像和官方 Android SDK Manager,HAXM 可以在支持 Intel VT 的系统上提供更快的 Android 模拟体验。有关 HAXM 的更多信息,请访问:http://software.intel.com

2.3 安装 HAXM

使用 Android SDK Manager 安装 HAXM(推荐),或者您也可以通过从 Intel 网站下载安装程序来手动安装 HAXM。如果您想自动更新,请按照图 2 所示使用 Android SDK Manager 进行安装。[1]

图 2:使用 Android SDK Manager 安装 Intel HAXM

您也可以从 http://www.intel.com/software/android 下载适合您主机平台的安装包,然后按照分步说明进行安装。

2.3.1 设置 HAXM

运行 HAXM 需要 Intel 提供的 Android x86 系统镜像。您可以使用 Android SDK Manager 下载系统镜像,或从 Intel® Developer Zone 网站手动下载。

镜像安装成功后,Intel® x86 Android 模拟器镜像将通过 Android SDK 提供的“emulator-x86”二进制文件自动执行。Android 模拟器由 Intel VT 加速,从而加快您的开发进程。

3. 为 Intel Atom 架构开发和移植 NDK 应用程序

3.1 为基于 Intel Atom 处理器设备开发 NDK 应用程序

成功安装 NDK 后,请花几分钟时间阅读 <ndk>/docs/ 目录下的文档,特别是 OVERVIEW.html 和 CPU-X86.html,以便您了解 NDK 机制及其用法。

NDK 应用程序开发可分为五个步骤,如图 3 所示。

图 3:NDK 应用程序开发流程

hello-jni 演示用于说明这五个步骤。您可以在 NDK 的 Root\samples\hello-jni 文件夹 [5] 中找到此演示。Hello-jni 演示是 NDK 中包含的一个简单应用程序,它从共享库中的原生方法获取一个字符串并在应用程序 UI 中使用它。

3.1.1. 创建原生代码

创建一个新的 Android 项目,并将您的原生源代码放在 <project>/jni/ 目录下。项目内容如图 4 所示。此演示包含一个简单的原生代码函数,名为 Java_com_example_hellojni_HelloJni_stringFromJNI()。如源代码所示,它从 JNI 返回一个简单的字符串。

图 4:创建原生代码

3.1.2 创建 MakeFile ‘Android.mk’

NDK 应用程序默认针对 ARM 平台构建。要为 Intel Atom 平台构建 NDK 应用程序,您需要在 MakeFile 中添加 APP_ABI := x86。

图 5:创建 MakeFile

3.1.3 编译原生代码

通过在项目目录中运行 'ndk-build' 脚本来构建原生代码。该脚本位于 NDK 的顶层目录中。结果如图 6 所示。

图 6:编译后的原生代码

构建工具会自动将剥离的共享库复制到应用程序项目目录中的相应位置。

3.1.4 从 Java 调用原生代码

成功部署共享库后,您可以从 Java 端调用该函数。代码如图 7 所示。在 Java 代码中创建了一个公共原生函数调用 stringFromJNI(),该函数使用 System.loadlibrary() 加载共享库。

图 7:从 Java 调用原生代码

3.1.5 使用 GDB 进行调试

如果您想使用 GDB 调试 NDK 应用程序,必须满足以下条件:

  • NDK 应用程序使用 'ndk-build' 构建
  • NDK 应用程序在 Android.manifest 中被设置为“debuggable”
  • NDK 应用程序在 Android 2.2(或更高版本)上运行
  • 只有一个目标正在运行
  • 将 adb 的目录添加到 PATH

使用 ndk-gdb 命令调试应用程序。您可以设置断点或逐行调试来跟踪变量值的更改历史记录,如图 8 所示。

图 8:使用 GDB 调试 NDK 应用程序

3.2 将现有 NDK 应用程序移植到基于 Intel Atom 处理器设备

在本节中,假设您有一个针对 ARM 平台的 Android 应用程序,并且需要将其移植到 Intel Atom 平台才能部署。

将 Android 应用程序移植到 Intel Atom 平台与开发过程类似。步骤如图 9 所示。

图 9:将 Android 应用程序移植到 Intel Atom 平台

3.2.1 移植 Dalvik 应用程序

Dalvik 应用程序可以直接在基于 Intel Atom 处理器设备上运行。用户界面需要针对目标设备进行调整。对于高分辨率设备,例如分辨率为 1280*800 或更高的平板电脑,默认内存分配可能无法满足应用程序的要求,从而导致应用程序无法启动。建议为高分辨率设备增加默认内存分配。

3.2.2 移植 Android NDK 应用程序

移植 NDK 应用程序比移植 Dalvik 应用程序要复杂一些。根据原生代码的以下属性,所有 NDK 应用程序可分为三类:

  • 仅包含 C/C++ 代码,且与硬件无关
  • 使用第三方动态链接库
  • 包含与非 IA 平台高度相关的汇编代码

仅包含 C/C++ 代码且与硬件无关的原生代码

  1. 重新编译原生代码以成功在 Intel Atom 平台上运行应用程序。
  2. 打开 NDK 项目,找到 Android.mk 文件,并在 Android.mk 中添加 APP_ABI := armeabi armeabi-v7a x86,然后使用 ndk-build 重新构建原生代码。
  3. 如果找不到 Android.mk 文件,请使用 ndk-build APP_ABI="armeabi armeabi-v7a x86" 命令来构建项目。 
  4. 再次打包应用程序,支持 x86 平台。

如果原生代码使用第三方动态链接库,则必须将该共享库重新编译成适用于 Intel Atom 平台的 x86 版本。

如果原生代码包含与非 IA 平台高度相关的汇编代码,则必须用 IA 汇编或 C/C++ 重写代码。

4. 开发原生代码的最佳实践

4.1 强制内存对齐

由于架构、平台和编译器的差异,不同平台上相同数据结构的数据大小可能不同。如果不强制内存对齐,不一致的数据大小可能会导致加载错误。[2]

以下示例解释了不同平台上相同数据结构的数据大小。

struct TestStruct { 
 int mVar1; 
 long long mVar2; 
 int mVar3; 
 };

这是一个简单的 struct,包含三个变量:mVar1mVar2mVar3

mVar1 是一个 int,需要 4 个字节。
mVar2 是一个 long long int,需要 8 个字节。
mVar3 也是一个 int,需要 4 个字节。

在 ARM 和 Intel Atom 平台上需要多少空间?

使用默认编译器开关编译的 ARM 和 Intel Atom 平台的数据大小如图 10 所示。ARM 自动采用双精度对齐,占用 24 字节,而 x86 占用 16 字节。

图 10:默认编译标志分配的内存

8 字节(64 位)的 mVar2 导致 TestStruct 的布局不同,因为 ARM 对 mVar2 等 64 位变量需要 8 字节对齐。在大多数情况下,这不会引起问题,因为针对 x86 与 ARM 的构建需要完全重新构建。

然而,如果应用程序序列化类或结构体,则可能发生大小不匹配。例如,您在 ARM 应用程序中创建一个文件,并将 TestStruct 写入该文件。如果您稍后在 x86 平台上从该文件中加载数据,则应用程序中的类大小与文件中的大小不同。类似的内存对齐问题可能会发生在网络流量中,这些流量需要特定的内存布局。

GCC 编译器选项“-malign-double”会在 x86 和 ARM 上生成相同的内存对齐。

图 11:添加 -malign-double 标志时分配的内存

4.2 将 NEON* 指令移植到 SSE [3]

4.2.1 NEON

ARM NEON* 技术主要用于智能手机和 HDTV 等多媒体应用。根据 ARM 文档,其基于 128 位 SIMD 引擎的技术是 ARM Cortex*-A 系列的扩展,性能比 ARMv5 架构至少提高了 3 倍,比后续的 ARMv6 至少提高了 2 倍。有关 NEON 技术的更多信息,请访问:http://www.arm.com/products/processors/technologies/neon.php

4.2.2 SSE:Intel 的等效技术

SSE 是 Intel 架构 (IA) 的 Streaming SIMD Extension。Intel Atom 处理器目前支持 SSSE3(Supplemental Streaming SIMD Extensions 3)及更早版本,但尚不支持 SSE4.x。SSE 是一个 128 位引擎,用于处理浮点数据的打包。其执行模型始于 MMX 技术,而 SSx 基本上是取代 MMX 的新一代技术。有关更多信息,请参阅 Intel 64 和 IA-32 架构软件开发人员手册的“Volume 1: Basic Architecture”部分。第 5.5 节的 SSE 概述提供了 SSE、SSE2、SSE3 和 SSSE3 的指令。这些数据操作在 XMM 寄存器之间或 XMM 寄存器与内存之间移动打包的、基于精度的浮点值。XMM 寄存器旨在取代 MMX 寄存器。

4.2.3 NEON 到 SSE 的汇编级别移植

在使用 IA 软件开发人员手册作为所有 SSE(x) 助记符的交叉引用时,还可以查看位于:http://neilkemp.us/src/sse_tutorial/sse_tutorial.html 的各种 SSE 汇编级别指令。使用目录访问代码示例或查阅背景信息。

同样,ARM 的以下手册提供了有关 NEON 的信息,并在第 1.4 节“Developing for NEON”中包含了一些小的汇编代码片段:http://infocenter.arm.com/help/topic/com.arm.doc.dht0002a/DHT0002A_introducing_neon.pdf

比较 NEON 和 SSE 汇编代码时的主要区别

  • 字节序。Intel 只支持小端字节序汇编,而 ARM 支持大端或小端字节序(ARM 是双端字节序)。在提供的代码示例中,ARM 代码是小端字节序,与 Intel 类似。注意:可能存在一些 ARM 编译器含义。例如,使用 GCC 为 ARM 编译包括了 -mlittle-endian 和 –mbig-endian 标志。有关更多信息,请参阅 http://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html。
  • 粒度。对于上面引用的简单汇编代码示例,请将 SSE(Intel)的 ADDPS 指令与 NEON 的 VADD.ix 进行比较,例如 x = 8 或 16。请注意,后者在要处理的数据中加入了一些粒度,作为引用的助记符的一部分。

注意:这些差异并非全部。您可能会发现 NEON 和 SSE 之间存在其他差异。

4.2.4 NEON 到 SSE 的 C/C++ 级别移植

在将 C/C++ 和 NEON 代码移植到 SSE 时,可能会出现许多 API 上的细微差别。请记住,假设不使用内联汇编,而是使用真正的 C/C++ 代码。NEON 指令还提供了一些原生的 C 库。尽管这些指令是 C 代码,但它们无法在 Intel Atom 平台上执行,必须重写。

5. 优化应用程序性能

5.1 性能调优

在编码过程中,请使用以下方法优化您的应用程序在 Intel Atom 平台上的性能。

5.1.1 对频繁使用的短函数使用 Inline

内联函数最适用于小函数,例如访问私有数据成员。短函数对函数调用开销很敏感。较长的函数在调用/返回序列上花费的时间比例较少,从内联中受益较少。[4]

内联函数可以节省开销:

  • 函数调用(包括参数传递和将对象的地址压入堆栈)
  • 保存调用者的堆栈帧
  • 新堆栈帧的设置
  • 返回值通信
  • 旧堆栈帧的恢复
  • 返回

5.1.2 使用 Float 而不是 Double

FPU(浮点单元)是计算机系统中专门用于执行浮点运算(如加法、减法、乘法、除法和平方根)的部分。某些系统(尤其是较旧的、基于微码的架构)还可以执行各种超越函数,如指数或三角函数计算。当前的处理器通过软件库例程执行这些计算。在大多数现代通用计算机体系结构中,一个或多个 FPU 与 CPU 集成。[6]

Intel Atom 平台支持 FPU。在大多数情况下,使用 Float 而不是 Double 可以加快数据计算过程,并在基于 Intel Atom 处理器的设备上节省内存带宽。

5.1.3 多线程编码

多线程编码允许您利用 Intel Atom 处理器的超线程功能来提高吞吐量并改善整体性能。有关多线程的更多信息,请参阅:http://www.intel.com/content/www/us/en/architecture-and-technology/hyper-threading/hyper-threading-technology.html

5.2 使用编译器标志构建高性能应用程序

正如您所知,原生代码在 Android 应用程序中由 GCC 构建。但您知道 GCC 的默认目标设备是什么吗?它是 Pentium® Pro 处理器。在不添加任何标志的情况下编译原生代码,目标二进制代码在 Pentium Pro 平台上运行效果最好。大多数 Android 应用程序在 Intel Atom 平台上运行,而不是 Pentium Pro。强烈建议根据目标平台添加特定标志。您可以在 Intel Atom 平台上编译时添加以下推荐标志:

-march=atom
-msse4
-mavx
-maes

有关编译器参数的更多信息,请参阅:http://gcc.gnu.org/onlinedocs/gcc/i386-and-x86_002d64-Options.html

6. 结论

本文档讨论了如何在 Intel Atom 平台上开发和优化 Android 应用程序,以及如何开发和移植 NDK 应用程序。

关键点的总结包括:

  • 大多数 Android 应用程序可以直接在 Intel Atom 平台上执行。NDK 应用程序需要重新编译原生代码。如果应用程序中包含汇编代码,则必须重写这部分代码。
  • 充分利用 IA (Intel Architecture) 功能来提高您的 Android 应用程序性能。
  • 添加特定于平台的编译开关,使 GCC 构建代码更有效。

参考

  1. http://software.intel.com/en-us/articles/installation-instructions-for-intel-hardware-accelerated-execution-manager-windows/
  2. http://software.intel.com/en-us/blogs/2011/08/18/understanding-x86-vs-arm-memory-alignment-on-android/
  3. http://software.intel.com/en-us/articles/ndk-android-application-porting-methodologies/
  4. http://msdn.microsoft.com/en-us/library/1w2887zk.aspx
  5. https://developer.android.com.cn/sdk/ndk/index.html
  6. http://en.wikipedia.org/wiki/Floating-point_unit

关于作者

Dawei 是一名应用程序工程师,专注于移动应用程序赋能,包括 x86 设备的 Android 应用程序开发与优化,以及 Web HTML5 应用程序开发。此外,Dawei 在移动应用程序 UI 和 UX 设计方面也拥有丰富的经验。

注意事项

本文档提供的信息是基于 Intel 产品提供的。本文档不授予任何明示或暗示的、通过禁止反言或其他方式获得的知识产权许可。除 Intel 产品销售条款和条件中提供的条款外,Intel 对任何事项概不负责,并免除任何与 Intel 产品销售和/或使用相关的明示或暗示的保证,包括对特定用途的适用性、适销性或对任何专利、版权或其他知识产权的侵权的保证。

除非 Intel 书面同意,否则 Intel 产品不设计也不用于任何可能导致人员伤亡的应用程序。

Intel 可能随时更改规格和产品描述,恕不另行通知。设计人员不得依赖标有“保留”或“未定义”的任何特性或说明的缺失或特性。Intel 保留这些以供将来定义,并对因未来更改而产生的任何冲突或不兼容概不负责。此处的信息可能会发生更改,恕不另行通知。请勿基于此信息定稿设计。

本文档中描述的产品可能包含已知为勘误的设计缺陷或错误,这可能导致产品偏离已发布的规范。当前的已表征勘误可应要求提供。

请联系您当地的英特尔销售办事处或您的经销商以获取最新的规范,并在下订单前进行咨询。

可通过致电 1-800-548-4725 或访问:http://www.intel.com/design/literature.htm 获取订购编号并在此文档中引用的文件副本或其他 Intel 文献。性能测试中使用的软件和工作负载可能已针对 Intel 微处理器进行了性能优化。性能测试(如 SYSmark 和 MobileMark)的测量是使用特定的计算机系统、组件、软件、操作和功能进行的。任何这些因素的更改都可能导致结果发生变化。您应该查阅其他信息和性能测试,以协助您全面评估您打算购买的产品,包括该产品与其他产品结合使用的性能。

本文档中重印的任何软件源代码均根据软件许可证提供,并且只能根据该许可证的条款使用或复制。

Intel、Atom、Pentium 和 Intel 徽标是 Intel Corporation 在美国和/或其他国家/地区的商标。

版权所有 © 2012 Intel Corporation。保留所有权利。

*其他名称和品牌可能被声明为他人的财产。

**此示例源代码根据英特尔示例源代码许可协议发布

其他相关文章

要详细了解 Intel 的 Android 开发工具,请访问 Intel® Android 开发者专区

© . All rights reserved.