ใน 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
บันทึกเหตุผลของการจำกัด
เมื่อแอปถูกจำกัด ให้บันทึกสาเหตุของการจำกัดนั้น CANNOT TRANSLATE
ตัวอย่างข้อมูลโค้ดของการบันทึกจาก
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 ] [-dduration ] [packagepackage-name ] - เพิ่ม/นำแพ็กเกจออกจากรายการที่อนุญาตพิเศษของผู้ใช้ดังนี้
cmd deviceidle whitelist [+/-]
package-name - ตรวจสอบสถานะภายในของ
jobscheduler
และตัวจัดการสัญญาณเตือน: วันที่dumpsys jobscheduler
dumpsys alarm
สแตนด์บายแอป
โหมดสแตนด์บายแอปจะยืดอายุการใช้งานแบตเตอรี่โดยการเลื่อนเวลาเครือข่ายในเบื้องหลัง กิจกรรมและงานของแอปที่ผู้ใช้ไม่ได้ใช้งานอยู่
วงจรการสแตนด์บายแอป
แพลตฟอร์มจะตรวจหาแอปที่ไม่ได้ใช้งานและวางไว้ในแอป สแตนด์บายจนกว่าผู้ใช้จะเริ่มมีส่วนร่วมกับแอป
ในระหว่างระยะการตรวจสอบ แพลตฟอร์มจะตรวจพบว่าแอปไม่ทำงานเมื่อ อุปกรณ์ไม่ได้ชาร์จอยู่และผู้ใช้ไม่ได้เปิดแอปโดยตรง หรือ โดยอ้อมสำหรับเวลาของนาฬิกาและเวลาที่เจาะจง รวมถึงเวลาอยู่หน้าจอที่เฉพาะเจาะจง (การเปิดโดยอ้อมเกิดขึ้นเมื่อแอปที่ทำงานอยู่เบื้องหน้าเข้าถึงบริการในแอปที่ 2)
ในระหว่างโหมดสแตนด์บายแอป แพลตฟอร์มจะป้องกันไม่ให้แอปเข้าถึงเครือข่าย มากกว่าวันละครั้ง การเลื่อนการซิงค์แอปและงานอื่นๆ
แพลตฟอร์มจะออกจากแอปออกจากโหมดสแตนด์บายในกรณีต่อไปนี้
- แอปจะเริ่มทำงาน
- อุปกรณ์เสียบปลั๊กและชาร์จอยู่
แอปที่ใช้งานอยู่จะไม่ได้รับผลกระทบจากการสแตนด์บายแอป แอปจะใช้งานอยู่เมื่อมีสิ่งต่อไปนี้
- การประมวลผลที่ทำงานอยู่เบื้องหน้า (ไม่ว่าจะเป็นกิจกรรมหรือ บริการที่ทำงานอยู่เบื้องหน้า หรือมีกิจกรรมอื่นหรือบริการที่ทำงานอยู่เบื้องหน้าใช้งานอยู่) เช่น ตัวฟังการแจ้งเตือน บริการการช่วยเหลือพิเศษ วอลเปเปอร์เคลื่อนไหว ฯลฯ
- การแจ้งเตือนที่ผู้ใช้ดู เช่น ในหน้าจอล็อก หรือ ถาดการแจ้งเตือน
- ผู้ใช้เปิดใช้อย่างชัดเจน
แอปจะไม่ได้ทำงานอยู่หากไม่มีกิจกรรมใดๆ ข้างต้นเกิดขึ้นเป็นระยะเวลาหนึ่ง
ทดสอบการสแตนด์บายแอป
คุณทดสอบการสแตนด์บายแอปด้วยตนเองได้โดยใช้adb
ต่อไปนี้
คำสั่ง:
adb shell dumpsys battery unplug
adb shell am set-idle
package-name trueadb shell am set-idle
package-name falseadb shell am get-idle
package-name