本指南用於幫助開發者將現有的基於 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