معمارية Android الداخلية: كيف يعمل النظام تحت الغطاء؟
نظام Android هو الأكثر انتشاراً في العالم، ويعتمد على نواة Linux معدلة. لفهم الأداء الحقيقي وحل المشاكل المعقدة مثل التجميد (Lags) أو استهلاك الذاكرة، يجب تجاوز مستوى الـ API والدخول إلى المعمارية الداخلية. هذا الدليل يشرح بالتفصيل كيف يبدأ النظام، كيف تترجم الأكواد، كيف تتواصل العمليات، وكيف تُدار الذاكرة والرسوميات.
⚙️ الجزء الأول: عملية Zygote وبدء التشغيل
عندما يضغط المستخدم على زر التشغيل، يقوم المعالج بتنفيذ كود الإقلاع (Bootloader) الذي يحمل نواة Linux. بعد تهيئة النواة، يتم تشغيل أول عملية في فضاء المستخدم تسمى init. هذه العملية هي "أم جميع العمليات" ومسؤولة عن تشغيل الخدمات الأساسية.
واحدة من أهم الخدمات التي يطلقها init هي Zygote. اسمها يعني "البويضة الملقحة"، ودورها حيوي جداً. تقوم Zygote بتحميل إطار عمل Java الأساسي (Android Framework) والموارد المشتركة في الذاكرة مرة واحدة. بعد ذلك، تنتظر Zygote طلبات تشغيل التطبيقات.
عندما يريد النظام تشغيل تطبيق جديد، لا يقوم بتحميل الإطار من الصفر، بل يقوم بعملية Fork (استنساخ) لعملية Zygote. بفضل تقنية Copy-on-Write في Linux، فإن التطبيق الجديد يشارك نفس صفحات الذاكرة التي تحملها Zygote طالما لم يقم بتعديلها. هذا يوفر مئات الميجابايتات من الذاكرة ويقلل وقت بدء التشغيل بشكل هائل.
بعد الاستنساخ، تقوم العملية الجديدة بتحميل كود التطبيق الخاص (classes.dex) والموارد المحددة، ثم تبدأ تشغيل الـ Main Thread (اللووبر الرئيسي).
نظام System Server
بالإضافة إلى التطبيقات، تقوم Zygote بتشغيل عملية system_server. هذه العملية تحتوي على جميع خدمات النظام الأساسية مثل ActivityManager، PackageManager، WindowManager، وPowerManager. كل تطبيق يتواصل مع هذه الخدمات عبر آلية IPC تسمى Binder.
☕ الجزء الثاني: Android Runtime (ART) وترجمة الكود
في السابق، كان Android يستخدم آلة Dalvik الافتراضية التي تعمل بنظام JIT (Just-In-Time). لكن منذ إصدار Lollipop، تم استبدالها بـ ART (Android Runtime). الفرق الجوهري هو أن ART يدعم الترجمة المسبقة (AOT - Ahead Of Time) بالإضافة إلى JIT.
كيف يعمل ART الآن؟
عند تثبيت التطبيق، يقوم ART بتحويل كود الـ Dalvik Executable (DEX) إلى كود آلة أصلي (Native Code) خاص بالمعالج (OAT file). هذا يجعل التطبيق يعمل بسرعة عالية لأنه لا يحتاج للترجمة أثناء التشغيل.
تحسين الملف الشخصي (Profile Guided Optimization):
مشكلة الترجمة المسبقة الكاملة هي أنها تستغرق وقتاً طويلاً عند التثبيت وتأخذ مساحة تخزين كبيرة. لذلك، يستخدم ART نهجاً هجيناً. يتم تجميع الكود الأكثر استخداماً (Hot Methods) مسبقاً، بينما يتم تبقية الكود الأقل استخداماً بطريقة JIT أو تفسيره. يقوم النظام بمراقبة سلوك التطبيق وإنشاء "ملف تعريف" (Profile) يحدد الدوال الساخنة، ثم يقوم بترجمتها في الخلفية عندما يكون الجهاز خاملاً ومشحوناً.
الجزء الثالث: Binder IPC وتواصل العمليات
Android هو نظام يعتمد على العزل (Sandboxing). كل تطبيق يعمل في عملية منفصلة ومعزولة. لكن التطبيقات تحتاج للتواصل مع بعضها ومع خدمات النظام (مثل طلب الموقع أو فتح الكاميرا). هنا يأتي دور Binder.
Binder هو آلية التواصل بين العمليات (IPC) المطورة خصيصاً لـ Android. تعتمد على مفهوم الـ Proxy-Stub. عندما يطلب التطبيق خدمة، يقوم بإرسال طلب عبر Binder Driver الموجود في النواة. يقوم الـ Driver بتوجيه الطلب إلى العملية المستهدفة.
لماذا Binder أسرع من آليات IPC الأخرى؟
لأنه يستخدم تقنية Memory Mapping. بدلاً من نسخ البيانات من مساحة المستخدم إلى مساحة النواة ثم إلى العملية الأخرى (نسخ مزدوج)، يتم ربط منطقة من الذاكرة بين العمليتين، مما يسمح بنقل البيانات بنسخة واحدة فقط.
محدودية Binder:
حجم البيانات المنقولة عبر Binder محدود (عادة 1MB). محاولة إرسال بيانات ضخمة (مثل Bitmap كبيرة) عبر Intent ستؤدي إلى انهيار التطبيق (TransactionTooLargeException).
🧠 الجزء الرابع: إدارة الذاكرة و Low Memory Killer
إدارة الذاكرة في Android معقدة لأنها يجب أن توازن بين أداء التطبيقات المتعددة واستهلاك البطارية.
Heap وأنواع الذاكرة
كل عملية لها كومة (Heap) مخصصة للـ Java Objects. حجم الـ Heap محدود ويعتمد على كثافة الشاشة وذاكرة الجهاز. بالإضافة إلى ذلك، هناك الذاكرة الأصلية (Native Memory) المستخدمة للمكتبات C/C++ وللـ Bitmaps الكبيرة.
جامع القمامة (Garbage Collector)
ART يستخدم خوارزميات متقدمة لجمع القمامة. في الإصدارات الحديثة، يستخدم "Concurrent Copying" الذي يعمل بشكل متوازٍ مع التطبيق لتقليل وقت التوقف (Pause Time). يتم تقسيم الـ Heap إلى مناطق (Generations): منطقة للكائنات قصيرة العمر (يتم تنظيفها بسرعة) ومنطقة للكائنات طويلة العمر.
Low Memory Killer (LMK)
عندما تنخفض الذاكرة الحرة في النظام، تقوم النواة بتفعيل LMK. هذه الآلية تقتل العمليات في الخلفية بناءً على أولويتها (OOM Adjustment). العمليات التي تحتوي على Activities مرئية للمستخدم لها أولوية عالية جداً ولا تُقتل إلا في الحالات الحرجة، بينما التطبيقات المخفية في الخلفية تقتل أولاً.
📊 الجزء الخامس: تحليل الأداء وأداة Perfetto
لتحليل الأداء بعمق، لم نعد نعتمد فقط على Android Studio Profiler. الأداة الأقوى هي Perfetto (المعروفة سابقاً بـ Systrace على مستوى النظام).
Perfetto تجمع بيانات من مصادر متعددة:
1. النواة: جدولة المعالج (Scheduler)، استخدام القرص، الشبكة.
2. ART: أحداث جامع القمامة، الترجمة.
3. النظام: أحداث WindowManager، SurfaceFlinger.
4. التطبيق: يمكن للمطور إضافة نقاط تتبع مخصصة (Custom Traces).
تحليل Jank (التقطيع):
الهدف هو رسم إطار كل 16.6 مللي ثانية (لـ 60Hz). إذا تأخر الرسم، يظهر "Jank". في Perfetto، يمكنك رؤية الـ Render Thread والـ UI Thread. إذا كان الـ UI Thread مشغولاً بعملية ثقيلة، سيظهر ذلك بوضوح، وعليك نقل العملية إلى Thread آخر.
🎨 الجزء السادس: واجهة المستخدم و SurfaceFlinger
كيف تظهر الرسومات على الشاشة؟
يقوم التطبيق برسم واجهته في Buffer (منطقة ذاكرة). ثم يرسل هذا الـ Buffer إلى عملية تسمى SurfaceFlinger.
SurfaceFlinger هي المسؤولة عن دمج (Compose) جميع النوافذ (Windows) من مختلف التطبيقات وعرضها على الشاشة. تستخدم GPU لتسريع هذا الدمج (Hardware Composer).
Hardware Acceleration
منذ Android 4.0، يتم تفعيل التسريع العتادي افتراضياً. هذا يعني أن عمليات الرسم تتم عبر GPU بدلاً من CPU. ومع ذلك، بعض العمليات لا تزال تتم على CPU (مثل قياس النصوص المعقدة)، مما قد يسبب اختناقات.
Jetpack Compose Internals
Compose يستخدم نهجاً مختلفاً عن View System التقليدي. بدلاً من شجرة Views ثابتة، يستخدم Compose "Slot Table" لتتبع حالة الواجهة. عند تغير البيانات (State)، تقوم Compose بإعادة رسم الأجزاء المتغيرة فقط (Smart Recomposition) بدلاً من إعادة رسم الشاشة كاملة، مما يحسن الأداء بشكل كبير إذا تم استخدامه بشكل صحيح.
الجزء السابع: الأمان الداخلي (SELinux)
Android لا يعتمد فقط على صلاحيات المستخدم (User Permissions). يستخدم SELinux (Security-Enhanced Linux) لتطبيق سياسات وصول إلزامية (MAC).
حتى لو كان التطبيق يملك صلاحيات Root، فإنه لا يستطيع الوصول لملف أو عملية إذا كانت سياسة SELinux تمنعه. السياسات محددة بدقة لكل عملية (Context). هذا يمنع التطبيقات الضارة من تجاوز العزل حتى في حال وجود ثغرة.
💡 الخلاصة الهندسية:
- ✅ فهم Zygote و ART يساعد في تحسين بدء التطبيق.
- ✅ Binder سريع لكن له حدود حجمية، احذر من TransactionTooLarge.
- ✅ استخدام Perfetto ضروري لاكتشاف الاختناقات الخفية.
- ✅ Compose قوي لكنه يتطلب فهم الـ State لتجنب إعادة الرسم الزائد.
- ✅ SELinux هو خط الدفاع الأخير والأقوى في النظام.
تعمق في الأساسيات، وابنِ تطبيقات احترافية! 🚀