در Android 12، GKI 2.0 به دلایل زیر، تخصیص دهنده ION را با پشته های DMA-BUF جایگزین می کند:
- امنیت: از آنجا که هر پشته DMA-BUF یک دستگاه کاراکتر جداگانه است، دسترسی به هر پشته را می توان به طور جداگانه با sepolicy کنترل کرد. این کار با ION ممکن نبود زیرا تخصیص از هر پشته فقط نیاز به دسترسی به دستگاه
/dev/ion
دارد. - پایداری ABI: برخلاف ION، رابط IOCTL چارچوب هیپ DMA-BUF پایدار ABI است زیرا در هسته بالادست لینوکس نگهداری میشود.
- استانداردسازی: چارچوب پشته های DMA-BUF یک UAPI کاملاً تعریف شده ارائه می دهد. ION به پرچمهای سفارشی و شناسههای پشته اجازه میدهد که از توسعه یک چارچوب آزمایشی مشترک جلوگیری میکند زیرا پیادهسازی ION هر دستگاه میتواند متفاوت رفتار کند.
شاخه android12-5.10
هسته مشترک Android CONFIG_ION
در 1 مارس 2021 غیرفعال کرد.
پس زمینه
در زیر مقایسه مختصری بین پشته های ION و DMA-BUF ارائه شده است.
شباهتهای بین چارچوب پشتههای ION و DMA-BUF
- چارچوبهای هیپ ION و DMA-BUF هر دو صادرکنندگان DMA-BUF مبتنی بر پشته هستند.
- هر دو به هر پشته اجازه می دهند تخصیص دهنده و عملیات DMA-BUF خود را تعریف کند.
- عملکرد تخصیص مشابه است زیرا هر دو طرح به یک IOCTL واحد برای تخصیص نیاز دارند.
تفاوت بین چارچوب پشته های ION و DMA-BUF
پشته های یون | پشته های DMA-BUF |
---|---|
تمام تخصیص های ION با /dev/ion انجام می شود. | هر پشته DMA-BUF یک دستگاه کاراکتری است که در /dev/dma_heap/<heap_name> موجود است. |
ION از پرچم های خصوصی heap پشتیبانی می کند. | پشتههای DMA-BUF از پرچمهای خصوصی پشتهای پشتیبانی نمیکنند. هر نوع تخصیص متفاوت در عوض از پشته متفاوتی انجام می شود. به عنوان مثال، انواع هیپ سیستم حافظه پنهان و ذخیره نشده، پشته های جداگانه ای هستند که در /dev/dma_heap/system و /dev/dma_heap/system_uncached قرار دارند. |
شناسه/ماسک پشته و پرچم ها باید برای تخصیص مشخص شوند. | از نام پشته برای تخصیص استفاده می شود. |
بخشهای زیر مؤلفههایی را فهرست میکند که با ION سروکار دارند و نحوه تغییر آنها به چارچوب پشتههای DMA-BUF را شرح میدهند.
انتقال درایورهای هسته از ION به پشته های DMA-BUF
درایورهای هسته در حال پیاده سازی پشته های ION
هر دو پشته های ION و DMA-BUF به هر پشته اجازه می دهند تخصیص دهنده ها و عملیات DMA-BUF خود را پیاده سازی کنند. بنابراین میتوانید با استفاده از مجموعهای از APIهای مختلف برای ثبت پشته، از اجرای یون هیپ به اجرای پشته DMA-BUF تغییر دهید. این جدول APIهای ثبت هیپ ION و APIهای هیپ DMA-BUF معادل آنها را نشان می دهد.
پشته های یون | پشته های 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()
API ثبت شود. برای تسهیل اشتراکگذاری کد، توصیه میشود همه انواع یک پشته را در یک درایور ثبت کنید. این مثال dma-buf: system_heap اجرای انواع کش و غیر کش سیستم heap را نشان می دهد.
از این الگوی نمونه dma-buf: heaps: برای ایجاد یک پشته DMA-BUF از ابتدا استفاده کنید.
درایورهای هسته که مستقیماً از پشته های ION تخصیص می یابند
چارچوب heaps DMA-BUF همچنین یک رابط تخصیص برای مشتریان درون هسته ارائه می دهد. به جای تعیین ماسک پشته و پرچمها برای انتخاب نوع تخصیص، رابط ارائه شده توسط پشتههای DMA-BUF یک نام پشته را به عنوان ورودی میگیرد.
در زیر API تخصیص ION درون هسته و APIهای تخصیص پشته DMA-BUF معادل آن را نشان می دهد. درایورهای هسته می توانند از API dma_heap_find()
برای پرس و جو در مورد وجود یک پشته استفاده کنند. The API returns a pointer to an instance of struct dma_heap , which can then be passed as an argument to the dma_heap_buffer_alloc()
API.
پشته های یون | پشته های DMA-BUF |
---|---|
struct dma_buf *ion_alloc(size_t len, unsigned int heap_id_mask, unsigned int flags) | |
درایورهای هسته که از DMA-BUF استفاده می کنند
برای درایورهایی که فقط DMA-BUF وارد می کنند، هیچ تغییری لازم نیست، زیرا یک بافر تخصیص یافته از یک پشته ION دقیقاً مشابه بافر اختصاص داده شده از یک پشته DMA-BUF معادل عمل می کند.
مشتریان فضای کاربری ION را به پشته های DMA-BUF منتقل کنید
برای آسان کردن انتقال برای مشتریان فضای کاربر ION، یک کتابخانه انتزاعی به نام libdmabufheap
در دسترس است. libdmabufheap
از تخصیص در پشته های DMA-BUF و پشته های ION پشتیبانی می کند. ابتدا بررسی میکند که آیا یک پشته DMA-BUF با نام مشخصشده وجود دارد یا نه، اگر وجود داشته باشد، به یک پشته یون معادل برمیگردد.
کلاینت ها باید به جای باز کردن /dev/ion using ion_open()
یک شی BufferAllocator
در طول مقداردهی اولیه خود مقداردهی کنند. این به این دلیل است که توصیفگرهای فایل ایجاد شده با باز کردن /dev/ion
و /dev/dma_heap/<heap_name>
به صورت داخلی توسط شی BufferAllocator
مدیریت میشوند.
برای تغییر از libion
به libdmabufheap
، رفتار مشتریان را به صورت زیر تغییر دهید:
- به جای شناسه/ماسک و پرچم پشته، نام پشته را برای استفاده برای تخصیص پیگیری کنید.
- API
ion_alloc_fd()
را که یک heap mask و آرگومان پرچم می گیرد، باBufferAllocator::Alloc()
API جایگزین کنید که به جای آن یک نام پشته می گیرد.
این جدول این تغییرات را با نشان دادن اینکه چگونه 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
است.
برای پشتیبانی از دستگاههای در حال ارتقا، API MapNameToIonHeap()
اجازه میدهد تا یک نام پشته به پارامترهای پشته ION (نام پشته یا ماسک و پرچمها) نگاشت شود تا این رابطها از تخصیصهای مبتنی بر نام استفاده کنند. در اینجا یک مثال تخصیص مبتنی بر نام آورده شده است.
اسناد مربوط به هر API که توسط libdmabufheap
در معرض دید قرار می گیرد در دسترس است. این کتابخانه همچنین یک فایل هدر را برای استفاده توسط کلاینت های C در معرض دید قرار می دهد.
مرجع پیاده سازی Gralloc
The Hikey960 gralloc implementation uses libdmabufheap
, so you can use it as a reference implementation .
اضافات مورد نیاز ueventd
برای هر انبوه DMA-BUF خاص دستگاه جدید ایجاد شده، یک ورودی جدید به فایل ueventd.rc
دستگاه اضافه کنید. این راهاندازی برای پشتیبانی از پشتههای DMA-BUF نشان میدهد که چگونه این کار برای پشته سیستم DMA-BUF انجام میشود.
ضمیمه های سیاست گذاری مورد نیاز
برای فعال کردن مشتری فضای کاربر برای دسترسی به پشته جدید DMA-BUF، مجوزهای سیاست را اضافه کنید. این مثال مجوزهای مورد نیاز اضافه کردن، مجوزهای سیاست ایجاد شده برای مشتریان مختلف برای دسترسی به پشته سیستم DMA-BUF را نشان می دهد.
از کد چارچوب به انبوه فروشنده دسترسی پیدا کنید
برای اطمینان از انطباق با Treble، کد چارچوب فقط می تواند از دسته های از پیش تأیید شده انبوه فروشنده تخصیص یابد.
بر اساس بازخورد دریافت شده از شرکا، Google دو دسته از انبوه فروشنده را شناسایی کرد که باید از کد چارچوب به آنها دسترسی داشت:
- Heap هایی که بر پایه هیپ سیستم با بهینه سازی عملکرد خاص دستگاه یا SoC هستند.
- انبوهی برای تخصیص از حافظه محافظت شده.
پشته های مبتنی بر هیپ سیستم با بهینه سازی عملکرد خاص دستگاه یا SoC
برای پشتیبانی از این مورد، میتوان اجرای Heap سیستم پیشفرض پشته DMA-BUF را نادیده گرفت.
-
CONFIG_DMABUF_HEAPS_SYSTEM
درgki_defconfig
غیرفعال شده است تا یک ماژول فروشنده باشد. - تستهای انطباق VTS اطمینان حاصل میکنند که heap در
/dev/dma_heap/system
وجود دارد. آزمایشها همچنین تأیید میکنند که heap را میتوان از آن تخصیص داد، و اینکه توصیفگر فایل برگشتی (fd
) را میتوان از فضای کاربر نقشهبرداری کرد (mmap) کرد.
نکات پیشین در مورد نوع ذخیره نشده سیستم heap نیز صادق است، اگرچه وجود آن برای دستگاه های کاملاً منسجم IO اجباری نیست.
انبوهی برای تخصیص از حافظه محافظت شده
پیاده سازی Secure Heap باید مختص فروشنده باشد، زیرا Android Common Kernel از اجرای Heap ایمن عمومی پشتیبانی نمی کند.
- پیاده سازی های خاص فروشنده خود را به عنوان
/dev/dma_heap/system-secure<vendor-suffix>
ثبت کنید. - این پیاده سازی های پشته اختیاری هستند.
- اگر انبوهها وجود داشته باشند، آزمایشهای VTS تضمین میکنند که میتوان از آنها تخصیص داد.
- اجزای چارچوب با دسترسی به این پشتهها ارائه میشوند تا بتوانند استفاده از پشتهها را از طریق کدک2 HAL/HALهای غیرصحیح و با همان فرآیند فعال کنند. با این حال، ویژگیهای فریمورک عمومی اندروید به دلیل تنوع در جزئیات پیادهسازی آنها نمیتوانند به آنها وابسته باشند. اگر در آینده یک اجرای پشته ایمن عمومی به هسته مشترک Android اضافه شود، باید از ABI دیگری استفاده کند تا از تداخل با دستگاه های در حال ارتقا جلوگیری کند.
تخصیص دهنده کدک 2 برای پشته های DMA-BUF
یک تخصیص دهنده کدک2 برای رابط هیپ DMA-BUF در AOSP موجود است.
رابط ذخیره کامپوننت که اجازه می دهد پارامترهای پشته از C2 HAL مشخص شود با تخصیص دهنده پشته C2 DMA-BUF در دسترس است.
نمونه جریان انتقال برای یک پشته یونی
libdmabufheap
برای هموار کردن انتقال از یون به پشتههای DMA-BUF، امکان تعویض یک پشته را در هر زمان فراهم میکند. مراحل زیر یک گردش کار پیشنهادی برای انتقال یک پشته یون غیر قدیمی به نام my_heap
را نشان می دهد که از یک پرچم، ION_FLAG_MY_FLAG
پشتیبانی می کند.
مرحله 1: معادلهایی از پشته ION در چارچوب DMA-BUF ایجاد کنید. در این مثال، از آنجایی که ION heap 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()
API برای نگاشت ترکیب <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()
API با نام و پارامترهای پرچم، میتوانید نگاشت را از <ION heap mask, flag>
به نامهای پشته DMA-BUF معادل با تنظیم پارامتر نام هیپ ION روی خالی ایجاد کنید.
مرحله 4: فراخوانی های ion_alloc_fd()
را با BufferAllocator::Alloc()
با استفاده از نام heap مناسب جایگزین کنید.
نوع تخصیص | لیبیون | 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 را ندارد.
مرحله 5: مجوزهای sepolicy مورد نیاز برای دسترسی مشتری به پشته های جدید DMA-BUF را ایجاد کنید. مشتری اکنون به طور کامل برای تخصیص از پشته جدید DMA-BUF مجهز است.
مرحله 6: با بررسی logcat بررسی کنید که تخصیص ها از پشته DMA-BUF جدید انجام می شود.
مرحله 7: ION heap my_heap
را در هسته غیرفعال کنید. اگر کد کلاینت نیازی به پشتیبانی از دستگاههای ارتقاء دهنده ندارد (که هستههای آنها فقط پشتههای ION را پشتیبانی میکنند)، میتوانید فراخوانهای MapNameToIonHeap()
را نیز حذف کنید.