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

في Android 12، تحلّ ذاكرات التخزين المؤقت DMA-BUF محلّ أداة تخصيص الذاكرة ION للأسباب التالية:

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

أوقفت السمة android12-5.10 من Android Common Kernel السمة CONFIG_ION في 1 مارس 2021.

خلفية

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

أوجه التشابه بين إطار عمل ION وإطار عمل ذاكرات التخزين المؤقت DMA-BUF

  • إنّ إطار عمل ION وإطار عمل ذاكرات التخزين المؤقت DMA-BUF هما من أدوات تصدير ذاكرة التخزين المؤقت DMA-BUF المستندة إلى ذاكرة التخزين المؤقت.
  • يسمح كلا الإطارَين لكل ذاكرة تخزين مؤقت بتحديد أداة تخصيص الذاكرة وعمليات ذاكرة التخزين المؤقت 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

برامج تشغيل النواة التي تنفّذ ذاكرات التخزين المؤقت 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 مع العلامات الخاصة بذاكرة التخزين المؤقت. لذلك، يجب تسجيل كل متغير من ذاكرة التخزين المؤقت بشكل فردي باستخدام 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()، التي تأخذ قناع ذاكرة تخزين مؤقت وحجة علامة، بواجهة برمجة التطبيقات BufferAllocator::Alloc()، التي تأخذ اسم ذاكرة تخزين مؤقت بدلاً من ذلك.

يوضّح هذا الجدول هذه التغييرات من خلال عرض كيفية إجراء 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 branch.

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

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

تنفيذ Gralloc المرجعي

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

الإضافات المطلوبة إلى ueventd

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

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

أضِف أذونات sepolicy للسماح لبرنامج عميل في مساحة المستخدم بالوصول إلى ذاكرة تخزين مؤقت DMA-BUF جديدة. يعرض مثال add required permissions أذونات sepolicy التي تم إنشاؤها لبرامج عميل مختلفة للوص101}ول إلى ذاكرة التخزين المؤقت DMA-BUF للنظام.

الوصول إلى ذاكرات التخزين المؤقت الخاصة بالمورّد من رمز إطار العمل

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

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

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

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

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

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

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

ذاكرات التخزين المؤقت التي يتم تخصيص الذاكرة منها في الذاكرة المحمية

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

  • سجِّل عمليات التنفيذ الخاصة بالمورّد على أنّها /dev/dma_heap/system-secure<vendor-suffix>.
  • إنّ عمليات تنفيذ ذاكرة التخزين المؤقت هذه اختيارية.
  • إذا كانت ذاكرات التخزين المؤقت موجودة، تضمن اختبارات VTS إمكانية تخصيص الذاكرة منها.
  • يتم منح مكوّنات إطار العمل إذن الوصول إلى ذاكرات التخزين المؤقت هذه حتى تتمكّن من تفعيل استخدام ذاكرات التخزين المؤقت من خلال Codec2 HAL/non-binderized وHALs في العملية نفسها. ومع ذلك، لا يمكن أن تعتمد ميزات إطار عمل Android العامة عليها بسبب الاختلاف في تفاصيل تنفيذها. إذا تمت إضافة تنفيذ ذاكرة تخزين مؤقت آمنة عامة إلى Android Common Kernel في المستقبل، يجب أن تستخدم واجهة ABI مختلفة لتجنُّب حدوث تعارضات مع الأجهزة التي تتم ترقيتها.

أداة تخصيص الذاكرة Codec 2 لذاكرات التخزين المؤقت DMA-BUF

تتوفّر أداة تخصيص ذاكرة codec2 لواجهة ذاكرات التخزين المؤقت DMA-BUF في AOSP.

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

مثال على تدفق النقل لذاكرة تخزين مؤقت 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، عدِّل ملفات make لربطها بـ 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 libdmabufheap
تخصيص الذاكرة من 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: أنشئ أذونات sepolicy المطلوبة لبرنامج العميل للوصول إلى ذاكرات التخزين المؤقت DMA-BUF الجديدة. أصبح برنامج العميل الآن مجهّزًا بالكامل لتخصيص الذاكرة من ذاكرة التخزين المؤقت DMA-BUF الجديدة.

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

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