في الإصدار 9 من Android والإصدارات الأحدث، يمكن لمنصّة Android مراقبة التطبيقات بحثًا عن السلوك الذي يؤثر سلبًا في عمر بطارية الأجهزة. تستخدم المنصة قواعد الإعداد وتقييمها لتوفير تجربة مستخدم تتيح للمستخدمين حظر التطبيقات التي تنتهك القواعد.
في الإصدار 8.0 من نظام التشغيل Android والإصدارات الأقدم، كانت هناك قيود من خلال ميزات مثل وضع "الاستراحة الذكية" ووضع "الاستعداد" للتطبيقات والقيود المفروضة على النشاط في الخلفية والقيود المفروضة على تحديد الموقع الجغرافي في الخلفية. ومع ذلك، استمرت بعض التطبيقات في عرض سلوكيات سيئة، وبعضها описан في مؤشرات Android الحيوية. قدّم نظام التشغيل 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 يعرض القيمة true.
عند حظر تطبيق، تأكَّد من أنّه عند إدخال 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