ใน Android 12 นั้น GKI 2.0 จะใช้กอง DMA-BUF แทนตัวจัดสรร ION ด้วยเหตุผลต่อไปนี้
- ความปลอดภัย: เนื่องจากกอง DMA-BUF แต่ละกองเป็นอุปกรณ์อักขระแยกต่างหาก คุณจึงควบคุมการเข้าถึงกองแต่ละกองแยกกันได้ด้วย sepolicy ซึ่ง ION ทำไม่ได้เนื่องจากการจัดสรรจากกองใดก็ตามต้องเข้าถึงอุปกรณ์
/dev/ion
เท่านั้น - ความเสถียรของ ABI: อินเทอร์เฟซ IOCTL ของเฟรมเวิร์กกอง DMA-BUF มีความเสถียรของ ABI ต่างจาก ION เนื่องจากได้รับการดูแลรักษาในเคอร์เนล Linux เวอร์ชันที่พัฒนาขึ้น
- มาตรฐาน: เฟรมเวิร์กกอง DMA-BUF มี UAPI ที่กําหนดไว้อย่างชัดเจน ION อนุญาตให้ใช้ Flag และรหัสกองที่กําหนดเองซึ่งทําให้พัฒนาเฟรมเวิร์กการทดสอบทั่วไปไม่ได้ เนื่องจากการติดตั้งใช้งาน ION ของอุปกรณ์แต่ละเครื่องอาจทํางานแตกต่างกัน
เราได้ปิดใช้สาขา android12-5.10
ของ Android Common Kernel
CONFIG_ION
ในวันที่ 1 มีนาคม 2021
ฉากหลัง
ต่อไปนี้เป็นการเปรียบเทียบคร่าวๆ ระหว่างฮีป ION และ DMA-BUF
ความคล้ายคลึงระหว่างเฟรมเวิร์กกอง ION กับ DMA-BUF
- เฟรมเวิร์กกอง ION และ DMA-BUF ต่างก็เป็นตัวส่งออก DMA-BUF ที่อิงตามกอง
- ทั้งสองช่วยให้แต่ละกองกำหนดตัวจัดสรรและการดำเนินการ DMA-BUF ของตนเองได้
- ประสิทธิภาพการจัดสรรจะคล้ายกันเนื่องจากทั้ง 2 รูปแบบต้องใช้ IOCTL เดียวสําหรับการจัดสรร
ความแตกต่างระหว่างเฟรมเวิร์กกอง ION กับ DMA-BUF
ฮีป ION | ฮีป DMA-BUF |
---|---|
การจัดสรร ION ทั้งหมดจะดำเนินการด้วย /dev/ion
|
กอง DMA-BUF แต่ละกองเป็นอุปกรณ์อักขระที่แสดงอยู่ที่ /dev/dma_heap/<heap_name>
|
ION รองรับ Flag ส่วนตัวของกอง heap | กอง DMA-BUF ไม่รองรับ Flag ส่วนตัวของกอง การจัดสรรแต่ละประเภทที่แตกต่างกันจะดำเนินการจากฮีปที่ต่างกันแทน เช่น ตัวแปรกองขยะของระบบที่แคชไว้และไม่ได้แคชไว้เป็นกองขยะแยกกันอยู่ที่ /dev/dma_heap/system และ /dev/dma_heap/system_uncached
|
ต้องระบุรหัส/มาสก์กองและ Flag สำหรับการกําหนด | ระบบจะใช้ชื่อกองสำหรับการจัดสรร |
ส่วนต่อไปนี้จะแสดงรายการคอมโพเนนต์ที่จัดการกับ 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 ไม่รองรับ Flag ส่วนตัวของกอง ดังนั้นแต่ละตัวแปรของฮีปจะต้องลงทะเบียนแยกกันโดยใช้ dma_heap_add()
API เราขอแนะนำให้ลงทะเบียนตัวแปรทั้งหมดของกองเดียวกันภายในไดรเวอร์เดียวกันเพื่อให้แชร์โค้ดได้ง่ายขึ้น
ตัวอย่าง dma-buf: system_heap นี้แสดงการใช้งานตัวแปรที่แคชและไม่แคชของ heap ระบบ
ใช้dma-buf: heaps: example template นี้เพื่อสร้างกอง DMA-BUF ขึ้นมาใหม่
โปรแกรมควบคุมเคอร์เนลที่จัดสรรจากกอง ION โดยตรง
เฟรมเวิร์กกอง DMA-BUF ยังมีอินเทอร์เฟซการจัดสรรสำหรับไคลเอ็นต์ในเคอร์เนลด้วย อินเทอร์เฟซที่นำเสนอโดยกอง DMA-BUF จะรับชื่อกองเป็นอินพุตแทนการระบุมาสก์กองและ Flag เพื่อเลือกประเภทการจัดสรร
ต่อไปนี้แสดง API การจัดสรร ION ในเคอร์เนลและ API การจัดสรรกอง heap ของ DMA-BUF ที่เทียบเท่า โปรแกรมควบคุมเคอร์เนลสามารถใช้ dma_heap_find()
API เพื่อค้นหาการมีอยู่ของกองได้ API จะแสดงผลพอยน์เตอร์ไปยังอินสแตนซ์ของ struct dma_heap ซึ่งสามารถส่งผ่านเป็นอาร์กิวเมนต์ไปยัง dma_heap_buffer_alloc()
API ได้
ฮีป ION | กอง DMA-BUF |
---|---|
struct dma_buf *ion_alloc(size_t len, unsigned int heap_id_mask, unsigned int flags)
|
|
ไดรเวอร์ Kernel ที่ใช้ 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
ให้แก้ไขลักษณะการทํางานของลูกค้าดังนี้
- ติดตามชื่อกองที่จะใช้สำหรับการจัดสรรแทนรหัส/มาสก์ส่วนหัวและ Flag กอง
- แทนที่
ion_alloc_fd()
API ซึ่งใช้อาร์กิวเมนต์เฮมพ์มาสก์และ Flag ด้วย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)
|
ตัวแปรกองขยะของระบบที่ไม่ได้แคชกําลังรอการอนุมัติจาก upstream แต่เป็นส่วนหนึ่งของสาขา 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
การทดสอบยังยืนยันว่าสามารถจัดสรรจากกอง และตัวระบุไฟล์ที่แสดงผล (fd
) สามารถแมปหน่วยความจำ (mmapped) จากพื้นที่ผู้ใช้ได้
ประเด็นก่อนหน้านี้ก็เป็นจริงเช่นกันสําหรับตัวแปรที่ไม่ได้แคชของฮีประบบ แม้ว่าการมีอยู่ของฮีประบบดังกล่าวจะไม่ได้จําเป็นสําหรับอุปกรณ์ที่มี IO ที่รองรับอย่างเต็มรูปแบบ
กองที่จะจัดสรรจากหน่วยความจําที่ได้รับการคุ้มครอง
การใช้งานกองข้อมูลที่ปลอดภัยต้องเจาะจงผู้ให้บริการ เนื่องจากเคอร์เนล Android Common ไม่รองรับการใช้งานกองข้อมูลที่ปลอดภัยทั่วไป
- ลงทะเบียนการใช้งานที่เจาะจงผู้ให้บริการเป็น
/dev/dma_heap/system-secure<vendor-suffix>
- การใช้กองเหล่านี้เป็นตัวเลือกที่ไม่บังคับ
- หากมีกองอยู่ การทดสอบ VTS จะตรวจสอบว่าสามารถจัดสรรจากกองได้
- คอมโพเนนต์เฟรมเวิร์กมีสิทธิ์เข้าถึงกองเหล่านี้เพื่อให้สามารถเปิดใช้การใช้งานกองผ่าน HAL ของ Codec2/HAL ที่อยู่ในกระบวนการเดียวกันซึ่งไม่ได้เป็น Binderized อย่างไรก็ตาม ฟีเจอร์เฟรมเวิร์ก Android ทั่วไปต้องไม่ใช้ Firebase เนื่องด้วยรายละเอียดการใช้งานที่หลากหลาย หากมีการเพิ่มการใช้งานกองข้อมูลที่ปลอดภัยทั่วไปลงในเคอร์เนลทั่วไปของ Android ในอนาคต การใช้งานดังกล่าวต้องใช้ ABI อื่นเพื่อหลีกเลี่ยงความขัดแย้งกับการอัปเกรดอุปกรณ์
ตัวจัดสรรตัวแปลงรหัส 2 สำหรับฮีป DMA-BUF
ตัวแปลงรหัสตัวแปลงรหัส 2 สำหรับอินเทอร์เฟซฮีป DMA-BUF มีให้ใช้งานใน AOSP
อินเทอร์เฟซของที่เก็บคอมโพเนนต์ที่อนุญาตให้ระบุพารามิเตอร์กองจาก C2 HAL พร้อมใช้งานกับตัวจัดสรรกอง C2 DMA-BUF
ตัวอย่างขั้นตอนการเปลี่ยนสำหรับกอง ION
libdmabufheap
อนุญาตให้สลับกองข้อมูลได้ครั้งละ 1 กองเพื่อให้การเปลี่ยนจากกอง ION ไปเป็นกอง DMA-BUF เป็นไปอย่างราบรื่น ขั้นตอนต่อไปนี้แสดงเวิร์กโฟลว์ที่แนะนําสําหรับการเปลี่ยนกอง ION ที่ไม่ใช่เดิมชื่อ my_heap
ซึ่งรองรับ Flag เดียว ION_FLAG_MY_FLAG
ขั้นตอนที่ 1: สร้างฮีปที่เทียบเท่ากับ ION ในเฟรมเวิร์ก DMA-BUF ในตัวอย่างนี้ เนื่องจากกอง ION my_heap
รองรับ Flag 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
ขึ้นมาและใช้ 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 ที่มีพารามิเตอร์ชื่อและ Flag คุณสามารถสร้างการแมปจาก <ION heap mask, flag>
ไปยังชื่อกอง heap DMA-BUF ที่เทียบเท่าได้ด้วยการกําหนดค่าพารามิเตอร์ชื่อกอง heap ION เป็นค่าว่าง
ขั้นตอนที่ 4: แทนที่การเรียกใช้ ion_alloc_fd()
ด้วย BufferAllocator::Alloc()
โดยใช้ชื่อกองที่เหมาะสม
ประเภทการจัดสรร | libion | Libdmabufheap |
---|---|---|
การจัดสรรจาก my_heap ที่มี Flag
ION_FLAG_MY_FLAG ไม่ได้ตั้งค่า
|
ion_alloc_fd(ionfd, size, 0, ION_HEAP_MY_HEAP, 0, &fd)
|
allocator->Alloc("my_heap", size)
|
การจัดสรรจาก my_heap ที่มีการตั้งค่า Flag
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()
ออกได้เช่นกัน