미디어 프레임워크 강화

기기 보안을 개선하기 위해 Android 7.0은 권한과 기능이 각 프로세스에서 필요한 항목으로만 제한된 여러 개의 프로세스로 모놀리식 mediaserver 프로세스를 분할합니다. 이러한 변화는 다음을 통해 미디어 프레임워크의 보안 취약점을 줄여줍니다.

  • AV 파이프라인 구성요소를 앱 전용 샌드박스 프로세스로 분할
  • 업데이트 가능한 미디어 구성요소 지원(추출기, 코덱 등)

또한 이러한 변화는 대부분의 미디어 관련 보안 취약점의 심각도를 크게 줄임으로써 최종 사용자의 보안을 개선하여 최종 사용자의 기기와 데이터를 안전하게 지켜줍니다.

OEM 및 SoC 공급업체는 HAL 및 프레임워크 변경사항을 업데이트하여 새 아키텍처와 호환되도록 해야 합니다. 특히 공급업체에서 제공하는 Android 코드는 모든 것이 동일한 프로세스에서 실행된다고 가정하는 경우가 많으므로 공급업체는 프로세스 간에 의미가 있는 네이티브 핸들(native_handle)을 전달하도록 코드를 업데이트해야 합니다. 미디어 강화와 관련된 변경사항의 참조 구현은 frameworks/avframeworks/native를 참고하세요.

아키텍처 변경사항

이전 버전의 Android에서는 수많은 권한(카메라 액세스, 오디오 액세스, 동영상 드라이버 액세스, 파일 액세스, 네트워크 액세스 등)이 있는 단일 모놀리식 mediaserver 프로세스를 사용했습니다. Android 7.0은 mediaserver 프로세스를 각 프로세스에 훨씬 적은 권한이 필요한 새로운 프로세스 여러 개로 분할합니다.

미디어 서버 강화

그림 1. 미디어 서버 강화와 관련된 아키텍처 변경사항

이 새로운 아키텍처는 프로세스가 손상되는 경우에도 악성 코드가 이전에 미디어 서버에서 보유했던 권한 모음 전체에 액세스하지 못하도록 합니다. 프로세스는 SElinux 및 seccomp 정책에 의해 제한됩니다.

참고: 공급업체 종속 항목으로 인해 일부 코덱은 여전히 mediaserver에서 실행되므로 필요한 권한보다 많은 권한을 mediaserver에 부여합니다. 특히 Widevine Classic은 Android 7.0의 mediaserver에서 계속 실행됩니다.

MediaServer 변경사항

Android 7.0에서는 mediaserver 프로세스가 재생 및 녹화를 유도하기 위해 존재합니다(예: 구성요소와 프로세스 간 버퍼 전달 및 동기화). 프로세스는 표준 바인더 메커니즘을 통해 통신합니다.

표준 로컬 파일 재생 세션에서는 애플리케이션이 파일 설명자(FD)를 mediaserver(일반적으로 MediaPlayer Java API를 통해)에 전달하고 mediaserver는 다음을 실행합니다.

  1. FD를 추출기 프로세스로 전달된 바인더 DataSource 객체에 래핑하는데 이 프로세스는 바인더 IPC를 사용하여 파일에서 읽는 데 FD를 사용합니다. (미디어 추출기는 FD를 가져오지 않고 대신 mediaserver에 바인더를 호출하여 데이터를 가져옵니다.)
  2. 파일을 살펴보고 파일 형식(예: MP3Extractor 또는 MPEG4Extractor)에 적합한 추출기를 만든 후 추출기의 바인더 인터페이스를 mediaserver 프로세스에 반환합니다.
  3. 추출기에 바인더 IPC를 호출하여 파일의 데이터 유형(MP3 또는 H.264 데이터)을 파악합니다.
  4. mediacodec 프로세스를 호출하여 필요한 유형의 코덱을 만들고 이러한 코덱의 바인더 인터페이스를 수신합니다.
  5. 추출기에 반복적으로 바인더 IPC를 호출하여 인코딩된 샘플을 읽고 바인더 IPC를 사용하여 인코딩된 데이터를 mediacodec 프로세스에 전송하여 디코딩한 후 디코딩된 데이터를 수신합니다.

경우에 따라서는 코덱이 개입되지 않거나(인코딩된 데이터가 바로 출력 장치로 전송되는 오프로드된 재생 등) 코덱이 디코딩된 데이터의 버퍼를 반환하는 대신 디코딩된 데이터를 직접적으로 렌더링할 수 있습니다(동영상 재생).

MediaCodecService 변경사항

코덱 서비스는 인코더 및 디코더가 상주하는 곳입니다. 공급업체 종속 항목으로 인해 일부 코덱은 아직까지 코덱 프로세스에 상주하지 않습니다. Android 7.0의 경우:

  • 비보안 디코더 및 소프트웨어 인코더가 코덱 프로세스에 상주합니다.
  • 보안 디코더와 하드웨어 인코더가 mediaserver(변경되지 않음)에 상주합니다.

애플리케이션 또는 미디어 서버는 코덱 프로세스를 호출하여 필요한 유형의 코덱을 생성한 다음 이 코덱을 호출하여 인코딩된 데이터를 전달하고 디코딩된 데이터를 검색하거나(디코딩의 경우), 디코딩된 데이터를 전달하고 인코딩된 데이터를 검색합니다(인코딩의 경우). 코덱과의 데이터 전송은 이미 공유된 메모리를 사용하므로 프로세스가 변경되지 않습니다.

MediaDrmServer 변경사항

DRM 서버는 Google Play 무비의 영화와 같은 DRM 보호 콘텐츠를 재생할 때 사용됩니다. 이 서버는 암호화된 데이터를 안전한 방식으로 복호화합니다. 따라서 인증서 저장소, 키 저장소 및 기타 민감한 구성요소에 안전하게 액세스할 수 있습니다. 공급업체 종속 항목으로 인해 아직까지는 DRM 프로세스가 사용되지 않는 경우도 있습니다.

AudioServer 변경사항

AudioServer 프로세스는 오디오 입력 및 출력, 오디오 라우팅을 결정하는 정책 관리자 서비스 및 FM 라디오 서비스와 같은 오디오 관련 구성요소를 호스팅합니다. 오디오 변경사항 및 구현 가이드에 관한 자세한 내용은 오디오 구현을 참고하세요.

CameraServer 변경사항

CameraServer는 카메라를 제어하며, 동영상을 녹화할 때 사용되어 동영상 프레임을 카메라에서 가져온 후 추가 처리를 위해 mediaserver에 전달합니다. CameraServer 변경사항 및 구현 가이드에 대한 자세한 내용은 카메라 프레임워크 강화를 참고하세요.

ExtractorService 변경사항

추출기 서비스는 미디어 프레임워크에서 지원하는 다양한 파일 형식을 파싱하는 구성요소인 추출기를 호스팅합니다. 추출기 서비스는 모든 서비스 중에서 가장 권한이 적으며 FD를 읽을 수 없으므로 대신 바인더 인터페이스(각 재생 세션의 mediaserver for에 의해 제공됨)를 호출하여 파일에 액세스합니다.

애플리케이션(또는 mediaserver)은 추출기 프로세스를 호출하여 IMediaExtractor를 가져오고 이 IMediaExtractor를 호출하여 파일에 포함된 트랙의 IMediaSources를 가져온 후 IMediaSources를 호출하여 데이터를 읽습니다.

프로세스 간에 데이터를 전송하기 위해 애플리케이션(또는 mediaserver)은 데이터를 바인더 트랜잭션의 일부로 reply-Parcel에 포함하거나 공유 메모리를 사용합니다.

  • 공유 메모리를 사용하려면 바인더를 추가로 호출하여 공유 메모리를 해제해야 하지만, 이렇게 하면 대규모 버퍼에서 더 빠르고 전력도 훨씬 적게 사용됩니다.
  • in-Parcel을 사용하려면 추가 복사가 필요하지만, 이렇게 하면 64KB보다 작은 버퍼에서 더 빠르고 전력도 훨씬 적게 사용됩니다.

구현

MediaDrmMediaCrypto 구성요소를 새로운 mediadrmserver 프로세스로 이동하는 과정을 지원하기 위해 공급업체는 보안 버퍼의 할당 메서드를 변경하여 버퍼가 프로세스 간에 공유되도록 허용해야 합니다.

이전 Android 출시에서는 보안 버퍼가 OMX::allocateBuffermediaserver에 할당되었으며 아래와 같이 동일한 프로세스에서 복호화 중에 사용되었습니다.

그림 2. Android 6.0 이하의 버퍼 할당(미디어 서버에서)

Android 7.0에서는 버퍼 할당 프로세스가 새로운 메커니즘으로 변경되었습니다. 이 메커니즘은 유연성을 제공하는 동시에 기존 구현에 미치는 영향을 최소화합니다. 새로운 mediadrmserver 프로세스의 MediaDrmMediaCrypto 스택을 사용하면 버퍼가 다르게 할당되고 공급업체는 MediaCodecMediaCrypto에서 복호화 작업을 호출할 때 바인더 전체에 걸쳐 전송될 수 있도록 보안 버퍼 핸들을 업데이트해야 합니다.

그림 3. Android 7.0 이상의 버퍼 할당(미디어 서버에서)

네이티브 핸들 사용

OMX::allocateBuffer는 파일 설명자(FD)와 추가 정수 데이터를 포함하는 native_handle 구조체 포인터를 반환해야 합니다. native_handle은 직렬화/역직렬화를 위한 기존 바인더 지원 등 FD 사용에 따른 장점을 모두 제공하는 동시에 현재 FD를 사용하지 않는 공급업체에 더 많은 유연성을 허용합니다.

native_handle_create()를 사용하여 네이티브 핸들을 할당합니다. 프레임워크 코드는 할당된 native_handle 구조체의 소유권을 가지며 native_handle이 원래 할당된 프로세스와 역직렬화된 프로세스에서 모두 리소스를 해제합니다. 프레임워크는 native_handle_close() 다음에 native_handle_delete()를 사용하여 네이티브 핸들을 해제하고 Parcel::writeNativeHandle()/readNativeHandle()을 사용하여 native_handle을 직렬화/역직렬화합니다.

FD를 사용하여 보안 버퍼를 나타내는 SoC 공급업체는 FD로 native_handle의 FD를 채울 수 있습니다. FD를 사용하지 않는 공급업체는 native_buffer의 추가 필드를 사용하여 보안 버퍼를 나타낼 수 있습니다.

복호화 위치 설정

공급업체는 native_handle에서 작동하는 OEMCrypto 복호화 메서드를 업데이트하여 native_handle를 새 프로세스 공간에서 사용할 수 있도록 하는 데 필요한 공급업체별 작업을 실행해야 합니다(변경사항에는 일반적으로 OEMCrypto 라이브러리 업데이트가 포함됨).

allocateBuffer는 표준 OMX 작업이므로 Android 7.0에는 이러한 지원을 쿼리할 새 OMX 확장 프로그램(OMX.google.android.index.allocateNativeHandle)과 OMX 구현에 네이티브 핸들을 사용해야 한다고 알리는 OMX_SetParameter 호출이 포함됩니다.