Android 10 wprowadza opcjonalne interfejsy API do zarządzania buforem camera HAL3, które umożliwiają implementację logiki zarządzania buforem w celu uzyskania różnych kompromisów między pamięcią a opóźnieniem w przypadku implementacji interfejsu camera HAL.
Interfejs HAL aparatu wymaga N żądań (gdzie N jest równe głębi potoku) w kole, ale często nie wymaga wszystkich N zestawów buforów wyjściowych w tym samym czasie.
Na przykład HAL może mieć 8 żądań w kole w systemie przetwarzania, ale potrzebuje tylko buforów wyjściowych dla 2 żądań w ostatnich etapach przetwarzania. Na urządzeniach z Androidem 9 lub starszym framework aparatu przydziela bufory, gdy prośba jest umieszczana w kole w interfejsie HAL, więc w interfejsie HAL może być 6 zestawów buforów, które nie są używane. W Androidzie 10 interfejsy API do zarządzania buforami w kamerze HAL3 umożliwiają rozdzielenie buforów wyjściowych, aby zwolnić 6 zestawów buforów. Może to prowadzić do oszczędności setek megabajtów pamięci na urządzeniach wysokiej klasy, a także przynieść korzyści w przypadku urządzeń o małej ilości pamięci.
Rys. 1 przedstawia diagram interfejsu HAL aparatu na urządzeniach z Androidem 9 lub starszym. Rysunek 2 przedstawia interfejs HAL aparatu w Androidzie 10 z zaimplementowanymi interfejsami API zarządzania buforem HAL3.
Rysunek 1. Interfejs Camera HAL w Androidzie 9 i starszych
Rysunek 2. Interfejs HAL aparatu w Androidzie 10 korzystający z interfejsów API do zarządzania buforem
Wdrażanie interfejsów API do zarządzania buforem
Aby zaimplementować interfejsy API zarządzania buforem, interfejs HAL aparatu musi:
- Zaimplementuj HIDL
ICameraDevice@3.5
. - Ustaw klucz właściwości aparatu
android.info.supportedBufferManagementVersion
naHIDL_DEVICE_3_5
.
HAL aparatu używa metod requestStreamBuffers
i returnStreamBuffers
do żądania i zwracania buforów.ICameraDeviceCallback.hal
Biblioteka HAL musi też implementować metodę signalStreamFlush
ICameraDeviceSession.hal
, aby sygnalizować bibliotece HAL aparatu, że ma zwrócić bufory.
requestStreamBuffers
Aby poprosić o bufory z ramki aparatu, użyj metody requestStreamBuffers
. Gdy używasz interfejsów API do zarządzania buforami w ramach aparatu HAL3, żądania rejestrowania z ramy aparatu nie zawierają buforów wyjściowych, czyli pole bufferId
w StreamBuffer
ma wartość 0
. Dlatego HAL aparatu musi używać funkcji requestStreamBuffers
, aby żądać buforów z ramy aparatu.
Metoda requestStreamBuffers
pozwala wywołującemu żądać wielu buforów z wielu strumieni wyjściowych w jednym wywołaniu, co pozwala ograniczyć liczbę wywołań HIDL IPC. Jednak wywołania zajmują więcej czasu, gdy jednocześnie jest wymagana większa liczba buforów, co może negatywnie wpłynąć na łączny czas od żądania do wyniku.
Ponadto, ponieważ wywołania do funkcji requestStreamBuffers
są serializowane w usłudze aparatu, zalecamy, aby interfejs HAL aparatu używał dedykowanego wątku o wysokim priorytecie do żądania buforów.
Jeśli żądanie bufora nie powiedzie się, interfejs HAL aparatu musi być w stanie prawidłowo obsłużyć błędy niekrytyczne. Poniżej znajdziesz listę najczęstszych przyczyn niepowodzeń żądań buforowania i sposób ich obsługi przez interfejs HAL aparatu.
- Aplikacja rozłącza się ze strumieniem wyjściowym: to błąd niekrytyczny. Interfejs HAL aparatu powinien wysyłać żądanie
ERROR_REQUEST
do każdego żądania rejestrowania, które kieruje do odłączonego strumienia, i być gotowy do przetwarzania kolejnych żądań w normalny sposób. - Limit czasu: może się to zdarzyć, gdy aplikacja jest zajęta intensywnym przetwarzaniem, a jednocześnie przechowuje niektóre bufory. Interfejs HAL aparatu powinien
wysyłać
ERROR_REQUEST
w przypadku żądań rejestrowania, których nie można zrealizować z powodu błędu limitu czasu, oraz być gotowy do przetwarzania kolejnych żądań w normalny sposób. - Framework aparatu przygotowuje nową konfigurację strumienia:
HAL aparatu powinien zaczekać, aż zakończy się wywołanie
configureStreams
, zanim ponownie wywołarequestStreamBuffers
. - HAL aparatu osiągnął limit bufora (pole
maxBuffers
): HAL aparatu powinien zaczekać, aż zwróci co najmniej 1 bufor strumienia, zanim ponownie wywoła funkcjęrequestStreamBuffers
.
returnStreamBuffers
Aby zwrócić dodatkowe bufory do aparatu, użyj metody returnStreamBuffers
. Interfejs HAL aparatu zazwyczaj zwraca do interfejsu aparatu za pomocą metody processCaptureResult
, ale może uwzględnić tylko żądania przechwytywania, które zostały wysłane do interfejsu HAL aparatu. W przypadku metody requestStreamBuffers
implementacja interfejsu HAL aparatu może zachować więcej buforów niż te, których wymaga interfejs aparatu. W takich przypadkach należy użyć metody returnStreamBuffers
. Jeśli implementacja HAL nigdy nie przechowuje więcej buforów niż wymagane, implementacja HAL aparatu nie musi wywoływać metody returnStreamBuffers
.
signalStreamFlush
Metoda signalStreamFlush
jest wywoływana przez framework kamery, aby powiadomić interfejs HAL kamery o konieczności zwrócenia wszystkich dostępnych buforów. Ta metoda jest zwykle wywoływana, gdy framework aparatu ma wywołać metodę configureStreams
i musi opróżnić potok przechwytywania aparatu. Podobnie jak w przypadku metody returnStreamBuffers
, jeśli implementacja interfejsu HAL aparatu nie przechowuje więcej buforów niż jest to wymagane, można użyć pustej implementacji tej metody.
Gdy framework aparatu wykona wywołanie signalStreamFlush
, przestaje wysyłać nowe żądania rejestrowania do interfejsu HAL aparatu, dopóki wszystkie bufory nie zostaną zwrócone do frameworku aparatu. Gdy wszystkie bufory zostaną zwrócone, wywołania metody requestStreamBuffers
zakończą się niepowodzeniem, a ramka aparatu może kontynuować pracę w czystym stanie. Następnie framework aparatu wywołuje metodę configureStreams
lub processCaptureRequest
. Jeśli framework aparatu wywoła metodę configureStreams
, po pomyślnym wywołaniu metody configureStreams
interfejs HAL aparatu może ponownie zacząć żądać buforów. Jeśli framework aparatu wywołuje metodę processCaptureRequest
, HAL aparatu może zacząć żądać buforów podczas wywołania processCaptureRequest
.
Metoda signalStreamFlush
różni się semantycznie od metody flush
. Gdy wywoływana jest metoda flush
, HAL może przerwać oczekujące żądania przechwytywania, aby jak najszybciej opróżnić kanał.ERROR_REQUEST
Gdy wywoływana jest metoda signalStreamFlush
, HAL musi normalnie zakończyć wszystkie oczekujące żądania przechwytywania i zwrócić wszystkie bufory do interfejsu aparatu.
Kolejną różnicą między metodą signalStreamFlush
a innymi metodami jest to, że signalStreamFlush
to jednokierunkowa metoda HIDL, co oznacza, że framework aparatu może wywoływać inne blokujące interfejsy API, zanim HAL otrzyma wywołanie signalStreamFlush
. Oznacza to, że metoda signalStreamFlush
i inne metody (w szczególności metoda configureStreams
) mogą docierać do aparatu HAL w innej kolejności niż kolejność wywołania w ramach interfejsu aparatu. Aby rozwiązać ten problem asynchroniczności, do metody StreamConfiguration
dodano pole streamConfigCounter
, a także jako argument dodano je do metody signalStreamFlush
. Implementacja HAL aparatu powinna używać argumentu streamConfigCounter
do określenia, czy wywołanie signalStreamFlush
jest późniejsze niż odpowiadające mu wywołanie configureStreams
. Przykład znajdziesz na rysunku 3.
Rysunek 3. Jak interfejs HAL aparatu powinien wykrywać i obsługiwać wywołania signalStreamFlush, które docierają z opóźnieniem
Zmiany w działaniu po wdrożeniu interfejsów API do zarządzania buforem
Podczas implementowania logiki zarządzania buforem za pomocą interfejsów API zarządzania buforem należy wziąć pod uwagę te możliwe zmiany zachowania aparatu i implementacji interfejsu HAL aparatu:
Żądania wykonania zdjęcia docierają do interfejsu HAL aparatu szybciej i częściej: bez interfejsów API do zarządzania buforami framework aparatu prosi o bufory wyjściowe dla każdego żądania wykonania zdjęcia, zanim prześle to żądanie do interfejsu HAL aparatu. Gdy używasz interfejsów API do zarządzania buforami, framework aparatu nie musi już czekać na bufory, więc może wcześniej wysyłać żądania rejestrowania do interfejsu HAL aparatu.
Ponadto bez interfejsów API do zarządzania buforami framework aparatu przestaje wysyłać żądania przechwytywania, jeśli jeden z wyjściowych strumieni żądania przechwytywania osiągnął maksymalną liczbę buforów, jaką może pomieścić HAL (ta wartość jest wyznaczana przez HAL aparatu w polu
HalStream::maxBuffers
w wartości zwracanej wywołaniaconfigureStreams
). Dzięki interfejsom API do zarządzania buforem nie ma już takiego ograniczania przepustowości, a implementacja interfejsu HAL aparatu nie może akceptować wywołańprocessCaptureRequest
, gdy ma zbyt wiele oczekujących żądań rejestrowania.Czas oczekiwania na połączenie
requestStreamBuffers
może się znacznie różnić: istnieje wiele powodów, dla których połączenierequestStreamBuffers
może trwać dłużej niż przeciętnie. Przykład:- W przypadku pierwszych kilku buforów nowo utworzonego strumienia wywołania mogą trwać dłużej, ponieważ urządzenie musi przydzielić pamięć.
- Oczekiwany czas oczekiwania zwiększa się proporcjonalnie do liczby buforów zażądanych w każdym wywołaniu.
- Aplikacja przechowuje bufory i przetwarza dane. Może to spowodować spowolnienie żądań buforowania lub przekroczenie limitu czasu z powodu braku buforów lub zajętego procesora.
Strategie zarządzania buforem
Interfejsy API do zarządzania buforem umożliwiają wdrażanie różnych strategii zarządzania buforem. Przykłady:
- Wsteczna zgodność: HAL prosi o bufory dla żądania rejestrowania podczas wywołania
processCaptureRequest
. Ta strategia nie pozwala na oszczędność pamięci, ale może służyć jako pierwsze wdrożenie interfejsów API do zarządzania buforem, wymagające bardzo niewielkich zmian w kodzie w istniejącym interfejsie HAL aparatu. - Maksymalizacja oszczędności pamięci: interfejs HAL aparatu prosi o bufory wyjściowe tylko tuż przed wypełnieniem jednego z nich. Ta strategia pozwala na zmaksymalizowanie oszczędności pamięci. Potencjalną wadą jest większa liczba żądań dotyczących strumienia kamery, gdy żądania buforowania trwają nienormalnie długo.
- Pamięć podręczna: interfejs HAL aparatu przechowuje w pamięci podręcznej kilka buforów, aby zmniejszyć prawdopodobieństwo wpływu na niego sporadycznie powolnego żądania bufora.
W przypadku niektórych zastosowań interfejs HAL aparatu może stosować różne strategie, na przykład strategię maksymalizacji oszczędzania pamięci w przypadku zastosowań, które zużywają dużo pamięci, oraz strategię zgodności wstecznej w innych przypadkach.
Przykładowa implementacja w interfejsie zewnętrznego aparatu HAL
Interfejs HAL aparatu zewnętrznego został wprowadzony w Androidzie 9 i można go znaleźć w drzewie źródłowym na stronie
hardware/interfaces/camera/device/3.5/
.
W Androidzie 10 interfejs ten został zaktualizowany i obsługuje ExternalCameraDeviceSession.cpp
, czyli implementację interfejsu API do zarządzania buforem. Ten HAL zewnętrznego aparatu fotograficznego implementuje strategię maksymalizacji oszczędzania pamięci wymienioną w artykule Strategie zarządzania buforem za pomocą kilkuset linii kodu C++.