Quản lý nguồn của ứng dụng

Trên Android 9 trở lên, nền tảng 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 luồng trải nghiệm người dùng cho phép 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 như Chế độ nghỉ, chế độ chờ ứng dụng, giới hạn ở chế độ nền và giới hạn vị trí ở chế độ nền. Tuy nhiên, một số ứng dụng vẫn tiếp tục thể hiện hành vi xấu, một số hành vi trong số đó được 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ế các ứng dụng dựa trên các quy tắc thiết lập có thể cập nhật theo thời gian.

Hạn chế trong nền

Người dùng có thể hạn chế ứng dụng hoặc hệ thống có thể đề xuất các ứng dụng mà hệ thống phát hiện là đang tác độ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ể chạy.
  • Không thể chạy công việc/chuông báo hoặc sử dụng mạng ở chế độ nền.
  • Không thể chạy dịch vụ trên nền trước.
  • Người dùng có thể thay đổi thành ứng dụng không bị hạn chế.

Người triển khai thiết bị có thể thêm các quy định hạn chế khác vào ứng dụng để:

  • Hạn chế ứng dụng tự khởi động lại.
  • Hạn chế liên kết các dịch vụ (rất rủi ro).

Các ứng dụng bị hạn chế chạy trong nền không được tiêu thụ bất kỳ tài nguyên nào của thiết bị, chẳng hạn như bộ nhớ, CPU và pin. Ứng dụng bị hạn chế ở chế độ nền không được ả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, các ứng dụng đó vẫn phải hoạt động đầy đủ khi người dùng khởi chạy.

Sử dụng phương thức 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 của họ để áp dụng các hạn chế đối với ứng dụng.

Tích hợp các quy định 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 các hạn chế về ứng dụng trên thiết bị. 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 xét kỹ các phần sau đây để biết những 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ã ví dụ 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 isBackgroundRestricted trả về true

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

Ghi lại 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ế. Đ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.

Người 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ã ví dụ 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));
    }

Kiểm thử các hạn chế đối với ứng dụng

Để kiểm thử hành vi của các quy định 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 ứng dụng vào chế độ hạn chế:
    appops set package-name RUN_ANY_IN_BACKGROUND ignore
  • Bỏ hạn chế đối với một ứng dụng và khôi phục hành vi mặc định:
    appops set package-name RUN_ANY_IN_BACKGROUND allow
  • Đặt ứng dụng ở chế độ nền chuyể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á gói khỏi danh sách cho phép của người dùng:
    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 bằng cách trì hoãn hoạt động mạng và công việc ở chế độ nền cho các ứng dụng mà người dùng không đang sử dụng.

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

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

Trong giai đoạn phát hiện, nền tảng phát hiện một ứng dụng không hoạt động khi thiết bị không sạc người dùng không 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 cụ thể cũng như một khoảng thời gian cụ thể màn hình bật. (Lượt 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 một dịch vụ trong ứng dụng thứ hai.)

Trong trạng thái 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 lần trong ngày, trì hoãn việc đồng bộ hoá ứng dụng và các công việc khác.

Nền tảng thoát ứng dụng khỏi trạng thái chờ khi:

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

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

  • Một quy trình hiện đang ở nền trước (dưới dạng một hoạt động hoặc dịch vụ trên nền trước hoặc đang được một hoạt động hoặc 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.
  • 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 một cách rõ ràng

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

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

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

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