ION से DMA-BUF हीप में ट्रांज़िशन

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

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

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

बैकग्राउंड

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

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

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

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

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

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

ट्रांज़िशन कर्नेल ड्राइवर को ION से DMA-BUF हेप में

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

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

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 टेंप्लेट का इस्तेमाल करें.

सीधे तौर पर ION हेप से एलोकेट करने वाले कर्नेल ड्राइवर

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

यहां इन-कर्नल ION ऐलोकेशन एपीआई और इसके बराबर के DMA-BUF हीप ऐलोकेशन एपीआई दिखाए गए हैं. हेप के मौजूद होने के बारे में क्वेरी करने के लिए, कर्नेल ड्राइवर 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)

DMA-BUFs का इस्तेमाल करने वाले कर्नेल ड्राइवर

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

ION के उपयोगकर्ता-स्पेस क्लाइंट को DMA-BUF हेप में ट्रांसफ़र करना

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, कैश मेमोरी में सेव नहीं किए गए सिस्टम हीप ऐलोकेशन को कैसे करते हैं.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

पहले के पॉइंट, सिस्टम हीप के कैश न किए गए वैरिएंट के लिए भी लागू होते हैं, हालांकि, पूरी तरह से IO के साथ काम करने वाले डिवाइसों के लिए इसका होना ज़रूरी नहीं है.

सुरक्षित मेमोरी से आवंटित करने के लिए ढेर

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

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

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

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

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

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

ION से DMA-BUF हेप पर आसानी से स्विच करने के लिए, libdmabufheap एक बार में एक हेप को स्विच करने की अनुमति देता है. यहां दिए गए चरणों में, my_heap नाम के ऐसे नॉन-लेगसी ION ढेर को ट्रांज़िशन करने के लिए सुझाया गया वर्कफ़्लो दिखाया गया है जो एक फ़्लैग, ION_FLAG_MY_FLAG के साथ काम करता है.

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

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

दूसरा चरण: नए my_heap और my_heap_special डीएमए-बीयूएफ़ हीप के लिए, अलग-अलग बदलाव बनाएं. इस समय, हेप /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 ढेर से एलोकेट करने के लिए पूरी तरह से तैयार है.

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

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