Czujniki HAL 2.0

Warstwę sprzętową czujników (HAL) stanowi interfejs między frameworkiem czujników Androida a czujnikami urządzenia, takimi jak akcelerometr czy żyroskop. Interfejs HAL czujników definiuje funkcje, które muszą zostać zaimplementowane, aby umożliwić platformie sterowanie czujnikami.

Interfejs HAL Sensorów 2.0 jest dostępny w Androidzie 10 i nowszych na nowych i uaktualnionych urządzeniach. Interfejs Sensors HAL 2.0 jest oparty na interfejsie Sensors HAL 1.0, ale ma kilka kluczowych różnic, które uniemożliwiają zgodność wsteczną. Interfejs HAL czujników 2.0 używa szybkich kolejek wiadomości (FMQ) do wysyłania zdarzeń czujnika z interfejsu HAL do interfejsu czujników Androida.

Interfejs HAL czujników 2.1 jest dostępny w Androidzie 11 i nowszych na nowych i uaktualnionych urządzeniach. Interfejs Sensors HAL 2.1 to wersja interfejsu Sensors HAL 2.0, która udostępnia typ czujnika HINGE_ANGLE i aktualizuje różne metody, aby akceptować typ HINGE_ANGLE.

Interfejs HAL 2.1

Głównym źródłem dokumentacji interfejsu HAL Sensors HAL 2.1 jest definicja HAL w pliku hardware/interfaces/sensors/2.1/ISensors.hal. Jeśli wymagania na tej stronie są sprzeczne z wymaganiami na stronie ISensors.hal, zastosuj wymagania na stronie ISensors.hal.

Interfejs HAL 2.0

Głównym źródłem dokumentacji interfejsu HAL Sensors HAL 2.0 jest definicja HAL w pliku hardware/interfaces/sensors/2.0/ISensors.hal. Jeśli występuje sprzeczność między wymaganiami na tej stronie a na stronie ISensors.hal, zastosuj wymagania na stronie ISensors.hal.

Wdrożenie interfejsu Sensors HAL 2.0 i HAL 2.1

Aby zaimplementować interfejs Sensors HAL 2.0 lub 2.1, obiekt musi rozszerzyć interfejs ISensors i implementować wszystkie funkcje zdefiniowane w 2.0/ISensors.hal lub 2.1/ISensors.hal.

Inicjowanie HAL

Zanim można użyć interfejsu HAL czujników, musi on zostać zainicjowany przez interfejs API czujników Androida. Platforma wywołuje funkcję initialize() w przypadku HAL 2.0 i funkcję initialize_2_1() w przypadku HAL 2.1, aby przekazać 3 parametry do interfejsu HAL czujników: 2 deskryptory FMQ i 1 wskaźnik do obiektu ISensorsCallback.

HAL używa pierwszego deskryptora do utworzenia zdarzenia FMQ służącego do zapisywania zdarzeń czujnika w platformie. HAL używa drugiego deskryptora do utworzenia FMQ blokady uśpienia używanego do synchronizacji, gdy HAL zwalnia blokadę uśpienia dla zdarzeń WAKE_UP. HAL musi zapisać wskaźnik do obiektu ISensorsCallback, aby umożliwić wywoływanie wszystkich niezbędnych funkcji wywołania zwrotnego.

Funkcja initialize() lub initialize_2_1() musi być pierwszą funkcją wywoływaną przy inicjowaniu interfejsu HAL Sensors.

Udostępnij dostępne czujniki

Aby uzyskać listę wszystkich dostępnych czujników statycznych na urządzeniu, użyj funkcji getSensorsList() w HAL 2.0 i funkcji getSensorsList_2_1() w HAL 2.1. Ta funkcja zwraca listę czujników, z których każdy jest jednoznacznie zidentyfikowany przez swój identyfikator. Identyfikator danego czujnika nie może się zmienić, gdy proces hostujący czujnik HAL zostanie ponownie uruchomiony. Nicki mogą się zmieniać po ponownym uruchomieniu urządzenia oraz po ponownym uruchomieniu serwera systemu.

Jeśli kilka czujników ma ten sam typ i właściwości wybudzania, pierwszy czujnik na liście jest nazywany czujnikiem default (domyślnym) i jest zwracany do aplikacji, które korzystają z funkcji getDefaultSensor(int sensorType, bool wakeUp).

Stabilność listy czujników

Po ponownym uruchomieniu interfejsu HAL czujników, jeśli dane zwrócone przez getSensorsList() lub getSensorsList_2_1() wskazują na znaczną zmianę w porównaniu z listą czujników pobraną przed ponownym uruchomieniem, platforma uruchamia ponowne uruchamianie środowiska wykonawczego Androida. Znaczące zmiany w liście czujników obejmują przypadki, w których brakuje czujnika o danym identyfikatorze lub zmieniły się jego atrybuty, a także przypadki wprowadzenia nowych czujników. Restartowanie środowiska uruchomieniowego Androida może być uciążliwe dla użytkownika, ale jest konieczne, ponieważ platforma Android nie może już spełniać wymagań interfejsu API Androida, które mówią, że czujniki statyczne (niedynamiczne) nie mogą się zmieniać w trakcie działania aplikacji. Może to też uniemożliwić platformie ponowne nawiązanie połączeń z aktywizowanymi przez aplikacje żądaniami czujników. Dlatego dostawcy HAL powinni zapobiegać niepotrzebnym zmianom listy czujników.

Aby zapewnić stabilne uchwyty czujników, HAL musi w sposób deterministyczny przypisać dany czujnik fizyczny na urządzeniu do jego uchwytu. Chociaż interfejs HAL czujników nie wymaga konkretnej implementacji, deweloperzy mają do dyspozycji kilka opcji, które umożliwiają spełnienie tego wymagania.

Na przykład listę czujników można sortować za pomocą kombinacji stałych atrybutów każdego czujnika, takich jak dostawca, model i typ czujnika. Inną opcją jest wykorzystanie faktu, że zestaw czujników statycznych urządzenia jest stały, więc HAL musi wiedzieć, kiedy wszystkie oczekiwane czujniki zakończyły inicjalizację, zanim wrócą z getSensorsList() lub getSensorsList_2_1(). Ta lista oczekiwanych czujników może zostać skompilowana w plik binarny HAL lub zapisana w pliku konfiguracyjnym w systemie plików. Kolejność występowania może posłużyć do wyodrębnienia stabilnych uchwytów. Najlepsze rozwiązanie zależy od szczegółów implementacji HAL, ale kluczowym wymaganiem jest to, aby uchwyty czujnika nie zmieniały się po ponownym uruchomieniu HAL.

Konfigurowanie czujników

Przed aktywacją czujnika należy skonfigurować go za pomocą funkcji batch(), określając okres próbkowania i maksymalną latencję raportowania.

Czujnik musi mieć możliwość zmiany konfiguracji w dowolnym momencie za pomocą batch() bez utraty danych.

Okres próbkowania

Okres próbkowania ma różne znaczenie w zależności od typu skonfigurowanego czujnika:

  • Ciągłe: zdarzenia czujnika są generowane z ciągłą częstotliwością.
  • W przypadku zmiany: zdarzenia są generowane nie szybciej niż w okresie próbkowania i mogą być generowane z częstotliwością niższą niż okres próbkowania, jeśli zmierzona wartość się nie zmienia.
  • jednorazowy: okres próbkowania jest ignorowany;
  • Specjalne: więcej informacji znajdziesz w sekcji Typy czujników.

Informacje o zależności między okresem próbkowania a trybami raportowania czujnika znajdziesz w sekcji Tryby raportowania.

Maksymalne opóźnienie raportowania

Maksymalne opóźnienie raportowania określa maksymalny czas w nanosekundach, przez który zdarzenia mogą być opóźniane i przechowywane w FIFO sprzętowym, zanim zostaną zapisane do Event FMQ za pomocą HAL, gdy SoC jest aktywny.

Wartość 0 oznacza, że zdarzenia muszą być zgłaszane, gdy tylko zostaną zmierzone, albo pomijanie kolejki FIFO, albo opróżnianie kolejki FIFO, gdy tylko w kolejce FIFO pojawi się jedno zdarzenie z czujnika.

Na przykład akcelerometr aktywowany przy częstotliwości 50 Hz z maksymalnym opóźnieniem raportowania wynoszącym 0 wyzwalaczy przerywa działanie 50 razy na sekundę, gdy układ SoC jest aktywny.

Jeśli maksymalny czas oczekiwania na raportowanie jest większy niż 0, zdarzenia z czujnika nie muszą być zgłaszane od razu po ich wykryciu. Zdarzenia mogą być tymczasowo przechowywane w FIFO sprzętowym i raportowane w partiach, o ile żadne zdarzenie nie jest opóźnione o więcej niż maksymalny czas opóźnienia raportowania. Wszystkie zdarzenia od poprzedniej partii są rejestrowane i zwracane od razu. Pozwala to zmniejszyć liczbę przerwań wysyłanych do SoC i pozwala SoC przejść w tryb oszczędzania energii, gdy czujnik rejestruje i zbiera dane.

Z każdym zdarzeniem jest powiązana sygnatura czasowa. Opóźnienie momentu raportowania zdarzenia nie może wpływać na sygnaturę czasową tego zdarzenia. Musi być ona dokładna i odpowiadać czasowi wystąpienia zdarzenia, a nie czasowi jego zgłoszenia.

Więcej informacji i wymagania dotyczące raportowania zdarzeń czujnika z niezerową maksymalną latencją raportowania znajdziesz w sekcji Przesyłanie zbiorcze.

Aktywowanie czujników

Platforma włącza i wyłącza czujniki za pomocą funkcji activate(). Przed aktywacją czujnika framework musi go skonfigurować za pomocą batch().

Po dezaktywowaniu czujnika nie można zapisywać dodatkowych zdarzeń z tego czujnika do kolejki FMQ zdarzeń.

Czujniki spłukowania

Jeśli czujnik jest skonfigurowany do zbiorczego przesyłania danych, framework może wymusić natychmiastowe opróżnianie zbiorczego bufora zdarzeń czujnika, wywołując funkcję flush(). W efekcie zdarzenia czujnika w grupie dotyczące określonego identyfikatora czujnika są natychmiast zapisywane w kole Event FMQ. HAL czujników musi dołączyć zdarzenie flush complete do końca zdarzeń czujnika zapisywanych w wyniku wywołania funkcji flush().

Wyczyszczanie odbywa się asynchronicznie (czyli ta funkcja musi zwracać dane natychmiast). Jeśli implementacja używa jednego kolejki FIFO dla kilku czujników, ta kolej jest opróżniana, a zdarzenie o pełnym opróżnieniu jest dodawane tylko w przypadku określonego czujnika.

Jeśli wskazany czujnik nie ma kolejki FIFO (nie można buforować) lub jeśli kolejka FIFO była pusta w momencie wywołania, flush() musi zakończyć się sukcesem i wysłać zdarzenie flushcomplete dla tego czujnika. Dotyczy to wszystkich czujników oprócz jednorazowych.

Jeśli zasada flush() jest wywoływana dla czujnika pojedynczego uderzenia, funkcja flush() musi zwrócić wartość BAD_VALUE i nie może generować zdarzenia zakończenia opróżniania.

Zapisuj zdarzenia z czujnika w FMQ

Komunikacja FMQ zdarzeń jest używana przez interfejs HAL czujników do przesyłania zdarzeń czujnika do interfejsu czujników Androida.

Event FMQ to zsynchronizowany FMQ, co oznacza, że każda próba zapisania większej liczby zdarzeń do FMQ niż pozwala na to dostępne miejsce kończy się niepowodzeniem zapisu. W takim przypadku HAL powinien określić, czy zapisać bieżący zbiór zdarzeń jako 2 mniejsze grupy zdarzeń, czy zapisać wszystkie zdarzenia razem, jeśli jest wystarczająco dużo miejsca.

Gdy HAL Sensors zapisze pożądaną liczbę zdarzeń z czujnika w Event FMQ, musi powiadomić platformę o tym, że zdarzenia są gotowe, zapisując bit EventQueueFlagBits::READ_AND_PROCESS w funkcji EventFlag::wake zdarzenia FMQ. Flagę zdarzenia można utworzyć z kolejki zdarzeń za pomocą funkcji EventFlag::createEventFlag i funkcji getEventFlagWord() tej kolejki.

Interfejs HAL Sensorów 2.0/2.1 obsługuje zarówno write, jak i writeBlocking w ramach kolejki zdarzeń FMQ. Domyślna implementacja zawiera informacje o używaniu write. Jeśli używasz funkcji writeBlocking, flaga readNotification musi mieć wartość EventQueueFlagBits::EVENTS_READ, która jest ustawiana przez framework podczas odczytu zdarzeń z kolejki zdarzeń FMQ. Flaga powiadomienia o zapisie musi mieć wartość EventQueueFlagBits::READ_AND_PROCESS, która informuje framework, że zdarzenia zostały zapisane w kole FMQ zdarzeń.

Zdarzenia WAKE_UP

Zdarzenia WAKE_UP to zdarzenia czujnika, które powodują, że procesor aplikacji (AP) natychmiast się aktywuje i obsługuje zdarzenie. Za każdym razem, gdy zdarzenie WAKE_UP jest zapisywane w Event FMQ, interfejs HAL czujników musi zabezpieczyć blokadę aktywacji, aby system pozostał aktywny, dopóki framework nie będzie mógł obsłużyć zdarzenia. Po otrzymaniu zdarzenia WAKE_UP framework zabezpiecza własny blokadę aktywacji, co pozwala Sensorom HAL zwolnić blokadę aktywacji. Aby zsynchronizować dane, gdy interfejs HAL czujników zwolni blokadę aktywacji, użyj kolejki FMQ blokady aktywacji.

Interfejs HAL czujników musi odczytać interfejs FMQ Wake Lock, aby określić liczbę zdarzeń WAKE_UP, które zostały obsłużone przez ten interfejs. HAL powinna zwalniać blokadę uśpienia w przypadku zdarzeń WAKE_UP tylko wtedy, gdy łączna liczba nieobsłużonych zdarzeń WAKE_UP wynosi 0. Po obsłudze zdarzeń czujnika platforma zlicza liczbę zdarzeń oznaczonych jako zdarzenia WAKE_UP i zapisują tę liczbę z powrotem do Wake Lock FMQ.

Framework ustawia powiadomienie o zapisywaniu WakeLockQueueFlagBits::DATA_WRITTEN w Wake Lock FMQ za każdym razem, gdy zapisuje dane w Wake Lock FMQ.

Czujniki dynamiczne

Czujniki dynamiczne to czujniki, które nie są fizyczną częścią urządzenia, ale mogą być używane jako wejście do urządzenia, np. gamepad z akcelerometrem.

Gdy czujnik dynamiczny jest połączony, z HAL czujników należy wywołać funkcję onDynamicSensorConnectedISensorsCallback. Informuje on framework o nowym czujniku dynamicznym i umożliwia sterowanie nim za pomocą frameworku oraz wykorzystanie zdarzeń czujnika przez klientów.

Podobnie, gdy czujnik dynamiczny zostanie odłączony, należy wywołać funkcję onDynamicSensorDisconnected w funkcji ISensorsCallback, aby platforma mogła usunąć każdy czujnik, który nie jest już dostępny.

Kanał bezpośredni

Kanał bezpośredni to metoda działania, w której zdarzenia czujnika są zapisywane w specyficznej pamięci z pominięciem interfejsu Android Sensors Framework. Klient, który rejestruje kanał bezpośredni, musi odczytywać zdarzenia czujnika bezpośrednio z pamięci użytej do utworzenia kanału bezpośredniego i nie będzie otrzymywać zdarzeń z czujnika przez platformę. Funkcja configDirectReport() działa podobnie do funkcji batch() w przypadku zwykłego działania i konfiguruje kanał raportów bezpośrednich.

Funkcje registerDirectChannel()unregisterDirectChannel() tworzą lub usuwają nowy kanał bezpośredni.

Tryby operacji

Funkcja setOperationMode() umożliwia frameworkowi skonfigurowanie czujnika, aby mógł wstrzyknąć dane do czujnika. Jest to przydatne podczas testowania, zwłaszcza w przypadku algorytmów, które znajdują się poniżej frameworka.

Funkcja injectSensorData() w HAL 2.0 i funkcja injectSensorsData_2_1() w HAL 2.0 są zwykle używane do przesyłania parametrów operacyjnych do interfejsu HAL czujników. Ta funkcja może też służyć do wstrzykiwania zdarzeń z czujnika do konkretnego czujnika.

Weryfikacja

Aby sprawdzić poprawność implementacji interfejsu HAL Sensors, uruchom testy CTS i VTS czujnika.

Testy CTS

Testy CTS czujnika występują zarówno w automatycznych testach CTS, jak i w ręcznej aplikacji CTS Verifier.

Testy automatyczne znajdują się w katalogu cts/tests/sensor/src/android/hardware/cts. Te testy służą do sprawdzania standardowych funkcji czujników, takich jak aktywowanie czujników, grupowanie i częstotliwość zdarzeń z czujników.

Testy CTS Verifier znajdują się w katalogu cts/apps/CtsVerifier/src/com/android/cts/verifier/sensors. Testy te wymagają ręcznego wprowadzenia danych przez operatora testowego i zapewniają, że czujniki przekazują dokładne wartości.

Przejście testów CTS jest kluczowe, aby mieć pewność, że testowane urządzenie spełnia wszystkie wymagania CDD.

Testy VTS

Testy VTS dla interfejsu Sensors HAL 2.0 znajdują się w folderze hardware/interfaces/sensors/2.0/vts. Testy VTS dla interfejsu Sensors HAL 2.1 znajdują się w folderze hardware/interfaces/sensors/2.1/vts. Te testy sprawdzają, czy interfejs HAL czujników jest prawidłowo zaimplementowany i czy są spełnione wszystkie wymagania w dokumentach ISensors.halISensorsCallback.hal.

Przejście z wersji 2.0 na 2.1 interfejsu API interfejsu API czujników

Podczas aktualizacji z wersji 2.0 na 2.1 interfejsu HAL interfejs HAL musi zawierać metody initialize_2_1(), getSensorsList_2_1()injectSensorsData_2_1() oraz typy HAL 2.1. Te metody muszą spełniać te same wymagania, które zostały opisane powyżej w przypadku HAL 2.0.

Konta HAL w wersji podrzędnej muszą obsługiwać wszystkie funkcje z poprzednich wersji HAL, dlatego ich obsługa w wersji 2.1 musi obsługiwać inicjowanie jako takich kont w wersji 2.0. Aby uniknąć złożoności związanej z obsługą obu wersji HAL, zdecydowanie zalecamy używanie Multi-HAL 2.1.

Przykład implementacji własnego interfejsu HAL interfejsu Sensors 2.1 znajdziesz w pliku Sensors.h.

Przejście z wersji 1.0 na 2.0 interfejsu HAL czujników

Podczas aktualizacji z HAL 1.0 na 2.0 sprawdź, czy implementacja HAL spełnia te wymagania.

Inicjowanie HAL

Aby utworzyć FMQ między frameworkiem a HAL, musi być obsługiwana funkcja initialize().

Wyświetlanie dostępnych czujników

W Sensors HAL 2.0 funkcja getSensorsList() musi zwracać tę samą wartość podczas uruchamiania urządzenia, nawet po ponownym uruchomieniu interfejsu Sensors HAL. Nowym wymaganiem funkcji getSensorsList() jest to, że musi ona zwracać tę samą wartość podczas uruchamiania urządzenia, nawet po ponownym uruchomieniu interfejsu HAL czujników. Dzięki temu framework może próbować ponownie nawiązać połączenia z czujnikami, jeśli serwer systemowy zostanie ponownie uruchomiony. Wartość zwracana przez getSensorsList() może się zmienić po ponownym uruchomieniu urządzenia.

Zapisuj zdarzenia z czujnika w FMQ

Zamiast czekać na wywołanie funkcji poll(), w Sensors HAL 2.0 czujniki muszą aktywnie zapisywać zdarzenia czujników w Event FMQ, gdy tylko są dostępne. HAL odpowiada też za zapisywanie odpowiednich bitów do EventFlag, aby wywołać odczyt FMQ w ramach frameworka.

Zdarzenia WAKE_UP

W wersji 1.0 interfejsu HAL dla czujników można było zwolnić blokadę aktywacji dla dowolnego zdarzenia WAKE_UP w dowolnym kolejnym wywołaniu funkcji poll() po opublikowaniu zdarzenia WAKE_UP w funkcji poll(), ponieważ oznaczało to, że framework przetworzył wszystkie zdarzenia czujnika i w razie potrzeby uzyskał blokadę aktywacji. Jako że w interfejsie Sensors HAL 2.0 HAL nie wie już, kiedy platforma przetworzyła zdarzenia zapisane w FMQ, umożliwia to jej komunikowanie się z HAL, gdy obsługuje ona zdarzenia WAKE_UP.

W Sensors HAL 2.0 blokada wybudzania zabezpieczona przez interfejs Sensors HAL w przypadku zdarzeń WAKE_UP musi się zaczynać od SensorsHAL_WAKEUP.

Czujniki dynamiczne

Czujniki dynamiczne zostały zwrócone przy użyciu funkcji poll() w programie Sensors HAL 1.0. Interfejs HAL czujników 2.0 wymaga wywołania funkcji onDynamicSensorsConnectedonDynamicSensorsDisconnectedISensorsCallback, gdy zmieniają się dynamiczne połączenia czujników. Te wywołania zwrotne są dostępne jako część wskaźnika ISensorsCallback dostarczanego przez funkcję initialize().

Tryby działania

Tryb DATA_INJECTION czujników WAKE_UP musi być obsługiwany w Sensors HAL 2.0.

Obsługa wielu HAL

Interfejs HAL czujników w wersji 2.0 i 2.1 obsługuje interfejs multi-HAL za pomocą ramy interfejsu multi-HAL czujników. Szczegółowe informacje o wdrożeniu znajdziesz w artykule Przenoszenie z Sensors HAL 1.0.