Quản lý nguồn điện cho ứng dụng

Trên Android 9 trở lên, nền tảng này có thể theo dõi các ứng dụng để tìm hành vi ảnh hưởng tiêu cực đến thời lượng pin của thiết bị. Nền tảng này sử dụng và đánh giá các quy tắc thiết lập để cung cấp quy trình trải nghiệm người dùng hạn chế các ứng dụng vi phạm quy tắc.

Trong Android 8.0 trở xuống, có các hạn chế thông qua các tính năng chẳng hạn như Nghỉ, chế độ chờ ứng dụng, giới hạn ở chế độ nền và quyền truy cập thông tin vị trí ở chế độ nền của Google. Tuy nhiên, một số ứng dụng vẫn tiếp tục biểu hiện hành vi xấu, một số theo mô tả trong Android vitals. Android 9 ra mắt một cơ sở hạ tầng hệ điều hành có thể phát hiện và hạn chế ứng dụng dựa trên quy tắc thiết lập và có thể được cập nhật theo thời gian.

Hạn chế trong nền

Người dùng có thể hạn chế các ứng dụng hoặc hệ thống có thể đề xuất những ứng dụng mà hệ thống phát hiện nào ảnh hưởng tiêu cực đến tình trạng của thiết bị.

Ứng dụng bị hạn chế:

  • Người dùng vẫn có thể khởi chạy.
  • Không thể chạy công việc/báo thức hoặc sử dụng mạng ở chế độ nền.
  • Không chạy được các dịch vụ trên nền trước.
  • Có thể được người dùng thay đổi thành ứng dụng không bị hạn chế.

Trình triển khai thiết bị có thể thêm các quy tắc hạn chế bổ sung cho ứng dụng để:

  • Hạn chế việc ứng dụng tự khởi động lại.
  • Hạn chế để các dịch vụ không bị ràng buộc (có rủi ro cao).

Các ứng dụng bị hạn chế ở chế độ nền sẽ không sử dụng bất kỳ tài nguyên thiết bị nào, chẳng hạn như bộ nhớ, CPU và pin. Ứng dụng bị hạn chế chạy trong nền sẽ không ảnh hưởng đến tình trạng thiết bị khi người dùng không chủ động sử dụng các ứng dụng đó. Tuy nhiên, chính những ứng dụng đó dự kiến sẽ đầy đủ chức năng khi người dùng khởi chạy ứng dụng.

Sử dụng các phương pháp triển khai tuỳ chỉnh

Người triển khai thiết bị có thể tiếp tục sử dụng các phương thức tuỳ chỉnh để áp dụng các hạn chế cho ứng dụng.

Tích hợp các hạn chế đối với ứng dụng

Các phần sau đây trình bày cách xác định và tích hợp ứng dụng trên thiết bị của bạn. Nếu bạn đang sử dụng các phương thức hạn chế ứng dụng từ Android 8.x trở xuống, hãy xem kỹ các phần sau để các thay đổi trong Android 9 trở lên.

Đặt cờ AppOpsManager

Khi một ứng dụng bị hạn chế, hãy đặt cờ thích hợp trong AppOpsManager. Đoạn mã mẫu từ 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);
    }

Đảm bảo isBackgroundRestrict trả về true (đúng)

Khi một ứng dụng bị hạn chế, hãy đảm bảo rằng ActivityManager.isBackgroundRestricted() trả về true.

Ghi nhật ký lý do hạn chế

Khi một ứng dụng bị hạn chế, hãy ghi lại lý do hạn chế. Một đoạn mã ví dụ về việc ghi nhật ký từ 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));
  }

Thay thế type bằng giá trị từ AnomalyType.

Trình triển khai thiết bị có thể sử dụng các hằng số được xác định trong 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;
    }

Khi người dùng hoặc hệ thống xoá các hạn chế của một ứng dụng, bạn phải ghi lại lý do xoá các hạn chế. Đoạn mã mẫu về việc ghi nhật ký từ 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));
    }

Các hạn chế đối với ứng dụng thử nghiệm

Để kiểm thử hành vi của các hạn chế đối với ứng dụng trong Android 9 trở lên, hãy sử dụng một trong các lệnh sau:

  • Đặt một ứng dụng vào trạng thái hạn chế:
    appops set package-name RUN_ANY_IN_BACKGROUND ignore
  • Đưa ứng dụng ra khỏi hạn chế và khôi phục hành vi mặc định:
    appops set package-name RUN_ANY_IN_BACKGROUND allow
  • Chuyển ứng dụng ở chế độ nền sang trạng thái rảnh ngay lập tức:
    am make-uid-idle [--user user-id | all | current] package-name
  • Thêm một gói vào tempwhitelist trong một khoảng thời gian ngắn:
    cmd deviceidle tempwhitelist [-u user] [-d duration] [package package-name]
  • Thêm/xoá một gói khỏi danh sách người dùng được phép:
    cmd deviceidle whitelist [+/-]package-name
  • Kiểm tra trạng thái nội bộ của jobscheduler và trình quản lý chuông báo:
    dumpsys jobscheduler
    dumpsys alarm

Chế độ chờ ứng dụng

Chế độ chờ ứng dụng giúp kéo dài thời lượng pin nhờ trì hoãn mạng ở chế độ nền hoạt động và công việc đối với những ứng dụng mà người dùng không thường xuyên sử dụng.

Vòng đời của chế độ chờ ứng dụng

Nền tảng này phát hiện các ứng dụng không hoạt động và đưa những ứng dụng đó vào ứng dụng chế độ chờ cho đến khi người dùng bắt đầu tích cực tương tác với ứng dụng.

Trong giai đoạn phát hiện, nền tảng phát hiện thấy một ứng dụng không hoạt động khi thiết bị đang không sạc người dùng chưa khởi chạy ứng dụng trực tiếp hoặc gián tiếp trong một khoảng thời gian đồng hồ cụ thể cũng như một khoảng thời gian sử dụng thiết bị cụ thể. (Các lần chạy gián tiếp xảy ra khi một ứng dụng trên nền trước truy cập vào dịch vụ trong ứng dụng thứ hai.)

Trong khi ở chế độ chờ ứng dụng, nền tảng sẽ ngăn các ứng dụng truy cập vào mạng nhiều hơn một lần mỗi ngày, trì hoãn quá trình đồng bộ hoá ứng dụng và các công việc khác.

Nền tảng sẽ thoát ứng dụng từ chế độ chờ khi:

  • Ứng dụng sẽ bắt đầu hoạt động.
  • Thiết bị đã được cắm điện và đang sạc.

Chế độ chờ ứng dụng không ảnh hưởng đến các ứng dụng đang hoạt động. Một ứng dụng hoạt động khi:

  • Một quy trình hiện đang chạy ở nền trước (dưới dạng hoạt động hoặc dịch vụ trên nền trước hoặc đang được một hoạt động khác hay dịch vụ trên nền trước khác sử dụng), chẳng hạn như trình nghe thông báo, dịch vụ hỗ trợ tiếp cận, hình nền động, v.v.
  • Một thông báo mà người dùng đã xem, chẳng hạn như trong màn hình khoá hoặc khay thông báo
  • Được người dùng khởi chạy rõ ràng

Ứng dụng ở trạng thái không hoạt động nếu không có hoạt động nào nêu trên xảy ra trong một khoảng thời gian thời gian.

Kiểm thử chế độ chờ của ứng dụng

Bạn có thể kiểm thử chế độ chờ ứng dụng theo cách thủ công bằng adb sau các lệnh:

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