Android 12에서 GKI 2.0은 다음과 같은 이유로 ION 할당자를 DMA-BUF 힙으로 대체합니다.
- 보안: 각 DMA-BUF 힙은 별도의 문자 장치이기 때문에 각 힙에 대한 액세스는 sepolicy를 통해 개별적으로 제어할 수 있습니다. 모든 힙에서 할당하려면
/dev/ion
장치에 대한 액세스만 필요하기 때문에 ION에서는 불가능했습니다. - ABI 안정성: ION과 달리 DMA-BUF 힙 프레임워크의 IOCTL 인터페이스는 업스트림 Linux 커널에서 유지 관리되기 때문에 ABI 안정성이 보장됩니다.
- 표준화: DMA-BUF 힙 프레임워크는 잘 정의된 UAPI를 제공합니다. ION은 각 장치의 ION 구현이 다르게 작동할 수 있기 때문에 공통 테스트 프레임워크 개발을 방해하는 사용자 지정 플래그 및 힙 ID를 허용했습니다.
Android 공통 커널의 android12-5.10
분기는 2021년 3월 1일 에 CONFIG_ION
을 비활성화했습니다.
배경
다음은 ION 힙과 DMA-BUF 힙을 간단히 비교한 것입니다.
ION과 DMA-BUF 힙 프레임워크 간의 유사점
- ION 및 DMA-BUF 힙 프레임워크는 모두 힙 기반 DMA-BUF 내보내기입니다.
- 둘 다 각 힙이 자체 할당자와 DMA-BUF 작업을 정의하도록 합니다.
- 두 체계 모두 할당을 위해 단일 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 에 있는 별도의 힙입니다. |
할당을 위해 힙 ID/마스크 및 플래그를 지정해야 합니다. | 힙 이름은 할당에 사용됩니다. |
다음 섹션에서는 ION을 처리하는 구성 요소를 나열하고 DMA-BUF 힙 프레임워크로 전환하는 방법을 설명합니다.
ION에서 DMA-BUF 힙으로 커널 드라이버 전환
ION 힙을 구현하는 커널 드라이버
ION 및 DMA-BUF 힙 모두 각 힙이 자체 할당자와 DMA-BUF 작업을 구현할 수 있도록 합니다. 따라서 다른 API 세트를 사용하여 힙을 등록함으로써 ION 힙 구현에서 DMA-BUF 힙 구현으로 전환할 수 있습니다. 이 표는 ION 힙 등록 API 및 이에 상응하는 DMA-BUF 힙 API를 보여줍니다.
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 템플릿 을 사용하여 처음부터 DMA-BUF 힙을 만듭니다.
ION 힙에서 직접 할당하는 커널 드라이버
DMA-BUF 힙 프레임워크는 커널 내 클라이언트에 대한 할당 인터페이스 도 제공합니다. 할당 유형을 선택하기 위해 힙 마스크와 플래그를 지정하는 대신 DMA-BUF 힙에서 제공하는 인터페이스는 힙 이름을 입력으로 사용합니다.
다음은 커널 내 ION 할당 API 및 이에 상응하는 DMA-BUF 힙 할당 API를 보여줍니다. 커널 드라이버는 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) | |
DMA-BUF를 사용하는 커널 드라이버
ION 힙에서 할당된 버퍼는 동등한 DMA-BUF 힙에서 할당된 버퍼와 정확히 동일하게 동작하기 때문에 DMA-BUF만 가져오는 드라이버에는 변경할 필요가 없습니다.
ION의 사용자 공간 클라이언트를 DMA-BUF 힙으로 전환
ION의 사용자 공간 클라이언트가 쉽게 전환할 수 있도록 libdmabufheap
이라는 추상화 라이브러리를 사용할 수 있습니다. libdmabufheap
은 DMA-BUF 힙 및 ION 힙에서 할당을 지원합니다. 먼저 지정된 이름의 DMA-BUF 힙이 존재하는지 확인하고 존재하지 않으면 동등한 ION 힙(있는 경우)으로 폴백합니다.
클라이언트는 /dev/ion using ion_open()
을 여는 대신 초기화 중에 BufferAllocator
객체를 초기화해야 합니다. /dev/ion
및 /dev/dma_heap/<heap_name>
을 열어 생성된 파일 기술자는 내부적으로 BufferAllocator
개체에 의해 관리되기 때문입니다.
libdmabufheap
에서 libion
으로 전환하려면 다음과 같이 클라이언트의 동작을 수정하십시오.
- 헤드 ID/마스크 및 힙 플래그 대신 할당에 사용할 힙 이름을 추적합니다.
- 힙 마스크 및 플래그 인수를 사용하는 ion_alloc_fd
ion_alloc_fd()
) API를 힙 이름을 대신 사용하는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
분기의 일부입니다.
장치 업그레이드를 지원하기 위해 MapNameToIonHeap()
API를 사용하면 힙 이름을 ION 힙 매개변수(힙 이름/마스크 및 플래그)에 매핑하여 해당 인터페이스에서 이름 기반 할당도 사용할 수 있습니다. 다음은 이름 기반 할당의 예 입니다.
libdmabufheap
에 의해 노출된 모든 API에 대한 문서를 사용할 수 있습니다. 라이브러리 는 또한 C 클라이언트에서 사용할 헤더 파일을 노출합니다.
참조 Granloc 구현
Hikey960 gralloc 구현은 libdmabufheap
을 사용하므로 참조 구현 으로 사용할 수 있습니다.
필수 이벤트 추가
새로 생성된 장치별 DMA-BUF 힙에 대해 장치의 ueventd.rc
파일에 새 항목을 추가합니다. DMA-BUF 힙을 지원하기 위한 이 설정 ueventd 예제 는 DMA-BUF 시스템 힙에 대해 이것이 어떻게 수행되는지 보여줍니다.
필수 sepolicy 추가
사용자 공간 클라이언트가 새 DMA-BUF 힙에 액세스할 수 있도록 sepolicy 권한을 추가합니다. 이 추가 필수 권한 예제는 DMA-BUF 시스템 힙에 액세스하기 위해 다양한 클라이언트에 대해 생성된 sepolicy 권한을 보여줍니다.
프레임워크 코드에서 공급업체 힙 액세스
Treble 준수를 보장하기 위해 프레임워크 코드는 사전 승인된 벤더 힙 범주에서만 할당할 수 있습니다.
파트너로부터 받은 피드백을 기반으로 Google은 프레임워크 코드에서 액세스해야 하는 두 가지 범주의 공급업체 힙을 식별했습니다.
- 장치 또는 SoC별 성능 최적화가 있는 시스템 힙을 기반으로 하는 힙입니다.
- 보호된 메모리에서 할당할 힙입니다.
장치 또는 SoC별 성능 최적화가 있는 시스템 힙 기반 힙
이 사용 사례를 지원하기 위해 기본 DMA-BUF 힙 시스템의 힙 구현을 재정의할 수 있습니다.
-
CONFIG_DMABUF_HEAPS_SYSTEM
은 공급업체 모듈이 될 수 있도록gki_defconfig
에서 꺼져 있습니다. - VTS 준수 테스트는 힙이
/dev/dma_heap/system
에 있는지 확인합니다. 테스트는 또한 힙이 할당될 수 있고 반환된 파일 설명자(fd
)가 사용자 공간에서 메모리 매핑(mmapped)될 수 있는지 확인합니다.
이전 사항은 시스템 힙의 캐시되지 않은 변형에도 해당되지만 완전한 IO 일관성 장치의 경우 반드시 존재해야 하는 것은 아닙니다.
보호된 메모리에서 할당할 힙
Android Common Kernel은 일반 보안 힙 구현을 지원하지 않으므로 보안 힙 구현은 공급업체에 따라 달라야 합니다.
- 공급업체별 구현을
/dev/dma_heap/system-secure<vendor-suffix>
로 등록하십시오. - 이러한 힙 구현은 선택 사항입니다.
- 힙이 존재하는 경우 VTS 테스트는 힙에서 할당이 이루어질 수 있는지 확인합니다.
- 프레임워크 구성 요소는 이러한 힙에 대한 액세스 권한이 제공되므로 Codec2 HAL/바인더화되지 않은 동일 프로세스 HAL을 통해 힙을 사용할 수 있습니다. 그러나 일반 Android 프레임워크 기능은 구현 세부정보의 가변성으로 인해 종속될 수 없습니다. 향후 일반 보안 힙 구현이 Android 공통 커널에 추가되는 경우 기기 업그레이드와 충돌을 피하기 위해 다른 ABI를 사용해야 합니다.
DMA-BUF 힙용 코덱 2 할당자
DMA-BUF 힙 인터페이스에 대한 코덱2 할당자는 AOSP에서 사용할 수 있습니다.
C2 HAL에서 힙 매개변수를 지정할 수 있도록 하는 구성 요소 저장소 인터페이스는 C2 DMA-BUF 힙 할당자와 함께 사용할 수 있습니다.
ION 힙에 대한 샘플 전환 흐름
ION에서 DMA-BUF 힙으로 원활하게 전환하기 위해 libdmabufheap
을 사용하면 한 번에 하나의 힙을 전환할 수 있습니다. 다음 단계는 하나의 플래그 my_heap
를 지원하는 ION_FLAG_MY_FLAG
이라는 레거시가 아닌 ION 힙을 전환하기 위해 제안된 워크플로를 보여줍니다.
1단계: DMA-BUF 프레임워크에서 ION 힙에 해당하는 항목을 만듭니다. 이 예에서는 ION 힙 my_heap
이 ION_FLAG_MY_FLAG
플래그를 지원하기 때문에 두 개의 DMA-BUF 힙을 등록합니다.
-
my_heap
동작은ION_FLAG_MY_FLAG
플래그가 비활성화된 ION 힙의 동작과 정확히 일치합니다. -
my_heap_special
동작은ION_FLAG_MY_FLAG
플래그가 활성화된 ION 힙의 동작과 정확히 일치합니다.
2단계: 새 my_heap
및 my_heap_special
DMA-BUF 힙에 대한 ueventd 변경 사항을 생성합니다. 이 시점에서 힙은 의도한 권한과 함께 /dev /dev/dma_heap/my_heap
및 /dev/dma_heap/my_heap_special
로 표시됩니다.
3단계: my_heap
에서 할당하는 클라이언트의 경우 해당 makefile을 수정하여 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 힙 이름 매개변수를 공백으로 설정하여 <ION heap mask, flag>
에서 동등한 DMA-BUF 힙 이름 으로의 매핑을 생성할 수 있습니다.
4단계: 적절한 힙 이름을 사용하여 ion_alloc_fd()
호출을 BufferAllocator::Alloc()
로 교체합니다.
할당 유형 | 리비온 | 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) |
이 시점에서 클라이언트는 작동하지만 DMA-BUF 힙을 여는 데 필요한 sepolicy 권한이 없기 때문에 여전히 ION 힙에서 할당합니다.
5단계: 클라이언트가 새 DMA-BUF 힙에 액세스하는 데 필요한 sepolicy 권한을 만듭니다. 클라이언트는 이제 새 DMA-BUF 힙에서 할당할 수 있는 모든 준비가 되었습니다.
6단계: logcat 을 검사하여 새 DMA-BUF 힙에서 할당이 발생하는지 확인합니다.
7단계: 커널에서 ION 힙 my_heap
을 비활성화합니다. 클라이언트 코드가 장치 업그레이드를 지원할 필요가 없는 경우(커널이 ION 힙만 지원할 수 MapNameToIonHeap()
호출을 제거할 수도 있습니다.