本指南用于帮助开发者将现有的基于 ARM* 的 NDK 应用移植到 x86。假设您已经拥有一个正常执行的应用,需要知道怎样能够高速让 x86 设备在 Android* Market 中找到您的应用,本文将能够为您提供一些入门信息。同一时候本指南还提供了一些技巧和指南,以帮助您解决在移植过程当中可能会遇到的编译器问题。php
原生开发套件 NDK 是一款强大的工具,将原生 x86 代码的强大功能和 Android* 应用的图形界面结合在一块儿。经过使用该工具,开发者将能够提高某些应用的性能优点。但同一时候开发者也需要十分慎重,因为在某些状况并不能实现预期的效果.html
NDK 致力于支持开发者完毕下面工做:java
对于以上提到的第二点。部分状况下可能仅仅需要简单地改动 Build Flag 并又一次编译就能够,但有时却并不这么简单。linux
好比。假设原生库涉及到 C 代码内的内嵌汇编,那么代码将没法经过简单的汇编来实现在两种不一样的架构自如执行的目标,此时将需要进行又一次编写(不少其它信息请參见比較 ARM* 的 NEON* 与英特尔的 SSE 的部分)。android
Java* 原生接口(JNI)将 Android* Java* 代码与由 NDK 预编译的原生代码结合在一块儿。编程
如欲了解有关该接口的不少其它信息,请訪问: http://java.sun.com/docs/books/jni/。架构
以上连接对 JNI 规范进行了普遍、深刻的剖析。 若仅仅是但愿了解其概况。Wiki 页面就能够知足您的要求(存在疑问时,请随时參考规范以检查其正确性)。Wiki 页面的网址例如如下: http://en.wikipedia.org/wiki/Java_Native_Interface。app
JNI 的开销十分庞大。所以在理想状况下,开发者应在应用中尽量下降对 JNI 的调用。ide
详细而言,在 Android* 应用中使用原生代码并不必定能提高性能。一般而言,当原生代码涉及到由 CPU 进行的运算时(如大量使用 SSE 指令),将可以实现必定的性能提高。
但在另一些状况下,如现有的应用仅用于为用户提供复杂的 Web 界面。此时经过 JNI 使用原生代码可能会下降性能。
在什么时候该用和不应用 NDK 上。不存在成文的规则,以上几点仅仅是提供了一些需要注意的通用准则和事项。
开发者可经过下面网址获取 NDK 的最新版本号: http://developer.android.com/sdk/ndk/index.html。 在最新版本号 NDK r6b 中。NDK 可用于构建基于 ARM* 和基于 x86(英特尔® 凌动™ 微架构)的原生库。 这为开发者在一个应用包内进行原生代码移植提供了方便。
开发者将需要为项目建立一个 Android.mk 文件和一个 Application.mk 文件(可选)。当中。Application.mk 文件用于描写叙述您的应用需要哪些原生模块。
Android.mk 文件用于控制怎样和从哪里构建一个模块(静态/共享库)。下面是一个简单 Android.mk 文件的片断:
图 1:简单 Android.mk 文件的内容
构建系统时将前置一个库,并同一时候生成一个名称为 libtest.so 的库。
按预期。开发人员将在 LOCAL_SRC_FILES 中为项目源文件命名。 LOCAL_LDLIBS 和 LOCAL_CFLAGS 分别用于指定 Linking Flag(连接标记)和Compilation Flag(编译标记)。
下面命令行提供了一个有关怎样指定构建指向 x86 架构的演示样例:ndk-build APP_ABI=x86
调用原生库可採用下面两种方法: System.loadLibrary("relative_path_and_name") and System.load("full_path_to_lib_file")。 前者更常用,后者更稳定。 使用前者时,Android.mk 指定的库名称中的“lib”部分可丢弃。 调用示比例如如下:
图 2:调用原生代码演示样例
此外,对于原生代码,开发者需要确保原生代码的输入方法具备正确的 JNIEXPORT 方法签名。而不是典型的 C/C++ 标头。前面说起的 JNI 连接包括有不少其它相关信息。
开发者可经过两种方式载入原生库:1)在 Android* apk 包中提供该库并在执行时对其进行引用;2)在 Android* 文件系统上提供通往该库的绝对路径。
採用以上方式中的哪种取决于开发者的偏好。
但无论採用哪一种方式,均应进行对应的正确处理。
经过使用 adb logcat 命令。开发者可确保在执行时成功载入目标原生库。
下面提供了一个描写叙述原生库已载入的系统日志的演示样例。注意需提供通往原生库文件的完整路径。
图 2:调用原生代码演示样例
以上各部分提供了有关怎样使用 NDK 的入门知识。
如欲了解更加复杂的细节,请阅读 NDK 应用包中包括的相关文档。 这些文档提供有出色的教程和针对各类应用的源码演示样例。
对于大多数应用而言。将现有的 NDK 应用移植到 x86 很easy。
除非原生代码使用 ARM* 特有的特性。不然移植应用仅仅需进行又一次编译、又一次打包和又一次公布操做就能够完毕。
下面内容向您介绍了将 NDK 应用移植到 x86 涉及到的步骤。
x86 支持最早在 android-ndk-r6 中提供,但当时仍存在一些问题,以后谷歌很是快进行了修复。确保您已经从 Android* NDK 站点 下载和安装了最新的(写入时,最新的 NDK 为 android-ndk-r6b)NDK。
使用命令行进行构建的操做与此一样。下面列出了又一次构建演示样例演示 hello-jni 时的演示样例输出内容:
$ android.bat update project --path C:/Tools/android-ndk-r6b/samples/hello-jni
Updated local.properties
Added file C:\Tools\android-ndk-r6b\samples\hello-jni\build.xml
Added file C:\Tools\android-ndk-r6b\samples\hello-jni\proguard.cfg
$ ant -f hello-jni/build.xml debug
Buildfile: C:\Tools\android-ndk-r6b\samples\hello-jni\build.xml
…
debug:
[echo] Running zip align on final apk...
[echo] Debug Package: android-ndk-r6b\samples\hello-jni\bin\HelloJni-debug.apk
BUILD SUCCESSFUL
验证所有二进制代码均已正确打包的最后一步为使用 zip 存档工具打开 APK 并确保当中包括二进制代码。下面是存在 x86 二进制代码时 APK 结构外观的截屏。
将应用移植到 x86 应当很是easy,虽然很是多人可能都有这种想法,但在实际的代码中。仍需要慎重注意并解决英特尔® 凌动™ 和 ARM* 架构之间的差别。下面主题介绍了您在移植过程当中可能遇到的问题以及怎样予以解决。
您的构建环境有可能直接使用了工具链,而不是 Android* 构建脚本。在 ARM* 中,所用的路径例如如下:
android-ndk\toolchains\arm-linux-androideabi-4.4.3
对于 x86。使用路径:
android-ndk\toolchains\x86-4.4.3
有关具体信息。请參阅位于 android-ndk/docs/STANDALONE-TOOLCHAIN.html 的 NDK 文档。
在 ARM* 和英特尔® 凌动™ 微架构之间移植 C/C++ 代码时可能出现内存对齐不匹配的状况。下面文章针对这一点提供了一个典型的演示样例: /en-us/blogs/2011/08/18/understanding-x86-vs-arm-memory-alignment-on-android。基本的一点是:开发人员应当在设计代码时,在必要的地方考虑对数据进行明白的强制对齐。不然,开发人员将没法保证数据在不一样的平台能够获得正确的处理。
眼下,在构建 NDK 库时,可以使用三种支持的应用二进制接口(ABI):
使用此 ABI 建立的二进制代码将可以在所有 ARM* 设备上执行。
所有这些 ABI 选项均支持浮点运算。除非使用的是特定于 ARM* 的汇编指令,不然在将代码移植到 x86 时不会发生故障。其优点在于,假设碰巧您的应用仅针对“armeabi”进行编译,而现在需要支持 x86,则您在进行大多数浮点运算时均能感受到性能提高。
将 ARM* NEON* 指令移植至英特尔® 凌动™ 的英特尔® SSE
虽然这篇短小的文章不可能一应俱全,但是下面提供的信息将可让您大体了解在英特尔架构和 ARM* 中。SIMD 扩展的实施有何不一样。借助此简单介绍,开发人员还将得到一些工具,以便于開始进行一些简单的编码练习。
NEON* 是一种 ARM* 技术,主要用于多媒体(智能手机和高清电视等)应用。ARM* 表示其基于 128 位 SIMD 引擎的技术 – ARM* Cortex*(一种串行扩展)—可提供比 ARM* v5 架构至少高 3 倍的性能,以及比 ARM* v6 至少高 2 倍的性能。如欲了解有关此技术的具体信息。以深刻了解 NEON 及其余性能考虑,请訪问下面网址:http://www.arm.com/products/processors/technologies/neon.php
此处的关键理念为,各寄存器被“堆积”成一个矢量。当中每一个寄存器均为一个元素,并与其余元素的数据类型相匹配。在此基础之上。运算在管道内运行。于是这一方法被称做 Packed SIMD。
SSE 指面向英特尔架构(IA)的SIMD 流指令扩展。眼下,英特尔® 凌动™ 最高支持 SSSE3(补充 SIMD 流指令扩展 3)。
凌动™ 暂不支持 SSE4.x。
后者也是一个 128 位引擎,用于打包浮点数据。这一运行模式開始于 MMX 技术。
SSx 是较新的技术,代替了 MMX。如欲了解具体信息,请參阅英特尔《IA-32 和 IA-64 软件开发者手冊》中的“第一卷: 基础架构”部分。网址为: http://www.intel.com/content/www/cn/zh/processors/architectures-software-developer-manuals.html。
眼下,SSE 概述部分在 5.5 节。
它提供 SSE、SSE二、SSE3 和 SSSE3 的操做码。注意。数据运算通常会涉及处处理基于精度的打包浮点数值;并且需要在 XMM 寄存器之间。或在这些寄存器与内存之间批量数据传输。XMM 寄存器主要用于代替 MMX 寄存器。
在推荐使用前述《英特尔架构软件开发者手冊》来了解所有单个 SSE(x) 助记符的同一时候,咱们也鼓舞开发者经过下面连接了解各类 SSE 汇编级指令。网址为: http://neilkemp.us/src/sse_tutorial/sse_tutorial.html。
在该连接中。您可经过“文件夹”部分直接跳到代码演示样例或首先具体了解某些背景信息。相同,下面直接来自 ARM* 的手冊提供了一些信息和 NEON* 汇编小片断:/sites/default/files/m/b/4/c/DHT0002A_introducing_neon.pdf。
请參阅 ARM* 文档中的第 1.4 节。
下面是在通常层面上比較 NEON 和 SSE 汇编代码时的几个要点(注意:随着技术的发展,信息随时会过期。依据详细的 SIMD 技术和当下的应用编码问题。可能还存在其余差别):
字节存储次序。英特尔仅支持低位优先汇编,而 ARM* 则同一时候支持高位或低位优先顺序(ARM* 支持两种顺序)。在提供的代码演示样例中,同英特尔同样。ARM* 代码採用的也是低位优先顺序。
注意虽然如此,在 ARM 中可能会存在一些编译器影响*。好比,使用 GCC* 为 ARM* 进行编译时具备 -mlittle-endian 和 -mbig-endian 标记。有关具体信息请訪问:http://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html
Granularity. 在引用简单汇编代码演示样例的状况中(请再次注意这并不包括开发者可能发现的 NEON 和 SSE 之间的所有差别),将 SSE 的 ADDPS 指令与 NEON 的 VADD.ix(即:x = 8 或 16)进行比較。
请注意,后者在做为引用助记符的一部分而待处理的数据上有必定粒度减小。
在将 C/C++ 代码 NEON 代码移植到 SSE 时,可能会出现很是多 API 问题。
此处请注意本文的一个若是。即这里未使用内嵌汇编。而使用的是真正的 C/C++ 代码。
对于更高层级的编程。NEON 与 SSE 之间的差别涉及到大尺寸数据(128 位)的处理。
本文针对这样的移植练习提供了一个简短演示样例: http://stackoverflow.com/questions/7203231/neon-vs-intel-sse-equivalence-of-certain-operations
咱们但愿这一指南能够为您提供一些有用信息,帮助您成功将基于 NDK 的应用移植到 x86。移植到 x86 后。您的应用将能够供一种全新类型的 Android* 设备进行下载、购买和使用。假设您在移植过程当中遇到问题,请随时在本文中发表评论。
咱们将很乐意回答您的问题,为您提供帮助。
相关文章与资源:
* 其它的名称和品牌多是其它所有者的资产
英特尔公司 © 2011 年版权所有。 所有权保留。
英特尔、Atom 和凌动是英特尔在美国和/或其它国家的商标。
本文件里包含关于英特尔产品的信息。 本文件不构成对不论什么知识产权的受权,包含明示的、暗示的,也无论是基于禁止反言的原则或其它。
英特尔不承担不论什么其它责任。英特尔在此做出免责声明:本文件不构成英特尔关于其产品的使用和/或销售的不论什么明示或暗示的保证。包含不就其产品的(i)对某一特定用途的适用性、(ii)适销性以及(iii)对不论什么专利、版权或其它知识产权的侵害的承担不论什么责任或做出不论什么担保。
除非通过英特尔的书面容许承认,英特尔的产品无心被设计用于或被用于下面应用:即在这种应用中可因英特尔产品的故障而致使人身伤亡。
英特尔有权随时更改产品的规格和描写叙述,恕不另行通知。设计者不该信赖不论什么英特产品所不具备的特性,设计者亦不该信赖不论什么标有“保留权利”或“没有定义”说明或特性描写叙述。对此。英特尔保留未来对其进行定义的权利,同一时候。英特尔不该为因其往后更改该等说明或特性描写叙述而产生的冲突和不相容承担不论什么责任。此处提供的信息可随时更改,恕不另行通知。请勿依据本文件提供的信息完毕一项产品设计。
本文件所描写叙述的产品可能包括使其与宣称的规格不符的设计缺陷或失误。这些缺陷或失误已收录于勘误表中。可索取得到。
在发出订单以前。请联系当地的英特尔营业部或分销商以获取最新的产品规格。
如欲得到本文涉及的带编号文档的副本或其它英特尔文献。可致电 1-800-548-4725。或訪问:http://www.intel.com/design/literature.htm