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) секунд после включения питания. Производители автомобилей могут модифицировать или заменять приложение EVS по своему усмотрению.
Менеджер EVS
Менеджер EVS ( /packages/services/Car/evs/manager ) предоставляет необходимые компоненты для реализации приложений EVS, от простого отображения изображения с камеры заднего вида до многокамерной визуализации с 6 степенями свободы. Его интерфейс представлен через HIDL и рассчитан на одновременное подключение нескольких клиентов. Другие приложения и сервисы (в частности, Car Service) могут запрашивать состояние менеджера EVS, чтобы узнать, когда система 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, требуются драйверы ядра. Вместо создания новых драйверов производители оборудования могут поддерживать необходимые для 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 кадров в секунду. Время, необходимое для запуска видеопотока, фактически учитывается в общем времени запуска камеры заднего вида. Если поток не запущен, возвращается код ошибки; в противном случае возвращается OK.
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() , этот обратный вызов может продолжаться по мере завершения работы конвейера. Каждый кадр по-прежнему должен быть возвращен; когда последний кадр в потоке доставлен, доставляется NULL bufferHandle , что означает конец потока и прекращение доставки кадров. Сам NULL bufferHandle не нужно отправлять обратно с помощью doneWithFrame() , но все остальные дескрипторы должны быть возвращены.
Хотя использование проприетарных форматов буфера технически возможно, для проверки совместимости требуется, чтобы буфер был в одном из четырех поддерживаемых форматов: NV21 (YCrCb 4:2:0 Semi-Planar), YV12 (YCrCb 4:2:0 Planar), YUYV (YCrCb 4:2:2 Interleaved), 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 Interleaved), 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 для сбора и отображения изображений с внешних камер. В тех случаях, когда драйверы оборудования допускают только один активный интерфейс на ресурс (камеру или дисплей), менеджер EVS обеспечивает совместный доступ к камерам. Единственное основное приложение EVS является первым клиентом менеджера EVS и единственным клиентом, которому разрешено записывать данные на дисплей (дополнительным клиентам может быть предоставлен доступ только для чтения к изображениям с камер).
Менеджер EVS реализует тот же API, что и базовые драйверы HAL, и обеспечивает расширенные возможности обслуживания, поддерживая одновременное подключение нескольких клиентов (более одного клиента может открыть камеру через менеджер EVS и получать видеопоток).

Приложения не видят различий при работе через реализацию EVS Hardware HAL или API EVS Manager, за исключением того, что API EVS Manager разрешает одновременный доступ к потоку с камеры. Сам EVS Manager является единственным разрешенным клиентом уровня EVS Hardware HAL и выступает в качестве прокси для EVS Hardware HAL.
В следующих разделах описаны только те вызовы, которые имеют иное (расширенное) поведение в реализации EVS Manager; остальные вызовы идентичны описаниям EVS HAL.
IEvsEnumerator
openCamera(string camera_id) generates (IEvsCamera camera);
Получает объект интерфейса, используемый для взаимодействия с конкретной камерой, идентифицированной уникальной строкой camera_id . Возвращает NULL в случае ошибки. На уровне EVS Manager, при наличии достаточных системных ресурсов, уже открытая камера может быть открыта снова другим процессом, что позволяет передавать видеопоток нескольким приложениям-потребителям. Строки camera_id на уровне EVS Manager совпадают со строками, передаваемыми на уровень EVS Hardware.
IEvsCamera
Реализация IEvsCamera, предоставляемая EVS Manager, внутренне виртуализирована, поэтому операции с камерой, выполняемые одним клиентом, не влияют на другие клиенты, которые сохраняют независимый доступ к своим камерам.
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 Manager допускается только один владелец дисплея. Manager не добавляет никакой функциональности и просто передает интерфейс IEvsDisplay напрямую в базовую реализацию HAL.
приложение EVS
Android включает в себя нативную реализацию приложения EVS на C++, которая взаимодействует с EVS Manager и Vehicle HAL для обеспечения базовых функций камеры заднего вида. Ожидается, что приложение запустится на очень раннем этапе загрузки системы, отображая подходящее видео в зависимости от доступных камер и состояния автомобиля (состояние передачи и указателей поворота). Производители автомобилей могут модифицировать или заменить приложение EVS собственной логикой и отображением, специфичными для конкретного автомобиля.


Поскольку данные изображения передаются приложению в стандартном графическом буфере, приложение отвечает за перемещение изображения из исходного буфера в выходной буфер. Хотя это и влечет за собой затраты на копирование данных, это также дает приложению возможность отображать изображение в буфере отображения любым желаемым способом.
Например, приложение может перемещать пиксельные данные самостоятельно, возможно, с помощью масштабирования или вращения по линии. Приложение также может использовать исходное изображение в качестве текстуры OpenGL и отображать сложную сцену в выходной буфер, включая виртуальные элементы, такие как значки, направляющие и анимации. Более сложное приложение может также выбирать несколько одновременно работающих входных камер и объединять их в один выходной кадр (например, для использования в виртуальном виде сверху вниз, показывающем окружение транспортного средства).
Используйте EGL/SurfaceFlinger в EVS Display HAL.
В этом разделе объясняется, как использовать 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
Используйте binder в реализации EVS HAL.
В Android 8 (и более поздних версиях) узел устройства /dev/binder стал доступен исключительно процессам фреймворка и, следовательно, недоступен для процессов сторонних разработчиков. Вместо этого процессы сторонних разработчиков должны использовать /dev/hwbinder и преобразовывать любые интерфейсы AIDL в HIDL. Для тех, кто хочет продолжать использовать интерфейсы AIDL между процессами сторонних разработчиков, следует использовать домен binder, /dev/vndbinder .
| Домен IPC | Описание |
|---|---|
/dev/binder | Межпроцессное взаимодействие между процессами фреймворка/приложения с использованием интерфейсов AIDL. |
/dev/hwbinder | Межпроцессное взаимодействие между процессами фреймворка/поставщика с использованием интерфейсов HIDL. Межпроцессное взаимодействие между процессами поставщиков с использованием интерфейсов HIDL. |
/dev/vndbinder | Межпроцессное взаимодействие между процессами поставщика с использованием интерфейсов 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
Если реализация устройства использует полную поддержку Treble, 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
Однако добавление этих разрешений приводит к ошибке сборки, поскольку нарушает следующие правила neverallow, определенные в файле system/sepolicy/domain.te для устройства с полным Treble-режимом.
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;