應用電源管理

在Android 9及更高版本中,該平台可以監視應用程序,查看是否會對設備的電池壽命產生負面影響的行為。該平台使用並評估設置規則以提供UX流,使用戶可以選擇限制違反規則的應用程序。

在Android 8.0及更低版本中,通過打ze,應用程序待機,背景限制和背景位置限制等功能存在一些限制。但是,某些應用程序仍然表現出不良行為,其中一些行為已在Android vitals中進行了描述。 Android 9引入了一個操作系統基礎架構,該基礎架構可以根據可以隨時間更新的設置規則來檢測和限​​制應用程序。

背景限制

用戶可以限制應用程序,或者係統可能會建議其檢測到的應用程序對設備的運行狀況產生負面影響。

受限制的應用程序:

  • 仍可由用戶啟動。
  • 無法在後台運行作業/警報或使用網絡。
  • 無法運行前台服務。
  • 可以由用戶更改為不受限制的應用。

設備實施者可以向以下應用添加其他限制:

  • 限制應用程序自重啟。
  • 限制服務不受約束(高風險)。

後台中受限制的應用程序不應消耗任何設備資源,例如內存,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));
  }

AnomalyType的值替換type

設備實施者可以使用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

應用待機

App Standby通過延遲後台網絡活動和用戶未積極使用的應用程序的工作來延長電池壽命。

應用程序待機生命週期

該平台會檢測到不活動的應用程序,並將其置於應用程序待機狀態,直到用戶開始積極參與該應用程序。

檢測階段,平台會在設備未充電用戶未在特定的時鐘時間量和特定的屏幕開啟時間中直接或間接啟動該應用程序時檢測到該應用程序處於非活動狀態。 (當前台應用訪問第二個應用中的服務時,會間接啟動。)

應用程序待機期間,該平台可防止應用程序每天多次訪問網絡,從而延遲了應用程序同步和其他作業。

在以下情況下,平台將從待機狀態退出應用程序

  • 該應用程序變為活動狀態。
  • 設備已插入並正在充電。

活動的應用程序不受應用程序待機的影響。一個應用程序在滿足以下條件時處於活動狀態:

  • 當前在前台的進程(作為活動或前台服務,或由另一個活動或前台服務使用),例如通知偵聽器,可訪問性服務,動態牆紙等。
  • 用戶查看的通知,例如在鎖定屏幕或通知托盤中
  • 已由用戶明確啟動

如果一段時間內未發生上述任何活動,則該應用程序處於非活動狀態

測試應用待機

您可以使用以下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