การจัดการพลังงานของแอป

ใน Android 9 ขึ้นไปแพลตฟอร์มสามารถตรวจสอบแอปเพื่อหาพฤติกรรมที่ส่งผลเสียต่ออายุการใช้งานแบตเตอรี่ของอุปกรณ์ แพลตฟอร์มใช้และประเมินกฎการตั้งค่าเพื่อจัดเตรียมโฟลว์ UX ที่ให้ผู้ใช้มีตัวเลือกในการ จำกัด แอปที่ละเมิดกฎ

ใน Android 8.0 และต่ำกว่านั้นมีข้อ จำกัด ผ่านคุณสมบัติต่างๆเช่น Doze การสแตนด์บายของแอปการ จำกัด พื้นหลังและการ จำกัด ตำแหน่งพื้นหลัง อย่างไรก็ตามแอปบางแอปยังคงแสดงพฤติกรรมที่ไม่ดีซึ่งบางแอปอธิบายไว้ใน 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 ส่งคืนจริง

เมื่อแอปถูก จำกัด ตรวจสอบให้แน่ใจว่า 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