在 Android 9 以上版本中,這個平台可監控應用程式的行為, 會對裝置的電池續航力造成負面影響平台會使用和 評估設定規則,提供使用者體驗流程,讓使用者選擇 限制違規應用程式
在 Android 8.0 以下版本中,我們發現某些功能會受到限制 例如打盹、應用程式待命、背景限制和背景位置資訊等功能 不過,有些應用程式還是持續出現不良行為, 請參閱 Android Vitals。 Android 9 導入了可偵測及限制的 OS 基礎架構 並定義適當的設定規則,且這些規則可以隨著時間更新。
背景限制
使用者可以限制應用程式,系統也可能會建議該應用程式 會對裝置的健康狀態有負面影響。
受限制的應用程式:
- 仍可由使用者啟動。
- 無法執行工作/鬧鐘,也無法在背景使用網路。
- 無法執行前景服務。
- 使用者可以變更為不受限制的應用程式。
裝置實作者可以為應用程式新增額外限制,以達成下列目的:
- 限制應用程式不會自行重新啟動。
- 限制服務無法繫結 (高風險)。
在背景中受限制的應用程式不會耗用任何裝置資源,例如 包括記憶體、CPU 和電池在下列情況中,背景受限制的應用程式不應影響裝置健康狀態 使用者未主動使用這些應用程式不過,這個應用程式 正常運作。
使用自訂導入方式
裝置實作者可以繼續使用自訂方法,為應用程式套用限制。
整合應用程式限制
以下各節將說明如何定義及整合應用程式 你的裝置受到限制如果您使用應用程式限制方法 (適用於 Android 8.x 以下版本),請詳閱下列各節,瞭解 Android 9 以上版本的變更。
設定 AppOpsManager 標記
應用程式受到限制時,請在以下位置設定適當的標記:
AppOpsManager
。以下是
packages/apps/Settings/src/com/android/settings/fuelgauge/BatteryUtils.java
:
public void setForceAppStandby(int uid, String packageName, int mode) { final boolean isPreOApp = isPreOApp(packageName); if (isPreOApp) { // Control whether app could run in the background if it is pre O app mAppOpsManager.setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, uid, packageName, mode); } // Control whether app could run jobs in the background mAppOpsManager.setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName, mode); }
確保 isBackgroundRestricted 傳回 true
應用程式受到限制時,請確認
ActivityManager.isBackgroundRestricted()
會傳回 true
。
記錄限制原因
如果應用程式受到限制,請記錄限制原因。一個
用來登入
packages/apps/Settings/src/com/android/settings/fuelgauge/batterytip/actions/RestrictAppAction.java
:
mBatteryUtils.setForceAppStandby(mBatteryUtils.getPackageUid(packageName), packageName,AppOpsManager.MODE_IGNORED); if (CollectionUtils.isEmpty(appInfo.anomalyTypes)) { // Only log context if there is no anomaly type mMetricsFeatureProvider.action(mContext, MetricsProto.MetricsEvent.ACTION_TIP_RESTRICT_APP, packageName, Pair.create(MetricsProto.MetricsEvent.FIELD_CONTEXT,metricsKey)); } else { // Log ALL the anomaly types for (int type : appInfo.anomalyTypes) { mMetricsFeatureProvider.action(mContext, MetricsProto.MetricsEvent.ACTION_TIP_RESTRICT_APP, packageName, Pair.create(MetricsProto.MetricsEvent.FIELD_CONTEXT, metricsKey), Pair.create(MetricsProto.MetricsEvent.FIELD_ANOMALY_TYPE, type)); }
將 type
替換為 AnomalyType
的值。
裝置實作者可以使用
src/com/android/settings/fuelgauge/batterytip/StatsManagerConfig.java
:
public @interface AnomalyType { // This represents an error condition in the anomaly detection. int NULL = -1; // The anomaly type does not match any other defined type. int UNKNOWN_REASON = 0; // The application held a partial (screen off) wake lock for a period of time that // exceeded the threshold with the screen off when not charging. int EXCESSIVE_WAKELOCK_ALL_SCREEN_OFF = 1; // The application exceeded the maximum number of wakeups while in the background // when not charging. int EXCESSIVE_WAKEUPS_IN_BACKGROUND = 2; // The application did unoptimized Bluetooth scans too frequently when not charging. int EXCESSIVE_UNOPTIMIZED_BLE_SCAN = 3; // The application ran in the background for a period of time that exceeded the // threshold. int EXCESSIVE_BACKGROUND_SERVICE = 4; // The application exceeded the maximum number of wifi scans when not charging. int EXCESSIVE_WIFI_SCAN = 5; // The application exceed the maximum number of flash writes int EXCESSIVE_FLASH_WRITES = 6; // The application used more than the maximum memory, while not spending any time // in the foreground. int EXCESSIVE_MEMORY_IN_BACKGROUND = 7; // The application exceeded the maximum percentage of frames with a render rate of // greater than 700ms. int EXCESSIVE_DAVEY_RATE = 8; // The application exceeded the maximum percentage of frames with a render rate // greater than 16ms. int EXCESSIVE_JANKY_FRAMES = 9; // The application exceeded the maximum cold start time - the app has not been // launched since last system start, died or was killed. int SLOW_COLD_START_TIME = 10; // The application exceeded the maximum hot start time - the app and activity are // already in memory. int SLOW_HOT_START_TIME = 11; // The application exceeded the maximum warm start time - the app was already in // memory but the activity wasn't created yet or was removed from memory. int SLOW_WARM_START_TIME = 12; // The application exceeded the maximum number of syncs while in the background. int EXCESSIVE_BACKGROUND_SYNCS = 13; // The application exceeded the maximum number of gps scans while in the background. int EXCESSIVE_GPS_SCANS_IN_BACKGROUND = 14; // The application scheduled more than the maximum number of jobs while not charging. int EXCESSIVE_JOB_SCHEDULING = 15; // The application exceeded the maximum amount of mobile network traffic while in // the background. int EXCESSIVE_MOBILE_NETWORK_IN_BACKGROUND = 16; // The application held the WiFi lock for more than the maximum amount of time while // not charging. int EXCESSIVE_WIFI_LOCK_TIME = 17; // The application scheduled a job that ran longer than the maximum amount of time. int JOB_TIMED_OUT = 18; // The application did an unoptimized Bluetooth scan that exceeded the maximum // time while in the background. int LONG_UNOPTIMIZED_BLE_SCAN = 19; // The application exceeded the maximum ANR rate while in the background. int BACKGROUND_ANR = 20; // The application exceeded the maximum crash rate while in the background. int BACKGROUND_CRASH_RATE = 21; // The application exceeded the maximum ANR-looping rate. int EXCESSIVE_ANR_LOOPING = 22; // The application exceeded the maximum ANR rate. int EXCESSIVE_ANRS = 23; // The application exceeded the maximum crash rate. int EXCESSIVE_CRASH_RATE = 24; // The application exceeded the maximum crash-looping rate. int EXCESSIVE_CRASH_LOOPING = 25; // The application crashed because no more file descriptors were available. int NUMBER_OF_OPEN_FILES = 26; }
當使用者或系統移除應用程式的限制時,您必須
記錄移除限制的原因。記錄範例的程式碼片段
packages/apps/Settings/src/com/android/settings/fuelgauge/batterytip/actions/UnrestrictAppAction.java
:
public void handlePositiveAction(int metricsKey) { final AppInfo appInfo = mUnRestrictAppTip.getUnrestrictAppInfo(); // Clear force app standby, then app can run in the background mBatteryUtils.setForceAppStandby(appInfo.uid, appInfo.packageName, AppOpsManager.MODE_ALLOWED); mMetricsFeatureProvider.action(mContext, MetricsProto.MetricsEvent.ACTION_TIP_UNRESTRICT_APP, appInfo.packageName, Pair.create(MetricsProto.MetricsEvent.FIELD_CONTEXT, metricsKey)); }
測試應用程式限制
如要測試 Android 9 以上版本中的應用程式限制行為,請使用 以下指令:
- 限制應用程式存取權:
appops set package-name RUN_ANY_IN_BACKGROUND ignore
- 解除應用程式限制,並還原預設行為:
appops set package-name RUN_ANY_IN_BACKGROUND allow
- 讓應用程式立即進入閒置狀態:
am make-uid-idle [--user user-id | all | current] package-name
- 將套件新增至
tempwhitelist
,縮短時間長度:cmd deviceidle tempwhitelist [-u user] [-d duration] [package package-name]
- 在使用者許可清單中新增/移除套件:
cmd deviceidle whitelist [+/-]package-name
- 檢查
jobscheduler
和鬧鐘管理員的內部狀態:dumpsys jobscheduler
dumpsys alarm
應用程式待命
應用程式待命功能會延後背景網路,藉此延長電池續航力 。
應用程式待命生命週期
平台會偵測閒置的應用程式,並放置在應用程式內 當使用者開始主動與應用程式互動為止。
在偵測階段,平台會偵測出應用程式在下列情況處於閒置狀態: 裝置未充電「且」使用者未直接啟動應用程式,或 或特定的螢幕開啟時間。 (當前景應用程式在第二個應用程式中存取服務時,就會發生間接啟動)。
在應用程式待命期間,平台會防止應用程式進一步存取網路 也就是延後應用程式同步處理和其他工作。
下列情況時,平台會從待機模式退出應用程式:
- 應用程式就會生效。
- 裝置已接上電源並開始充電。
使用中的應用程式不會受到應用程式待機模式的影響。符合下列條件的應用程式就會成為「使用中」:
- 前景中目前程序 (以活動或 前景服務,或供其他活動或前景服務使用), 例如通知事件監聽器、無障礙服務、動態桌布等
- 使用者查看的通知,例如螢幕鎖定 通知匣
- 由使用者明確啟動
如果應用程式在某段時間內未發生上述任何活動,表示應用程式已停用 讓應用程式從可以最快做出回應的位置 回應使用者要求
測試應用程式待命模式
您可以使用下列 adb
手動測試應用程式待命模式
指令:
adb shell dumpsys battery unplug
adb shell am set-idle package-name true
adb shell am set-idle package-name false
adb shell am get-idle package-name