Interfejsy API do zarządzania buforem w aparacie HAL3

Android 10 wprowadza opcjonalne interfejsy API zarządzania buforem HAL3 aparatu, które umożliwiają wdrożenie logiki zarządzania buforem w celu uzyskania różnych kompromisów między pamięcią a opóźnieniem przechwytywania w implementacjach HAL aparatu.

Warstwa HAL aparatu wymaga N żądań (gdzie N jest równe głębokości potoku) w kolejce w potoku, ale często nie wymaga wszystkich N zestawów buforów wyjściowych w tym samym czasie.

Na przykład w kolejce HAL może być 8 żądań, ale bufory wyjściowe są potrzebne tylko w przypadku 2 żądań na ostatnich etapach przetwarzania. Na urządzeniach z Androidem 9 i starszymi wersjami platforma aparatu przydziela bufory, gdy żądanie jest umieszczane w kolejce w warstwie HAL. W warstwie HAL może być 6 zestawów buforów, które nie są używane. W Androidzie 10 interfejsy API zarządzania buforami HAL3 aparatu umożliwiają odłączenie buforów wyjściowych, aby zwolnić 6 zestawów buforów. Może to prowadzić do oszczędności pamięci rzędu setek megabajtów na urządzeniach z wyższej półki, a także być korzystne w przypadku urządzeń z małą ilością pamięci.

Na rysunku 1 przedstawiono schemat interfejsu HAL aparatu na urządzeniach z Androidem 9 i starszymi wersjami. Ilustracja 2 przedstawia interfejs HAL aparatu w Androidzie 10 z zaimplementowanymi interfejsami API zarządzania buforem HAL3 aparatu.

Zarządzanie buforem w wersji 9 lub starszej

Rysunek 1. Interfejs HAL aparatu w Androidzie 9 i starszych wersjach

Zarządzanie buforem w Androidzie 10

Rysunek 2. Interfejs HAL aparatu w Androidzie 10 korzystający z interfejsów API do zarządzania buforami

Wdrażanie interfejsów API zarządzania buforem

Aby zaimplementować interfejsy API zarządzania buforem, HAL aparatu musi:

HAL aparatu używa metod requestStreamBuffers i returnStreamBuffers w interfejsie ICameraDeviceCallback.hal do wysyłania żądań buforów i ich zwracania. HAL musi też implementować metodę signalStreamFlush w interfejsie ICameraDeviceSession.hal, aby sygnalizować HAL-owi aparatu, że ma zwracać bufory.

requestStreamBuffers

Aby poprosić o bufory z platformy aparatu, użyj metody requestStreamBuffers. Gdy używasz interfejsów API HAL3 aparatu do zarządzania buforami, żądania przechwytywania z frameworka aparatu nie zawierają buforów wyjściowych, czyli pole bufferId w strukturze StreamBuffer ma wartość 0. Dlatego HAL aparatu musi używać requestStreamBuffers, aby wysyłać do platformy aparatu żądania buforów.

Metoda requestStreamBuffers umożliwia wywołującemu zażądanie wielu buforów z wielu strumieni wyjściowych w jednym wywołaniu, co pozwala zmniejszyć liczbę wywołań HIDL IPC. Jednak w przypadku jednoczesnego żądania większej liczby buforów połączenia trwają dłużej, co może negatywnie wpłynąć na całkowite opóźnienie od żądania do wyniku. Ponadto wywołania w requestStreamBuffers są serializowane w usłudze aparatu, dlatego zalecamy, aby HAL aparatu używał dedykowanego wątku o wysokim priorytecie do żądania buforów.

Jeśli żądanie bufora nie powiedzie się, HAL aparatu musi być w stanie prawidłowo obsłużyć błędy niekrytyczne. Poniżej znajdziesz listę najczęstszych przyczyn niepowodzeń żądań bufora oraz sposoby ich obsługi przez HAL aparatu.

  • Aplikacja odłącza się od strumienia wyjściowego: to błąd niekrytyczny. Warstwa HAL aparatu powinna wysyłać sygnał ERROR_REQUEST w przypadku każdego żądania przechwytywania kierowanego do odłączonego strumienia i być gotowa do normalnego przetwarzania kolejnych żądań.
  • Przekroczenie limitu czasu: może się to zdarzyć, gdy aplikacja jest zajęta intensywnym przetwarzaniem, a jednocześnie przechowuje niektóre bufory. Warstwa HAL aparatu powinna wysyłać ERROR_REQUEST w przypadku żądań przechwytywania, których nie można zrealizować z powodu błędu przekroczenia limitu czasu, i być gotowa do normalnego przetwarzania kolejnych żądań.
  • Framework aparatu przygotowuje nową konfigurację strumienia: HAL aparatu powinien poczekać, aż zakończy się kolejne wywołanie funkcji configureStreams przed ponownym wywołaniem funkcji requestStreamBuffers.
  • HAL aparatu osiągnął limit bufora (pole maxBuffers): HAL aparatu powinien poczekać, aż zwróci co najmniej 1 bufor strumienia, zanim ponownie wywoła requestStreamBuffers.

returnStreamBuffers

Użyj metody returnStreamBuffers , aby zwrócić dodatkowe bufory do struktury aparatu. HAL aparatu zwykle zwraca bufory do platformy aparatu za pomocą metody processCaptureResult, ale może uwzględniać tylko żądania przechwytywania, które zostały wysłane do HAL aparatu. W przypadku metody requestStreamBuffers implementacja HAL aparatu może zachować więcej buforów niż zażądała platforma aparatu. W takiej sytuacji należy użyć metody returnStreamBuffers. Jeśli implementacja HAL nigdy nie przechowuje więcej buforów niż żądane, implementacja HAL aparatu nie musi wywoływać metody returnStreamBuffers.

signalStreamFlush

Metoda signalStreamFlush jest wywoływana przez platformę aparatu, aby powiadomić HAL aparatu o konieczności zwrócenia wszystkich dostępnych buforów. Ta funkcja jest zwykle wywoływana, gdy framework kamery ma wywołać funkcję configureStreams i musi opróżnić potok przechwytywania obrazu z kamery. Podobnie jak w przypadku metody returnStreamBuffers, jeśli implementacja HAL aparatu nie zawiera więcej buforów niż wymagane, można mieć pustą implementację tej metody.

Gdy framework aparatu wywoła signalStreamFlush, przestanie wysyłać do HAL aparatu nowe żądania przechwytywania, dopóki wszystkie bufory nie zostaną zwrócone do frameworka aparatu. Gdy wszystkie bufory zostaną zwrócone, wywołania metody requestStreamBuffers zakończą się niepowodzeniem, a framework aparatu będzie mógł kontynuować pracę w czystym stanie. Framework aparatu wywołuje wtedy metodę configureStreams lub processCaptureRequest. Jeśli framework aparatu wywoła metodę configureStreams, interfejs HAL aparatu może ponownie zacząć wysyłać żądania buforów po pomyślnym powrocie wywołania configureStreams. Jeśli framework aparatu wywoła metodę processCaptureRequest, HAL aparatu może zacząć wysyłać żądania buforów podczas wywołania processCaptureRequest.

Semantyka metody signalStreamFlush i metody flush jest inna. Gdy wywoływana jest metoda flush, HAL może przerwać oczekujące żądania przechwytywania za pomocą ERROR_REQUEST, aby jak najszybciej opróżnić potok. Gdy wywoływana jest metoda signalStreamFlush, HAL musi normalnie zakończyć wszystkie oczekujące żądania przechwytywania i zwrócić wszystkie bufory do struktury 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 HAL aparatu w innej kolejności niż kolejność, w jakiej zostały wywołane w platformie aparatu. Aby rozwiązać ten problem z asynchronicznością, do streamConfigCounter dodano pole StreamConfiguration, które zostało też dodane jako argument do metody signalStreamFlush. Implementacja HAL aparatu powinna używać argumentu streamConfigCounter, aby określić, czy wywołanie signalStreamFlush następuje później 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 HAL kamery powinien wykrywać i obsługiwać wywołania signalStreamFlush, które docierają z opóźnieniem

Zmiany w działaniu podczas wdrażania interfejsów API zarządzania buforem

Podczas korzystania z interfejsów API do zarządzania buforem w celu wdrożenia logiki zarządzania buforem weź pod uwagę te możliwe zmiany w działaniu aparatu i implementacji HAL aparatu:

  • Żądania przechwytywania docierają do HAL aparatu szybciej i częściej: bez interfejsów API do zarządzania buforami framework aparatu wysyła żądania buforów wyjściowych dla każdego żądania przechwytywania przed wysłaniem żądania przechwytywania do HAL aparatu. Podczas korzystania z interfejsów API zarządzania buforem platforma aparatu nie musi już czekać na bufory, dzięki czemu może wcześniej wysyłać żądania przechwytywania do HAL aparatu.

    Ponadto bez interfejsów API do zarządzania buforami framework aparatu przestaje wysyłać żądania przechwytywania, jeśli jeden ze strumieni wyjściowych żądania przechwytywania osiągnie maksymalną liczbę buforów, które HAL może przechowywać w danym momencie (wartość ta jest określana przez HAL aparatu w polu HalStream::maxBuffers w wartości zwracanej wywołania configureStreams). Dzięki interfejsom API do zarządzania buforem to ograniczanie przepustowości nie występuje, a implementacja HAL aparatu nie może akceptować wywołań processCaptureRequest, gdy w kolejce HAL znajduje się zbyt wiele żądań przechwytywania.

  • requestStreamBuffers opóźnienie połączenia znacznie się różni: istnieje wiele powodów, dla których requestStreamBuffers połączenie może trwać dłużej niż średnia. 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 rośnie 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ń buforowania lub przekroczenie limitu czasu z powodu braku buforów lub zajętego procesora.

Strategie zarządzania buforem

Interfejsy API zarządzania buforem umożliwiają wdrażanie różnych strategii zarządzania buforem. Oto kilka przykładów:

  • Wsteczna zgodność: HAL żąda buforów dla żądania przechwytywania podczas wywołania processCaptureRequest. Ta strategia nie zapewnia oszczędności pamięci, ale może służyć jako pierwsza implementacja interfejsów API zarządzania buforem, która wymaga bardzo niewielu zmian w istniejącym HAL aparatu.
  • Maksymalne oszczędzanie pamięci: HAL aparatu żąda buforów wyjściowych tylko wtedy, gdy są one potrzebne do wypełnienia. Ta strategia pozwala maksymalnie oszczędzać pamięć. Potencjalną wadą jest większe zacinanie się potoku kamery, gdy żądania bufora trwają wyjątkowo długo.
  • Buforowanie: HAL aparatu buforuje kilka buforów, dzięki czemu jest mniej podatny na sporadyczne wolne żądania buforów.

HAL aparatu może stosować różne strategie w zależności od konkretnych przypadków użycia, np. strategię maksymalnego oszczędzania pamięci w przypadkach użycia, które wymagają dużej ilości pamięci, a strategię zgodną wstecznie w innych przypadkach użycia.

Przykładowa implementacja w HAL kamery zewnętrznej

Zewnętrzny HAL aparatu został wprowadzony w Androidzie 9 i znajduje się w drzewie źródłowym w lokalizacji hardware/interfaces/camera/device/3.5/. W Androidzie 10 został on zaktualizowany i zawiera ExternalCameraDeviceSession.cpp implementację interfejsu API zarządzania buforem. Ten zewnętrzny HAL aparatu wdraża strategię maksymalnego oszczędzania pamięci opisaną w sekcji Strategie zarządzania buforem w kilkuset wierszach kodu C++.