1. 程式人生 > >Android 7.0 行為變更

Android 7.0 行為變更

電池和記憶體

Android 7.0 包括旨在延長裝置電池壽命和減少 RAM 使用的系統行為變更。這些變更可能會影響您的應用訪問系統資源,以及您的應用通過特定隱式 intent 與其他應用互動的方式。

低電耗模式

Android 6.0(API 級別 23)引入了低電耗模式,當用戶裝置未插接電源、處於靜止狀態且螢幕關閉時,該模式會推遲 CPU 和網路活動,從而延長電池壽命。而 Android 7.0 則通過在裝置未插接電源且螢幕關閉狀態下、但不一定要處於靜止狀態(例如使用者外出時把手持式裝置裝在口袋裡)時應用部分 CPU 和網路限制,進一步增強了低電耗模式。

圖 1. 低電耗模式如何應用第一級系統活動限制以延長電池壽命的圖示。

當裝置處於充電狀態且螢幕已關閉一定時間後,裝置會進入低電耗模式並應用第一部分限制:關閉應用網路訪問、推遲作業和同步。如果進入低電耗模式後設備處於靜止狀態達到一定時間,系統則會對 、 鬧鈴、GPS 和 WLAN 掃描應用餘下的低電耗模式限制。無論是應用部分還是全部低電耗模式限制,系統都會喚醒裝置以提供簡短的維護時間視窗,在此視窗期間,應用程式可以訪問網路並執行任何被推遲的作業/同步。

圖 2. 低電耗模式如何在裝置處於靜止狀態達到一定時間後應用第二級系統活動限制的圖示。

請注意,啟用螢幕或插接裝置電源時,系統將退出低電耗模式並移除這些處理限制。此項新增的行為不會影響有關使您的應用適應 Android 6.0(API 級別 23)中所推出的舊版本低電耗模式的建議和最佳做法,如

對低電耗模式和應用待機模式進行鍼對性優化中所討論。您仍應遵循這些建議(例如使用 Google 雲訊息傳遞 (GCM) 傳送和接收訊息)並開始安排更新計劃以適應新增的低電耗模式行為。

Project Svelte:後臺優化

Android 7.0 移除了三項隱式廣播,以幫助優化記憶體使用和電量消耗。此項變更很有必要,因為隱式廣播會在後臺頻繁啟動已註冊偵聽這些廣播的應用。刪除這些廣播可以顯著提升裝置效能和使用者體驗。

移動裝置會經歷頻繁的連線變更,例如在 WLAN 和移動資料之間切換時。目前,可以通過在應用清單中註冊一個接收器來偵聽隱式 廣播,讓應用能夠監控這些變更。由於很多應用會註冊接收此廣播,因此單次網路切換即會導致所有應用被喚醒並同時處理此廣播。

同理,在之前版本的 Android 中,應用可以註冊接收來自其他應用(例如相機)的隱式  和  廣播。當用戶使用相機應用拍攝照片時,這些應用即會被喚醒以處理廣播。

為緩解這些問題,Android 7.0 應用了以下優化措施:

  • 面向 Android 7.0 開發的應用不會收到  廣播,即使它們已有清單條目來請求接受這些事件的通知。在前臺執行的應用如果使用 請求接收通知,則仍可以在主執行緒中偵聽 CONNECTIVITY_CHANGE

如果您的應用使用任何 intent,您仍需要儘快移除它們的依賴關係,以正確適配 Android 7.0 裝置。Android 框架提供多個解決方案來緩解對這些隱式廣播的需求。例如, API 提供了一個穩健可靠的機制來安排滿足指定條件(例如連入無限流量網路)時所執行的網路操作。您甚至可以使用 來適應內容提供程式變化。

如需瞭解有關 Android N 中後臺優化以及如何改寫應用的詳細資訊,請參閱後臺優化

許可權更改

Android 7.0 做了一些許可權更改,這些更改可能會影響您的應用。

系統許可權更改

為了提高私有檔案的安全性,面向 Android 7.0 或更高版本的應用私有目錄被限制訪問 (0700)。此設定可防止私有檔案的元資料洩漏,如它們的大小或存在性。此許可權更改有多重副作用:

在應用間共享檔案

對於面向 Android 7.0 的應用,Android 框架執行的  API 政策禁止在您的應用外部公開 file:// URI。如果一項包含檔案 URI 的 intent 離開您的應用,則應用出現故障,並出現 FileUriExposedException 異常。

要在應用間共享檔案,您應傳送一項 content:// URI,並授予 URI 臨時訪問許可權。進行此授權的最簡單方式是使用  類。如需瞭解有關許可權和共享檔案的詳細資訊,請參閱共享檔案

無障礙改進

為提高平臺對於視力不佳或視力受損使用者的易用性,Android 7.0 做出了一些更改。這些更改一般並不要求更改您的應用程式碼,不過您應仔細檢查並使用您的應用測試這些功能,以評估它們對使用者體驗的潛在影響。

螢幕縮放

Android 7.0 支援使用者設定顯示尺寸,以放大或縮小螢幕上的所有元素,從而提升裝置對視力不佳使用者的可訪問性。使用者無法將螢幕縮放至低於最小螢幕寬度 sw320dp,該寬度是 Nexus 4 的寬度,也是常規中等大小手機的寬度。

圖 3. 右側螢幕顯示的是一臺執行 Android 7.0 系統映像的裝置增大顯示尺寸後的效果。

當裝置密度發生更改時,系統會以如下方式通知正在執行的應用:

  • 如果是面向 API 級別 23 或更低版本系統的應用,系統會自動終止其所有後臺程序。這意味著如果使用者切換離開此類應用,轉而開啟 Settings 螢幕並更改 Display size 設定,則系統會像處理記憶體不足的情況一樣終止該應用。如果應用具有任何前臺程序,則系統會如處理執行時更改中所述將配置變更通知給這些程序,就像對待裝置螢幕方向變更一樣。
  • 如果是面向 Android 7.0 的應用,則其所有程序(前臺和後臺)都會收到有關配置變更的通知,如處理執行時更改中所述。

大多數應用並不需要進行任何更改即可支援此功能,不過前提是這些應用遵循 Android 最佳做法。具體要檢查的事項:

  • 在螢幕寬度為  的裝置上測試您的應用,並確保其充分執行。
  • 當裝置配置發生變更時,更新任何與密度相關的快取資訊,例如快取點陣圖或從網路載入的資源。當應用從暫停狀態恢復執行時,檢查配置變更。

    :如果您要快取與配置相關的資料,則最好也包括相關元資料,例如該資料對應的螢幕尺寸或畫素密度。儲存這些元資料便於您在配置變更後決定是否需要重新整理快取資料。

  • 避免用畫素單位指定尺寸,因為畫素不會隨螢幕密度縮放。應改為使用與密度無關畫素 (dp) 單位指定尺寸。

設定嚮導中的視覺設定

Android 7.0 在“Welcome”螢幕中加入了“Vision Settings”,使用者可以在新裝置上設定以下無障礙功能設定:Magnification gestureFont sizeDisplay size 和話語提示。此項變更讓您可以更容易發現與不同螢幕設定有關的錯誤。要評估此功能的影響,您應在啟用這些設定的狀態下測試應用。您可以在Settings > Accessibility 中找到這些設定。

NDK 應用連結至平臺庫

從 Android 7.0 開始,系統將阻止應用動態連結非公開 NDK 庫,這種庫可能會導致您的應用崩潰。此行為變更旨在為跨平臺更新和不同裝置提供統一的應用體驗。即使您的程式碼可能不會連結私有庫,但您的應用中的第三方靜態庫可能會這麼做。因此,所有開發者都應進行相應檢查,確保他們的應用不會在執行 Android 7.0 的裝置上崩潰。如果您的應用使用原生程式碼,則只能使用公開 NDK API

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

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

應用不應使用 NDK 中未包含的原生庫,因為這些庫可能會發生更改或在不同 Android 版本之間的可用性不同。例如,從 OpenSSL 切換至 BoringSSL 即屬於此類更改。此外,由於不屬於 NDK 中的平臺庫沒有相容性要求,因此不同的裝置可能提供不同級別的相容性。

為降低此限制可能對當前釋出的應用的影響,面向 API 級別 23 或更低級別的應用在 Android N 上可暫時訪問頗為常用的一組庫,例如libandroid_runtime.solibcutils.solibcrypto.so 和 libssl.so。如果您的應用載入其中某個庫,logcat 會生成一個警告,並在目標裝置上顯示一個 Toast 來通知您。如果您看到這些警告,您應更新您的應用以新增該應用自己的庫副本,或僅使用公開 NDK API。將來發布的 Android 平臺可能會完全限制對私有庫的使用,並導致您的應用崩潰。

所有應用在呼叫既非公開又不可暫時訪問的 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)

如果您的應用使用動態連結到私有平臺 API 的第三方庫,您可能也會看到上述 logcat 輸出。利用 Android 7.0DK 中的 readelf 工具,您可以通過執行以下命令生成給定 .so 檔案的所有動態連結的共享庫列表:

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

更新您的應用

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

  • 如果您的應用使用私有平臺庫,您應更新它,以新增該應用自己的庫副本或使用公開 NDK API
  • 如果您的應用使用訪問私有符號的第三方庫,則聯絡庫作者以更新庫。
  • 請確保將您的所有非 NDK 庫與您的 APK 打包在一起。
  • 使用標準 JNI 函式而非來自 libandroid_runtime.so 的 getJavaVM 和 getJNIEnv
    AndroidRuntime::getJavaVM -> GetJavaVM from <jni.h>
    AndroidRuntime::getJNIEnv -> JavaVM::GetEnv or
    JavaVM::AttachCurrentThread from <jni.h>.
    
  • 使用 __system_property_get 而非來自 libcutils.so 的私有 property_get 符號。為此,請使用 __system_property_get 及以下 include 函式:
    #include<sys/system_properties.h>

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

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

Android for Work

Android 7.0 包含一些針對面向 Android for Work 的應用的變更,包括對證書安裝、密碼重置、二級使用者管理、裝置識別符號訪問許可權的變更。如果您是要針對 Android for Work 環境開發應用,則應仔細檢查這些變更並相應地修改您的應用。

  • 您必須先安裝授權證書安裝程式,然後 DPC 才能對其進行設定。對於面向 N SDK 的配置檔案和裝置所有者應用,您應在裝置規範控制器 (DPC) 呼叫DevicePolicyManager.setCertInstallerPackage() 之前安裝授權證書安裝程式。如果尚未安裝此安裝程式,則系統會引發IllegalArgumentException
  • 針對裝置管理員的重置密碼限制現在也適用於配置檔案所有者。裝置管理員無法再使用 DevicePolicyManager.resetPassword() 來清除或更改已經設定的密碼。裝置管理員仍可以設定密碼,但只能在裝置沒有密碼、PIN 碼或圖案時這樣做。
  • 即使設定了限制,裝置所有者和配置檔案所有者仍可以管理帳戶。而且,即使具有 DISALLOW_MODIFY_ACCOUNTS 使用者限制,裝置所有者和配置檔案所有者仍可呼叫 Account Management API。
  • 裝置所有者可以更輕鬆地管理二級使用者。當裝置在裝置所有者模式下執行時,系統將自動設定 DISALLOW_ADD_USER 限制。這樣可以防止使用者建立非託管二級使用者。此外,CreateUser() 和 createAndInitializeUser() 方法已棄用,取而代之的是 DevicePolicyManager.createAndManageUser() 方法。
  • 裝置所有者可以訪問裝置識別符號。裝置所有者可以使用 DevicePolicyManagewr.getWifiMacAddress() 訪問裝置的 WLAN MAC 地址。如果裝置上從未啟用 WLAN,則此方法將返回一個 null 值。
  • 工作模式設定控制工作應用訪問。當工作模式關閉時,系統啟動器通過使工作應用顯示為灰色來指示它們不可用。啟用工作模式會再次恢復正常行為。
  • 從 Settings UI 安裝包含客戶端證書鏈和對應的私鑰的 PKCS #12 檔案時,系統不再將該證書鏈中的 CA 證書安裝到受信任的憑據儲存空間。當應用稍後嘗試檢索客戶端證書鏈時,這不會影響  的結果。如果需要,使用 .crt 或 .cer 副檔名的 DER 編碼格式通過 Settings UI 單獨將 CA 證書安裝到受信任的憑據儲存空間。
  • 從 Android 7.0 開始,可針對每個使用者管理指紋登記和儲存空間。如果配置檔案所有者的裝置規範客戶端 (DPC) 面向 Android N 裝置上的 Android N 之前的版本,則使用者仍可以在該裝置上設定指紋,但工作應用不能訪問裝置指紋。當 DPC 面向 Android N 和更高版本時,使用者可以通過轉到 Settings > Security > Work profile security 專門為託管配置檔案設定指紋。
  • DevicePolicyManager.getStorageEncryptionStatus() 返回新的加密狀態 ENCRYPTION_STATUS_ACTIVE_PER_USER,以表明加密處於活動狀態,且加密金鑰與使用者關聯。僅當 DPC 面向 API 級別 24 和更高級別時才會返回新的狀態。對於面向更早的 API 級別的應用,即使加密金鑰是使用者或配置檔案特有的,系統也會返回 ENCRYPTION_STATUS_ACTIVE

如需瞭解有關 Android 7.0 中針對 Android for Work 所做變更的詳細資訊,請參閱 Android for Work 更新

註解保留

Android 7.0 修復了一個註解可見性被忽略的錯誤。這種問題會導致應用可在執行時訪問原本不允許訪問的註解。這些註解包括:

  • VISIBILITY_BUILD:僅應編譯時可見。
  • VISIBILITY_SYSTEM:執行時應可見,但僅限底層系統。

如果您的應用依賴這種行為,請為執行時必須可用的註解新增保留政策。您可通過使用 @Retention(RetentionPolicy.RUNTIME) 來執行此操作。

其他重要說明

  • 如果一個應用在 Android 7.0 上執行,但卻是針對更低 API 級別開發的,那麼在使用者更改顯示尺寸時,系統將終止此應用程序。應用必須能夠妥善處理此情景。否則,當用戶從最近使用記錄中恢復執行應用時,應用將會出現崩潰現象。

    您應測試應用以確保不會發生此行為。要進行此測試,您可以通過 DDMS 手動終止應用,以造成相同的崩潰現象。

    在密度發生更改時,系統不會自動終止面向 N 及更高版本的應用;不過,這些應用仍可能對配置變更做出不良響應。

  • Android 7.0 上的應用應能夠妥善處理配置變更,並且在後續啟動時不會出現崩潰現象。您可以通過更改字型大小 (Setting >Display > Font size) 並隨後從最近使用記錄中恢復執行應用,來驗證應用行為。
  • 由於之前的 Android 版本中的一項錯誤,系統未能將對主執行緒上的一個 TCP 套接字的寫入操作舉報為違反嚴格模式。Android 7.0 修復了此錯誤。呈現出這種行為的應用現在會引發 android.os.NetworkOnMainThreadException。一般情況下,我們不建議在主執行緒上執行網路操作,因為這些操作通常會出現可能導致 ANR 和卡頓的高尾延遲。
  • Debug.startMethodTracing() 方法系列現在預設在您的共享儲存空間上的軟體包特定目錄中儲存輸出,而非 SD 卡根目錄。這意味著應用不再需要請求 WRITE_EXTERNAL_STORAGE 許可權來使用這些 API 。
  • 許多平臺 API 現在開始檢查在  事務間傳送的大負載,系統現在會將 TransactionTooLargeExceptions 作為 RuntimeExceptions 再次引發,而不再只是默默記錄或抑制它們。一個常見例子是在  上儲存過多資料,導致 ActivityThread.StopInfo 在您的應用面向 Android 7.0 時引發 RuntimeException
  • 如果應用向 View 釋出  任務,並且 View 未附加到視窗,系統會用 View 為  任務排隊;在 View 附加到視窗之前,不會執行 任務。此行為會修復以下錯誤:
    • 如果一項應用是從並非預期視窗 UI 執行緒的其他執行緒釋出到 View,則  可能會因此執行錯誤的執行緒。
    • 如果  任務是從並非環路執行緒的其他執行緒釋出,則應用可能會曝光  任務。
  • 名為 Crypto 的 JCA 提供程式已棄用,因為它僅有的 SHA1PRNG 演算法為弱加密。應用無法再使用 SHA1PRNG(不安全地)派生金鑰,因為不再提供此提供程式。如需瞭解詳細資訊,請參閱博文 Android N 中已棄用“Crypto”安全提供程式