Android содержит автомобильный уровень аппаратной абстракции HIDL (HAL), который обеспечивает захват и отображение изображений на самых ранних этапах процесса загрузки Android и продолжает функционировать в течение всего срока службы системы. HAL включает в себя стек системы внешнего обзора (EVS) и обычно используется для поддержки камеры заднего вида и дисплеев кругового обзора в автомобилях с бортовыми информационно-развлекательными системами (IVI) на базе Android. EVS также позволяет реализовать расширенные функции в пользовательских приложениях.
Android также включает в себя интерфейс драйвера захвата и отображения, предназначенный для EVS (в /hardware/interfaces/automotive/evs/1.0
). Хотя можно создать приложение для камеры заднего вида поверх существующих служб камер и дисплеев Android, такое приложение, скорее всего, будет запускаться слишком поздно в процессе загрузки Android. Использование выделенного HAL обеспечивает оптимизированный интерфейс и дает понять, что OEM-производителю необходимо реализовать для поддержки стека EVS.
Компоненты системы
EVS включает в себя следующие компоненты системы:
приложение EVS
Пример приложения EVS на C++ ( /packages/services/Car/evs/app
) служит эталонной реализацией. Это приложение отвечает за запрос видеокадров у EVS Manager и отправку готовых кадров для отображения обратно в EVS Manager. Ожидается, что он будет запущен с помощью init, как только EVS и Car Service станут доступны, в течение двух (2) секунд после включения питания. OEM-производители могут модифицировать или заменить приложение EVS по своему желанию.
Менеджер ЕВС
Менеджер EVS ( /packages/services/Car/evs/manager
) предоставляет строительные блоки, необходимые приложению EVS для реализации чего угодно: от простого отображения камеры заднего вида до многокамерного рендеринга с 6 степенями свободы. Его интерфейс представлен через HIDL и создан для одновременной работы нескольких клиентов. Другие приложения и службы (в частности, Car Service) могут запрашивать состояние EVS Manager, чтобы узнать, когда система EVS активна.
EVS-HIDL-интерфейс
Система EVS, как камера, так и элементы дисплея, определена в пакете android.hardware.automotive.evs
. Пример реализации, которая тестирует интерфейс (генерирует синтетические тестовые изображения и проверяет, проходят ли изображения туда и обратно), представлен в /hardware/interfaces/automotive/evs/1.0/default
.
OEM-производитель отвечает за реализацию API, выраженного в файлах .hal в /hardware/interfaces/automotive/evs
. Такие реализации отвечают за настройку и сбор данных с физических камер и их доставку через буферы общей памяти, распознаваемые Gralloc. Сторона отображения реализации отвечает за предоставление буфера общей памяти, который может быть заполнен приложением (обычно с помощью EGL-рендеринга), и представление готовых кадров вместо всего остального, что может захотеть появиться на физическом дисплее. Реализации интерфейса EVS от поставщика могут храниться в каталоге /vendor/… /device/…
или hardware/…
(например, /hardware/[vendor]/[platform]/evs
.
Драйверы ядра
Для устройства, поддерживающего стек EVS, требуются драйверы ядра. Вместо создания новых драйверов OEM-производители имеют возможность поддерживать функции, необходимые для EVS, через существующие драйверы оборудования камеры или дисплея. Повторное использование драйверов может быть полезным, особенно для драйверов дисплея, где представление изображения может потребовать координации с другими активными потоками. Android 8.0 включает образец драйвера на основе v4l2 (в packages/services/Car/evs/sampleDriver
), который зависит от ядра для поддержки v4l2 и от SurfaceFlinger для представления выходного изображения.
Описание аппаратного интерфейса EVS
В этом разделе описывается HAL. Ожидается, что поставщики предоставят реализации этого API, адаптированные для их оборудования.
IEvsEnumerator
Этот объект отвечает за перечисление доступного оборудования EVS в системе (одна или несколько камер и одно устройство отображения).
getCameraList() generates (vec<CameraDesc> cameras);
Возвращает вектор, содержащий описания всех камер в системе. Предполагается, что набор камер фиксирован и доступен во время загрузки. Подробную информацию об описаниях камер см. в CameraDesc
.
openCamera(string camera_id) generates (IEvsCamera camera);
Получает объект интерфейса, используемый для взаимодействия с определенной камерой, идентифицируемой уникальной строкой camera_id . Возвращает NULL в случае ошибки. Попытки повторно открыть уже открытую камеру не могут быть неудачными. Чтобы избежать состояний гонки, связанных с запуском и завершением работы приложения, повторное открытие камеры должно завершить работу предыдущего экземпляра, чтобы можно было выполнить новый запрос. Экземпляр камеры, который был вытеснен таким образом, должен быть переведен в неактивное состояние, ожидая окончательного уничтожения и отвечая на любой запрос, чтобы повлиять на состояние камеры, кодом возврата OWNERSHIP_LOST
.
closeCamera(IEvsCamera camera);
Освобождает интерфейс IEvsCamera (и является противоположностью вызова openCamera()
). Видеопоток камеры необходимо остановить, вызвав stopVideoStream()
перед вызовом closeCamera
.
openDisplay() generates (IEvsDisplay display);
Получает объект интерфейса, используемый исключительно для взаимодействия с дисплеем EVS системы. Только один клиент может одновременно содержать функциональный экземпляр IEvsDisplay. Подобно агрессивному поведению при открытии, описанному в openCamera
, новый объект IEvsDisplay может быть создан в любое время и отключает все предыдущие экземпляры. Недействительные экземпляры продолжают существовать и отвечать на вызовы функций своих владельцев, но не должны выполнять никаких операций изменения, когда они мертвы. В конце концов ожидается, что клиентское приложение заметит коды возврата ошибки OWNERSHIP_LOST
, закроет и освободит неактивный интерфейс.
closeDisplay(IEvsDisplay display);
Освобождает интерфейс IEvsDisplay (и является противоположностью вызова openDisplay()
). Невыполненные буферы, полученные с помощью getTargetBuffer()
, должны быть возвращены на дисплей перед закрытием дисплея.
getDisplayState() generates (DisplayState state);
Получает текущее состояние отображения. Реализация HAL должна сообщать о фактическом текущем состоянии, которое может отличаться от последнего запрошенного состояния. Логика, отвечающая за изменение состояний отображения, должна существовать над уровнем устройства, что делает нежелательным самопроизвольное изменение состояний отображения в реализации HAL. Если дисплей в данный момент не удерживается ни одним клиентом (при вызове openDisplay), эта функция возвращает NOT_OPEN
. В противном случае он сообщает о текущем состоянии дисплея EVS (см. API IEvsDisplay ).
struct CameraDesc { string camera_id; int32 vendor_flags; // Opaque value }
-
camera_id
. Строка, которая однозначно идентифицирует данную камеру. Это может быть имя устройства ядра или имя устройства, например Rearview . Значение этой строки выбирается реализацией HAL и непрозрачно используется стеком выше. -
vendor_flags
. Метод непрозрачной передачи специализированной информации о камере от водителя в специальное приложение EVS. Он передается в неинтерпретированном виде от драйвера приложению EVS, которое может его игнорировать.
IEvsCamera
Этот объект представляет одну камеру и является основным интерфейсом для захвата изображений.
getCameraInfo() generates (CameraDesc info);
Возвращает CameraDesc
этой камеры.
setMaxFramesInFlight(int32 bufferCount) generates (EvsResult result);
Указывает глубину цепочки буферов, которую требуется поддерживать камере. До этого количества кадров клиент IEvsCamera может хранить одновременно. Если такое количество кадров было доставлено получателю без возврата с помощью doneWithFrame
, поток пропускает кадры до тех пор, пока не будет возвращен буфер для повторного использования. Этот вызов может поступать в любое время, даже когда потоки уже запущены, и в этом случае буферы должны быть добавлены или удалены из цепочки по мере необходимости. Если к этой точке входа не производится вызов, IEvsCamera по умолчанию поддерживает как минимум один кадр; с более приемлемым.
Если запрошенный bufferCount не может быть размещен, функция возвращает BUFFER_NOT_AVAILABLE
или другой соответствующий код ошибки. В этом случае система продолжает работать с ранее установленным значением.
startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);
Запрашивает доставку кадров EVS с этой камеры. IEvsCameraStream начинает периодически получать вызовы с новыми кадрами изображения, пока не будет вызвана stopVideoStream()
. Кадры должны начать доставляться в течение 500 мс после вызова startVideoStream
и после запуска должны генерироваться со скоростью не менее 10 кадров в секунду. Время, необходимое для запуска видеопотока, эффективно учитывается при любых требованиях ко времени запуска камеры заднего вида. Если поток не запускается, должен быть возвращен код ошибки; в противном случае возвращается ОК.
oneway doneWithFrame(BufferDesc buffer);
Возвращает кадр, доставленный в IEvsCameraStream. После завершения использования кадра, доставленного в интерфейс IEvsCameraStream, этот кадр необходимо вернуть в IEvsCamera для повторного использования. Доступно небольшое, конечное число буферов (возможно, всего один), и если их запас исчерпан, дальнейшие кадры не доставляются до тех пор, пока не будет возвращен буфер, что потенциально может привести к пропуску кадров (буфер с нулевым дескриптором обозначает конец потока и его не нужно возвращать через эту функцию). Возвращает OK в случае успеха или соответствующий код ошибки, возможно, включая INVALID_ARG
или BUFFER_NOT_AVAILABLE
.
stopVideoStream();
Останавливает доставку кадров камеры EVS. Поскольку доставка является асинхронной, кадры могут продолжать поступать в течение некоторого времени после возврата этого вызова. Каждый кадр должен возвращаться до тех пор, пока IEvsCameraStream не получит сигнал о закрытии потока. Разрешено вызывать stopVideoStream
для потока, который уже был остановлен или никогда не запускался; в этом случае он игнорируется.
getExtendedInfo(int32 opaqueIdentifier) generates (int32 value);
Запрашивает информацию о драйвере из реализации HAL. Значения, разрешенные для opaqueIdentifier
зависят от драйвера, но отсутствие переданного значения может привести к сбою драйвера. Драйвер должен возвращать 0 для любого нераспознанного opaqueIdentifier
.
setExtendedInfo(int32 opaqueIdentifier, int32 opaqueValue) generates (EvsResult result);
Отправляет значение, специфичное для драйвера, в реализацию HAL. Это расширение предоставляется только для облегчения расширения, специфичного для транспортного средства, и никакая реализация HAL не должна требовать, чтобы этот вызов функционировал в состоянии по умолчанию. Если драйвер распознает и принимает значения, должно быть возвращено OK; в противном случае должен быть возвращен INVALID_ARG
или другой репрезентативный код ошибки.
struct BufferDesc { uint32 width; // Units of pixels uint32 height; // Units of pixels uint32 stride; // Units of pixels uint32 pixelSize; // Size of single pixel in bytes uint32 format; // May contain values from android_pixel_format_t uint32 usage; // May contain values from Gralloc.h uint32 bufferId; // Opaque value handle memHandle; // gralloc memory buffer handle }
Описывает изображение, передаваемое через API. Диск HAL отвечает за заполнение этой структуры для описания буфера изображения, и клиент HAL должен рассматривать эту структуру как доступную только для чтения. Поля содержат достаточно информации, чтобы клиент мог восстановить объект ANativeWindowBuffer
, что может потребоваться для использования изображения с EGL с расширением eglCreateImageKHR()
.
-
width
. Ширина представленного изображения в пикселях. -
height
. Высота в пикселях представленного изображения. -
stride
. Количество пикселей, которое фактически занимает в памяти каждая строка, с учетом любого заполнения для выравнивания строк. Выражается в пикселях, чтобы соответствовать соглашению, принятому gralloc для описаний буферов. -
pixelSize
. Количество байтов, занимаемых каждым отдельным пикселем, позволяющее вычислить размер в байтах, необходимый для перехода между строками изображения (stride
в байтах =stride
в пикселях *pixelSize
). -
format
. Формат пикселей, используемый изображением. Предоставленный формат должен быть совместим с реализацией OpenGL платформы. Чтобы пройти тестирование совместимости, для использования камеры следует отдать предпочтениеHAL_PIXEL_FORMAT_YCRCB_420_SP
, а для отображения следует предпочестьRGBA
илиBGRA
. -
usage
. Флаги использования, установленные реализацией HAL. Ожидается, что клиенты HAL будут передавать эти данные в неизмененном виде (подробнее см. Флаги, связанные сGralloc.h
). -
bufferId
. Уникальное значение, указанное реализацией HAL, позволяющее распознавать буфер после прохождения через API-интерфейсы HAL. Значение, хранящееся в этом поле, может быть произвольно выбрано реализацией HAL. -
memHandle
. Дескриптор базового буфера памяти, содержащего данные изображения. Реализация HAL может сохранить здесь дескриптор буфера Gralloc.
IevsCameraStream
Клиент реализует этот интерфейс для получения асинхронной доставки видеокадров.
deliverFrame(BufferDesc buffer);
Получает вызовы от HAL каждый раз, когда видеокадр готов к проверке. Дескрипторы буфера, полученные этим методом, должны быть возвращены посредством вызовов IEvsCamera::doneWithFrame()
. Когда видеопоток останавливается с помощью вызова IEvsCamera::stopVideoStream()
, этот обратный вызов может продолжаться по мере истощения конвейера. Каждый кадр все равно должен быть возвращен; когда последний кадр в потоке доставлен, доставляется bufferHandle
, обозначающий конец потока, и дальнейшая доставка кадров не происходит. Сам NULL bufferHandle
не нужно отправлять обратно с помощью doneWithFrame()
, но все остальные дескрипторы должны быть возвращены.
Хотя технически возможны собственные форматы буферов, тестирование совместимости требует, чтобы буфер был в одном из четырех поддерживаемых форматов: NV21 (YCrCb 4:2:0 Semi-Planar), YV12 (YCrCb 4:2:0 Planar), YUYV (YCrCb 4: 2:2 с чередованием), RGBA (32 бита R:G:B:x), BGRA (32 бита B:G:R:x). Выбранный формат должен быть допустимым источником текстур GL в реализации GLES платформы.
Приложение не должно полагаться на какое-либо соответствие между полем bufferId
и memHandle
в структуре BufferDesc
. Значения bufferId
по существу являются частными для реализации драйвера HAL, и он может использовать (и повторно использовать) их по своему усмотрению.
IEvsDisplay
Этот объект представляет дисплей Evs, управляет состоянием дисплея и обрабатывает фактическое представление изображений.
getDisplayInfo() generates (DisplayDesc info);
Возвращает основную информацию о дисплее EVS, предоставляемую системой (см. DisplayDesc ).
setDisplayState(DisplayState state) generates (EvsResult result);
Устанавливает состояние отображения. Клиенты могут установить состояние отображения для выражения желаемого состояния, а реализация HAL должна корректно принять запрос на любое состояние, находясь в любом другом состоянии, хотя ответом может быть игнорирование запроса.
При инициализации дисплей запускается в состоянии NOT_VISIBLE
, после чего ожидается, что клиент запросит состояние VISIBLE_ON_NEXT_FRAME
и начнет предоставлять видео. Когда отображение больше не требуется, ожидается, что клиент запросит состояние NOT_VISIBLE
после передачи последнего видеокадра.
Он действителен для любого состояния и может быть запрошен в любое время. Если дисплей уже виден, он должен оставаться видимым, если установлено значение VISIBLE_ON_NEXT_FRAME
. Всегда возвращает OK, если только запрошенное состояние не является нераспознанным значением перечисления, в этом случае возвращается INVALID_ARG
.
getDisplayState() generates (DisplayState state);
Получает состояние отображения. Реализация HAL должна сообщать о фактическом текущем состоянии, которое может отличаться от последнего запрошенного состояния. Логика, отвечающая за изменение состояний отображения, должна существовать над уровнем устройства, что делает нежелательным самопроизвольное изменение состояний отображения в реализации HAL.
getTargetBuffer() generates (handle bufferHandle);
Возвращает дескриптор буфера кадров, связанного с дисплеем. Этот буфер может быть заблокирован и записан в него программным обеспечением и/или GL. Этот буфер должен быть возвращен вызовом returnTargetBufferForDisplay()
даже если дисплей больше не виден.
Хотя технически возможны собственные форматы буферов, тестирование совместимости требует, чтобы буфер был в одном из четырех поддерживаемых форматов: NV21 (YCrCb 4:2:0 Semi-Planar), YV12 (YCrCb 4:2:0 Planar), YUYV (YCrCb 4: 2:2 с чередованием), RGBA (32 бита R:G:B:x), BGRA (32 бита B:G:R:x). Выбранный формат должен быть допустимой целью рендеринга GL в реализации GLES платформы.
В случае ошибки возвращается буфер с нулевым дескриптором, но такой буфер не нужно передавать обратно в returnTargetBufferForDisplay
.
returnTargetBufferForDisplay(handle bufferHandle) generates (EvsResult result);
Сообщает дисплею, что буфер готов к отображению. Для использования с этим вызовом допустимы только буферы, полученные с помощью вызова getTargetBuffer()
, а содержимое BufferDesc
не может быть изменено клиентским приложением. После этого вызова буфер больше не доступен для использования клиентом. Возвращает OK в случае успеха или соответствующий код ошибки, возможно, включая INVALID_ARG
или BUFFER_NOT_AVAILABLE
.
struct DisplayDesc { string display_id; int32 vendor_flags; // Opaque value }
Описывает основные свойства дисплея EVS, необходимые для реализации EVS. HAL отвечает за заполнение этой структуры для описания дисплея EVS. Это может быть физический дисплей или виртуальный дисплей, наложенный или смешанный с другим устройством представления.
-
display_id
. Строка, которая однозначно идентифицирует дисплей. Это может быть имя устройства ядра устройства или имя устройства, например Rearview . Значение этой строки выбирается реализацией HAL и непрозрачно используется стеком выше. -
vendor_flags
. Метод непрозрачной передачи специализированной информации о камере от водителя в специальное приложение EVS. Он передается в неинтерпретированном виде от драйвера приложению EVS, которое может его игнорировать.
enum DisplayState : uint32 { NOT_OPEN, // Display has not been “opened” yet NOT_VISIBLE, // Display is inhibited VISIBLE_ON_NEXT_FRAME, // Will become visible with next frame VISIBLE, // Display is currently active DEAD, // Display is not available. Interface should be closed }
Описывает состояние дисплея EVS, который можно отключить (не видеть водителю) или включить (показывать изображение водителю). Включает переходное состояние, в котором дисплей еще не виден, но готов стать видимым при доставке следующего кадра изображения с помощью вызова returnTargetBufferForDisplay()
.
Менеджер ЕВС
Менеджер EVS обеспечивает общедоступный интерфейс системы EVS для сбора и представления изображений с внешних камер. Если драйверы оборудования допускают только один активный интерфейс для каждого ресурса (камеры или дисплея), EVS Manager обеспечивает общий доступ к камерам. Единственное основное приложение EVS является первым клиентом EVS Manager и единственным клиентом, которому разрешено записывать данные отображения (дополнительным клиентам может быть предоставлен доступ только для чтения к изображениям с камеры).
EVS Manager реализует тот же API, что и базовые драйверы HAL, и предоставляет расширенные услуги за счет поддержки нескольких одновременных клиентов (более одного клиента могут открыть камеру через EVS Manager и получить видеопоток).
Приложения не видят различий при работе через реализацию аппаратного обеспечения EVS HAL или API EVS Manager, за исключением того, что API EVS Manager обеспечивает одновременный доступ к потоку камеры. EVS Manager сам по себе является единственным разрешенным клиентом уровня HAL оборудования EVS и действует как прокси для HAL оборудования EVS.
В следующих разделах описаны только те вызовы, которые имеют другое (расширенное) поведение в реализации EVS Manager; остальные вызовы идентичны описаниям EVS HAL.
IEvsEnumerator
openCamera(string camera_id) generates (IEvsCamera camera);
Получает объект интерфейса, используемый для взаимодействия с определенной камерой, идентифицируемой уникальной строкой camera_id . Возвращает NULL в случае ошибки. На уровне EVS Manager, пока доступны достаточные системные ресурсы, уже открытая камера может быть открыта снова другим процессом, что позволяет передавать видеопоток нескольким пользовательским приложениям. Строки camera_id
на уровне EVS Manager такие же, как и строки, передаваемые на уровень оборудования EVS.
IEvsCamera
EVS Manager обеспечил реализацию IEvsCamera внутренней виртуализацией, поэтому операции с камерой одного клиента не влияют на других клиентов, которые сохраняют независимый доступ к своим камерам.
startVideoStream(IEvsCameraStream receiver) generates (EvsResult result);
Запускает видеопотоки. Клиенты могут независимо запускать и останавливать видеопотоки на одной базовой камере. Базовая камера запускается при запуске первого клиента.
doneWithFrame(uint32 frameId, handle bufferHandle) generates (EvsResult result);
Возвращает кадр. Каждый клиент должен вернуть свои кадры, когда они будут готовы, но ему разрешено удерживать свои кадры столько, сколько он пожелает. Когда количество кадров, хранящихся у клиента, достигает настроенного предела, он больше не будет получать кадры, пока не вернет один. Этот пропуск кадров не влияет на других клиентов, которые продолжают получать все кадры, как ожидалось.
stopVideoStream();
Останавливает видеопоток. Каждый клиент может остановить свой видеопоток в любое время, не затрагивая других клиентов. Базовый поток камеры на аппаратном уровне останавливается, когда последний клиент данной камеры останавливает свой поток.
setExtendedInfo(int32 opaqueIdentifier, int32 opaqueValue) generates (EvsResult result);
Отправляет значение, специфичное для драйвера, что потенциально позволяет одному клиенту влиять на другого клиента. Поскольку EVS Manager не может понять значения управляющих слов, определенных поставщиком, они не виртуализируются, и любые побочные эффекты применяются ко всем клиентам данной камеры. Например, если поставщик использовал этот вызов для изменения частоты кадров, все клиенты затронутой камеры аппаратного уровня будут получать кадры с новой частотой.
IEvsDisplay
Допускается только один владелец дисплея, даже на уровне менеджера EVS. Диспетчер не добавляет никаких функций и просто передает интерфейс IEvsDisplay непосредственно базовой реализации HAL.
приложение EVS
Android включает в себя эталонную реализацию приложения EVS на C++, которое взаимодействует с EVS Manager и HAL транспортного средства, обеспечивая базовые функции камеры заднего вида. Ожидается, что приложение запустится на очень ранней стадии процесса загрузки системы, и будет показано подходящее видео в зависимости от доступных камер и состояния автомобиля (состояние включенной передачи и указателя поворота). OEM-производители могут модифицировать или заменить приложение EVS своей собственной логикой и представлением, специфичными для конкретного автомобиля.
Поскольку данные изображения передаются приложению в стандартном графическом буфере, приложение отвечает за перемещение изображения из исходного буфера в выходной буфер. Хотя это увеличивает стоимость копирования данных, оно также дает приложению возможность визуализировать изображение в буфер дисплея любым желаемым способом.
Например, приложение может выбрать перемещение самих данных пикселей, возможно, с помощью встроенного масштабирования или операции вращения. Приложение также может использовать исходное изображение в качестве текстуры OpenGL и отображать сложную сцену в выходном буфере, включая виртуальные элементы, такие как значки, направляющие и анимацию. Более сложное приложение может также выбрать несколько камер одновременного ввода и объединить их в один выходной кадр (например, для использования в виртуальном виде сверху вниз на окрестности автомобиля).
Используйте EGL/SurfaceFlinger в HAL дисплея EVS.
В этом разделе объясняется, как использовать EGL для рендеринга реализации EVS Display HAL в Android 10.
Эталонная реализация EVS HAL использует EGL для предварительного просмотра изображения камеры на экране и использует libgui
для создания целевой поверхности рендеринга EGL. В Android 8 (и более поздних версиях) libgui
классифицируется как VNDK-private , что относится к группе библиотек, доступных библиотекам VNDK, которые процессы поставщика не могут использовать. Поскольку реализации HAL должны находиться в разделе поставщика, поставщики не могут использовать Surface в реализациях HAL.
Создание libgui для процессов поставщиков
Использование libgui
является единственным вариантом использования EGL/SurfaceFlinger в реализациях EVS Display HAL. Самый простой способ реализовать libgui
— напрямую через frameworks/native/libs/gui, используя дополнительную цель сборки в скрипте сборки. Эта цель точно такая же, как цель libgui
за исключением добавления двух полей:
-
name
-
vendor_available
cc_library_shared { name: "libgui_vendor", vendor_available: true, vndk: { enabled: false, }, double_loadable: true,
defaults: ["libgui_bufferqueue-defaults"],
srcs: [ … // bufferhub is not used when building libgui for vendors target: { vendor: { cflags: [ "-DNO_BUFFERHUB", "-DNO_INPUT", ], …
Примечание. Целевые объекты поставщиков создаются с помощью макроса NO_INPUT
, который удаляет одно 32-битное слово из данных посылки. Поскольку SurfaceFlinger ожидает, что это поле будет удалено, SurfaceFlinger не сможет проанализировать участок. Это наблюдается как сбой fcntl
:
W Parcel : Attempt to read object from Parcel 0x78d9cffad8 at offset 428 that is not in the object list E Parcel : fcntl(F_DUPFD_CLOEXEC) failed in Parcel::read, i is 0, fds[i] is 0, fd_count is 20, error: Unknown error 2147483647 W Parcel : Attempt to read object from Parcel 0x78d9cffad8 at offset 544 that is not in the object list
Чтобы устранить это условие:
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 6066421fa..25cf5f0ce 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -54,6 +54,9 @@ status_t layer_state_t::write(Parcel& output) const output.writeFloat(color.b); #ifndef NO_INPUT inputInfo.write(output); +#else + // Write a dummy 32-bit word. + output.writeInt32(0); #endif output.write(transparentRegion); output.writeUint32(transform);
Примеры инструкций по сборке приведены ниже. Ожидайте получения $(ANDROID_PRODUCT_OUT)/system/lib64/libgui_vendor.so
.
$ cd <your_android_source_tree_top> $ . ./build/envsetup. $ lunch <product_name>-<build_variant> ============================================ PLATFORM_VERSION_CODENAME=REL PLATFORM_VERSION=10 TARGET_PRODUCT=<product_name> TARGET_BUILD_VARIANT=<build_variant> TARGET_BUILD_TYPE=release TARGET_ARCH=arm64 TARGET_ARCH_VARIANT=armv8-a TARGET_CPU_VARIANT=generic TARGET_2ND_ARCH=arm TARGET_2ND_ARCH_VARIANT=armv7-a-neon TARGET_2ND_CPU_VARIANT=cortex-a9 HOST_ARCH=x86_64 HOST_2ND_ARCH=x86 HOST_OS=linux HOST_OS_EXTRA=<host_linux_version> HOST_CROSS_OS=windows HOST_CROSS_ARCH=x86 HOST_CROSS_2ND_ARCH=x86_64 HOST_BUILD_TYPE=release BUILD_ID=QT OUT_DIR=out ============================================
$ m -j libgui_vendor … $ find $ANDROID_PRODUCT_OUT/system -name "libgui_vendor*" .../out/target/product/hawk/system/lib64/libgui_vendor.so .../out/target/product/hawk/system/lib/libgui_vendor.so
Используйте связующее в реализации EVS HAL.
В Android 8 (и более поздних версиях) узел устройства /dev/binder
стал эксклюзивным для процессов платформы и, следовательно, недоступен для процессов поставщика. Вместо этого процессы поставщика должны использовать /dev/hwbinder
и конвертировать любые интерфейсы AIDL в HIDL. Для тех, кто хочет продолжать использовать интерфейсы AIDL между процессами поставщика, используйте домен связывания /dev/vndbinder
.
Домен МПК | Описание |
---|---|
/dev/binder | IPC между процессами платформы/приложения с интерфейсами AIDL |
/dev/hwbinder | IPC между процессами платформы/поставщика с интерфейсами HIDL IPC между процессами поставщиков с интерфейсами HIDL |
/dev/vndbinder | IPC между процессами поставщика/поставщика с помощью интерфейсов AIDL |
Хотя SurfaceFlinger определяет интерфейсы AIDL, процессы поставщиков могут использовать только интерфейсы HIDL для взаимодействия с процессами платформы. Требуется нетривиальный объем работы для преобразования существующих интерфейсов AIDL в HIDL. К счастью, Android предоставляет метод, с помощью которого можно выбрать драйвер связывателя для libbinder
, с которым связаны процессы библиотеки пользовательского пространства.
diff --git a/evs/sampleDriver/service.cpp b/evs/sampleDriver/service.cpp index d8fb3166..5fd02935 100644 --- a/evs/sampleDriver/service.cpp +++ b/evs/sampleDriver/service.cpp @@ -21,6 +21,7 @@ #include <utils/Errors.h> #include <utils/StrongPointer.h> #include <utils/Log.h> +#include <binder/ProcessState.h> #include "ServiceNames.h" #include "EvsEnumerator.h" @@ -43,6 +44,9 @@ using namespace android; int main() { ALOGI("EVS Hardware Enumerator service is starting"); + // Use /dev/binder for SurfaceFlinger + ProcessState::initWithDriver("/dev/binder"); + // Start a thread to listen to video device addition events. std::atomic<bool> running { true }; std::thread ueventHandler(EvsEnumerator::EvsUeventThread, std::ref(running));
Примечание. Процессы поставщика должны вызывать это перед вызовом Process
или IPCThreadState
или перед выполнением каких-либо вызовов связывания.
Политики SELinux
Если реализация устройства является полной тройной, SELinux не позволяет процессам поставщика использовать /dev/binder
. Например, пример реализации EVS HAL назначен домену hal_evs_driver
и требует разрешений на чтение и запись в binder_device
.
W ProcessState: Opening '/dev/binder' failed: Permission denied F ProcessState: Binder driver could not be opened. Terminating. F libc : Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 9145 (android.hardwar), pid 9145 (android.hardwar) W android.hardwar: type=1400 audit(0.0:974): avc: denied { read write } for name="binder" dev="tmpfs" ino=2208 scontext=u:r:hal_evs_driver:s0 tcontext=u:object_r:binder_device:s0 tclass=chr_file permissive=0
Однако добавление этих разрешений приводит к сбою сборки, поскольку нарушает следующие правила никогда не разрешать, определенные в system/sepolicy/domain.te
для устройства с полной тройкой.
libsepol.report_failure: neverallow on line 631 of system/sepolicy/public/domain.te (or line 12436 of policy.conf) violated by allow hal_evs_driver binder_device:chr_file { read write }; libsepol.check_assertions: 1 neverallow failures occurred
full_treble_only(` neverallow { domain -coredomain -appdomain -binder_in_vendor_violators } binder_device:chr_file rw_file_perms; ')
binder_in_vendor_violators
— это атрибут, предназначенный для обнаружения ошибок и руководства разработкой. Его также можно использовать для устранения описанного выше нарушения Android 10.
diff --git a/evs/sepolicy/evs_driver.te b/evs/sepolicy/evs_driver.te index f1f31e9fc..6ee67d88e 100644 --- a/evs/sepolicy/evs_driver.te +++ b/evs/sepolicy/evs_driver.te @@ -3,6 +3,9 @@ type hal_evs_driver, domain, coredomain; hal_server_domain(hal_evs_driver, hal_evs) hal_client_domain(hal_evs_driver, hal_evs) +# Allow to use /dev/binder +typeattribute hal_evs_driver binder_in_vendor_violators; + # allow init to launch processes in this context type hal_evs_driver_exec, exec_type, file_type, system_file_type; init_daemon_domain(hal_evs_driver)
Создайте эталонную реализацию EVS HAL как процесс поставщика.
Для справки вы можете применить следующие изменения к packages/services/Car/evs/Android.mk
. Обязательно убедитесь, что все описанные изменения работают для вашей реализации.
diff --git a/evs/sampleDriver/Android.mk b/evs/sampleDriver/Android.mk index 734feea7d..0d257214d 100644 --- a/evs/sampleDriver/Android.mk +++ b/evs/sampleDriver/Android.mk @@ -16,7 +16,7 @@ LOCAL_SRC_FILES := \ LOCAL_SHARED_LIBRARIES := \ android.hardware.automotive.evs@1.0 \ libui \ - libgui \ + libgui_vendor \ libEGL \ libGLESv2 \ libbase \ @@ -33,6 +33,7 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_INIT_RC := android.hardware.automotive.evs@1.0-sample.rc LOCAL_MODULE := android.hardware.automotive.evs@1.0-sample +LOCAL_PROPRIETARY_MODULE := true LOCAL_MODULE_TAGS := optional LOCAL_STRIP_MODULE := keep_symbols @@ -40,6 +41,7 @@ LOCAL_STRIP_MODULE := keep_symbols LOCAL_CFLAGS += -DLOG_TAG=\"EvsSampleDriver\" LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code +LOCAL_CFLAGS += -Iframeworks/native/include #NOTE: It can be helpful, while debugging, to disable optimizations #LOCAL_CFLAGS += -O0 -g diff --git a/evs/sampleDriver/service.cpp b/evs/sampleDriver/service.cpp index d8fb31669..5fd029358 100644 --- a/evs/sampleDriver/service.cpp +++ b/evs/sampleDriver/service.cpp @@ -21,6 +21,7 @@ #include <utils/Errors.h> #include <utils/StrongPointer.h> #include <utils/Log.h> +#include <binder/ProcessState.h> #include "ServiceNames.h" #include "EvsEnumerator.h" @@ -43,6 +44,9 @@ using namespace android; int main() { ALOGI("EVS Hardware Enumerator service is starting"); + // Use /dev/binder for SurfaceFlinger + ProcessState::initWithDriver("/dev/binder"); + // Start a thread to listen video device addition events. std::atomic<bool> running { true }; std::thread ueventHandler(EvsEnumerator::EvsUeventThread, std::ref(running)); diff --git a/evs/sepolicy/evs_driver.te b/evs/sepolicy/evs_driver.te index f1f31e9fc..632fc7337 100644 --- a/evs/sepolicy/evs_driver.te +++ b/evs/sepolicy/evs_driver.te @@ -3,6 +3,9 @@ type hal_evs_driver, domain, coredomain; hal_server_domain(hal_evs_driver, hal_evs) hal_client_domain(hal_evs_driver, hal_evs) +# allow to use /dev/binder +typeattribute hal_evs_driver binder_in_vendor_violators; + # allow init to launch processes in this context type hal_evs_driver_exec, exec_type, file_type, system_file_type; init_daemon_domain(hal_evs_driver) @@ -22,3 +25,7 @@ allow hal_evs_driver ion_device:chr_file r_file_perms; # Allow the driver to access kobject uevents allow hal_evs_driver self:netlink_kobject_uevent_socket create_socket_perms_no_ioctl; + +# Allow the driver to use the binder device +allow hal_evs_driver binder_device:chr_file rw_file_perms;