Trong Android 12, GKI 2.0 thay thế trình phân bổ ION bằng vùng nhớ khối xếp DMA-BUF vì những lý do sau:
- Bảo mật: Vì mỗi vùng nhớ khối xếp DMA-BUF là một thiết bị ký tự riêng biệt, nên bạn có thể kiểm soát quyền truy cập vào từng vùng nhớ khối xếp bằng sepolicy. Điều này không thể thực hiện được với ION vì việc phân bổ từ bất kỳ vùng nhớ khối xếp nào chỉ yêu cầu quyền truy cập vào thiết bị
/dev/ion
. - Độ ổn định của ABI: Không giống như ION, giao diện IOCL của khung vùng nhớ khối xếp DMA-BUF có ổn định theo ABI vì giao diện này được duy trì trong nhân hệ điều hành Linux ngược dòng.
- Tiêu chuẩn hoá: Khung vùng nhớ khối xếp DMA-BUF cung cấp một UAPI được xác định rõ ràng. ION cho phép cờ tuỳ chỉnh và mã nhận dạng vùng nhớ khối xếp ngăn việc phát triển một khung kiểm thử chung vì cách triển khai ION của mỗi thiết bị có thể khác nhau.
Nhánh android12-5.10
của Hạt nhân chung Android đã tắt
CONFIG_ION
vào ngày 1 tháng 3 năm 2021.
Thông tin khái quát
Sau đây là thông tin so sánh ngắn gọn giữa vùng nhớ khối xếp ION và DMA-BUF.
Điểm tương đồng giữa khung vùng nhớ khối xếp ION và DMA-BUF
- Khung vùng nhớ khối xếp ION và DMA-BUF đều là trình xuất DMA-BUF dựa trên vùng nhớ khối xếp.
- Cả hai đều cho phép mỗi vùng nhớ khối xếp xác định trình phân bổ và hoạt động DMA-BUF riêng.
- Hiệu suất phân bổ tương tự nhau vì cả hai giao thức đều cần một IOCTL duy nhất để phân bổ.
Sự khác biệt giữa khung vùng nhớ khối xếp ION và DMA-BUF
Vùng nhớ khối xếp ION | Vùng nhớ khối xếp DMA-BUF |
---|---|
Tất cả các lượt phân bổ ION đều được thực hiện bằng /dev/ion .
|
Mỗi vùng nhớ khối xếp DMA-BUF là một thiết bị ký tự có tại /dev/dma_heap/<heap_name> .
|
ION hỗ trợ cờ riêng tư của vùng nhớ khối xếp. | Vùng nhớ khối xếp DMA-BUF không hỗ trợ cờ riêng tư của vùng nhớ khối xếp. Thay vào đó, mỗi loại phân bổ được thực hiện từ một vùng nhớ khối xếp khác nhau. Ví dụ: các biến thể vùng nhớ khối xếp hệ thống được lưu vào bộ nhớ đệm và không được lưu vào bộ nhớ đệm là các vùng nhớ khối xếp riêng biệt nằm ở /dev/dma_heap/system và /dev/dma_heap/system_uncached .
|
Bạn cần chỉ định mã nhận dạng/mặt nạ vùng nhớ khối xếp và cờ để phân bổ. | Tên vùng nhớ khối xếp được dùng để phân bổ. |
Các phần sau đây liệt kê các thành phần xử lý ION và mô tả cách chuyển các thành phần đó sang khung vùng nhớ khối xếp DMA-BUF.
Chuyển đổi trình điều khiển hạt nhân từ ION sang vùng nhớ khối xếp DMA-BUF
Trình điều khiển hạt nhân triển khai vùng nhớ khối xếp ION
Cả vùng nhớ khối xếp ION và DMA-BUF đều cho phép mỗi vùng nhớ khối xếp triển khai trình phân bổ và thao tác DMA-BUF riêng. Vì vậy, bạn có thể chuyển từ cách triển khai vùng nhớ khối xếp ION sang cách triển khai vùng nhớ khối xếp DMA-BUF bằng cách sử dụng một nhóm API khác để đăng ký vùng nhớ khối xếp. Bảng này cho thấy các API đăng ký vùng nhớ khối xếp ION và các API vùng nhớ khối xếp DMA-BUF tương đương.
Vùng nhớ khối xếp ION | Vùng nhớ khối xếp 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);
|
Vùng nhớ khối xếp DMA-BUF không hỗ trợ cờ riêng tư của vùng nhớ khối xếp. Vì vậy, bạn phải đăng ký riêng từng biến thể của vùng nhớ khối xếp bằng API dma_heap_add()
. Để tạo điều kiện cho việc chia sẻ mã, bạn nên đăng ký tất cả các biến thể của cùng một vùng nhớ khối xếp trong cùng một trình điều khiển.
Ví dụ về dma-buf: system_heap này cho thấy cách triển khai các biến thể đã lưu vào bộ nhớ đệm và không lưu vào bộ nhớ đệm của vùng nhớ khối xếp hệ thống.
Sử dụng dma-buf: heaps: example template (dma-buf: vùng nhớ khối xếp: mẫu ví dụ) này để tạo vùng nhớ khối xếp DMA-BUF từ đầu.
Trình điều khiển nhân hệ điều hành đang phân bổ trực tiếp từ vùng nhớ khối xếp ION
Khung vùng nhớ khối xếp DMA-BUF cũng cung cấp một giao diện phân bổ cho các ứng dụng trong nhân. Thay vì chỉ định mặt nạ vùng nhớ khối xếp và cờ để chọn loại phân bổ, giao diện do vùng nhớ khối xếp DMA-BUF cung cấp sẽ lấy tên vùng nhớ khối xếp làm dữ liệu đầu vào.
Sau đây là ví dụ về API phân bổ ION trong nhân hệ điều hành và các API phân bổ vùng nhớ khối xếp DMA-BUF tương đương. Trình điều khiển kernel có thể sử dụng API dma_heap_find()
để truy vấn sự tồn tại của vùng nhớ khối xếp. API này trả về một con trỏ đến một thực thể của cấu trúc dma_heap, sau đó có thể được truyền dưới dạng đối số đến API dma_heap_buffer_alloc()
.
Vùng nhớ khối xếp ION | Vùng nhớ khối xếp DMA-BUF |
---|---|
struct dma_buf *ion_alloc(size_t len, unsigned int heap_id_mask, unsigned int flags)
|
|
Trình điều khiển hạt nhân sử dụng DMA-BUF
Không cần thay đổi đối với các trình điều khiển chỉ nhập DMA-BUF, vì vùng đệm được phân bổ từ vùng nhớ khối xếp ION hoạt động giống hệt như vùng đệm được phân bổ từ vùng nhớ khối xếp DMA-BUF tương đương.
Chuyển đổi ứng dụng không gian người dùng của ION sang vùng nhớ khối xếp DMA-BUF
Để giúp quá trình chuyển đổi trở nên dễ dàng cho các ứng dụng không gian người dùng của ION, bạn có thể sử dụng thư viện trừu tượng có tên là libdmabufheap
. libdmabufheap
hỗ trợ phân bổ trong vùng nhớ khối xếp DMA-BUF và vùng nhớ khối xếp ION. Trước tiên, hàm này sẽ kiểm tra xem có vùng nhớ khối xếp DMA-BUF có tên đã chỉ định hay không. Nếu không, hàm này sẽ quay lại vùng nhớ khối xếp ION tương đương (nếu có).
Ứng dụng khách nên khởi tạo đối tượng BufferAllocator
trong quá trình khởi tạo thay vì mở /dev/ion using
ion_open()
. Điều này là do chỉ số mô tả tệp được tạo bằng cách mở /dev/ion
và /dev/dma_heap/<heap_name>
được đối tượng BufferAllocator
quản lý nội bộ.
Để chuyển từ libion
sang libdmabufheap
, hãy sửa đổi hành vi của ứng dụng như sau:
- Theo dõi tên vùng nhớ khối xếp dùng để phân bổ, thay vì mã nhận dạng đầu/mặt nạ và cờ vùng nhớ khối xếp.
- Thay thế API
ion_alloc_fd()
(sẽ lấy mặt nạ vùng nhớ khối xếp và đối số gắn cờ) bằng APIBufferAllocator::Alloc()
. API này sẽ lấy tên vùng nhớ khối xếp.
Bảng này minh hoạ những thay đổi này bằng cách cho thấy cách libion
và libdmabufheap
thực hiện việc phân bổ vùng nhớ khối xếp hệ thống không được lưu vào bộ nhớ đệm.
Loại phân bổ | libion | libdmabufheap |
---|---|---|
Phân bổ bộ nhớ đệm từ vùng nhớ khối xếp hệ thống | ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, ION_FLAG_CACHED, &fd)
|
allocator->Alloc("system", size)
|
Phân bổ không được lưu vào bộ nhớ đệm khỏi vùng nhớ khối xếp của hệ thống | ion_alloc_fd(ionfd, size, 0, ION_HEAP_SYSTEM, 0, &fd)
|
allocator->Alloc("system-uncached", size)
|
Biến thể vùng nhớ khối xếp hệ thống không được lưu vào bộ nhớ đệm đang chờ phê duyệt ở thượng nguồn nhưng đã là một phần của nhánh android12-5.10
.
Để hỗ trợ nâng cấp thiết bị, API MapNameToIonHeap()
cho phép liên kết tên vùng nhớ khối xếp với các tham số vùng nhớ khối xếp ION (tên vùng nhớ khối xếp hoặc mặt nạ và cờ) để cho phép các giao diện đó sử dụng cơ chế phân bổ dựa trên tên. Dưới đây là ví dụ về cách phân bổ dựa trên tên.
Tài liệu về mọi API do libdmabufheap
hiển thị đã có sẵn. Thư viện cũng hiển thị một tệp tiêu đề để các ứng dụng C sử dụng.
Triển khai tham chiếu Gralloc
Việc triển khai gralloc Hikey960 sử dụng libdmabufheap
, vì vậy, bạn có thể sử dụng phương thức này làm triển khai tham chiếu.
Các phần bổ sung ueventd bắt buộc
Đối với mọi vùng nhớ khối xếp DMA-BUF mới dành riêng cho thiết bị được tạo, hãy thêm một mục mới vào tệp ueventd.rc
của thiết bị.
Ví dụ về Thiết lập không gian để hỗ trợ vùng nhớ khối xếp DMA-BUF minh hoạ cách thực hiện việc này đối với vùng nhớ khối xếp hệ thống DMA-BUF.
Các nội dung bổ sung bắt buộc về chính sách bảo mật
Thêm quyền sepolicy để cho phép ứng dụng không gian người dùng truy cập vào vùng nhớ khối xếp DMA-BUF mới. Ví dụ về thêm quyền cần thiết này cho thấy các quyền sepolicy được tạo cho nhiều ứng dụng để truy cập vào vùng nhớ khối xếp hệ thống DMA-BUF.
Truy cập vào vùng nhớ khối xếp của nhà cung cấp từ mã khung
Để đảm bảo tuân thủ Treble, mã khung chỉ có thể phân bổ từ các danh mục vùng nhớ khối xếp của nhà cung cấp được phê duyệt trước.
Dựa trên ý kiến phản hồi của các đối tác, Google đã xác định được hai danh mục vùng nhớ khối xếp của nhà cung cấp mà bạn phải truy cập từ mã khung:
- Các vùng nhớ khối xếp dựa trên vùng nhớ khối xếp hệ thống với các tính năng tối ưu hoá hiệu suất dành riêng cho thiết bị hoặc SoC.
- Vùng nhớ khối xếp để phân bổ từ bộ nhớ được bảo vệ.
Xử lý khối lượng lớn dựa trên vùng nhớ khối xếp hệ thống bằng cách tối ưu hoá hiệu suất dành riêng cho thiết bị hoặc SoC
Để hỗ trợ trường hợp sử dụng này, bạn có thể ghi đè cách triển khai vùng nhớ khối xếp của hệ thống vùng nhớ khối xếp DMA-BUF mặc định.
CONFIG_DMABUF_HEAPS_SYSTEM
bị tắt tronggki_defconfig
để trở thành mô-đun nhà cung cấp.- Các kiểm thử tuân thủ VTS đảm bảo rằng vùng nhớ khối xếp tồn tại tại
/dev/dma_heap/system
. Các chương trình kiểm thử cũng xác minh rằng vùng nhớ khối xếp có thể được phân bổ từ và chỉ số mô tả tệp được trả về (fd
) có thể được ánh xạ bộ nhớ (mmapped) từ không gian người dùng.
Các điểm trước đó cũng đúng đối với biến thể không được lưu vào bộ nhớ đệm của vùng nhớ khối xếp hệ thống, mặc dù sự tồn tại của biến thể này không bắt buộc đối với các thiết bị hoàn toàn nhất quán với IO.
Vùng nhớ khối xếp để phân bổ từ bộ nhớ được bảo vệ
Việc triển khai vùng nhớ khối xếp bảo mật phải dành riêng cho từng nhà cung cấp vì Android Common Kernel không hỗ trợ triển khai vùng nhớ khối xếp bảo mật chung.
- Đăng ký các phương thức triển khai dành riêng cho nhà cung cấp dưới dạng
/dev/dma_heap/system-secure<vendor-suffix>
. - Bạn không bắt buộc phải triển khai các vùng nhớ khối xếp này.
- Nếu vùng nhớ khối xếp tồn tại, các kiểm thử VTS sẽ đảm bảo rằng bạn có thể phân bổ từ các vùng nhớ khối xếp đó.
- Các thành phần khung được cấp quyền truy cập vào các vùng nhớ khối xếp này để có thể bật tính năng sử dụng vùng nhớ khối xếp thông qua HAL Codec2/HAL không liên kết, cùng quy trình. Tuy nhiên, các tính năng khung Android chung không thể phụ thuộc vào các tính năng này do sự biến động trong thông tin chi tiết về cách triển khai. Nếu trong tương lai, một phương thức triển khai vùng nhớ khối xếp bảo mật chung được thêm vào Hạt nhân chung của Android, thì phương thức đó phải sử dụng một ABI khác để tránh xung đột với các thiết bị nâng cấp.
Bộ phân bổ Codec 2 cho vùng nhớ khối xếp DMA-BUF
Trình phân bổ codec2 cho giao diện vùng nhớ khối xếp DMA-BUF có trong AOSP.
Giao diện kho thành phần cho phép chỉ định các tham số vùng nhớ khối xếp từ C2 HAL có sẵn với bộ phân bổ vùng nhớ khối xếp C2 DMA-BUF.
Luồng chuyển đổi mẫu cho vùng nhớ khối xếp ION
Để chuyển đổi mượt mà từ vùng nhớ khối xếp ION sang DMA-BUF, libdmabufheap
cho phép chuyển đổi một vùng nhớ khối xếp tại một thời điểm. Các bước sau đây minh hoạ quy trình công việc được đề xuất để chuyển đổi vùng nhớ khối xếp ION không phải cũ có tên là my_heap
hỗ trợ một cờ là ION_FLAG_MY_FLAG
.
Bước 1: Tạo các vùng nhớ khối xếp tương đương của ION trong khung DMA-BUF. Trong ví dụ này, vì vùng nhớ khối xếp ION my_heap
hỗ trợ cờ ION_FLAG_MY_FLAG
, nên chúng ta đăng ký hai vùng nhớ khối xếp DMA-BUF:
- Hành vi của
my_heap
khớp chính xác với hành vi của vùng nhớ khối xếp ION với cờION_FLAG_MY_FLAG
bị tắt. - Hành vi của
my_heap_special
khớp chính xác với hành vi của vùng nhớ khối xếp ION khi bật cờION_FLAG_MY_FLAG
.
Bước 2: Tạo các thay đổi ueventd cho vùng nhớ khối xếp DMA-BUF my_heap
và my_heap_special
mới. Tại thời điểm này, các vùng nhớ khối xếp sẽ hiển thị dưới dạng /dev/dma_heap/my_heap
và /dev/dma_heap/my_heap_special
, với các quyền dự kiến.
Bước 3: Đối với các ứng dụng phân bổ từ my_heap
, hãy sửa đổi tệp makefile của ứng dụng để liên kết với libdmabufheap
. Trong quá trình khởi chạy ứng dụng, hãy tạo thực thể cho đối tượng BufferAllocator
và sử dụng API MapNameToIonHeap()
để liên kết tổ hợp <ION heap name/mask, flag>
với các tên vùng nhớ khối xếp DMA-BUF tương đương.
Ví dụ:
allocator->MapNameToIonHeap("my_heap_special" /* name of DMA-BUF heap */, "my_heap" /* name of the ION heap */, ION_FLAG_MY_FLAG /* ion flags */ )
Thay vì sử dụng API MapNameToIonHeap()
với các tham số tên và cờ, bạn có thể tạo mối liên kết từ <ION heap mask, flag>
đến các tên vùng nhớ khối xếp DMA-BUF tương đương bằng cách đặt tham số tên vùng nhớ khối xếp ION thành trống.
Bước 4: Thay thế lệnh gọi ion_alloc_fd()
bằng BufferAllocator::Alloc()
bằng cách sử dụng tên vùng nhớ khối xếp thích hợp.
Loại phân bổ | libion | libdmabufheap |
---|---|---|
Phân bổ từ my_heap khi chưa đặt cờ
ION_FLAG_MY_FLAG
|
ion_alloc_fd(ionfd, size, 0, ION_HEAP_MY_HEAP, 0, &fd)
|
allocator->Alloc("my_heap", size)
|
Phân bổ từ my_heap với cờ ION_FLAG_MY_FLAG được đặt
|
ion_alloc_fd(ionfd, size, 0, ION_HEAP_MY_HEAP,
ION_FLAG_MY_FLAG, &fd)
|
allocator->Alloc("my_heap_special", size)
|
Tại thời điểm này, ứng dụng đang hoạt động nhưng vẫn phân bổ từ vùng nhớ khối xếp ION vì ứng dụng không có các quyền sepolicy bắt buộc để mở vùng nhớ khối xếp DMA-BUF.
Bước 5: Tạo các quyền sepolicy cần thiết để ứng dụng truy cập vào các vùng nhớ khối xếp DMA-BUF mới. Ứng dụng hiện đã được trang bị đầy đủ để phân bổ từ vùng nhớ khối xếp DMA-BUF mới.
Bước 6: Xác minh rằng các lượt phân bổ đang diễn ra từ vùng nhớ khối xếp DMA-BUF mới bằng cách kiểm tra logcat.
Bước 7: Tắt vùng nhớ khối xếp ION my_heap
trong hạt nhân. Nếu mã ứng dụng không cần hỗ trợ nâng cấp thiết bị (có thể hạt nhân chỉ hỗ trợ vùng nhớ khối xếp ION), bạn cũng có thể xoá các lệnh gọi MapNameToIonHeap()
.