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

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

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

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

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

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

يدير ActivityManagerService جميع عمليات التطبيق ويتخذ قرارات بشأن دورة حياة التطبيق. تتحمّل CachedAppOptimizer مسؤولية إيقاف عملية التطبيق.

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

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

تتم إعادة تفعيل عمليات التطبيق المخزّنة مؤقتًا عندما ترتفع حالة العملية من مخزّنة مؤقتًا إلى حالة ذات أهمية أعلى. للحدّ من أحداث إلغاء التجميد في نظام التشغيل Android 14 والإصدارات الأحدث، يضع النظام عمليات البث المسجّلة في السياق في قائمة الانتظار أثناء وجود التطبيق في حالة التخزين المؤقت. عمليات البث المسجّلة حسب السياق هي أجهزة استقبال يسجّلها التطبيق بشكل ديناميكي من خلال استدعاء 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 v2 في النواة. ويمكن تفعيلها على الأجهزة التي تتضمّن نواة متوافقة. فعِّل خيار المطوّر تعليق التنفيذ للتطبيقات المخزّنة مؤقتًا أو اضبط علامة إعدادات الجهاز 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

بدءًا من Android 16 (المستوى 36 لواجهة برمجة التطبيقات) والإصدارات الأحدث، يوفّر نظام التشغيل Android واجهات برمجة تطبيقات رسمية وعامة، مثل IBinder.FrozenStateChangeCallback وIBinder.addFrozenStateChangeCallback، لمراقبة وقت تجميد العمليات البعيدة أو إلغاء تجميدها. يمكن للمكوّنات التي تتفاعل مع التطبيقات التي قد يتم تخزينها مؤقتًا استخدام واجهات برمجة التطبيقات هذه لتتبُّع حالة التجميد للعمليات البعيدة.

متطلبات الجهاز ونظام التشغيل

تتطلّب ميزة تجميد التطبيقات المخزّنة مؤقتًا توفُّر الإصدار 2 من مجموعة التحكّم في النواة (cgroup). بالإضافة إلى ذلك، تتطلّب الإشعارات المتعلقة بتغيير حالة التجميد باستخدام IBinder.FrozenStateChangeCallback توفُّر دعم برنامج تشغيل Binder في النواة، وهو أمر عادي في &quot;نواة Android الشائعة&quot; (ACK) و&quot;صور النواة العامة&quot; (GKI) بدءًا من الإصدار 14 من نظام التشغيل Android (المستوى 34 من واجهة برمجة التطبيقات) والإصدارات الأحدث.

يمكنك التحقّق مما إذا كان الجهاز يتيح هذه الإمكانات باستخدام أوامر adb عادية، وذلك على النحو التالي:

  • تحقَّق مما إذا كانت ميزة "التجميد" مفعَّلة على الجهاز (بالنسبة إلى إصدارات المستخدمين أو إصدارات تصحيح الأخطاء):

    adb shell device_config get activity_manager_native_boot use_freezer

    أو تأكَّد من أنّ النظام يجمّد العمليات بشكل نشط:

    adb shell dumpsys activity | grep -A 20 "Apps frozen:"
  • التحقّق من توفّر وحدة التحكّم في التجميد cgroup v2 (لأي جهاز):

    تأكَّد من إدراج freezer ضمن أدوات التحكّم المتاحة في cgroup v2:

    adb shell cat /sys/fs/cgroup/cgroup.controllers

    بدلاً من ذلك، على الجهاز الجذر أو إصدار userdebug، تحقَّق من أنّه تم تثبيت عقدة cgroup v2 freezer في cgroup فرعي:

    adb root && adb shell ls /sys/fs/cgroup/uid_0/cgroup.freeze

    إذا كان هذا الملف متوفّرًا، يعني ذلك أنّ النواة تتوافق مع أداة التجميد cgroup v2.

  • التحقّق من إمكانية تلقّي إشعارات بشأن تغيير حالة التجميد (لأي جهاز):

    على الأجهزة التي تعمل بالإصدار 14 من نظام التشغيل Android والإصدارات الأحدث والتي تتضمّن برامج تشغيل متوافقة مع Generic Kernel Image (GKI) binder، يتم تسجيل عمليات رد الاتصال بنجاح.IBinder.addFrozenStateChangeCallback إذا كان برنامج تشغيل Binder الأساسي في النواة لا يتيح إشعارات التجميد، سيعرض الأسلوب UnsupportedOperationException.

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

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

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

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

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

معاملات المجلّد المتزامنة مع العمليات المجمدة

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

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

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

إدارة عمليات معاودة الاتصال عن بُعد بعمليات العميل

يمكن للخدمات ومكوّنات النظام التي تحتفظ بعمليات ردّ اتصال طويلة الأمد في Binder إلى عمليات العميل منع حدوث أعطال متزامنة وطفح مخزن مؤقت غير متزامن من خلال تتبُّع حالة تجميد العميل:

  • تسجيل أداة معالجة تغيير الحالة: استخدِم IBinder.addFrozenStateChangeCallback على رموز ربط العميل الواردة لتلقّي إشعارات عندما تدخل عملية العميل إلى وضع التجميد أو تخرج منه.
  • إيقاف الإرسال مؤقتًا أثناء التجميد: عندما يدخل العميل إلى الحالة STATE_FROZEN، أوقِف مؤقتًا عمليات إرسال معاودة الاتصال أو تعديلات الحالة إلى هذا العميل.
  • استئناف التسليم عند إلغاء التجميد: عند انتقال العميل إلى STATE_UNFROZEN، استأنِف إرسال عمليات الاستدعاء، وقدِّم أي تحديثات مجمّعة أو موحّدة ضرورية.
  • استخدام RemoteCallbackList: يمكن لخدمات النظام التي تستخدم RemoteCallbackList ضبط سياسات المتصل المجمدة لإيقاف وإعادة بدء إرسال عمليات رد الاتصال تلقائيًا بدون الاحتفاظ بمنطق التتبُّع اليدوي. لمزيد من المعلومات، يُرجى الاطّلاع على اقتراحات بشأن تجميد Binder لخدمات النظام.

فائض سعة المخزن المؤقت لمعاملة وحدة التجميع غير المتزامنة

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

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

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

إذا كان التطبيق ينفّذ مهام متكررة، يتم تعليقها أثناء تجميد العملية. لمزيد من المعلومات، راجِع 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 في بروتوكول buffer.

فحص 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 إلى مسار باسم 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.