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 , но он может учитывать только запросы захвата, отправленные в фреймворк камеры HAL. С методом requestStreamBuffers реализация камеры HAL может сохранять больше буферов, чем было запрошено фреймворком камеры. В этом случае следует использовать метод returnStreamBuffers . Если реализация HAL никогда не удерживает больше буферов, чем запрошено, реализация камеры 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++.