أداة تجميد التطبيقات المخزَّنة مؤقتًا

الإصدار 11 من نظام التشغيل Android (مستوى واجهة برمجة التطبيقات 30) أو إصدار أحدث يتيح استخدام ميزة "تجميد التطبيقات المخزَّنة مؤقتًا". توقف هذه الميزة تنفيذ العمليات المخزَّنة مؤقتًا وتقلّل من استخدام الموارد من قِبل التطبيقات التي قد تحاول العمل أثناء تخزينها مؤقتًا.

تحتفظ ميزة "تجميد التطبيقات المخزَّنة مؤقتًا" بالتطبيقات في ذاكرة الوصول العشوائي (RAM) مع إيقافها عن استخدام وحدة المعالجة المركزية (CPU). إذا رأى نظام Android أنّه لا يجب أن يعمل تطبيق معيّن ولكن قد يكون مطلوبًا في المستقبل، فسيجمّد عملية التطبيق بدلاً من إنهاءها. يمنع ذلك حدوث تشغيل على البارد عندما يكون التطبيق مطلوبًا مرة أخرى.

يجمّد Android التطبيقات المخزَّنة مؤقتًا عن طريق نقل عملياتها إلى مجموعة تحكّم مجمدة. يقلّل ذلك من استهلاك وحدة المعالجة المركزية (CPU) النشطة وغير النشطة في حال وجود تطبيقات نشطة مخزَّنة مؤقتًا. يمكنك تفعيل ميزة "تجميد التطبيقات" باستخدام علامة ضبط النظام أو خيار المطوّرين.

في الإصدار 14 من نظام التشغيل Android (مستوى واجهة برمجة التطبيقات 34) والإصدارات الأحدث، تتضمّن ميزة "تجميد التطبيقات المخزَّنة مؤقتًا" السلوكيات القوية التالية:

  • يتم تجميد عمليات التطبيق في الحالة المخزَّنة مؤقتًا بعد 10 ثوانٍ من الدخول إلى الحالة المخزَّنة مؤقتًا.
  • يزيل النظام على الفور تجميد عملية تطبيق مجمَّدة أثناء حدث دورة الحياة. تشمل هذه الأحداث تلقّي هدف أو بدء خدمة مهمة أو استئناف المستخدم لـ نشاط.

تتولى ActivityManagerService إدارة جميع عمليات التطبيق وتتخذ قرارات دورة حياة التطبيق. تتولى CachedAppOptimizer مسؤولية تجميد عملية التطبيق.

عند تجميد عملية تطبيق، يتم تعليق جميع سلاسل المحادثات الخاصة بها ولا يمكنها تنفيذ أي عمل على وحدة المعالجة المركزية (CPU) إلى أن يتم إزالة تجميدها. نتيجةً لذلك، لا يمكن للتطبيق تنفيذ عملية جمع البيانات غير الضرورية ولا يمكنه الرد على أحداث تقليل الذاكرة. للاطّلاع على التفاصيل، يُرجى الرجوع إلى ComponentCallbacks2.onTrimMemory(int). لحلّ هذه المشكلة، بدءًا من الإصدار 14 من نظام التشغيل Android:

  • يتم إشعار التطبيقات التي تتضمّن مثيلاً مرئيًا من Activity بـ TRIM_MEMORY_UI_HIDDEN فور انتقالها إلى الخلفية. قد تتلقّى التطبيقات التي تظل في دورة حياة بدون واجهة مستخدم، مثل التطبيقات التي تتضمّن خدمة تعمل في المقدّمة، الإشعار TRIM_MEMORY_BACKGROUND. لا يتم تسليم أحداث تقليل الذاكرة الأخرى، لأنّه من المتوقّع أن يتم تجميد التطبيقات عندما تكون مؤهلة لتلقّي هذه الأحداث.
  • بعد فترة قصيرة من الدخول إلى الحالة المخزَّنة مؤقتًا، قد يطلب النظام من وقت تشغيل التطبيق تنفيذ عملية جمع البيانات غير الضرورية استعدادًا لاحتمالية التجميد.
  • عند تجميد عملية تطبيق، قد تحدث خطوات إضافية لضغط الذاكرة، مثل كتابة الصفحات غير النظيفة في وحدة التخزين الاحتياطية ونقل الصفحات المجهولة إلى ZRAM.
  • إذا تم تجميد جميع عمليات تطبيق معيّن، ينهي النظام أي مقابس TCP نشطة يحتفظ بها التطبيق. يمنع ذلك جانب الخادم من المقبس من إرسال طلبات ping لـ TCP keepalive التي من شأنها تنبيه مودم الجهاز.

تتم إزالة تجميد عمليات التطبيقات المخزَّنة مؤقتًا عندما ترتفع حالة العملية من الحالة المخزَّنة مؤقتًا إلى حالة أهمية أعلى. للحد من أحداث إزالة التجميد في الإصدار 14 من نظام التشغيل Android والإصدارات الأحدث، يضع النظام عمليات البث المسجَّلة في السياق في قائمة الانتظار أثناء وجود التطبيق في الحالة المخزَّنة مؤقتًا. عمليات البث المسجَّلة في السياق هي أجهزة استقبال يسجّلها التطبيق ديناميكيًا من خلال استدعاء Context.registerReceiver. لا يسلّم النظام عمليات البث هذه التي تم وضعها في قائمة الانتظار إلا بعد إزالة تجميد التطبيق. في المقابل، لا يضع النظام عمليات البث المُعلَنة في ملف البيان في قائمة الانتظار. عمليات البث المُعلَنة في ملف البيان هي أجهزة استقبال يتم الإعلان عنها بشكل ثابت في AndroidManifest.xml باستخدام العنصر <receiver> يزيل النظام على الفور تجميد التطبيق المخزَّن مؤقتًا لتسليم عمليات البث المُعلَنة في ملف البيان.

التأثير على سلامة النظام

ينهي Android عملية التطبيق المخزَّن مؤقتًا الأقل استخدامًا مؤخرًا إذا كان هناك أكثر من MAX_CACHED_PROCESSES من عمليات التطبيقات المخزَّنة مؤقتًا. على الأجهزة المتوافقة التي تعمل بالإصدار 14 من نظام التشغيل Android أو إصدار أحدث، يتم زيادة MAX_CACHED_PROCESSES بشكل ملحوظ، ما يسمح للأجهزة بالاحتفاظ بعدد أكبر بكثير من عمليات التطبيقات المخزَّنة مؤقتًا في ذاكرة الوصول العشوائي (RAM).

يؤدي الاحتفاظ بعدد أكبر من التطبيقات المخزَّنة مؤقتًا في ذاكرة الوصول العشوائي (RAM) إلى تقليل عمليات التشغيل المتأخِّر على البارد بنسبة تصل إلى% 30، مع تقليل عمليات التشغيل المتأخِّر على البارد بشكل متناسب مع إجمالي ذاكرة الوصول العشوائي (RAM) للجهاز. في الوقت نفسه، يتم تقليل استهلاك وحدة المعالجة المركزية (CPU) من قِبل التطبيقات المخزَّنة مؤقتًا، ما يؤدي إلى توفير شحن البطارية بشكل كبير.

الاستثناءات من ميزة "تجميد التطبيقات"

في ظروف معيّنة، قد تدخل عملية التطبيق إلى الحالة المخزَّنة مؤقتًا ولكن تظل غير مجمَّدة. هذه الاستثناءات هي تفاصيل التنفيذ وقد تتغير في إصدارات Android المستقبلية:

  • عمليات قفل الملفات: إذا كانت عملية مخزَّنة مؤقتًا تحتفظ بقفل ملف يمنع العمليات الأخرى غير المخزَّنة مؤقتًا، فلن يتم تجميد العملية التي تحتفظ بالقفل.
  • BIND_WAIVE_PRIORITY عمليات الربط: يمكن أن تدخل عمليات التطبيق التي تتضمّن عمليات ربط واردة تم إنشاؤها باستخدام Context.BIND_WAIVE_PRIORITY إلى الحالة المخزَّنة مؤقتًا ولكن تظل غير مجمَّدة إلى أن يتم أيضًا تخزين جميع عمليات العميل المتصلة مؤقتًا. يدعم هذا الاستثناء التطبيقات المتعددة العمليات، مثل متصفّحات الويب التي تستخدم علامات التبويب المخصّصة.

تنفيذ ميزة "تجميد التطبيقات"

تستفيد ميزة "تجميد التطبيقات المخزَّنة مؤقتًا" من ميزة "تجميد مجموعة التحكّم" (cgroup) الإصدار 2 في النواة. يمكن للأجهزة التي يتم شحنها بنواة متوافقة تفعيل هذه الميزة. فعِّل خيار المطوّرين تعليق التنفيذ للتطبيقات المخزَّنة مؤقتًا أو اضبط علامة إعداد الجهاز activity_manager_native_boot use_freezer على true. على سبيل المثال:

adb shell device_config put activity_manager_native_boot use_freezer true && adb reboot

يتم إيقاف ميزة "تجميد التطبيقات" عند ضبط العلامة use_freezer على false أو إيقاف خيار المطوّرين. على سبيل المثال:

adb shell device_config put activity_manager_native_boot use_freezer false && adb reboot

يمكنك تبديل هذا الإعداد عن طريق تغيير إعداد الجهاز في إصدار برنامج أو تحديث.

لإلغاء MAX_CACHED_PROCESSES، مثلاً لضبط القيمة على 1024 للاختبار:

adb shell device_config put activity_manager max_cached_processes 1024
adb shell device_config set_sync_disabled_for_tests persistent

لإعادة ضبط الإلغاء لـ MAX_CACHED_PROCESSES:

adb shell device_config delete activity_manager max_cached_processes
adb shell device_config set_sync_disabled_for_tests none

لا تعرض ميزة "تجميد التطبيقات" واجهات برمجة تطبيقات رسمية وليس لديها عميل تنفيذ مرجعي، ولكنها تستخدم واجهات برمجة تطبيقات النظام المخفية setProcessFrozen لتجميد عملية فردية وenableFreezer لتفعيل التجميد أو إيقافه على مستوى العالم.

التعامل مع الميزات المخصّصة

من غير المتوقّع أن تنفّذ عمليات التطبيق أي عمل عند تخزينها مؤقتًا، ولكن قد تتضمّن بعض التطبيقات ميزات مخصّصة يتم دعمها من خلال عمليات من المتوقّع أن يتم تشغيلها أثناء التخزين المؤقت. عند تفعيل ميزة "تجميد التطبيقات" على جهاز يشغّل مثل هذه التطبيقات، يتم تجميد العمليات المخزَّنة مؤقتًا وقد يمنع ذلك الميزات المخصّصة من العمل.

كحل بديل، يمكنك تغيير حالة العملية إلى غير مخزَّنة مؤقتًا قبل أن تحتاج العملية إلى تنفيذ أي عمل. يسمح هذا التغيير للتطبيقات بالبقاء نشطة. تشمل أمثلة الحالات النشطة خدمة تعمل في المقدّمة أو حالة المقدّمة.

أوضاع الأعطال الشائعة

عند تجميد عمليات التطبيق، يمكن أن يؤدي التواصل البيني للعمليات (IPC) غير السليم أو جدولة المهام إلى إنهاء التطبيق أو حدوث سلوك غير متوقّع.

معاملات الرابط المتزامنة للعمليات المجمَّدة

عندما ترسل عملية تطبيق عميل معاملة رابط متزامنة إلى عملية تطبيق خادم مجمَّدة، ينهي النظام على الفور عملية تطبيق الخادم. يمنع ذلك سلسلة محادثات العميل من الحظر إلى أجل غير مسمى أثناء انتظار استجابة من الخادم المجمَّد. تتلقّى سلسلة محادثات العميل بعد ذلك RemoteException، ويتم تفعيل أي مستمعين مسجَّلين. للاطّلاع على التفاصيل، يُرجى الرجوع إلى IBinder.linkToDeath.

السبب الجذري: عادةً ما يكون سبب هذا العطل هو خطأ في تطبيق العميل. عندما يرتبط عميل بخدمة، ترتبط عملية الخادم بالعميل ويتم منعها من الدخول إلى الحالة المخزَّنة مؤقتًا قبل العميل. للاطّلاع على التفاصيل، يُرجى الرجوع إلى Context.bindService. ومع ذلك، بعد أن يستدعي العميل Context.unbindService، يمكن أن تصبح عملية الخادم مخزَّنة مؤقتًا ومجمَّدة. إذا واصل العميل استخدام مرجع IBinder المخزَّن مؤقتًا بعد إلغاء الربط، فإنّه يخاطر بالتواصل مع عملية مجمَّدة.

لتجنُّب هذه المشكلة، تأكَّد من أنّ تطبيقات العميل تتجاهل IBinder المراجع فور استدعاء Context.unbindService.

فائض سعة المخزن المؤقت لمعاملات الرابط غير المتزامنة

عندما تتلقّى عملية تطبيق خادم معاملات رابط غير متزامنة (oneway) أثناء تجميدها، يتم تخزين المعاملات مؤقتًا في مخزن مؤقت لكل عملية. إذا تلقّى الخادم عددًا كبيرًا جدًا من المعاملات غير المتزامنة أثناء تجميده، يحدث فائض سعة المخزن المؤقت، وينهي النظام عملية تطبيق الخادم.

لمنع حدوث فائض سعة المخزن المؤقت هذا، تجنَّب إرسال عدد كبير جدًا من معاملات الرابط غير المتزامنة إلى العمليات التي قد يتم تخزينها مؤقتًا أو تجميدها.

التنفيذ المتكرّر للمهام المجدولة عند إزالة التجميد

إذا كان التطبيق ينفّذ مهام متكرّرة، يتم تعليقها أثناء تجميد العملية. للاطّلاع على التفاصيل، يُرجى الرجوع إلى ScheduledThreadPoolExecutor.scheduleAtFixedRate أو Timer.scheduleAtFixedRate. عند إزالة تجميد العملية، قد يتم تشغيل عمليات التنفيذ المتراكمة التي تم تفويتها بسرعة متتالية بدون أي تأخير تقريبًا.

لمنع حدوث زيادة كبيرة في عمليات التنفيذ عند إزالة تجميد التطبيق، استخدِم scheduleWithFixedDelay بدلاً من scheduleAtFixedRate للمهام التي تعمل في الخلفية. يمكنك أيضًا استخدام WorkManager.

اختبار ميزة "تجميد التطبيقات" وتحديد المشاكل وحلّها

للتحقّق من أنّ ميزة "تجميد التطبيقات" تعمل على النحو المطلوب أو لتحديد المشاكل المتعلقة بميزة "تجميد التطبيقات" وحلّها، استخدِم أدوات وأوامر التشخيص التالية:

أوامر "مدير الأنشطة"

يمكنك استخدام أوامر adb shell am للتحكّم يدويًا في التجميد والضغط لعملية معيّنة:

  • فرض تجميد عملية:

    adb shell am freeze <process>
  • فرض إزالة تجميد عملية:

    adb shell am unfreeze <process>
  • فرض ضغط كامل للذاكرة على عملية:

    adb shell am compact full <process>

فحص أداة Logcat

يمكنك عرض أداة Logcat للاطّلاع على الإدخالات المجمَّدة وغير المجمَّدة في كل مرة تنتقل فيها عملية إلى ميزة "تجميد التطبيقات" أو خارجها:

adb logcat | grep -i "\(freezing\|froze\)"

تعرض سجلّات سبب إزالة التجميد قيمًا مُعدَّدة من تعداد المخزن المؤقت للبروتوكول UnfreezeReason.

فحص أداة Dumpsys

يمكنك البحث عن قائمة بالعمليات المجمَّدة باستخدام dumpsys activity:

adb shell dumpsys activity | grep -A 20 "Apps frozen:"

يمكنك البحث عن الملف /sys/fs/cgroup/uid_0/cgroup.freeze.

ApplicationExitInfo

للاستعلام عن سبب إنهاء عملية سابقة، يُرجى الرجوع إلى ActivityManager.getHistoricalProcessExitReasons. إذا تم إنهاء عملية تطبيق بسبب مشكلة متعلقة بميزة "تجميد التطبيقات"، مثل تلقّي معاملة رابط متزامنة أثناء التجميد، يتم ضبط سبب الخروج على ApplicationExitInfo.REASON_FREEZER.

تتبُّع Perfetto

يتم إرسال الأحداث المتعلقة بميزة "تجميد التطبيقات" إلى مسار باسم Freezer ضمن عملية system_server في عمليات تتبُّع Perfetto:

  • تشير الشرائح Freeze وUnfreeze إلى وقت تغيير حالة العملية.
  • تعرض أحداث updateAppFreezeStateLSP متى يعيد خادم النظام فحص سمات العملية لاتخاذ قرارات التجميد أو إزالة التجميد.

يمكنك فحص هذه الأحداث مباشرةً في واجهة مستخدم Perfetto أو تحليلها باستخدام PerfettoSQL:

INCLUDE PERFETTO MODULE slices.with_context;
SELECT *
FROM process_slice
WHERE process_name = "system_server"
AND track_name = "Freezer"
AND (name LIKE "Freeze %" OR name LIKE "Unfreeze %");

في مكتبة PerfettoSQL العادية، يتم أيضًا تلخيص أحداث ميزة "تجميد التطبيقات" في الجدول android_freezer_events.