1. 程式人生 > >android7.0新特性---NDK應用連結至平臺庫

android7.0新特性---NDK應用連結至平臺庫

從 Android 7.0 開始,系統將阻止應用動態連結非公開 NDK 庫,這種庫可能會導致您的應用崩潰。

(1) 檢查應用是否使用第三方庫:

利用 Android 7.0DK 中的 readelf 工具,您可以通過執行以下命令生成給定 .so 檔案的所有動態連結的共享庫列表:

aarch64-linux-android-readelf -dW libMyLibrary.so

通過下面的一些步驟,您可以修復上述型別的錯誤並確保您的應用不會在將來的更新版平臺上崩潰:

(2)如果您的應用使用私有平臺庫,您應更新它,以新增該應用自己的庫副本或使用公開 NDK API

(3)如果您的應用使用訪問私有符號的第三方庫,則聯絡庫作者以更新庫。

(4)請確保將您的所有非 NDK 庫與您的 APK 打包在一起。

(5)使用標準 JNI 函式而非來自 libandroid_runtime.so 的 getJavaVM 和 getJNIEnv

  • AndroidRuntime::getJavaVM -> GetJavaVM from <jni.h>
    AndroidRuntime::getJNIEnv -> JavaVM::GetEnv or
    JavaVM::AttachCurrentThread from <jni.h>.
    
  • (6)使用 __system_property_get 而非來自 libcutils.so
     的私有 property_get 符號。為此,請使用 __system_property_get 及以下 include 函式:
  • #include<sys/system_properties.h>

    :系統屬性的可用性和內容未通過 CTS 進行測試。應執行進一步修復以避免同時使用這些屬性。

  • (7)使用來自 libcrypto.so 的 SSL_ctrl 符號的本地版本。例如,您應在您的 .so 檔案中靜態連結 libcyrpto.a,或從 BoringSSL/OpenSSL 新增一個動態連結的 libcrypto.so 版本,並將其打包到您的 APK 中

您的應用可通過以下三種方式嘗試訪問私有平臺 API:

  • 您的應用直接訪問私有平臺庫。您應更新您的應用以新增該應用的庫副本,或使用公開 NDK API
  • 您的應用使用一個可訪問私有平臺庫的第三方庫。即使您確定您的應用不會直接訪問私有庫,您仍應針對此情景測試您的應用。
  • 您的應用引用一個其 APK 中未包含的庫。例如,如果您嘗試使用您自己的 OpenSSL 副本,但忘記將它與應用的 APK 進行捆綁,則可能會出現此情況。正常情況下,此應用可在包含 libcrypto.so 的 Android 平臺版本上執行。不過,此應用在不包含此庫的新版 Android(例如,Android 6.0 和更高的版本)上會崩潰。為修復此問題,請確保您的 APK 捆綁您的所有非 NDK 庫。

為降低此限制可能對當前釋出的應用的影響,面向 API 級別 23 或更低級別的應用在 Android N 上可暫時訪問頗為常用的一組庫,例如 libandroid_runtime.solibcutils.solibcrypto.so 和 libssl.so

所有應用在呼叫既非公開又不可暫時訪問的 API 時都會生成一個執行時錯誤。結果就是 System.loadLibrary 和 dlopen(3) 同時返回 NULL,並可能導致您的應用崩潰。您應檢查應用程式碼以移除對私有平臺 API 的使用,並使用預覽版裝置或模擬器全面測試應用。如果您不確定您的應用是否使用私有庫,您可以檢查 logcat 以識別執行時錯誤。

下表描述的是根據應用使用的私有原生庫及其目標 API 級別 (android:targetSdkVersion),應用預期顯示的行為。

目標 API 級別 通過動態連結器進行執行時訪問 N Developer Preview 行為 最終 Android N 版本行為 未來的 Android 平臺行為
公開 NDK 任意 可訪問 合乎預期 合乎預期 合乎預期
私有(暫時可訪問的私有庫) 23 或更低 暫時可訪問 合乎預期,但您會在目標裝置上收到一個 logcat 警告和一條訊息。 合乎預期,但您會收到一個 logcat 警告。 執行時錯誤
私有(暫時可訪問的私有庫) 24 或更高 受限 執行時錯誤 執行時錯誤 執行時錯誤
私有(其他) 任意 受限 執行時錯誤 執行時錯誤 執行時錯誤

檢查您的應用是否使用私有庫

為幫助您識別載入私有庫的問題,logcat 可能會生成一個警告或執行時錯誤。例如,如果您的應用面向 API 級別 23 或更低級別,並在執行 Android 7.0 的裝置上嘗試訪問私有庫,您可能會看到一個類似於下面所示的警告:

03-21 17:07:51.502 31234 31234 W linker  : library "libandroid_runtime.so"
("/system/lib/libandroid_runtime.so") needed or dlopened by
"/data/app/com.popular-app.android-2/lib/arm/libapplib.so" is not accessible
for the namespace "classloader-namespace" - the access is temporarily granted
as a workaround for http://b/26394120

這些 logcat 警告通知您哪個庫正在嘗試訪問私有平臺 API,但不會導致您的應用崩潰。但是,如果應用面向 API 級別 24 或更高級別,logcat 會生成以下執行時錯誤,您的應用可能會崩潰:

java.lang.UnsatisfiedLinkError: dlopen failed: library "libcutils.so"
("/system/lib/libcutils.so") needed or dlopened by
"/system/lib/libnativeloader.so" is not accessible for the namespace
"classloader-namespace"
  at java.lang.Runtime.loadLibrary0(Runtime.java:977)
  at java.lang.System.loadLibrary(System.java:1602)