Чтобы повысить безопасность устройства, Android 7.0 разбивает монолитный процесс mediaserver
на несколько процессов, при этом разрешения и возможности ограничены только теми, которые необходимы каждому процессу. Эти изменения устраняют уязвимости безопасности медиа-инфраструктуры за счет:
- Разделение компонентов AV-конвейера на изолированные процессы для конкретных приложений.
- Включение обновляемых медиа-компонентов (экстракторов, кодеков и т.п.).
Эти изменения также повышают безопасность конечных пользователей за счет значительного снижения серьезности большинства уязвимостей безопасности, связанных с мультимедиа, обеспечивая безопасность устройств и данных конечных пользователей.
OEM-производителям и поставщикам SoC необходимо обновить свои HAL и изменения в структуре, чтобы сделать их совместимыми с новой архитектурой. В частности, поскольку код Android, предоставленный поставщиком, часто предполагает, что все выполняется в одном и том же процессе, поставщики должны обновлять свой код, чтобы передавать собственные дескрипторы ( native_handle
), которые имеют значение между процессами. Справочную реализацию изменений, связанных с усилением защиты мультимедиа, см. в frameworks/av
и frameworks/native
.
Архитектурные изменения
Предыдущие версии Android использовали единый монолитный процесс mediaserver
с большим количеством разрешений (доступ к камере, доступ к аудио, доступ к видеодрайверу, доступ к файлам, доступ к сети и т. д.). В Android 7.0 процесс mediaserver
разделен на несколько новых процессов, каждый из которых требует гораздо меньшего набора разрешений:
Эта новая архитектура гарантирует, что даже в случае взлома процесса вредоносный код не получит доступа ко всему набору разрешений, ранее принадлежавших mediaserver
. Процессы ограничены политиками SElinux и seccomp.
Примечание. Из-за зависимости от поставщика некоторые кодеки по-прежнему работают на mediaserver
и, следовательно, предоставляют mediaserver
больше разрешений, чем необходимо. В частности, Widevine Classic продолжает работать на mediaserver
для Android 7.0.
Изменения медиасервера
В Android 7.0 существует процесс mediaserver
для управления воспроизведением и записью, например, для передачи и синхронизации буферов между компонентами и процессами. Процессы взаимодействуют через стандартный механизм Binder.
В стандартном сеансе воспроизведения локального файла приложение передает дескриптор файла (FD) mediaserver
(обычно через Java API MediaPlayer), а mediaserver
:
- Обертывает FD в объект Binder DataSource, который передается процессу извлечения, который использует его для чтения из файла с помощью Binder IPC. (Медиаэкстрактор не получает FD, а вместо этого отправляет Binder обратный вызов
mediaserver
для получения данных.) - Проверяет файл, создает соответствующий экстрактор для данного типа файла (например, MP3Extractor или MPEG4Extractor) и возвращает интерфейс Binder для экстрактора процессу
mediaserver
. - Выполняет вызовы Binder IPC к экстрактору для определения типа данных в файле (например, данные MP3 или H.264).
- Вызывает процесс
mediacodec
для создания кодеков требуемого типа; получает интерфейсы Binder для этих кодеков. - Выполняет повторные вызовы Binder IPC к экстрактору для чтения закодированных выборок, использует Binder IPC для отправки закодированных данных в процесс
mediacodec
для декодирования и получает декодированные данные.
В некоторых случаях использования кодек не используется (например, при воспроизведении с разгрузкой, при котором закодированные данные отправляются непосредственно на устройство вывода), или кодек может визуализировать декодированные данные напрямую вместо возврата буфера декодированных данных (воспроизведение видео).
Изменения в Медиакодексервице
Служба кодеков — это место, где живут кодеры и декодеры. Из-за зависимостей от поставщиков не все кодеки пока включены в процесс кодирования. В Android 7.0:
- Незащищенные декодеры и программные кодеры встроены в процесс кодирования.
- Безопасные декодеры и аппаратные кодировщики находятся на
mediaserver
(без изменений).
Приложение (или mediaserver
) вызывает процесс кодека для создания кодека требуемого типа, затем вызывает этот кодек для передачи закодированных данных и получения декодированных данных (для декодирования) или для передачи декодированных данных и получения закодированных данных (для кодирования). . Передача данных к кодекам и обратно уже использует общую память, поэтому процесс не меняется.
Изменения МедиаДрмсервера
Сервер DRM используется при воспроизведении контента, защищенного DRM, например фильмов в Google Play Movies. Он безопасно расшифровывает зашифрованные данные и поэтому имеет доступ к хранилищу сертификатов и ключей, а также к другим конфиденциальным компонентам. Из-за зависимости от поставщиков процесс DRM пока используется не во всех случаях.
Изменения Аудиосервера
В процессе AudioServer размещаются компоненты, связанные со звуком, такие как аудиовход и выход, служба диспетчера политик, определяющая маршрутизацию звука, и служба FM-радио. Подробные сведения об изменениях звука и руководствах по реализации см. в разделе «Реализация звука» .
Изменения в CameraServer
CameraServer управляет камерой и используется при записи видео для получения видеокадров с камеры и последующей передачи их на mediaserver
для дальнейшей обработки. Подробные сведения об изменениях и рекомендации по реализации изменений CameraServer см. в разделе Усиление защиты платформы камеры .
Изменения в ExtractorService
В службе экстрактора размещаются экстракторы — компоненты, которые анализируют различные форматы файлов, поддерживаемые медиа-инфраструктурой. Служба извлечения является наименее привилегированной из всех служб: она не может читать FD, поэтому вместо этого она обращается к интерфейсу Binder (предоставляемому ей mediaserver for
каждого сеанса воспроизведения) для доступа к файлам.
Приложение (или mediaserver
) вызывает процесс извлечения для получения IMediaExtractor
, вызывает этот IMediaExtractor
для получения IMediaSources
для дорожки, содержащейся в файле, а затем вызывает IMediaSources
для чтения данных из них.
Для передачи данных между процессами приложение (или mediaserver
) включает данные в ответную посылку как часть транзакции Binder или использует общую память:
- Использование общей памяти требует дополнительного вызова Binder для освобождения общей памяти, но это быстрее и требует меньше энергии для больших буферов.
- Использование In-Parcel требует дополнительного копирования, но выполняется быстрее и потребляет меньше энергии для буферов размером менее 64 КБ.
Выполнение
Чтобы поддержать перемещение компонентов MediaDrm
и MediaCrypto
в новый процесс mediadrmserver
, поставщики должны изменить метод выделения безопасных буферов, чтобы разрешить совместное использование буферов между процессами.
В предыдущих выпусках Android безопасные буферы выделялись на mediaserver
с помощью OMX::allocateBuffer
и использовались во время расшифровки в том же процессе, как показано ниже:
В Android 7.0 процесс выделения буфера изменился на новый механизм, обеспечивающий гибкость и минимизирующий влияние на существующие реализации. Благодаря стекам MediaDrm
и MediaCrypto
в новом процессе mediadrmserver
буферы распределяются по-разному, и поставщики должны обновлять дескрипторы безопасных буферов, чтобы их можно было транспортировать через связующее, когда MediaCodec
вызывает операцию дешифрования в MediaCrypto
.
Используйте собственные дескрипторы
OMX::allocateBuffer
должен возвращать указатель на структуру native_handle
, которая содержит файловые дескрипторы (FD) и дополнительные целочисленные данные. native_handle
обладает всеми преимуществами использования FD, включая существующую поддержку привязки для сериализации/десериализации, а также обеспечивает большую гибкость для поставщиков, которые в настоящее время не используют FD.
Используйте native_handle_create()
, чтобы выделить собственный дескриптор. Код платформы берет на себя ответственность за выделенную структуру native_handle
и отвечает за освобождение ресурсов как в процессе, в котором изначально выделяется native_handle
, так и в процессе его десериализации. Платформа выпускает собственные дескрипторы с помощью native_handle_close()
, за которым следует метод native_handle_delete()
, и сериализует/десериализует native_handle
с помощью Parcel::writeNativeHandle()/readNativeHandle()
.
Поставщики SoC, которые используют FD для представления безопасных буферов, могут заполнить FD в native_handle
своим FD. Поставщики, которые не используют FD, могут представлять безопасные буферы, используя дополнительные поля в native_buffer
.
Установить местоположение расшифровки
Поставщики должны обновить метод дешифрования OEMCrypto, который работает с native_handle
, чтобы выполнять любые специфичные для поставщика операции, необходимые для того, чтобы native_handle
можно было использовать в новом пространстве процессов (изменения обычно включают обновления библиотек OEMCrypto).
Поскольку allocateBuffer
является стандартной операцией OMX, Android 7.0 включает новое расширение OMX ( OMX.google.android.index.allocateNativeHandle
) для запроса этой поддержки и вызов OMX_SetParameter
, который уведомляет реализацию OMX о необходимости использования собственных дескрипторов.