الانتقال من ION إلى أكوام DMA-BUF (الإصدار 5.4 من kernel فقط)

في نظام التشغيل Android 12، يحلّ GKI 2.0 محلّ أداة تخصيص ION باستخدام حزم DMA-BUF للأسباب التالية:

  • الأمان: بما أنّ كل لقطة لأجزاء من الذاكرة في DMA-BUF هي جهاز مستقل يستخدم الأحرف، فيمكن التحكم في الوصول إلى كل جزء من الذاكرة بشكل منفصل باستخدام sepolicy. لم يكن هذا الإجراء ممكنًا باستخدام ION لأنّ تخصيص الذاكرة من أي كومّة يتطلّب الوصول فقط إلى جهاز /dev/ion.
  • ثبات ABI: على عكس ION، على عكس ION، تكون واجهة IOCTL لإطار عمل DMA-BUF مستقرة لـ ABI، نظرًا لأنه يتم الاحتفاظ بها في نواة Linux الرئيسية.
  • التوحيد: يقدّم إطار عمل "كومات DMA-BUF" واجهة برمجة تطبيقات معرّفة جيدًا. كانت ION تسمح بإعدادات مخصّصة وأرقام تعريف ذاكرة عشوائية منعت تطوير إطار عمل اختبار موحّد لأنّ تنفيذ ION على كل جهاز قد يختلف عن غيره.

تم إيقاف الإصدار android12-5.10 من "النواة الشائعة لنظام التشغيل Android" CONFIG_ION في 1 آذار (مارس) 2021.

خلفية

في ما يلي مقارنة موجزة بين كومدات ION وDMA-BUF.

أوجه التشابه بين إطار عمل لقطات العناصر المتعدّدة في ION وDMA-BUF

  • إنّ إطارَي عمل HEAP ION وDMA-BUF هما من برامج تصدير DMA-BUF المستندة إلى HEAP.
  • ويسمح كلاهما لكل كومّة بتحديد موزّعها وعمليات DMA-BUF الخاصة بها.
  • يتشابه أداء التخصيص لأن كلا المخططين يحتاجان إلى IOCTL واحد للتخصيص.

الاختلافات بين إطار عمل كومدات ION وDMA-BUF

أكواد ION المتعددة عناصر ذاكرة العناصر المتعدّدة في DMA-BUF
تتم جميع عمليات تخصيص ION باستخدام /dev/ion. كل لقطة لعناصر DMA-BUF هي جهاز حرفي متوفر في /dev/dma_heap/<heap_name>.
تتوافق ION مع علامات الذاكرة العشوائية الخاصة. لا تتوافق أكوام DMA-BUF مع علامات أكوام الذاكرة الخاصة. بدلاً من ذلك، يتم تنفيذ كل نوع مختلف من عملية التخصيص من خلال كومة مختلف. على سبيل المثال، النسختان المخزنتان لعناصر النظام من النظام المخزَّنة مؤقتًا وغير المخزّنة مؤقتًا هي أكواد منفصلة مجمّعة في /dev/dma_heap/system و/dev/dma_heap/system_uncached.
يجب تحديد معرّف/قناع الشريحة والرموز لتحديدها. ويُستخدم اسم لقطة العناصر في عملية التخصيص.

تسرد الأقسام التالية المكوّنات التي تتعامل مع ION وتوضّح كيفية تبديلها إلى إطار عمل "كومات DMA-BUF".

نقل برامج تشغيل النواة من ION إلى أكوام DMA-BUF

برامج تشغيل kernel التي تنفِّذ أكوام ION

تسمح كل من كومدات ION وDMA-BUF لكل كومدة بتنفيذ موزّعي عناوين الذاكرة الخاصة بها وعمليات DMA-BUF. وبالتالي، يمكنك التبديل من تنفيذ كومّة ION إلى تنفيذ كومّة DMA-BUF باستخدام مجموعة مختلفة من واجهات برمجة التطبيقات لتسجيل الكومة. يعرض هذا الجدول واجهات برمجة التطبيقات لتسجيل كومّة ION وواجهات برمجة التطبيقات المقابلة لها لكومّة DMA-BUF.

مجموعات ION عناصر ذاكرة العناصر المتعدّدة في DMA-BUF
void ion_device_add_heap(struct ion_heap *heap) struct dma_heap *dma_heap_add(const struct dma_heap_export_info *exp_info);
void ion_device_remove_heap(struct ion_heap *heap) void dma_heap_put(struct dma_heap *heap);

لا تتوافق أكوام DMA-BUF مع علامات أكوام الذاكرة الخاصة. لذلك، يجب تسجيل كلّ صيغة من ملف heap بشكلٍ فردي باستخدام واجهة برمجة التطبيقات dma_heap_add(). لتسهيل مشاركة الرموز، ننصحك بتسجيل جميع الصيغ للكومة نفسها ضمن برنامج التشغيل نفسه. يعرض مثال dma-buf: system_heap طريقة تنفيذ الصيغ المخزّنة مؤقتًا وغير المخزّنة مؤقتًا لمساحة تخزين برمجة التطبيقات.

استخدِم dma-buf: heaps: example template لإنشاء كومّة DMA-BUF من الصفر.

برامج تشغيل النواة التي تخصص مباشرةً من أكوام ION

يقدّم إطار عمل "كومات DMA-BUF" أيضًا واجهة تخصيص للعملاء داخل النواة. بدلاً من تحديد قناع الحِزمة والرموز لاختيار نوع التخصيص، تأخذ الواجهة التي تقدّمها حِزم DMA-BUF اسم الحِزمة كمدخل.

يعرض ما يلي واجهة برمجة التطبيقات لنظام تخصيص ION داخل النواة وواجهات برمجة التطبيقات المماثلة لنظام تخصيص مساحة الذاكرة DMA-BUF. يمكن لبرامج تشغيل النواة استخدام واجهة برمجة التطبيقات dma_heap_find() لطلب معرفة ما إذا كانت هناك كومّة. تعرض واجهة برمجة التطبيقات مؤشرًا إلى مثيل struct dma_heap، والذي يمكن تمريره بعد ذلك كوسيطة إلى واجهة برمجة التطبيقات dma_heap_buffer_alloc().

مجموعات ION أكوام DMA-BUF
struct dma_buf *ion_alloc(size_t len, unsigned int heap_id_mask, unsigned int flags)

struct dma_heap *dma_heap_find(const char *name)

struct dma_buf *struct dma_buf *dma_heap_buffer_alloc(struct dma_heap *heap, size_t len, unsigned int fd_flags, unsigned int heap_flags)

برامج تشغيل النواة التي تستخدم وحدات DMA-BUF

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

نقل عملاء مساحة المستخدم من ION إلى أكوام DMA-BUF

لتسهيل عملية النقل لعملاء مساحة المستخدمين في ION، تتوفّر مكتبة تجريدية تُسمى libdmabufheap. يتيح libdmabufheap التخصيص في وحدات ذاكرة التخزين المؤقت لـ DMA-BUF وأكواد ION. يتحقّق أولاً مما إذا كانت هناك كومّة DMA-BUF بالاسم المحدّد وإذا لم تكن متوفّرة، يتم الرجوع إلى كومّة ION مكافئة، في حال توفّرها.

يجب أن يبدأ العملاء BufferAllocator كائنًا أثناء عملية الإعداد بدلاً من فتح /dev/ion using ion_open(). ويعود السبب في ذلك إلى أنّ ملفّات الوصف التي تم إنشاؤها من خلال فتح /dev/ion و/dev/dma_heap/<heap_name> تتم إدارتها داخليًا بواسطة عنصر BufferAllocator.

للتبديل من libion إلى libdmabufheap، عدِّل سلوك العملاء على النحو التالي:

  • تتبّع اسم الحِزمة المطلوب استخدامه في عملية التخصيص، بدلاً من رأس رقم التعريف/القناع وعلامة الحِزمة
  • استبدِل واجهة برمجة التطبيقات ion_alloc_fd() API التي تأخذ قناعًا للمساحة التخزينية ووسيطة علامة، بواجهة برمجة التطبيقات BufferAllocator::Alloc() API التي تأخذ اسم مساحة تخزينية بدلاً من ذلك.

يوضّح هذا الجدول هذه التغييرات من خلال توضيح كيفية تنفيذ libion وlibdmabufheap لتخصيص جزء من الذاكرة في النظام غير المخزّنة مؤقتًا.

نوع التخصيص libion libdmabufheap
التخصيص المخزن مؤقتًا من لقطة لعناصر النظام ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, ION_FLAG_CACHED, &fd) allocator->Alloc("system", size)
تخصيص غير مخزّن مؤقتًا من ذاكرة تخزين النظام ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, 0, &fd) allocator->Alloc("system-uncached", size)

بانتظار الموافقة نسخة لعناصر متعدّدة من النظام غير المخزّنة مؤقتًا في انتظار الموافقة عليها، لكنّها تشكّل جزءًا من فرع android12-5.10.

لدعم ترقية الأجهزة، تسمح واجهة برمجة التطبيقات MapNameToIonHeap() API بربط اسم ملف ذاكرة heap بمَعلمات ملف ذاكرة ION heap (اسم ملف الذاكرة أو القناع والأعلام) للسماح لتلك الواجهات باستخدام عمليات التوزيع المستندة إلى الاسم. في ما يلي مثال على التخصيص بالاستناد إلى الاسم.

تتوفّر مستندات كل واجهة برمجة تطبيقات يوفّرها libdmabufheap. تعرض المكتبة أيضًا ملف رأس لاستخدامه من خلال عملاء C.

مرجع تنفيذ Gralloc

يستخدم تطبيق Hikey960 gralloc libdmabufheap، لذا يمكنك استخدامه كأحد مراجع تنفيذ.

الإضافات المطلوبة غير النشطة

بالنسبة إلى أيّ مجموعات جديدة من DMA-BUF خاصة بالجهاز تم إنشاؤها، أضِف إدخالًا جديدًا إلىملفueventd.rc الجهاز. يوضّح مثال إعداد ueventd للتوافق مع مجموعات DMA-BUF كيفية إجراء ذلك في ذاكرة التخزين المؤقت لنظام DMA-BUF.

إضافات sepolicy المطلوبة

أضِف أذونات سياسة الأمان (sepolicy) لتفعيل برنامج عميل مساحة المستخدم للوصول إلى ملف ذاكرة HEAP جديد في DMA-BUF. يعرِض مثال إضافة الأذونات المطلوبة أذونات سياسة الأمان التي تم إنشاؤها لبرامج مختلفة بهدف الوصول إلى ذاكرة نظام DMA-BUF.

الوصول إلى مجموعات ذاكرة المورّد من رمز الإطار

لضمان الامتثال لإطار عمل Treble، لا يمكن تخصيص رمز الإطار إلا من فئات ملفّات تخزين المورّدين المعتمَدة مسبقًا.

استنادًا إلى الملاحظات الواردة من الشركاء، حددت Google فئتَين من أكواد الموردين التي يجب الوصول إليها من رمز إطار العمل:

  1. الحِزم التي تستند إلى حزمة النظام مع تحسينات الأداء الخاصة بالجهاز أو المنظومة على الرقاقة
  2. مجموعات الذاكرة التي يتم تخصيصها من الذاكرة المحمية

مجموعات الذاكرة المؤقتة المستندة إلى مجموعة الذاكرة المؤقتة للنظام مع تحسينات الأداء الخاصة بالجهاز أو المنظومة على الرقاقة

لدعم حالة الاستخدام هذه، يمكن إلغاء تنفيذ كومّة نظام كومّة DMA-BUF التلقائية.

  • تم إيقاف CONFIG_DMABUF_HEAPS_SYSTEM في gki_defconfig للسماح له بأن يصبح وحدة مورِّد.
  • تضمن اختبارات الامتثال لبيانات VTS توفُّر لقطة لأجزاء من الذاكرة في /dev/dma_heap/system. تتحقّق الاختبارات أيضًا من إمكانية تخصيص الذاكرة من الحِزمة، ومن أنّه يمكن ربط ملف الوصف الذي تم إرجاعه (fd) بالذاكرة (mmapped) من مساحة المستخدم.

تنطبق النقاط السابقة أيضًا على الصيغة غير المخزّنة من ذاكرة التخزين المؤقت للنظام، على الرغم من أنّ وجودها ليس إلزاميًا للأجهزة المتسقة تمامًا مع عمليات I/O.

مجموعات الذاكرة التي يجب تخصيصها من الذاكرة المحمية

يجب أن تكون عمليات تنفيذ "المساحة المحجوزة الآمنة" خاصة بالمورّد لأنّ "النواة المشتركة" في Android لا تتوافق مع تنفيذ "المساحة المحجوزة الآمنة" العام.

  • سجِّل عمليات التنفيذ الخاصة بالمورّد على أنّها /dev/dma_heap/system-secure<vendor-suffix>.
  • إنّ عمليات تنفيذ الحِزم هذه اختيارية.
  • وفي حال توفّر لقطات لأجزاء من الذاكرة، تضمن اختبارات VTS إمكانية إجراء التخصيصات منها.
  • يتم منح مكوّنات إطار العمل إذن الوصول إلى هذه الحِزم لكي تتمكّن من تفعيل استخدام الحِزم من خلال واجهة HAL لبرنامج الترميز 2 أو واجهات HAL غير المرتبطة بالربط لعملية التنفيذ نفسها. ومع ذلك، لا يمكن أن تعتمد ميزات إطار عمل Android العامة على هذه الميزات بسبب اختلاف تفاصيل تنفيذها. في حال تمت إضافة تنفيذ مجمع تخزين آمن عام إلى "النواة المشتركة لنظام التشغيل Android" في المستقبل، يجب أن يستخدم ABI مختلفًا لتجنّب حدوث تعارضات مع الأجهزة التي يتم ترقيتها.

تخصيص برنامج الترميز 2 لعناصر التحكم في الذاكرة التي تم إنشاؤها باستخدام DMA-BUF

يتوفّر مخصّص تنسيق ترميز 2 لواجهة كومبوتات DMA-BUF في AOSP.

تتوفّر واجهة متجر المكوّنات التي تسمح بتحديد مَعلمات الذاكرة المحجوزة للبرامج من HAL C2 مع أداة تخصيص الذاكرة المحجوزة للبرامج C2 DMA-BUF.

نموذج لتدفق الانتقال في كومّة ION

لتسهيل الانتقال من ION إلى كومدات DMA-BUF، يسمح libdmabufheap بالتبديل بين كومدات واحدة في كل مرة. توضِّح الخطوات التالية سير عمل مقترَح لنقل كومّة ION غير القديمة التي تحمل الاسم my_heap والتي تتيح استخدام علامة واحدة، وهي ION_FLAG_MY_FLAG.

الخطوة 1: أنشئ مكافئًا لكومة ION في إطار عمل DMA-BUF. في هذا المثال، بما أنّ كومّة ION my_heap تتيح استخدام علامة ION_FLAG_MY_FLAG، فإنّنا نسجِّل كومّتَي DMA-BUF:

  • يتطابق سلوك my_heap تمامًا مع سلوك حزمة ION مع إيقاف العلامة ION_FLAG_MY_FLAG.
  • يتطابق سلوك my_heap_special تمامًا مع سلوك كومّة ION مع تفعيل العلامة ION_FLAG_MY_FLAG.

الخطوة 2: أنشئ تغييرات ueventd لحِزم my_heap و my_heap_special DMA-BUF الجديدة. في هذه المرحلة، تظهر الحِزم على النحو التالي: /dev/dma_heap/my_heap و/dev/dma_heap/my_heap_special، مع الأذونات المقصودة.

الخطوة 3: بالنسبة إلى العملاء الذين يخصّصون مساحة من my_heap، عدِّل ملفات الإنشاء لربطها بـ libdmabufheap. أثناء بدء تشغيل العميل، أنشئ مثيلًا لعنصر BufferAllocator واستخدِم واجهة برمجة التطبيقات MapNameToIonHeap() لتعيين تركيبة <ION heap name/mask, flag> إلى أسماء كومّة DMA-BUF المكافئ.

مثلاً:

allocator->MapNameToIonHeap("my_heap_special" /* name of DMA-BUF heap */, "my_heap" /* name of the ION heap */, ION_FLAG_MY_FLAG /* ion flags */ )

بدلاً من استخدام واجهة برمجة التطبيقات MapNameToIonHeap() مع مَعلمتَي الاسم والعلامة، يمكنك إنشاء عملية الربط من <ION heap mask, flag> إلى أسماء كومّة DMA-BUF المكافئ من خلال ضبط مَعلمة اسم كومّة ION على فارغة.

الخطوة 4: استبدِل عمليات استدعاء ion_alloc_fd() باستخدام BufferAllocator::Alloc() باستخدام اسم الحِزمة المناسب.

نوع التخصيص libion ليبdmabufheap
التخصيص من my_heap مع عدم ضبط العلامة ION_FLAG_MY_FLAG ion_alloc_fd(ionfd, size, 0, ION_HEAP_MY_HEAP, 0, &fd) allocator->Alloc("my_heap", size)
تخصيص من my_heap مع ضبط العلامة ION_FLAG_MY_FLAG ion_alloc_fd(ionfd, size, 0, ION_HEAP_MY_HEAP, ION_FLAG_MY_FLAG, &fd) allocator->Alloc("my_heap_special", size)

في هذه المرحلة، يعمل البرنامج، ولكنه لا يزال يخصّص من كومة الذاكرة المؤقتة في ION، لأنه لا يملك أذونات sepolicy المطلوبة لفتح ذاكرة التخزين المؤقت DMA-BUF.

الخطوة 5: أنشئ أذونات سياسة الأمان المطلوبة لكي يتمكّن العميل من الوصول إلى كومات DMA-BUF الجديدة. أصبح العميل مجهّزًا بالكامل الآن للتخصيص من كومة الذاكرة المؤقتة DMA-BUF الجديدة.

الخطوة 6: تأكَّد من أنّ عمليات التخصيص تتم من كومّة DMA-BUF الجديدة من خلال فحص logcat.

الخطوة 7: أوقِف كومّة ION my_heap في النواة. إذا لم يكن رمز العميل يحتاج إلى إتاحة ترقية الأجهزة (التي قد لا تتيح نواتها سوى كومدات ION )، يمكنك أيضًا إزالة عمليات استدعاء MapNameToIonHeap().