ใน Android 12, GKI 2.0 จะแทนที่ตัวจัดสรร ION ด้วยฮีป DMA-BUF ด้วยเหตุผลต่อไปนี้
- ความปลอดภัย: เนื่องจากฮีป DMA-BUF แต่ละรายการเป็นอุปกรณ์อักขระแยกกัน จึงควบคุมการเข้าถึงฮีปแต่ละรายการแยกกันได้ด้วย sepolicy ซึ่งทำไม่ได้ใน ION เนื่องจากการจัดสรรจากฮีปใดๆ ต้องมีการเข้าถึง
/dev/ion
อุปกรณ์ - ความเสถียรของ ABI: อินเทอร์เฟซ IOCTL ของเฟรมเวิร์กฮีป DMA-BUF มีความเสถียรของ ABI เนื่องจากมีการดูแลรักษาในเคอร์เนล Linux ต้นทาง ซึ่งแตกต่างจาก ION
- การกำหนดมาตรฐาน: กรอบกอง DMA-BUF มี UAPI ที่กำหนดไว้อย่างดี ION อนุญาตให้ใช้แฟล็กที่กําหนดเองและรหัสฮีปที่ทําให้พัฒนาเฟรมเวิร์กการทดสอบทั่วไปไม่ได้ เนื่องจากการติดตั้งใช้งาน ION ของอุปกรณ์แต่ละเครื่องอาจทํางานแตกต่างกัน
android12-5.10
สาขาของเคอร์เนลทั่วไปของ Android ถูกปิดใช้
CONFIG_ION
ในวันที่ 1 มีนาคม 2021
ฉากหลัง
ต่อไปนี้คือการเปรียบเทียบคร่าวๆ ระหว่างกอง ION กับกอง DMA-BUF
ความคล้ายคลึงระหว่างเฟรมเวิร์กฮีป ION และ DMA-BUF
- ทั้งเฟรมเวิร์ก ION และ DMA-BUF heaps เป็นเครื่องมือส่งออก DMA-BUF ที่อิงตามฮีป
- ทั้ง 2 อย่างนี้ช่วยให้แต่ละฮีปกำหนดตัวจัดสรรและ DMA-BUF ops ของตัวเองได้
- ประสิทธิภาพการจัดสรรจะคล้ายกันเนื่องจากทั้ง 2 รูปแบบต้องใช้ IOCTL เดียว สำหรับการจัดสรร
ความแตกต่างระหว่างเฟรมเวิร์กฮีป ION กับ DMA-BUF
ฮีป ION | ฮีป DMA-BUF |
---|---|
การจัดสรร ION ทั้งหมดดำเนินการด้วย /dev/ion
|
ฮีป DMA-BUF แต่ละรายการคืออุปกรณ์อักขระที่อยู่ใน /dev/dma_heap/<heap_name>
|
ION รองรับฟีเจอร์ส่วนตัวของฮีป | ฮีป DMA-BUF ไม่รองรับแฟล็กส่วนตัวของฮีป การจัดสรรประเภทต่างๆ
จะดำเนินการจากฮีปอื่นแทน เช่น ฮีปของระบบที่แคชและไม่ได้แคชเป็นฮีปแยกกันซึ่งอยู่ที่ /dev/dma_heap/system และ /dev/dma_heap/system_uncached
|
ต้องระบุรหัส/มาสก์ของฮีปและแฟล็กสำหรับการจัดสรร | ระบบจะใช้ชื่อฮีปสำหรับการจัดสรร |
ส่วนต่อไปนี้จะแสดงรายการคอมโพเนนต์ที่เกี่ยวข้องกับ ION และอธิบายวิธี เปลี่ยนไปใช้เฟรมเวิร์กฮีป DMA-BUF
เปลี่ยนไดรเวอร์เคอร์เนลจากกอง ION เป็นกอง DMA-BUF
ไดรเวอร์เคอร์เนลที่ใช้ฮีป ION
ทั้งกอง ION และ DMA-BUF อนุญาตให้แต่ละกองใช้ตัวจัดสรรและ การดำเนินการ DMA-BUF ของตัวเอง คุณจึงเปลี่ยนจากการใช้งานฮีป ION ไปเป็นการใช้งานฮีป DMA-BUF ได้โดยใช้ชุด API อื่นเพื่อลงทะเบียนฮีป ตารางนี้ แสดง API การลงทะเบียนฮีป ION และ API ฮีป DMA-BUF ที่เทียบเท่า
ฮีป 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 ขอแนะนำให้ลงทะเบียนตัวแปรทั้งหมดของฮีปเดียวกันภายในไดรเวอร์เดียวกันเพื่ออำนวยความสะดวกในการแชร์โค้ด
ตัวอย่าง dma-buf: system_heap
แสดงการใช้งานตัวแปรที่แคชและไม่ได้แคชของฮีประบบ
ใช้dma-buf: heaps: example template นี้เพื่อสร้างฮีป DMA-BUF ตั้งแต่ต้น
ไดรเวอร์เคอร์เนลที่จัดสรรโดยตรงจากกอง ION
เฟรมเวิร์กฮีป DMA-BUF ยังมีอินเทอร์เฟซการจัดสรร สำหรับไคลเอ็นต์ในเคอร์เนลด้วย อินเทอร์เฟซที่ฮีป DMA-BUF มีให้จะใช้ชื่อฮีปเป็นอินพุตแทนการระบุมาสก์ฮีปและแฟล็กเพื่อเลือก ประเภทการจัดสรร
ต่อไปนี้แสดง API การจัดสรร ION ในเคอร์เนลและ API การจัดสรรฮีป DMA-BUF
ที่เทียบเท่า ไดรเวอร์เคอร์เนลสามารถใช้ dma_heap_find()
API เพื่อค้นหา
การมีอยู่ของฮีปได้ API จะส่งคืนพอยน์เตอร์ไปยังอินสแตนซ์ของ
struct dma_heap ซึ่งสามารถส่งเป็นอาร์กิวเมนต์ไปยัง API ของ
dma_heap_buffer_alloc()
ได้
ฮีป ION | ฮีป 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
เรามีไลบรารีการแยกส่วนที่ชื่อ libdmabufheap
เพื่อให้ผู้ใช้ไคลเอ็นต์ในพื้นที่ผู้ใช้ของ ION เปลี่ยนไปใช้ได้ง่าย libdmabufheap
รองรับการจัดสรรในฮีป DMA-BUF
และฮีป ION โดยจะตรวจสอบก่อนว่ามีฮีป DMA-BUF ที่มีชื่อที่ระบุหรือไม่
หากไม่มี ระบบจะกลับไปใช้ฮีป ION ที่เทียบเท่า หากมี
ไคลเอ็นต์ควรเริ่มต้นออบเจ็กต์
BufferAllocator
ในระหว่างการเริ่มต้นแทนที่จะเปิด /dev/ion using
ion_open()
เนื่องจากตัวอธิบายไฟล์ที่สร้างขึ้นโดยการเปิด /dev/ion
และ /dev/dma_heap/<heap_name>
จะได้รับการจัดการภายในโดยออบเจ็กต์ BufferAllocator
หากต้องการเปลี่ยนจาก libion
เป็น libdmabufheap
ให้แก้ไขลักษณะการทำงานของไคลเอ็นต์ดังนี้
- ติดตามชื่อฮีปเพื่อใช้ในการจัดสรรแทนที่จะใช้รหัส/มาสก์ของฮีปและแฟล็กฮีป
- แทนที่
ion_alloc_fd()
API ซึ่งรับอาร์กิวเมนต์มาสก์ฮีปและแฟล็ก ด้วยBufferAllocator::Alloc()
API ซึ่งรับชื่อฮีปแทน
ตารางนี้แสดงการเปลี่ยนแปลงเหล่านี้โดยแสดงวิธีที่ 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 (ชื่อหรือมาสก์และแฟล็กของฮีป) เพื่อให้อินเทอร์เฟซเหล่านั้นใช้การจัดสรรตามชื่อได้ เพื่อรองรับการอัปเกรดอุปกรณ์ ต่อไปนี้คือตัวอย่างการจัดสรรตามชื่อ
เอกสารประกอบสำหรับ API ทุกรายการที่
libdmabufheap
เปิดให้ใช้งาน
ไลบรารี
ยังแสดงไฟล์ส่วนหัวเพื่อให้ไคลเอ็นต์ C ใช้ด้วย
การใช้งาน Gralloc อ้างอิง
การติดตั้งใช้งาน Gralloc ของ Hikey960 ใช้ libdmabufheap
คุณจึงใช้เป็นการติดตั้งใช้งานอ้างอิงได้
การเพิ่ม ueventd ที่จำเป็น
สําหรับฮีป DMA-BUF เฉพาะอุปกรณ์ใหม่ที่สร้างขึ้น ให้เพิ่มรายการใหม่ลงในไฟล์ ueventd.rc
ของอุปกรณ์
ตัวอย่างการตั้งค่า ueventd เพื่อรองรับฮีป DMA-BUF
แสดงวิธีดำเนินการนี้สำหรับฮีประบบ DMA-BUF
การเพิ่ม sepolicy ที่จำเป็น
เพิ่มสิทธิ์ sepolicy เพื่อให้ไคลเอ็นต์ในพื้นที่ผู้ใช้เข้าถึงฮีป DMA-BUF ใหม่ได้ ตัวอย่างเพิ่มสิทธิ์ ที่จำเป็นนี้แสดงสิทธิ์ sepolicy ที่สร้างขึ้นสำหรับไคลเอ็นต์ต่างๆ เพื่อ เข้าถึงฮีปของระบบ DMA-BUF
เข้าถึงฮีปของผู้ให้บริการจากโค้ดเฟรมเวิร์ก
เพื่อให้มั่นใจว่า Treble เป็นไปตามข้อกำหนด โค้ดเฟรมเวิร์กจะจัดสรรได้จากหมวดหมู่ฮีปของผู้ให้บริการที่ได้รับอนุมัติล่วงหน้าเท่านั้น
Google ได้ระบุหมวดหมู่ของฮีปของผู้ให้บริการ 2 หมวดหมู่ที่ต้องเข้าถึงจากโค้ดเฟรมเวิร์กตามความคิดเห็นที่ได้รับจากพาร์ทเนอร์
- ฮีปที่อิงตามฮีประบบที่มีการเพิ่มประสิทธิภาพเฉพาะอุปกรณ์หรือ SoC
- ฮีปที่จะจัดสรรจากหน่วยความจำที่ได้รับการป้องกัน
ฮีปที่อิงตามฮีประบบที่มีการเพิ่มประสิทธิภาพเฉพาะอุปกรณ์หรือ SoC
หากต้องการรองรับกรณีการใช้งานนี้ คุณสามารถลบล้างการใช้งานฮีปของฮีป DMA-BUF เริ่มต้น ของระบบได้
CONFIG_DMABUF_HEAPS_SYSTEM
จะปิดในgki_defconfig
เพื่อให้เป็นโมดูลของผู้ให้บริการ- การทดสอบการปฏิบัติตามข้อกำหนดของ VTS ช่วยให้มั่นใจได้ว่าฮีปมีอยู่ที่
/dev/dma_heap/system
การทดสอบยังยืนยันว่าสามารถจัดสรรฮีปได้ และสามารถแมปหน่วยความจำ (mmapped) ของตัวอธิบายไฟล์ (fd
) ที่ส่งคืนจากพื้นที่ผู้ใช้ได้
ประเด็นข้างต้นยังใช้ได้กับตัวแปรของฮีปของระบบที่ไม่ได้แคชด้วย แม้ว่าอุปกรณ์ที่สอดคล้องกับ I/O อย่างสมบูรณ์ไม่จำเป็นต้องมีตัวแปรนี้ก็ตาม
กองที่จะจัดสรรจากหน่วยความจำที่ได้รับการป้องกัน
การใช้งานฮีปที่ปลอดภัยต้องเป็นของผู้ให้บริการรายใดรายหนึ่ง เนื่องจากเคอร์เนลทั่วไปของ Android ไม่รองรับการใช้งานฮีปที่ปลอดภัยทั่วไป
- ลงทะเบียนการใช้งานเฉพาะผู้ให้บริการเป็น
/dev/dma_heap/system-secure<vendor-suffix>
- การติดตั้งใช้งานฮีปเหล่านี้เป็นตัวเลือก
- หากมีฮีปอยู่ การทดสอบ VTS จะช่วยให้มั่นใจว่าสามารถจัดสรรจากฮีปเหล่านั้นได้
- คอมโพเนนต์ของเฟรมเวิร์กจะได้รับสิทธิ์เข้าถึงฮีปเหล่านี้เพื่อให้สามารถ เปิดใช้การใช้งานฮีปผ่าน HAL ของ Codec2/HAL ที่ไม่ใช่ Binderized และ HAL ในกระบวนการเดียวกัน อย่างไรก็ตาม ฟีเจอร์ของเฟรมเวิร์ก Android ทั่วไปไม่สามารถขึ้นอยู่กับฟีเจอร์เหล่านี้ได้เนื่องจาก รายละเอียดการใช้งานมีความหลากหลาย หากมีการเพิ่มการใช้งานฮีปที่ปลอดภัยทั่วไป ลงในเคอร์เนลทั่วไปของ Android ในอนาคต จะต้องใช้ ABI อื่นเพื่อหลีกเลี่ยงการขัดแย้งกับอุปกรณ์ที่อัปเกรด
ตัวจัดสรร Codec 2 สำหรับฮีป DMA-BUF
ตัวจัดสรร codec2 สำหรับอินเทอร์เฟซ DMA-BUF heaps พร้อมใช้งานใน AOSP
อินเทอร์เฟซที่เก็บคอมโพเนนต์ซึ่งอนุญาตให้ระบุพารามิเตอร์ฮีปจาก C2 HAL พร้อมใช้งานกับตัวจัดสรรฮีป DMA-BUF ของ C2
ตัวอย่างโฟลว์การเปลี่ยนสำหรับฮีป ION
libdmabufheap
อนุญาตให้เปลี่ยนฮีปทีละรายการเพื่อการเปลี่ยนจากฮีป ION เป็น DMA-BUF ที่ราบรื่น
ขั้นตอนต่อไปนี้แสดงเวิร์กโฟลว์ที่แนะนำ
สำหรับการเปลี่ยนฮีป ION ที่ไม่ใช่รุ่นเดิมชื่อ my_heap
ซึ่งรองรับแฟล็กเดียว
ION_FLAG_MY_FLAG
ขั้นตอนที่ 1: สร้างฮีป ION ที่เทียบเท่าในเฟรมเวิร์ก DMA-BUF ในตัวอย่างนี้ เนื่องจากฮีป ION my_heap
รองรับแฟล็ก ION_FLAG_MY_FLAG
เราจึงลงทะเบียนฮีป DMA-BUF 2 รายการ ดังนี้
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
ให้แก้ไขไฟล์ Make เพื่อลิงก์กับ 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 */ )
คุณสามารถสร้างการแมปจาก <ION heap mask, flag>
ไปยังชื่อฮีป DMA-BUF ที่เทียบเท่า
ได้โดยการตั้งค่าพารามิเตอร์ชื่อฮีป ION เป็นค่าว่าง แทนการใช้ MapNameToIonHeap()
API กับพารามิเตอร์ชื่อและแฟล็ก
ขั้นตอนที่ 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)
|
ในตอนนี้ ไคลเอ็นต์ทำงานได้ แต่ยังคงจัดสรรจากฮีป ION เนื่องจากไม่มีสิทธิ์ sepolicy ที่จำเป็นในการเปิดฮีป DMA-BUF
ขั้นตอนที่ 5: สร้างสิทธิ์ sepolicy ที่ไคลเอ็นต์ต้องใช้เพื่อเข้าถึง ฮีป DMA-BUF ใหม่ ตอนนี้ไคลเอ็นต์พร้อมที่จะจัดสรรจากฮีป DMA-BUF ใหม่แล้ว
ขั้นตอนที่ 6: ตรวจสอบว่าการจัดสรรเกิดขึ้นจากฮีป DMA-BUF ใหม่ โดยการตรวจสอบ logcat
ขั้นตอนที่ 7: ปิดใช้ฮีป ION my_heap
ในเคอร์เนล หากโค้ดไคลเอ็นต์ไม่จำเป็นต้องรองรับการอัปเกรดอุปกรณ์ (ซึ่งเคอร์เนลอาจรองรับเฉพาะฮีป ION) คุณก็นำการเรียกใช้ MapNameToIonHeap()
ออกได้เช่นกัน