W systemie Android 10 wprowadzono opcjonalne interfejsy API do zarządzania buforem HAL3 kamery , które umożliwiają implementację logiki zarządzania buforami w celu uzyskania różnych kompromisów w zakresie pamięci i przechwytywania opóźnień w implementacjach HAL kamery.
Kamera HAL wymaga N żądań (gdzie N jest równa głębokości potoku ) umieszczonych w kolejce, ale często nie wymaga jednocześnie wszystkich N zestawów buforów wyjściowych.
Na przykład warstwa HAL może mieć w kolejce osiem żądań, ale wymaga buforów wyjściowych jedynie dla dwóch żądań na ostatnich etapach potoku. Na urządzeniach z systemem Android 9 i starszym struktura kamery przydziela bufory, gdy żądanie jest umieszczane w kolejce w warstwie HAL, więc w warstwie HAL może znajdować się sześć zestawów buforów, które nie są używane. W systemie Android 10 interfejsy API zarządzania buforem HAL3 kamery umożliwiają oddzielenie buforów wyjściowych w celu zwolnienia sześciu zestawów buforów. Może to prowadzić do zaoszczędzenia setek megabajtów pamięci na urządzeniach z najwyższej półki, ale może być również korzystne w przypadku urządzeń o małej ilości pamięci.
Rysunek 1 przedstawia schemat interfejsu HAL kamery dla urządzeń z systemem Android 9 i starszym. Rysunek 2 przedstawia interfejs HAL kamery w systemie Android 10 z zaimplementowanymi interfejsami API zarządzania buforem HAL3 kamery.
Rysunek 1. Interfejs HAL kamery w systemie Android 9 i starszych wersjach
Rysunek 2. Interfejs HAL kamery w systemie Android 10 wykorzystujący interfejsy API zarządzania buforem
Implementacja interfejsów API zarządzania buforami
Aby zaimplementować interfejsy API zarządzania buforami, warstwa HAL kamery musi:
- Zaimplementuj HIDL
ICameraDevice@3.5
. - Ustaw klucz charakterystyki kamery
android.info.supportedBufferManagementVersion
naHIDL_DEVICE_3_5
.
Kamera HAL używa metod requestStreamBuffers
i returnStreamBuffers
w ICameraDeviceCallback.hal
do żądania i zwracania buforów. HAL musi także implementować metodę signalStreamFlush
w ICameraDeviceSession.hal
, aby zasygnalizować HAL kamery, aby zwróciła bufory.
Bufory żądania strumienia
Użyj metody requestStreamBuffers
, aby zażądać buforów ze struktury kamery. W przypadku korzystania z interfejsów API zarządzania buforem HAL3 kamery żądania przechwytywania ze struktury kamery nie zawierają buforów wyjściowych, co oznacza, że pole bufferId
w StreamBuffer
ma 0
. Dlatego warstwa HAL kamery musi używać requestStreamBuffers
w celu żądania buforów ze struktury kamery.
Metoda requestStreamBuffers
umożliwia wywołującemu żądanie wielu buforów z wielu strumieni wyjściowych w jednym wywołaniu, co pozwala na mniejszą liczbę wywołań HIDL IPC. Jednakże wywołania zajmują więcej czasu, gdy jednocześnie żąda się większej liczby buforów, co może negatywnie wpłynąć na całkowite opóźnienie od żądania do wyniku. Ponadto, ponieważ wywołania requestStreamBuffers
są serializowane w usłudze kamery, zaleca się, aby warstwa HAL kamery korzystała z dedykowanego wątku o wysokim priorytecie w celu żądania buforów.
Jeśli żądanie bufora nie powiedzie się, warstwa HAL kamery musi być w stanie prawidłowo obsłużyć błędy niekrytyczne. Na poniższej liście opisano typowe przyczyny niepowodzenia żądań bufora oraz sposób ich obsługi przez warstwę HAL kamery.
- Aplikacja odłącza się od strumienia wyjściowego: jest to błąd niekrytyczny. Kamera HAL powinna wysłać
ERROR_REQUEST
w przypadku każdego żądania przechwytywania skierowanego do odłączonego strumienia i być gotowa do normalnego przetwarzania kolejnych żądań. - Limit czasu: może się to zdarzyć, gdy aplikacja jest zajęta intensywnym przetwarzaniem, trzymając niektóre bufory. Kamera HAL powinna wysłać
ERROR_REQUEST
w przypadku żądań przechwytywania, których nie można zrealizować ze względu na błąd przekroczenia limitu czasu, i powinna być gotowa do normalnego przetwarzania kolejnych żądań. - Struktura kamery przygotowuje nową konfigurację strumienia: warstwa HAL kamery powinna poczekać do zakończenia następnego wywołania
configureStreams
przed ponownym wywołaniemrequestStreamBuffers
. - HAL kamery osiągnął limit bufora (pole
maxBuffers
): HAL kamery powinien poczekać, aż zwróci przynajmniej jeden bufor strumienia, zanim ponownie wywołarequestStreamBuffers
.
returnBufory strumienia
Użyj metody returnStreamBuffers
, aby zwrócić dodatkowe bufory do struktury kamery. HAL kamery zwykle zwraca bufory do struktury kamery za pomocą metody processCaptureResult
, ale może uwzględniać tylko żądania przechwytywania wysłane do warstwy HAL kamery. Dzięki metodzie requestStreamBuffers
implementacja warstwy HAL kamery może zachować więcej buforów, niż zażądała struktura kamery. W tym przypadku należy zastosować metodę returnStreamBuffers
. Jeśli implementacja HAL nigdy nie przechowuje więcej buforów niż żądano, implementacja HAL kamery nie musi wywoływać metody returnStreamBuffers
.
SignalStreamFlush
Metoda signalStreamFlush
jest wywoływana przez platformę kamery w celu powiadomienia warstwy HAL kamery o konieczności zwrócenia wszystkich dostępnych buforów. Jest to zwykle wywoływane, gdy struktura kamery ma zamiar configureStreams
i musi opróżnić potok przechwytywania kamery. Podobnie jak w przypadku metody returnStreamBuffers
, jeśli implementacja HAL kamery nie przechowuje więcej buforów niż żądano, możliwa jest pusta implementacja tej metody.
Gdy struktura kamery wywoła funkcję signalStreamFlush
, platforma przestaje wysyłać nowe żądania przechwytywania do warstwy HAL kamery, dopóki wszystkie bufory nie zostaną zwrócone do struktury kamery. Po zwróceniu wszystkich buforów wywołania metody requestStreamBuffers
kończą się niepowodzeniem i struktura kamery może kontynuować pracę w czystym stanie. Następnie struktura kamery wywołuje configureStreams
lub processCaptureRequest
. Jeśli struktura kamery wywoła configureStreams
, warstwa HAL kamery może ponownie rozpocząć żądanie buforów po pomyślnym powrocie wywołania configureStreams
. Jeśli struktura kamery wywoła metodę processCaptureRequest
, warstwa HAL kamery może rozpocząć żądanie buforów podczas wywołania processCaptureRequest
.
Semantyka metody signalStreamFlush
i metody flush
jest inna. Po wywołaniu metody flush
HAL może przerwać oczekujące żądania przechwytywania za pomocą ERROR_REQUEST
w celu jak najszybszego opróżnienia potoku. Po wywołaniu metody signalStreamFlush
warstwa HAL musi normalnie zakończyć wszystkie oczekujące żądania przechwytywania i zwrócić wszystkie bufory do struktury kamery.
Inną różnicą między metodą signalStreamFlush
a innymi metodami jest to, że signalStreamFlush
jest jednokierunkową metodą HIDL, co oznacza, że struktura kamery może wywoływać inne blokujące interfejsy API, zanim warstwa HAL odbierze wywołanie signalStreamFlush
. Oznacza to, że metoda signalStreamFlush
i inne metody (w szczególności configureStreams
) mogą dotrzeć do warstwy HAL kamery w innej kolejności niż kolejność, w jakiej zostały wywołane w środowisku kamery. Aby rozwiązać ten problem z asynchronią, do StreamConfiguration
dodano pole streamConfigCounter
i dodano je jako argument metody signalStreamFlush
. Implementacja warstwy HAL kamery powinna używać argumentu streamConfigCounter
w celu ustalenia, czy wywołanie signalStreamFlush
nadejdzie później niż odpowiadające mu wywołanie configureStreams
. Zobacz rysunek 3 jako przykład.
Rysunek 3. Jak kamera HAL powinna wykrywać i obsługiwać spóźnione wywołania SignalStreamFlush
Zachowanie zmienia się podczas implementowania interfejsów API zarządzania buforami
Korzystając z interfejsów API zarządzania buforami do implementacji logiki zarządzania buforami, należy wziąć pod uwagę następujące możliwe zmiany zachowania kamery i implementacji warstwy HAL kamery:
Żądania przechwytywania docierają do warstwy HAL kamery szybciej i częściej: bez interfejsów API do zarządzania buforami struktura kamery żąda buforów wyjściowych dla każdego żądania przechwytywania przed wysłaniem żądania przechwytywania do warstwy HAL kamery. Podczas korzystania z interfejsów API zarządzania buforami struktura kamery nie musi już czekać na bufory i dlatego może wcześniej wysyłać żądania przechwytywania do warstwy HAL kamery.
Ponadto bez interfejsów API do zarządzania buforami struktura kamery przestaje wysyłać żądania przechwytywania, jeśli jeden ze strumieni wyjściowych żądania przechwytywania osiągnął maksymalną liczbę buforów, jakie warstwa HAL może pomieścić jednocześnie (wartość ta jest wyznaczana przez warstwę HAL kamery w Pole
HalStream::maxBuffers
w wartości zwracanej przez wywołanieconfigureStreams
). W przypadku interfejsów API zarządzania buforami to zachowanie ograniczające już nie występuje, a implementacja warstwy HAL kamery nie może akceptować wywołańprocessCaptureRequest
, gdy warstwa HAL ma w kolejce zbyt wiele żądań przechwytywania.Opóźnienie wywołania
requestStreamBuffers
znacznie się różni: Istnieje wiele powodów, dla których wywołanierequestStreamBuffers
może zająć więcej czasu niż przeciętnie. Na przykład:- W przypadku kilku pierwszych buforów nowo utworzonego strumienia wywołania mogą trwać dłużej, ponieważ urządzenie musi przydzielić pamięć.
- Oczekiwane opóźnienie wzrasta proporcjonalnie do liczby buforów żądanych w każdym wywołaniu.
- Aplikacja przechowuje bufory i jest zajęta przetwarzaniem. Może to spowodować spowolnienie żądań bufora lub przekroczenie limitu czasu z powodu braku buforów lub zajętego procesora.
Strategie zarządzania buforami
Interfejsy API zarządzania buforami umożliwiają wdrażanie różnych rodzajów strategii zarządzania buforami. Oto kilka przykładów:
- Kompatybilny wstecz: warstwa HAL żąda buforów dla żądania przechwytywania podczas wywołania
processCaptureRequest
. Strategia ta nie zapewnia żadnych oszczędności pamięci, ale może służyć jako pierwsza implementacja interfejsów API zarządzania buforami, wymagająca bardzo niewielu zmian w kodzie w istniejącej warstwie HAL kamery. - Maksymalna oszczędność pamięci: kamera HAL żąda buforów wyjściowych tylko bezpośrednio przed koniecznością ich zapełnienia. Strategia ta umożliwia maksymalizację oszczędności pamięci. Potencjalną wadą jest większe zacinanie się potoku kamery, gdy żądania bufora trwają niezwykle długo.
- Buforowana: kamera HAL buforuje kilka buforów, dzięki czemu jest mniej prawdopodobne, że sporadyczne żądania powolnego bufora będą miały na nią wpływ.
Kamera HAL może przyjąć różne strategie dla konkretnych przypadków użycia, na przykład stosując strategię maksymalnego oszczędzania pamięci dla przypadków użycia, które zużywają dużo pamięci i stosując strategię kompatybilności wstecznej dla innych przypadków użycia.
Przykładowa realizacja w kamerze zewnętrznej HAL
Kamera zewnętrzna HAL została wprowadzona w systemie Android 9 i można ją znaleźć w drzewie źródłowym pod hardware/interfaces/camera/device/3.5/
. W systemie Android 10 został zaktualizowany w celu dołączenia ExternalCameraDeviceSession.cpp
, implementacji interfejsu API zarządzania buforami. Ta zewnętrzna kamera HAL implementuje strategię maksymalnego oszczędzania pamięci wspomnianą w Strategiach zarządzania buforami w kilkuset wierszach kodu C++.