A. 說說Android項目中的armeabi,armeabi-v7a和x86
這三者都表示的是CPU類型,早期的Android系統幾乎只支持ARMv5的CPU架構,但是現在已經有7種了。ARMv5,ARMv7 (從2010年起),x86 (從2011年起),MIPS (從2012年起),ARMv8,MIPS64和x86_64 (從2014年起),每一種都關聯著一個相應的ABI(應用程序二進制介面(ApplicationBinary Interface)定義了二進制文件(尤其是.so文件)如何運行在相應的系統平台上,從使用的指令集,內存對齊到可用的系統函數庫)。Android現在的主流CPU是armeabi-v7a。armeabi-v7a是針對有浮點運算或高級擴展功能的ARMv7 CPU。
當一個應用安裝在設備上,只有該設備支持的CPU架構對應的.so文件會被安裝。不同CPU架構的Android手機載入時會在libs下找自己對應的目錄,從對應的目錄下尋找需要的.so文件;如果沒有對應的目錄,就會去armeabi下去尋找,如果已經有對應的目錄,但是如果沒有找到對應的.so文件,也不會去armeabi下去尋找了。
以x86設備為例,x86設備會在項目中的 libs文件夾尋找是否含有x86文件夾,如果含有x86文件夾,則默認為該項目有x86對應的so可運行文件,只有x86文件夾而文件夾下沒有so,程序運行也是會出現findlibrary returned null的錯誤的;如果工程本身不含有x86文件夾,則會尋找armeabi或者armeabi-v7a文件夾,兼容運行。以armeabi-v7a設備為例,該Android設備當然優先尋找libs目錄下的armeabi-v7a文件夾,同樣,如果只有armeabi-v7a文件夾而沒有 so也是會報錯的;如果找不到armeabi-v7a文件夾,則尋找armeabi文件夾,兼容運行該文件夾下的so,但是不能兼容運行x86的so。所以項目中如果只含有x86的so,在armeabi和armeabi-v7a也是無法運行的。以上就是不同CPU架構運行時載入so的策略。
目前主流的Android設備是armeabi-v7a架構的,然後就是x86和armeabi了。如果同時包含了 armeabi,armeabi-v7a和x86,所有設備都可以運行,程序在運行的時候去載入不同平台對應的so,這是較為完美的一種解決方案,但是同時也會導致包變大。
armeabi-v7a是可以兼容armeabi的,而v7a的CPU支持硬體浮點運算,目前絕大對數設備已經是armeabi-v7a了,所以為了性能上的更優,就不要為了兼容放到armeabi下了。x86也是可以兼容armeabi平台運行的,另外需要指出的是,打出包的x86的so,總會比armeabi平台的體積更小,對於性能有潔癖的童鞋們,還是建議在打包so的時候支持x86。
第三方的類庫只提供了armeabi下的.so文件,我們項目里適配了armeabi-v7a和x86,如果不在對應的文件下放對應的.so文件,就可能導致某些Android設備會出一些問題,我們可以復制armeabi下得.so文件到不同的文件夾下。如果第三方提供了不同平台的.so文件,則復制不同平台的.so文件到項目中對應的文件夾下即可。
關於.so文件之前有一個坑,svn會把提交的so文件過濾掉,在接第三方SDK的時候通過SVN更新了文檔,但是沒有注意到少了幾個so文件,浪費了大把的時間去找原因。記得去掉svn對so的忽略!!!
B. Android 的ARM架構和X86架構
Android開發中,在打包發布應用時會選擇應用適配的cpu架構平台,在引用第三方庫時也遇到根據不同cpu架構引入相應的so包。Android主要包括一下cpu架構:
在Android系統上,每一個CPU架構對應一個ABI:
ABI是Application Binary Interface的縮寫,常表示兩個程序模塊之間的介面,且其中一個模塊常為機器碼級別的library或操作系統。它定義了函數庫的調用、應用的二進制文件(尤其是.so)如何運行在相應的系統平台上等細節。其中mips及mips64極少用於手機,出發點是高性能,主要用於路由器、貓。
從CPU發明到現在,有非常多種架構,從我們熟悉的X86,ARM,到不太熟悉的MIPS,IA64,它們之間的差距都非常大。但是如果從最基本的邏輯角度來分類的話,它們可以被分為兩大類,即所謂的「復雜指令集(CISC)」與「精簡指令集(RISC)」系統。
Intel和ARM處理器的第一個區別是,前者使用復雜指令集(CISC),後者使用精簡指令集(RISC)。屬於這兩種類中的各種架構之間最大的區別,在於它們的設計者考慮問題方式的不同。
ARM架構是一個32位精簡指令集RISC(Reced Instruction Set Computing)處理器架構,其廣泛地使用在許多嵌入式系統設計。但在其他領域上也有很多作為,由於節能的特點,ARM處理器非常適用於移動通信領域,匹配其主要設計目標為低成本、高性能、低耗電的特性。
ARM的優勢不在於性能強大而在於效率,ARM採用RISC流水線指令集,在完成綜合性工作方面根本就處於劣勢,而在一些任務相對固定的應用場合其優勢就能發揮得淋漓盡致。ARM結構的電腦是通過專用的數據介面使CPU與數據存儲設備進行連接,所以ARM的存儲、內存等性能擴展難以進行(一般在產品設計時已經定好其內存及數據存儲的容量),所以採用ARM結構的系統,一般不考慮擴展。基本奉行「夠用就好」的原則。
x86 架構是一個復雜指令集CISC(Complex Instruction Set Computer)處理器架構。X86結構的電腦無論如何都比ARM結構的系統在性能方面要快得多、強得多。X86的CPU隨便就是1G以上、雙核、四核。X86結構的電腦採用「橋」的方式與擴展設備(如:硬碟、內存等)進行連接,而且x86結構的電腦出現了近30年,其配套擴展的設備種類多、價格也比較便宜,所以x86結構的電腦能很容易進行性能擴展,如增加內存、硬碟等。
C. Android中的armeabi、armeabi-v7a、arm64-v8a及x86的詳解
一. lib和libs
放在lib中的是被reference的,放在libs中的是被include的。
放在libs中的文件會自動被編輯器所include。所以不要把API放到libs里去。
lib的內容是不會被打包到APK中,libs中的內容是會被打包進APK中
二. .so庫
NDK編譯出來的動態鏈接庫。
一些重要的加密演算法或者核心協議一般都用c寫然後給java調用。這樣可以避免反編譯後查看到應用的源碼。
三. .so庫該如何存放
放置 .so 文件的正確姿勢其實就兩句話:
• 為了減小 apk 體積,只保留 armeabi 和 armeabi-v7a 兩個文件夾,並保證這兩個文件夾中 .so 數量一致
• 對只提供 armeabi 版本的第三方 .so,原樣復制一份到 armeabi-v7a 文件夾
存放so的規則:
你應該盡可能的提供專為每個ABI優化過的.so文件,但要麼全部支持,要麼都不支持:你不應該混合著使用。你應該為每個ABI目錄提供對應的.so文件。
四. libs下armeabi等的作用是什麼
存放.so庫,主要針對不同的設備兼容,也可以說是專門針對不同Android手機下CPU架構的兼容。
Android 設備的CPU類型(通常稱為」ABIs」)
早期的Android系統幾乎只支持ARMv5的CPU架構,後面發展到支持七種不同的CPU架構:ARMv5,ARMv7 (從2010年起),x86 (從2011年起),MIPS (從2012年起),ARMv8,MIPS64和x86_64 (從2014年起),每一種都關聯著一個相應的ABI。
應用程序二進制介面(Application Binary Interface)定義了二進制文件(尤其是.so文件)如何運行在相應的系統平台上,從使用的指令集,內存對齊到可用的系統函數庫。在Android 系統上,每一個CPU架構對應一個ABI:armeabi,armeabi-v7a,x86,mips,arm64- v8a,mips64,x86_64。
armeabi-v7a: 第7代及以上的 ARM 處理器。2011年以後生產的大部分Android設備都使用它.
arm64-v8a: 第8代、64位ARM處理器,很少設備,三星 Galaxy S6是其中之一。
armeabi: 第5代、第6代的ARM處理器,早期的手機用的比較多。
x86: 平板、模擬器用得比較多。
x86_64: 64位的平板。
如果項目只包含了 armeabi,那麼在所有Android設備都可以運行;
如果項目只包含了 armeabi-v7a,除armeabi架構的設備外都可以運行;
如果項目只包含了 x86,那麼armeabi架構和armeabi-v7a的Android設備是無法運行的; 如果同時包含了 armeabi, armeabi-v7a和x86,所有設備都可以運行,程序在運行的時候去載入不同平台對應的so,這是較為完美的一種解決方案,同時也會導致包變大。
最後,如果我們只想支持armeabi-v7a,那麼需要在gradle中配置
因為默認情況下,打包後會自動生成armeabi 到 x86的所有文件夾。這就有可能導致一些x86的設備因為在x86文件夾下找不到so文件而崩潰。