Interfejsy API do zarządzania buforem w aparacie HAL3

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.

Zarządzanie buforem w Androidzie 9 lub starszym

Rysunek 1. Interfejs Camera HAL w Androidzie 9 i starszych

Zarządzanie buforem w Androidzie 10

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:

HAL aparatu używa metod requestStreamBuffers i returnStreamBuffers do żądania i zwracania buforów.ICameraDeviceCallback.hal Biblioteka HAL musi też implementować metodę signalStreamFlushICameraDeviceSession.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 bufferIdStreamBuffer 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ła requestStreamBuffers.
  • 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.

Obsługa połączeń, które docierają z opóźnieniem

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łania configureStreams). 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łączenie requestStreamBuffers 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++.