ב-Android 12, GKI 2.0 מחליף את מקצה הזיכרון ION בערימות DMA-BUF מהסיבות הבאות:
- אבטחה: כל ערימת DMA-BUF היא מכשיר נפרד, ולכן אפשר לשלוט בגישה לכל ערימה בנפרד באמצעות sepolicy. ב-ION זה לא היה אפשרי כי הקצאה מכל ערימה דרשה גישה רק למכשיר
/dev/ion
. - יציבות ABI: בניגוד ל-ION, ממשק ה-IOCTL של מסגרת הערימות DMA-BUF הוא יציב ABI כי הוא מתוחזק בקרנל Linux במעלה הזרם.
- תקנון: מסגרת ה-DMA-BUF heaps מציעה UAPI מוגדר היטב. ION אפשר דגלים מותאמים אישית ומזהי ערימה שמנעו פיתוח של מסגרת בדיקה משותפת, כי ההטמעה של ION בכל מכשיר יכולה להתנהג בצורה שונה.
הסניף android12-5.10
של ליבת Android Common Kernel הושבת ב-1 במרץ 2021.CONFIG_ION
רקע
בהמשך מוצגת השוואה קצרה בין ערימות ION לבין ערימות DMA-BUF.
קווי דמיון בין ION לבין DMA-BUF heaps framework
- המסגרות ION ו-DMA-BUF הן שתיהן יצואנים של DMA-BUF שמבוססים על ערימה.
- שניהם מאפשרים לכל ערימה להגדיר את מקצה הזיכרון ואת פעולות ה-DMA-BUF שלה.
- ביצועי ההקצאה דומים כי שתי הסכימות צריכות IOCTL יחיד להקצאה.
ההבדלים בין מסגרת הערימות של ION לבין מסגרת הערימות של DMA-BUF
ערימות (heaps) של ION | ערימות DMA-BUF |
---|---|
כל ההקצאות של ION מתבצעות באמצעות /dev/ion .
|
כל ערימת DMA-BUF היא מכשיר תווים שמופיע ב-/dev/dma_heap/<heap_name> .
|
ION תומך בדגלים פרטיים של ערימה. | ערימות DMA-BUF לא תומכות בדגלים פרטיים של ערימות. במקום זאת, כל סוג שונה של הקצאה מתבצע מערימה שונה. לדוגמה, גרסאות ה-heap של המערכת שנשמרו במטמון ושלא נשמרו במטמון הן heaps נפרדים שנמצאים בכתובות /dev/dma_heap/system ו-/dev/dma_heap/system_uncached .
|
צריך לציין הקצאה של מזהה/מסכה ודגלים של ערימה. | השם של ה-heap משמש להקצאה. |
בקטעים הבאים מפורטים הרכיבים שקשורים ל-ION, ומוסבר איך להעביר אותם למסגרת של ערימות DMA-BUF.
מעבר של מנהלי התקנים של ליבת המערכת מ-ION ל-DMA-BUF heaps
מנהלי התקנים של הליבה שמטמיעים ערימות ION
גם ב-ION וגם ב-DMA-BUF, כל ערימה יכולה להטמיע הקצאות משלה ופעולות DMA-BUF. לכן, אפשר לעבור מהטמעה של ערימת ION להטמעה של ערימת DMA-BUF באמצעות קבוצה אחרת של ממשקי API לרישום הערימה. בטבלה הזו מפורטים ממשקי ה-API של ION heap registration וממשקי ה-API המקבילים של DMA-BUF heap.
ערימות (heaps) של 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()
API. כדי להקל על שיתוף קוד, מומלץ לרשום את כל הווריאציות של אותו heap באותו מנהל התקן.
בדוגמה dma-buf: system_heap מוצגת ההטמעה של גרסאות עם מטמון וגרסאות ללא מטמון של ערימת המערכת.
אפשר להשתמש בתבנית לדוגמה של dma-buf: heaps כדי ליצור ערימת DMA-BUF מאפס.
מנהלי התקנים של ליבת המערכת שמקצים ישירות מ-ION heaps
מסגרת הערימות של DMA-BUF מציעה גם ממשק הקצאה ללקוחות בתוך הליבה. במקום לציין את מסיכת הערימה ואת הדגלים כדי לבחור את סוג ההקצאה, הממשק שמציעות ערימות DMA-BUF מקבל שם של ערימה כקלט.
בדוגמה הבאה מוצג ה-API להקצאת ION בתוך הליבה, וממשקי ה-API המקבילים להקצאת DMA-BUF heap. מנהלי התקנים של ליבת המערכת יכולים להשתמש ב-API dma_heap_find()
כדי לשלוח שאילתה לגבי קיום ערימה. ה-API מחזיר מצביע למופע של struct dma_heap, שאפשר להעביר אותו כארגומנט ל-API dma_heap_buffer_alloc()
.
ערימות (heaps) של ION | ערימות DMA-BUF |
---|---|
struct dma_buf *ion_alloc(size_t len, unsigned int heap_id_mask, unsigned int flags)
|
|
דרייברים של ליבת מערכת ההפעלה שמשתמשים ב-DMA-BUFs
נהגים שמייבאים רק DMA-BUFs לא צריכים לבצע שינויים, כי מאגר שהוקצה מ-ION heap מתנהג בדיוק כמו מאגר שהוקצה מ-DMA-BUF heap מקביל.
העברה של לקוחות במרחב המשתמשים של ION לערימות DMA-BUF
כדי להקל על המעבר ללקוחות במרחב המשתמש של ION, זמינה ספריית הפשטה בשם libdmabufheap
. libdmabufheap
תומך בהקצאה ב-DMA-BUF heaps וב-ION heaps. הפונקציה בודקת קודם אם קיים ערימת DMA-BUF עם השם שצוין, ואם לא, היא חוזרת לערימת ION שוות ערך, אם קיימת כזו.
במהלך האתחול, הלקוחות צריכים לאתחל אובייקט BufferAllocator
במקום לפתוח את /dev/ion using
ion_open()
. הסיבה לכך היא שמתארים של קבצים שנוצרים על ידי פתיחה של /dev/ion
ו-/dev/dma_heap/<heap_name>
מנוהלים באופן פנימי על ידי אובייקט BufferAllocator
.
כדי לעבור מ-libion
ל-libdmabufheap
, צריך לשנות את ההתנהגות של הלקוחות באופן הבא:
- כדי להקצות זיכרון, צריך לעקוב אחרי שם הערימה במקום אחרי מזהה/מסכת הראש ודגל הערימה.
- מחליפים את ה-API
ion_alloc_fd()
, שמקבל מסכת ערימה וארגומנט של דגל, ב-APIBufferAllocator::Alloc()
, שמקבל שם ערימה במקום זאת.
בטבלה הזו מוצגים השינויים האלה, ומוסבר איך libion
ו-libdmabufheap
מבצעים הקצאה של ערימת מערכת לא מאוחסנת במטמון.
סוג ההקצאה | libion | libdmabufheap |
---|---|---|
הקצאה במטמון מתוך ערימת המערכת | ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, ION_FLAG_CACHED, &fd)
|
allocator->Alloc("system", size)
|
הקצאה שלא נשמרה במטמון מ-System heap | ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, 0, &fd)
|
allocator->Alloc("system-uncached", size)
|
uncached system heap variant
ממתין לאישור במעלה הזרם, אבל הוא כבר חלק מהסניף android12-5.10
.
כדי לתמוך בשדרוג מכשירים, MapNameToIonHeap()
API מאפשר מיפוי של שם heap לפרמטרים של ION heap (שם או מסכה של heap ודגלים) כדי לאפשר לממשקים האלה להשתמש בהקצאות מבוססות-שם. הנה דוגמה להקצאה לפי שם.
מסמכי התיעוד של כל ממשק API שנחשף על ידי libdmabufheap
זמינים. הספרייה גם חושפת קובץ כותרת לשימוש על ידי לקוחות C.
הטמעה לדוגמה של Gralloc
ההטמעה של Hikey960 gralloc משתמשת ב-libdmabufheap
, כך שאפשר להשתמש בה כהטמעה לדוגמה.
תוספות נדרשות ל-ueventd
לכל ערימת DMA-BUF חדשה שנוצרת עבור מכשיר ספציפי, מוסיפים רשומה חדשה לקובץ ueventd.rc
של המכשיר.
בדוגמה הזו להגדרת ueventd לתמיכה ב-DMA-BUF heaps מוסבר איך עושים את זה עבור ה-DMA-BUF system heap.
תוספות נדרשות למדיניות sepolicy
מוסיפים הרשאות sepolicy כדי לאפשר ללקוח במרחב המשתמשים לגשת ל-DMA-BUF heap חדש. בדוגמה add required permissions מוצגות הרשאות sepolicy שנוצרו עבור לקוחות שונים כדי לגשת לזיכרון המערכת של DMA-BUF.
גישה ל-heaps של ספקים מקוד המסגרת
כדי להבטיח תאימות ל-Treble, קוד המסגרת יכול להקצות רק מקטגוריות שאושרו מראש של ערימות ספקים.
על סמך משוב שהתקבל משותפים, Google זיהתה שתי קטגוריות של ערימות ספקים שצריך לגשת אליהן מקוד המסגרת:
- ערימות שמבוססות על ערימת המערכת עם אופטימיזציות של ביצועים שספציפיות למכשיר או ל-SoC.
- ערימות להקצאה מזיכרון מוגן.
ערימות שמבוססות על ערימת המערכת עם אופטימיזציות של הביצועים שספציפיות למכשיר או ל-SoC
כדי לתמוך בתרחיש השימוש הזה, אפשר לשנות את ההטמעה של ה-heap של מערכת DMA-BUF heap שמוגדרת כברירת מחדל.
- האפשרות
CONFIG_DMABUF_HEAPS_SYSTEM
מושבתת ב-gki_defconfig
כדי שהיא תהיה מודול של ספק. - בדיקות התאימות של VTS מוודאות שה-heap קיים בכתובת
/dev/dma_heap/system
. הבדיקות גם מוודאות שאפשר להקצות את הערימה, ושאפשר למפות את מתאר הקובץ המוחזר (fd
) בזיכרון (mmapped) ממרחב המשתמש.
הנקודות הקודמות נכונות גם לגבי גרסת ה-heap של המערכת שלא נשמרה במטמון, למרות שהקיום שלה לא חובה במכשירים עם קלט/פלט קוהרנטי לחלוטין.
ערימות להקצאה מזיכרון מוגן
הטמעות מאובטחות של ערימה חייבות להיות ספציפיות לספק, כי ליבת Android Common לא תומכת בהטמעה מאובטחת כללית של ערימה.
- צריך לרשום את ההטמעות הספציפיות לספק כ-
/dev/dma_heap/system-secure<vendor-suffix>
. - ההטמעות האלה של הערימה הן אופציונליות.
- אם הערימות קיימות, בדיקות VTS מוודאות שאפשר להקצות מהן זיכרון.
- רכיבי המסגרת מקבלים גישה לזיכרונות האלה כדי שיוכלו להשתמש בהם דרך Codec2 HAL/non-binderized, HALs באותו תהליך. עם זאת, תכונות כלליות של מסגרת Android לא יכולות להיות תלויות בהן בגלל השונות בפרטי ההטמעה שלהן. אם בעתיד תתווסף הטמעה גנרית של ערימה מאובטחת לליבת Android Common Kernel, היא תצטרך להשתמש ב-ABI שונה כדי למנוע התנגשויות בשדרוג מכשירים.
מקצה זיכרון Codec 2 עבור ערימות DMA-BUF
ב-AOSP זמין מקצה זיכרון codec2 לממשק של ערימות DMA-BUF .
ממשק מאגר הרכיבים שמאפשר לציין פרמטרים של ערימה מ-C2 HAL זמין עם מקצה הערימה C2 DMA-BUF.
דוגמה לזרימת מעבר עבור ערימת ION
כדי להקל על המעבר מ-ION לערימות DMA-BUF, libdmabufheap
מאפשר מעבר בין ערימות בכל פעם. השלבים הבאים מתארים תהליך עבודה מומלץ להעברת ערימת ION שאינה מדור קודם בשם my_heap
שתומכת בדגל אחד, ION_FLAG_MY_FLAG
.
שלב 1: יוצרים מקבילות של ערימת ה-ION במסגרת DMA-BUF. בדוגמה הזו, מכיוון ש-ION heap my_heap
תומך בדגל ION_FLAG_MY_FLAG
, אנחנו רושמים שני DMA-BUF heaps:
- ההתנהגות של
my_heap
זהה בדיוק להתנהגות של ION heap כשהדגלION_FLAG_MY_FLAG
מושבת. - ההתנהגות של
my_heap_special
זהה בדיוק להתנהגות של ION heap עם הדגל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
, משנים את קובצי ה-Makefile שלהם כדי לקשר ל-libdmabufheap
. במהלך אתחול הלקוח, יוצרים מופע של אובייקט BufferAllocator
ומשתמשים ב-API 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 */ )
במקום להשתמש ב-API MapNameToIonHeap()
עם הפרמטרים name ו-flag, אפשר ליצור את המיפוי מ-<ION heap mask, flag>
לשמות שווי ערך של DMA-BUF heap על ידי הגדרת הפרמטר ION heap name כריק.
שלב 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)
|
בשלב הזה, הלקוח פועל אבל עדיין מקצה זיכרון מה-heap של ION כי אין לו את ההרשאות הנדרשות של sepolicy כדי לפתוח את ה-heap של DMA-BUF.
שלב 5: יוצרים את ההרשאות של sepolicy שנדרשות ללקוח כדי לגשת ל-DMA-BUF heaps החדשים. עכשיו הלקוח מצויד באופן מלא להקצאה מה-heap החדש של DMA-BUF.
שלב 6: בודקים שההקצאות מתבצעות מה-heap החדש של DMA-BUF על ידי בדיקה של logcat.
שלב 7: משביתים את ה-heap של ION my_heap
בקרנל. אם קוד הלקוח לא צריך לתמוך בשדרוג מכשירים (שהקרנלים שלהם עשויים לתמוך רק ב-ION heaps), אפשר גם להסיר את הקריאות ל-MapNameToIonHeap()
.