API управления буфером камеры HAL3

В Android 10 представлены дополнительные API-интерфейсы управления буфером камеры HAL3 , которые позволяют реализовать логику управления буфером для достижения различных компромиссов в отношении памяти и задержки при реализации HAL камеры.

Камере HAL требуется N запросов (где N равно глубине конвейера ), поставленных в очередь в ее конвейере, но часто ей не требуются все N наборов выходных буферов одновременно.

Например, в очереди конвейера HAL может находиться восемь запросов, но выходные буферы требуются только для двух запросов на последних этапах конвейера. На устройствах под управлением Android 9 и ниже фреймворк камеры выделяет буферы, когда запрос помещается в очередь HAL, поэтому в HAL может быть шесть неиспользуемых наборов буферов. В Android 10 API управления буферами камеры HAL3 позволяют разделить выходные буферы, чтобы освободить шесть наборов буферов. Это может привести к экономии сотен мегабайт памяти на высокопроизводительных устройствах и также может быть полезно для устройств с небольшим объёмом памяти.

На рисунке 1 показана схема интерфейса HAL камеры для устройств под управлением Android 9 и более ранних версий. На рисунке 2 показан интерфейс HAL камеры в Android 10 с реализованными API управления буфером камеры HAL3.

Управление буфером в версии 9 или ниже

Рисунок 1. Интерфейс HAL камеры в Android 9 и ниже

Управление буфером в Android 10

Рисунок 2. Интерфейс HAL камеры в Android 10 с использованием API управления буфером

Реализовать API управления буферами

Для реализации API управления буфером HAL камеры должен:

HAL камеры использует методы requestStreamBuffers и returnStreamBuffers в ICameraDeviceCallback.hal для запроса и возврата буферов. HAL также должен реализовать метод signalStreamFlush в ICameraDeviceSession.hal , чтобы подать сигнал HAL камеры о необходимости возврата буферов.

requestStreamBuffers

Используйте метод requestStreamBuffers для запроса буферов из фреймворка камеры. При использовании API управления буферами камеры HAL3 запросы на захват из фреймворка камеры не содержат выходных буферов, то есть поле bufferId в StreamBuffer равно 0 Поэтому HAL камеры должен использовать requestStreamBuffers для запроса буферов из фреймворка камеры.

Метод requestStreamBuffers позволяет вызывающему объекту запрашивать несколько буферов из нескольких выходных потоков за один вызов, что позволяет сократить количество вызовов HIDL IPC. Однако при одновременном запросе большего количества буферов вызовы занимают больше времени, что может негативно сказаться на общей задержке между запросом и результатом. Кроме того, поскольку вызовы requestStreamBuffers сериализуются в сервисе камеры, рекомендуется, чтобы HAL камеры использовал выделенный высокоприоритетный поток для запроса буферов.

В случае сбоя запроса буфера HAL камеры должен быть способен корректно обрабатывать нефатальные ошибки. Ниже перечислены распространённые причины сбоев запроса буфера и способы их обработки HAL камеры.

  • Приложение отключается от выходного потока: это нефатальная ошибка. HAL камеры должен отправлять ERROR_REQUEST на любой запрос захвата, направленный на отключённый поток, и быть готовым к обработке последующих запросов в обычном режиме.
  • Тайм-аут: это может произойти, когда приложение выполняет интенсивную обработку, удерживая некоторые буферы. HAL камеры должен отправлять ERROR_REQUEST для запросов на захват, которые не могут быть выполнены из-за ошибки тайм-аута, и быть готовым к обработке последующих запросов в обычном режиме.
  • Платформа камеры готовит новую конфигурацию потока: HAL камеры должен дождаться завершения следующего вызова configureStreams , прежде чем снова вызывать requestStreamBuffers .
  • Камера HAL достигла предела буфера (поле maxBuffers ): камера HAL должна подождать, пока не вернет хотя бы один буфер потока, прежде чем снова вызывать requestStreamBuffers .

returnStreamBuffers

Используйте метод returnStreamBuffers для возврата дополнительных буферов в фреймворк камеры. Уровень HAL камеры обычно возвращает буферы в фреймворк камеры через метод processCaptureResult , но он может учитывать только запросы на захват, отправленные в фреймворк камеры. С помощью метода requestStreamBuffers реализация HAL камеры может сохранять больше буферов, чем было запрошено фреймворком камеры. В этом случае следует использовать метод returnStreamBuffers . Если реализация HAL никогда не хранит больше буферов, чем запрошено, ей не нужно вызывать метод returnStreamBuffers .

signalStreamFlush

Метод signalStreamFlush вызывается фреймворком камеры, чтобы уведомить HAL-систему камеры о необходимости вернуть все доступные буферы. Обычно он вызывается, когда фреймворк камеры готовится вызвать configureStreams и должен очистить конвейер захвата камеры. Подобно методу returnStreamBuffers , если реализация HAL-системы камеры не содержит больше буферов, чем запрошено, реализация этого метода может оказаться пустой.

После того, как фреймворк камеры вызывает signalStreamFlush , он прекращает отправку новых запросов на захват в HAL камеры до тех пор, пока все буферы не будут возвращены фреймворку камеры. После возврата всех буферов вызовы метода requestStreamBuffers завершаются ошибкой, и фреймворк камеры может продолжить работу в чистом состоянии. Затем фреймворк камеры вызывает метод configureStreams или processCaptureRequest . Если фреймворк камеры вызывает метод configureStreams , HAL камеры может снова начать запрашивать буферы после успешного завершения вызова configureStreams . Если фреймворк камеры вызывает метод processCaptureRequest , HAL камеры может начать запрашивать буферы во время вызова processCaptureRequest .

Семантика методов signalStreamFlush и flush различается. При вызове метода flush HAL может прерывать ожидающие запросы захвата с помощью ERROR_REQUEST , чтобы как можно скорее очистить конвейер. При вызове метода signalStreamFlush HAL должен завершить все ожидающие запросы захвата обычным образом и вернуть все буферы фреймворку камеры.

Другое отличие метода signalStreamFlush от других методов заключается в том, что signalStreamFlushодносторонний HIDL-метод, что означает, что фреймворк камеры может вызывать другие блокирующие API до того, как HAL получит вызов signalStreamFlush . Это означает, что метод signalStreamFlush и другие методы (в частности, метод configureStreams ) могут поступать в HAL камеры в порядке, отличном от того, в котором они вызывались во фреймворке камеры. Для решения этой проблемы асинхронности поле streamConfigCounter было добавлено в StreamConfiguration и добавлено в качестве аргумента к методу signalStreamFlush . Реализация HAL камеры должна использовать аргумент streamConfigCounter для определения, поступает ли вызов signalStreamFlush позже соответствующего вызова configureStreams . Пример см. на рисунке 3.

Обработка звонков, поступивших с опозданием

Рисунок 3. Как HAL камеры должен обнаруживать и обрабатывать вызовы signalStreamFlush, поступающие с опозданием

Изменения поведения при реализации API управления буфером

При использовании API управления буферами для реализации логики управления буферами рассмотрите следующие возможные изменения поведения камеры и реализации HAL камеры:

  • Запросы на захват поступают в HAL камеры быстрее и чаще: без API управления буферами фреймворк камеры запрашивает выходные буферы для каждого запроса на захват, прежде чем отправлять запрос на захват в HAL камеры. При использовании API управления буферами фреймворку камеры больше не нужно ждать буферов, и, следовательно, он может отправлять запросы на захват в HAL камеры раньше.

    Кроме того, без API управления буферами фреймворк камеры прекращает отправку запросов на захват, если один из выходных потоков запроса на захват достиг максимального количества буферов, которое HAL может хранить одновременно (это значение задаётся HAL камеры в поле HalStream::maxBuffers в возвращаемом значении вызова configureStreams ). С появлением API управления буферами такое ограничение больше не применяется, и реализация HAL камеры не должна принимать вызовы processCaptureRequest , когда в очереди HAL слишком много запросов на захват.

  • Задержка вызова requestStreamBuffers может значительно варьироваться: существует множество причин, по которым вызов requestStreamBuffers может занимать больше времени, чем обычно. Например:

    • Для первых нескольких буферов вновь созданного потока вызовы могут занимать больше времени, поскольку устройству необходимо выделить память.
    • Ожидаемая задержка увеличивается пропорционально количеству буферов, запрошенных в каждом вызове.
    • Приложение удерживает буферы и выполняет обработку. Это может привести к замедлению запросов к буферам или тайм-ауту из-за нехватки буферов или загруженности процессора.

Стратегии управления буфером

API управления буферами позволяют реализовывать различные стратегии управления буферами. Вот некоторые примеры:

  • Обратная совместимость: HAL запрашивает буферы для запроса захвата во время вызова processCaptureRequest . Эта стратегия не обеспечивает экономии памяти, но может служить первой реализацией API управления буферами, требуя лишь незначительных изменений кода в существующем HAL камеры.
  • Максимальная экономия памяти: HAL камеры запрашивает выходные буферы только непосредственно перед тем, как требуется их заполнение. Эта стратегия обеспечивает максимальную экономию памяти. Потенциальным недостатком является увеличение задержек в работе конвейера камеры, когда запросы к буферам выполняются необычно долго.
  • Кэширование: HAL камеры кэширует несколько буферов, чтобы снизить вероятность влияния случайных медленных запросов буфера.

Камера HAL может применять различные стратегии для конкретных случаев использования, например, использовать стратегию максимальной экономии памяти для случаев использования, требующих большого объема памяти, и использовать стратегию обратной совместимости для других случаев использования.

Пример реализации во внешней камере HAL

HAL внешней камеры был представлен в Android 9 и находится в дереве исходного кода по адресу hardware/interfaces/camera/device/3.5/ . В Android 10 он был обновлён и включает в себя ExternalCameraDeviceSession.cpp — реализацию API управления буфером. Этот HAL внешней камеры реализует стратегию максимальной экономии памяти, упомянутую в разделе «Стратегии управления буфером», всего в нескольких сотнях строк кода на C++.