ION से DMA-BUF हेप में ट्रांज़िशन (सिर्फ़ 5.4 कर्नल के लिए)

Android 12 में, GKI 2.0 ने ION ऐलोकेटर को डीएमए-बीयूएफ़ हीप से बदल दिया है. इसकी वजहें यहां दी गई हैं:

  • सुरक्षा: हर DMA-BUF हीप एक अलग कैरेक्टर डिवाइस होता है. इसलिए, sepolicy की मदद से हर हीप के ऐक्सेस को अलग-अलग कंट्रोल किया जा सकता है. ION के साथ ऐसा नहीं किया जा सकता था, क्योंकि किसी भी हीप से मेमोरी असाइन करने के लिए, सिर्फ़ /dev/ion डिवाइस का ऐक्सेस ज़रूरी होता है.
  • एबीआई स्टेबल: ION के उलट, DMA-BUF हीप फ़्रेमवर्क का IOCTL इंटरफ़ेस एबीआई स्टेबल होता है. ऐसा इसलिए, क्योंकि इसे अपस्ट्रीम Linux कर्नल में बनाए रखा जाता है.
  • स्टैंडर्डाइजेशन: डीएमए-बीयूएफ़ हीप फ़्रेमवर्क, अच्छी तरह से तय किया गया यूएपीआई उपलब्ध कराता है. ION में कस्टम फ़्लैग और हीप आईडी की अनुमति दी गई थी. इससे एक सामान्य टेस्टिंग फ़्रेमवर्क डेवलप करने में रुकावट आई, क्योंकि हर डिवाइस पर ION को अलग-अलग तरीके से लागू किया जा सकता था.

Android Common Kernel की android12-5.10 ब्रांच को 1 मार्च, 2021 को बंद कर दिया गया था.CONFIG_ION

बैकग्राउंड

यहां ION और DMA-BUF हीप की तुलना की गई है.

ION और डीएमए-बीयूएफ़ हीप फ़्रेमवर्क के बीच समानताएं

  • ION और डीएमए-बीयूएफ़ हीप फ़्रेमवर्क, दोनों ही हीप-आधारित डीएमए-बीयूएफ़ एक्सपोर्टर हैं.
  • इन दोनों से, हर हीप को अपना ऐलोकेटर और डीएमए-बफ़ ऑप्स तय करने की अनुमति मिलती है.
  • दोनों स्कीम के लिए, मेमोरी को एक ही IOCTL की ज़रूरत होती है. इसलिए, मेमोरी के बंटवारे की परफ़ॉर्मेंस एक जैसी होती है.

ION और DMA-BUF हीप फ़्रेमवर्क के बीच अंतर

ION हीप डीएमए-बीयूएफ़ हीप
सभी ION ऐलोकेशन, /dev/ion की मदद से किए जाते हैं. हर डीएमए-बीयूएफ़ हीप एक कैरेक्टर डिवाइस होता है, जो /dev/dma_heap/<heap_name> पर मौजूद होता है.
ION, हीप के निजी फ़्लैग के साथ काम करता है. डीएमए-बीयूएफ़ हीप में, हीप के निजी फ़्लैग काम नहीं करते. हर तरह का अलग-अलग एलॉकेशन, अलग-अलग हीप से किया जाता है. उदाहरण के लिए, कैश मेमोरी में सेव किए गए और कैश मेमोरी में सेव नहीं किए गए सिस्टम हीप के वैरिएंट, /dev/dma_heap/system और /dev/dma_heap/system_uncached पर मौजूद अलग-अलग हीप होते हैं.
बंटवारे के लिए, Heap आईडी/मास्क और फ़्लैग तय किए जाने चाहिए. हीप के नाम का इस्तेमाल, मेमोरी को असाइन करने के लिए किया जाता है.

यहां दिए गए सेक्शन में, ION से जुड़े कॉम्पोनेंट की सूची दी गई है. साथ ही, उन्हें DMA-BUF हीप फ़्रेमवर्क पर स्विच करने का तरीका बताया गया है.

कर्नेल ड्राइवर को ION से डीएमए-बीयूएफ़ हीप में ट्रांसफ़र करना

ION हीप लागू करने वाले कर्नेल ड्राइवर

ION और डीएमए-बीयूएफ़ हीप, दोनों ही हर हीप को अपने ऐलोकेटर और डीएमए-बीयूएफ़ ऑप्स लागू करने की अनुमति देते हैं. इसलिए, हीप को रजिस्टर करने के लिए एपीआई के किसी दूसरे सेट का इस्तेमाल करके, ION हीप को DMA-BUF हीप में बदला जा सकता है. इस टेबल में, ION हीप रजिस्ट्रेशन एपीआई और उनके बराबर के डीएमए-बीयूएफ़ हीप एपीआई दिखाए गए हैं.

ION हीप डीएमए-बीयूएफ़ हीप
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_heap_add() एपीआई का इस्तेमाल करके अलग-अलग रजिस्टर करना होगा. कोड शेयर करने की सुविधा को आसान बनाने के लिए, यह सुझाव दिया जाता है कि एक ही ड्राइवर में एक ही हीप के सभी वैरिएंट रजिस्टर करें. dma-buf: system_heap के इस उदाहरण में, सिस्टम हीप के कैश किए गए और कैश नहीं किए गए वैरिएंट को लागू करने का तरीका दिखाया गया है.

शुरुआत से डीएमए-बीयूएफ़ हीप बनाने के लिए, इस dma-buf: heaps: example template का इस्तेमाल करें.

कर्नेल ड्राइवर, सीधे तौर पर ION हीप से मेमोरी असाइन कर रहे हैं

डीएमए-बीयूएफ़ हीप फ़्रेमवर्क, कर्नल में मौजूद क्लाइंट के लिए ऐलोकेशन इंटरफ़ेस भी उपलब्ध कराता है. डीएमए-बफ़र हीप के ज़रिए उपलब्ध कराया गया इंटरफ़ेस, हीप मास्क और फ़्लैग तय करने के बजाय, हीप के नाम को इनपुट के तौर पर लेता है. इससे यह तय किया जाता है कि किस तरह का मेमोरी स्पेस असाइन करना है.

यहां कर्नल में मौजूद ION ऐलोकेशन एपीआई और इसके बराबर के डीएमए-बीयूएफ़ हीप ऐलोकेशन एपीआई दिखाए गए हैं. कर्नेल ड्राइवर, dma_heap_find() एपीआई का इस्तेमाल करके हीप के मौजूद होने के बारे में क्वेरी कर सकते हैं. यह एपीआई, struct dma_heap के इंस्टेंस का पॉइंटर दिखाता है. इसे dma_heap_buffer_alloc() एपीआई में आर्ग्युमेंट के तौर पर पास किया जा सकता है.

ION हीप डीएमए-बीयूएफ़ हीप
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)

डीएमए-बीयूएफ़ का इस्तेमाल करने वाले कर्नेल ड्राइवर

सिर्फ़ डीएमए-बीयूएफ़ इंपोर्ट करने वाले ड्राइवर के लिए, कोई बदलाव करने की ज़रूरत नहीं है. इसकी वजह यह है कि ION हीप से असाइन किया गया बफ़र, डीएमए-बीयूएफ़ हीप से असाइन किए गए बफ़र की तरह ही काम करता है.

ION के यूज़र-स्पेस क्लाइंट को डीएमए-बीयूएफ़ हीप में ट्रांज़िशन करना

ION के यूज़र-स्पेस क्लाइंट के लिए ट्रांज़िशन को आसान बनाने के लिए, libdmabufheap नाम की एक ऐब्स्ट्रैक्शन लाइब्रेरी उपलब्ध है. libdmabufheap डीएमए-बीयूएफ़ हीप और ION हीप में मेमोरी ऐलोकेट करने की सुविधा देता है. यह सबसे पहले यह देखता है कि क्या दिए गए नाम का कोई DMA-BUF हीप मौजूद है. अगर ऐसा नहीं है, तो यह ION हीप का इस्तेमाल करता है.

क्लाइंट को /dev/ion using ion_open() खोलने के बजाय, शुरू होने के दौरान BufferAllocator ऑब्जेक्ट को शुरू करना चाहिए. ऐसा इसलिए होता है, क्योंकि /dev/ion और /dev/dma_heap/<heap_name> को खोलने पर बनाए गए फ़ाइल डिस्क्रिप्टर, BufferAllocator ऑब्जेक्ट के ज़रिए अंदरूनी तौर पर मैनेज किए जाते हैं.

libion से libdmabufheap पर स्विच करने के लिए, क्लाइंट के व्यवहार में इस तरह बदलाव करें:

  • हेड आईडी/मास्क और हीप फ़्लैग के बजाय, हीप के नाम को ट्रैक करें, ताकि इसे मेमोरी असाइन करने के लिए इस्तेमाल किया जा सके.
  • ion_alloc_fd() एपीआई को BufferAllocator::Alloc() एपीआई से बदलें. 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 ब्रांच का हिस्सा है.

डिवाइसों को अपग्रेड करने के लिए, MapNameToIonHeap() API, हीप के नाम को ION हीप पैरामीटर (हीप का नाम या मास्क और फ़्लैग) से मैप करने की अनुमति देता है. इससे वे इंटरफ़ेस, नाम के आधार पर मेमोरी असाइन कर पाते हैं. यहां नाम के आधार पर किए गए बंटवारे का उदाहरण दिया गया है.

libdmabufheap के ज़रिए उपलब्ध कराए गए हर एपीआई के लिए दस्तावेज़ उपलब्ध है. लाइब्रेरी, C क्लाइंट के इस्तेमाल के लिए एक हेडर फ़ाइल भी उपलब्ध कराती है.

Gralloc को रेफ़रंस के तौर पर लागू करना

Hikey960 gralloc, libdmabufheap का इस्तेमाल करता है. इसलिए, इसे रेफ़रंस इंपलीमेंटेशन के तौर पर इस्तेमाल किया जा सकता है.

ueventd में ज़रूरी बदलाव

डिवाइस के हिसाब से बनाए गए किसी भी नए DMA-BUF हीप के लिए, डिवाइस की ueventd.rc फ़ाइल में एक नई एंट्री जोड़ें. इस डीएमए-बीयूएफ़ हीप के लिए ueventd सेट अप करने के उदाहरण में बताया गया है कि डीएमए-बीयूएफ़ सिस्टम हीप के लिए यह कैसे किया जाता है.

sepolicy में ज़रूरी बदलाव

किसी यूज़रस्पेस क्लाइंट को नए DMA-BUF हीप को ऐक्सेस करने की अनुमति देने के लिए, sepolicy अनुमतियां जोड़ें. ज़रूरी अनुमतियां जोड़ने के इस उदाहरण में, अलग-अलग क्लाइंट के लिए बनाई गई sepolicy अनुमतियां दिखाई गई हैं. इनकी मदद से, डीएमए-बीयूएफ़ सिस्टम हीप को ऐक्सेस किया जा सकता है.

फ़्रेमवर्क कोड से वेंडर हीप ऐक्सेस करना

Treble के नियमों का पालन करने के लिए, फ़्रेमवर्क कोड सिर्फ़ वेंडर हीप की पहले से मंज़ूरी पा चुकी कैटगरी से मेमोरी असाइन कर सकता है.

पार्टनर से मिले सुझाव/राय के आधार पर, Google ने वेंडर हीप की दो कैटगरी की पहचान की है. इन्हें फ़्रेमवर्क कोड से ऐक्सेस किया जाना चाहिए:

  1. ऐसे हीप जो सिस्टम हीप पर आधारित होते हैं. इनमें डिवाइस या SoC के हिसाब से परफ़ॉर्मेंस को बेहतर बनाने के लिए ऑप्टिमाइज़ेशन किए जाते हैं.
  2. सुरक्षित मेमोरी से असाइन करने के लिए ढेर.

डिवाइस या SoC के हिसाब से परफ़ॉर्मेंस को ऑप्टिमाइज़ करने के लिए, सिस्टम हीप पर आधारित हीप

इस इस्तेमाल के उदाहरण के लिए, डिफ़ॉल्ट डीएमए-बीयूएफ़ हीप सिस्टम के हीप को बदला जा सकता है.

  • CONFIG_DMABUF_HEAPS_SYSTEM में gki_defconfig को बंद कर दिया जाता है, ताकि यह वेंडर मॉड्यूल बन सके.
  • वीटीएस के कंप्लायंस टेस्ट से यह पक्का किया जाता है कि हीप, /dev/dma_heap/system पर मौजूद है. इन टेस्ट से यह भी पुष्टि की जाती है कि हीप को असाइन किया जा सकता है और लौटाए गए फ़ाइल डिस्क्रिप्टर (fd) को उपयोगकर्ता स्पेस से मेमोरी-मैप (mmapped) किया जा सकता है.

ऊपर बताई गई बातें, सिस्टम हीप के अनकैश्ड वैरिएंट पर भी लागू होती हैं. हालांकि, पूरी तरह से आई/ओ-कोहेरेंट डिवाइसों के लिए, इसका होना ज़रूरी नहीं है.

सुरक्षित मेमोरी से असाइन करने के लिए हीप

सुरक्षित हीप मेमोरी को लागू करने के लिए, वेंडर के हिसाब से अलग-अलग तरीके इस्तेमाल करने होंगे. ऐसा इसलिए, क्योंकि Android Common Kernel, सामान्य सुरक्षित हीप मेमोरी को लागू करने की सुविधा नहीं देता.

  • वेंडर के हिसाब से लागू किए गए बदलावों को /dev/dma_heap/system-secure<vendor-suffix> के तौर पर रजिस्टर करें.
  • इन हीप को लागू करना ज़रूरी नहीं है.
  • अगर हीप मौजूद हैं, तो वीटीएस टेस्ट यह पक्का करते हैं कि उनसे मेमोरी असाइन की जा सकती है.
  • फ़्रेमवर्क कॉम्पोनेंट को इन हीप का ऐक्सेस दिया जाता है, ताकि वे Codec2 HAL/non-binderized, सेम-प्रोसेस एचएएल के ज़रिए हीप के इस्तेमाल को चालू कर सकें. हालांकि, Android फ़्रेमवर्क की सामान्य सुविधाएं इन पर निर्भर नहीं हो सकतीं, क्योंकि इनके लागू करने के तरीके में अंतर होता है. अगर आने वाले समय में, Android के कॉमन कर्नल में सामान्य सिक्योर हीप लागू किया जाता है, तो उसे अलग ABI का इस्तेमाल करना होगा. इससे डिवाइसों को अपग्रेड करने में कोई समस्या नहीं आएगी.

डीएमए-बीयूएफ़ हीप के लिए कोडेक 2 ऐलोकेटर

AOSP में, डीएमए-बीयूएफ़ हीप इंटरफ़ेस के लिए codec2 ऐलोकेटर उपलब्ध है.

C2 डीएमए-बीयूएफ़ हीप ऐलोकेटर के साथ, कॉम्पोनेंट स्टोर इंटरफ़ेस उपलब्ध है. इसकी मदद से, C2 एचएएल से हीप पैरामीटर तय किए जा सकते हैं.

किसी ION हीप के लिए ट्रांज़िशन फ़्लो का सैंपल

ION से डीएमए-बीयूएफ़ हीप पर आसानी से स्विच करने के लिए, libdmabufheap एक बार में एक ही हीप को स्विच करने की अनुमति देता है. यहां दिए गए तरीके से, my_heap नाम के नॉन-लेगसी ION हीप को माइग्रेट करने का सुझाव दिया गया है. यह हीप, ION_FLAG_MY_FLAG फ़्लैग के साथ काम करता है.

पहला चरण: DMA-BUF फ़्रेमवर्क में ION हीप के बराबर मेमोरी बनाएं. इस उदाहरण में, ION हीप my_heap फ़्लैग ION_FLAG_MY_FLAG के साथ काम करता है. इसलिए, हम दो डीएमए-बीयूएफ़ हीप रजिस्टर करते हैं:

  • my_heap का व्यवहार, ION हीप के व्यवहार से पूरी तरह मेल खाता है. हालांकि, इसमें ION_FLAG_MY_FLAG फ़्लैग बंद होता है.
  • my_heap_special का व्यवहार, ION_FLAG_MY_FLAG फ़्लैग चालू होने पर ION हीप के व्यवहार से पूरी तरह मेल खाता है.

दूसरा चरण: नए my_heap और my_heap_special DMA-BUF हीप के लिए, ueventd में बदलाव करें. इस समय, ढेर /dev/dma_heap/my_heap और /dev/dma_heap/my_heap_special के तौर पर दिखते हैं. साथ ही, इनके लिए तय की गई अनुमतियां भी दिखती हैं.

तीसरा चरण: 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 हीप के नाम वाले पैरामीटर को खाली पर सेट करें.

चौथा चरण: सही हीप नाम का इस्तेमाल करके, 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 हीप से मेमोरी असाइन कर रहा है. इसकी वजह यह है कि उसके पास DMA-BUF हीप को खोलने के लिए, ज़रूरी sepolicy अनुमतियां नहीं हैं.

पांचवां चरण: क्लाइंट को नए DMA-BUF हीप ऐक्सेस करने के लिए ज़रूरी sepolicy अनुमतियां बनाएं. क्लाइंट अब नए DMA-BUF हीप से पूरी तरह से मेमोरी असाइन कर सकता है.

छठा चरण: logcat की जांच करके, पुष्टि करें कि नए डीएमए-बीयूएफ़ हीप से मेमोरी असाइन की जा रही है.

सातवां चरण: कर्नल में ION हीप my_heap को बंद करें. अगर क्लाइंट कोड को ऐसे डिवाइसों के अपग्रेड को सपोर्ट करने की ज़रूरत नहीं है जिनके कर्नल सिर्फ़ ION हीप को सपोर्ट कर सकते हैं, तो MapNameToIonHeap() इनवोकेशन को भी हटाया जा सकता है.