Interfejsy API do zarządzania buforem w aparacie HAL3

Android 10 wprowadza opcjonalne interfejsy API zarządzania buforami HAL3 aparatu, które umożliwiają wdrożenie logiki zarządzania buforami 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 swoim potoku, ale często nie wymaga wszystkich N zestawów buforów wyjściowych w tym samym czasie.

Na przykład HAL może mieć w kolejce 8 żądań, ale potrzebuje buforów wyjściowych tylko dla 2 żądań na ostatnich etapach przetwarzania. Na urządzeniach z Androidem 9 i starszym struktura aparatu przydziela bufory, gdy żądanie jest umieszczane w kolejce w warstwie HAL. W warstwie HAL może więc znajdować się 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 przynosić korzyści na urządzeniach z małą ilością pamięci.

Rysunek 1 przedstawia diagram interfejsu HAL aparatu na urządzeniach z Androidem 9 i starszym. 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, warstwa 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 konieczność zwrócenia buforów.

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 bufferIdStreamBuffer jest 0. Dlatego HAL aparatu musi używać funkcji 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 ramach jednego wywołania, co pozwala zmniejszyć liczbę wywołań HIDL IPC. Jednak gdy jednocześnie żądanych jest więcej 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 się nie powiedzie, 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 korzysta z buforów. 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 do zwracania dodatkowych buforów do platformy 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 struktura 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ę kamery, aby powiadomić HAL kamery o konieczności zwrócenia wszystkich dostępnych buforów. Ta metoda jest zwykle wywoływana, gdy framework kamery ma wywołać metodę configureStreams i musi opróżnić potok przechwytywania obrazu z kamery. Podobnie jak w przypadku metody returnStreamBuffers, jeśli implementacja HAL kamery nie zawiera więcej buforów niż wymagane, można zastosować pustą implementację tej metody.

Gdy framework aparatu wywoła funkcję signalStreamFlush, przestaje 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 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 różni się. 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 platformy 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 do 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 buforem framework aparatu żąda buforów wyjściowych dla każdego żądania przechwytywania przed wysłaniem żądania przechwytywania do HAL aparatu. Gdy używasz interfejsów API do zarządzania buforem, framework aparatu nie musi już czekać na bufory, więc 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 połączenie requestStreamBuffers może trwać dłużej niż średnia. Na 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. Przykłady:

  • Zgodność wsteczna: 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 bezpośrednio przed ich wypełnieniem. 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 zewnętrznej warstwie HAL aparatu

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++.