ใน 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