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

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 के साथ काम करने वाले कॉम्पोनेंट की सूची दी गई है. साथ ही, उन्हें DMA-BUF हेप्स फ़्रेमवर्क पर स्विच करने का तरीका भी बताया गया है.

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

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

ION और DMA-BUF, दोनों ही तरह की हेप में हर हेप के लिए, अपने एलोकेटर और 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 हेप बनाने के लिए, इस dma-buf: heaps: example template का इस्तेमाल करें.

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

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

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

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

नीति में ज़रूरी बदलाव

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

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

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/बिना बाइंडर वाले, एक ही प्रोसेस वाले 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 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हीप नेम पैरामीटर को खाली पर सेट करके, <ION heap mask, flag> से मिलते-जुलते डीएमए-BUF हीप नेम से मैपिंग बनाई जा सकती है.

चौथा चरण: हीप के सही नाम का इस्तेमाल करके, 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() को भी हटाया जा सकता है.