UnsatisfiedLinkError X.so is 64-bit instead of 32-bit之Android 64 bit SO加載機制

今天用戶反饋應用閃退崩潰了。然後找呀找…
過程原來是這樣的:

還是說下項目背景

  1. 應用本身是個Android App,感覺這是費話呵,引用了一個JAVA項目。在應用啓動後會將App res/raw中的動態庫壓縮包複製到Sdcard進行解壓,然後使用System.load(libPath)加載。libPath是根據System.getProperty(“os.arch”);獲取當前處理器的架構動態匹配出來的(例:mnt/sdcard/mylib/armv7l/a.so)。
  2. 前期開發時只放了armv7l的動態庫,當一些有錢的客戶買了新的Android設備後,如果處理器是aarch64的架構,問題就來了,加載mnt/sdcard/mylib/aarch64/a.so時,這個路徑下是沒有so的。
  3. 與 此同時App項目的lib/目錄還是有其它so的。

Canney原創,轉載請註明:http://blog.csdn.net/canney_chen/article/details/50633982

爲解決上面的這個問題,那當然是再生成一個aarch64的動態庫。當這一些就緒後就出瞭如題UnsatisfiedLinkError a.so is 64-bit instead of 32-bit 的錯誤。

以下是對產生這個錯誤進行的相關研究

從錯誤信息可以看出:

  1. 從錯誤信息可以看出當前的a.so爲64 bit這個是沒有問題的。
  2. 但從 instead of 32-bit可以看出當前的環境並不是64 bit的而是32 bit。

當前設備是64 bit爲什麼運行的程序是32 bit環境??

於是找到了下面的這個資料:http://malideveloper.arm.com/downloads/01_Demystifying_64-bit_development_on_Android_Ramin_Zaghi.pdf
這份文檔第一部分寫了ARM 64-bit Architecture in Android™,其中的一個圖拉出來看看。
How does it all Work by ARM 64-bit Architecture in Android

How Does It All Work?

  • All Apps are forked from a background Virtual Machine (VM) process called Zygote
  • Multilib devices run two Zygotes (a 32-bit one and a 64-bit one) in parallel!
  • When an application is launched on a 64-bit system
    • If it contains a supported 64-bit library, it runs as a 64-bit process against the loaded system
    • If it contains a supported 32-bit library, it is launched as a 32-bit process
    • Applications with no native code are launched using the default virtual machine (typically 64-bit)

上面這段話是原文對上圖的說明,能看懂的就略過我下面的解析。

  • 所有的app運行都是由Zygote進程創建VM再運行的。
  • 支持多種庫運行的設備,有兩個Zytgote(一個32-bit,一個64-bit)進程同時運行。
  • 當App運行在64-bit 系統上時:
    • 如果App包含64-bit庫,它將運行在一個64位進程中,即VM是由Zytgote 64創建的(圖中的2)。
    • 如果App包含32-bit 庫,它將運行在一個32 bit進程中,即VM是由Zytgote創建的(圖中的3)
    • 如果App不包含本地庫,它將默認運行在64 bit進程中。

對於圖中的1,4,5位置表明系統默認運行在64 bit進程中。

有了上面的基礎後,對錯誤就不難理解了:
1. App是否包含本地庫、32/64bit是從App/libs目錄下進行掃描的。
2. 我的應用在App/libs目錄下只有32 bit的so。根據上面的第二條可以判斷出我的應用Zytgote(32)創建的VM加載起來的。即32-bit進程在運行。
3. 動態從sdcard加載的a.so(64-bit)對應用啓動來說並不知道。

綜合上面的分析得出錯誤產生的原因。

解決辦法就是:

  • 方法1:所有so都增加aarch64的so(動態加載及App/libs下的so)。
  • 方法2:所有so都使用32-bit的(即把原來匹配aarch64目錄下的so,刪除換成32位的或將aarch64直接匹配到32位的arm7l目錄)。

總結一下

  • aarch64是armv8架構下的64-bit執行狀態, 當然同版本下還有aarch32 32-bit執行狀態,具體可以查看[ARMv8 百度百科]
  • 64-bit/32-bit 動態庫不能混用
  • 64-bit處理器可以向下兼容32-bit指令集,即可以運行32-bit動態庫
  • 當App中沒有使用到64-bit處理器特性且動態庫容量很大時可以考慮只使用32-bit動態庫,這樣可以減小安裝包的大小。

Canney原創,轉載請註明:http://blog.csdn.net/canney_chen/article/details/50633982

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章