Wiele obecnych architektur pojazdów zawiera wiele elektronicznych jednostek sterujących (ECU) poza systemem multimedialnym, które kontrolują ergonomię, np. ustawienia siedzeń i regulację lusterek. Biorąc pod uwagę obecne rozwiązania sprzętowe i architektury zasilania, wiele urządzeń ECU włącza się przed włączeniem systemu multimedialnego opartego na Androidzie. Te sterowniki mogą współpracować z systemem multimedialno-rozrywkowym opartym na Androidzie za pomocą warstwy abstrakcji sprzętu pojazdu (VHAL).
Od Androida 11 system operacyjny Android Automotive (AAOS) zawiera nowy zestaw właściwości VHAL do tworzenia, przełączania, usuwania i kojarzenia akcesoriów zewnętrznych w celu identyfikowania użytkowników. Te nowe właściwości umożliwiają na przykład kierowcy sparowanie zewnętrznego akcesorium, takiego jak pilot, z użytkownikiem Androida. Gdy kierowca zbliża się do pojazdu, jednostka sterująca ECU się włącza i wykrywanie kluczyka. Ta funkcja ECU wskazuje HAL, który użytkownik Androida powinien uruchomić system multimedialny. Skraca to czas oczekiwania kierowcy na wczytanie użytkownika Androida.
Włączanie interfejsu HAL użytkownika
Właściwości HAL użytkownika muszą być włączone, co wymaga ustawienia właściwości systemowej android.car.user_hal_enabled
na true
.
(możesz to zrobić w pliku car.mk
, aby nie trzeba było go ustawiać ręcznie). Sprawdź, czy user_hal_enabled=true
jest włączona, wykonując kopię pliku UserHalService
:
$ adb shell dumpsys car_service --hal UserHalService|grep enabled user_hal_enabled=true
Możesz też sprawdzić user_hal_enabled
, używając adb shell
getprop android.car.user_hal_enabled
lub adb logcat
CarServiceHelper *:s
. Jeśli usługa jest wyłączona, po uruchomieniu system_server
wyświetli się komunikat podobny do tego:
I CarServiceHelper: Not using User HAL
Aby ręcznie włączyć user_hal_enabled
, ustaw właściwość systemową android.car.user_hal_enabled
i ponownym uruchomieniu system_server
:
$ adb shell setprop android.car.user_hal_enabled true $ adb shell stop && adb shell start
Dane wyjściowe logcat
wyglądają tak:
I CarServiceHelper: User HAL enabled with timeout of 5000ms D CarServiceHelper: Got result from HAL: OK I CarServiceHelper: User HAL returned DEFAULT behavior
Właściwości HAL użytkownika
Właściwości cyklu życia użytkownika
Te właściwości dostarczają informacji HAL o stanach cyklu życia użytkownika, które umożliwiają synchronizację cyklu życia użytkownika między systemem Android a zewnętrznym ECU. Te właściwości korzystają z protokołu żądania i odpowiedzi, w którym system Android wysyła żądanie przez ustawienie wartości właściwości, a HAL odpowiada, wysyłając zdarzenie zmiany właściwości.
Uwaga: gdy obsługiwany jest interfejs HAL użytkownika, należy zaimplementować wszystkie te właściwości.
Właściwość HAL | Opis |
---|---|
INITIAL_USER_INFO (odczyt/zapis) |
Ta właściwość jest wywoływana przez system Android, aby określić, którego użytkownika Androida uruchomić po uruchomieniu urządzenia lub wznowieniu z pamięci podręcznej (STR). Po wywołaniu HAL musi odpowiedzieć jedną z tych opcji:
Uwaga: jeśli interfejs HAL nie odpowiada, domyślnie jest wykonywany po upływie czasu oczekiwania (domyślnie 5 sekund), co opóźnia rozruch. Jeśli HAL odpowie, ale system Android nie wykona działania (na przykład po osiągnięciu maksymalnej liczby użytkowników), używane jest działanie domyślne. Przykład: po uruchomieniu system Android uruchamia ostatnio aktywnego użytkownika. Jeśli wykryto kluczyk innego użytkownika, ECU zastąpi właściwość HAL, a podczas uruchamiania system Android przełączy się na uruchomienie tego użytkownika. |
SWITCH_USER (odczyt/zapis) |
Ta właściwość jest wywoływana podczas przełączania aktywnego użytkownika na pierwszym planie w Androidzie.
Właściwość może zostać wywołana przez system Android lub przez HAL, aby zażądać przełączenia użytkownika. Te 3 procesy to:
Nowoczesny przepływ pracy wykorzystuje dwufazowe zatwierdzanie, aby zapewnić synchronizację systemu Android i zewnętrznego ECU. Gdy Android zainicjuje przełączenie:
HAL powinien poczekać na odpowiedź Przykład: podczas jazdy kierowca próbuje przełączyć użytkowników Androida w interfejsie systemu informacyjno-rozrywkowego. Ponieważ jednak ustawienia fotela samochodowego są powiązane z użytkownikiem Androida, fotel przesuwa się, gdy użytkownik przełącza urządzenie. W związku z tym ECU sterujący fotelami nie potwierdza przełączenia, HAL odpowiada błędem, a użytkownik Androida nie jest przełączany.
Stary proces to wywołanie jednokierunkowe wysyłane po przełączeniu użytkownika (tak, aby HAL nie mógł zablokować przełączenia). Jest wywoływany tylko podczas uruchamiania (po początkowej zmianie użytkownika) lub w przypadku aplikacji, które wywołują funkcję
Przykład: jeśli aplikacja używa do przełączania użytkowników Proces związany z pojazdem pochodzi z HAL, a nie z systemu Android:
Przykład: Bob używał kluczyka Alice, aby otworzyć samochód. HAL odpowiedział na żądanie |
CREATE_USER (odczyt/zapis) |
Ta właściwość jest wywoływana przez system Androida, gdy tworzony jest nowy użytkownik Androida (za pomocą interfejsu API CarUserManager.createUser() ).
HAL odpowiada za pomocą Przykład: kierowca klika ikonę interfejsu systemu infotainment, aby utworzyć nowego użytkownika Androida. Spowoduje to wysłanie żądania do interfejsu HAL i pozostałych podsystemów pojazdu. ECU są informowane o nowo utworzonym użytkowniku. Inne podsystemy i ECU przypisują następnie swój wewnętrzny identyfikator użytkownika do identyfikatora użytkownika Androida. |
REMOVE_USER (Tylko do zapisu) |
System Android wywołuje tę właściwość po usunięciu użytkownika Androida (za pomocą metody CarUserManager.removeUser() ).
Jest to połączenie jednokierunkowe i HAL nie oczekuje na odpowiedź. Przykład: kierowca klika, aby usunąć istniejącego użytkownika Androida w interfejsie systemu informacyjno-rozrywkowego. System HAL oraz inne podsystemy pojazdu i ECU są informowane o usunięciu użytkownika, aby mogły usunąć jego wewnętrzny identyfikator. |
Dodatkowe właściwości
Poniżej znajdują się dodatkowe właściwości, które nie są powiązane ze stanami cyklu życia użytkownika. Każdą z nich można zaimplementować bez obsługi interfejsu HAL użytkownika.
Właściwość HAL | Opis |
---|---|
USER_IDENTIFICATION_ASSOCIATION (odczyt/zapis) |
Użyj tej właściwości, aby powiązać dowolnego użytkownika Androida z mechanizmem identyfikacji, takim jak brelok do kluczy lub telefon. Użyj tej samej właściwości do powiązań get lub set .
Przykład: kierowca klika ikonę w interfejsie systemu multimedialnego, aby powiązać kluczyk do otwierania pojazdu ( |
Biblioteki pomocnicze
Wszystkie obiekty używane w wiadomościach z prośbą i odpowiedzią (takie jak UserInfo
, InitialUserInfoRequest
, InitialUSerInfoResponse
itd.) mają reprezentacje wysokiego poziomu za pomocą C++ struct
, ale usunięcie musi być spłaszczone w standardowe obiekty VehiclePropValue
(patrz przykłady poniżej). Aby ułatwić proces tworzenia, w AOSP udostępniono bibliotekę pomocniczą C++, która automatycznie konwertuje structs
HAL użytkownika na VehiclePropValue
(i odwrotnie).
Przykłady
INITIAL_USER_INFO
Przykład żądania (przy pierwszym uruchomieniu)
VehiclePropValue { // flattened from InitialUserInfoRequest prop: 299896583 // INITIAL_USER_INFO prop.values.int32Values: [0] = 1 // Request ID [1] = 1 // InitialUserInfoRequestType.FIRST_BOOT [2] = 0 // user id of current user [3] = 1 // flags of current user (SYSTEM) [4] = 1 // number of existing users [5] = 0 // existingUser[0].id [6] = 1 // existingUser[0].flags }
Przykładowa odpowiedź (utwórz administratora)
VehiclePropValue { // flattened from InitialUserInfoResponse prop: 299896583 // INITIAL_USER_INFO prop.values.int32Values: [0] = 1 // Request ID (must match request) [1] = 2 // InitialUserInfoResponseAction.CREATE [2] = -10000 // user id (not used on CREATE) [3] = 8 // user flags (ADMIN) prop.values.stringValue: "en-US||Car Owner" // User locale and user name }
SWITCH_USER
Rzeczywista nazwa klas i właściwości nieco się różni, ale ogólny przepływ pracy jest taki sam, jak na ilustracji:
Rysunek 1. Proces właściwości HAL użytkownika.
Przykład żądania w ramach nowoczesnego przepływu pracy
VehiclePropValue { // flattened from SwitchUserRequest prop: 299896585 // SWITCH_USER prop.values.int32Values: [0] = 42 // Request ID [1] = 2 // SwitchUserMessageType::ANDROID_SWITCH ("modern") [2,3] = 11,0 // target user id (11) and flags (none in this case) [4,5] = 10,8 // current user id (10) and flags (ADMIN) [6] = 3 // number of existing users (0, 10, 11) [7,8] = 0,1 // existingUser[0] (id=0, flags=SYSTEM) [9,10] = 10,8 // existingUser[1] (id=10, flags=ADMIN) [11,12] = 11,0 // existingUser[2] (id=11, flags=NONE) }
Przykład odpowiedzi w ramach nowoczesnego przepływu pracy
VehiclePropValue { // flattened from SwitchUserResponse prop: 299896584 // SWITCH_USER prop.values.int32Values: [0] = 42 // Request ID (must match request) [1] = 3 // SwitchUserMessageType::VEHICLE_RESPONSE [2] = 1 // SwitchUserStatus::SUCCESS }
Przykład odpowiedzi po zmianie przepływu pracy w nowoczesnym procesie
Ta odpowiedź zwykle występuje wtedy, gdy po przełączeniu się na Androida:
VehiclePropValue { // flattened from SwitchUserRequest prop: 299896584 // SWITCH_USER prop.values.int32Values: [0] = 42 // Request ID (must match "pre"-SWITCH_USER request ) [1] = 5 // SwitchUserMessageType::ANDROID_POST_SWITCH [2,3] = 11,0 // target user id (11) and flags (none in this case) [4,5] = 11,0 // current user id (11) and flags (none in this case) [6] = 3 // number of existing users (0, 10, 11) [7,8] = 0,1 // existingUser[0] (id=0, flags=SYSTEM) [9,10] = 10,8 // existingUser[1] (id=10, flags=ADMIN) [11,12] = 11,0 // existingUser[2] (id=11, flags=NONE) }
Odpowiedź po zmianie przepływu pracy w nowoczesnym procesie
Ta odpowiedź zwykle występuje, gdy przełącznik Androida nie działa:
VehiclePropValue { // flattened from SwitchUserRequest prop: 299896584 // SWITCH_USER prop.values.int32Values: [0] = 42 // Request ID (must match "pre"-SWITCH_USER request ) [1] = 5 // SwitchUserMessageType::ANDROID_POST_SWITCH [2,3] = 11,0 // target user id (11) and flags (none in this case) [4,5] = 10,8 // current user id (10) and flags (ADMIN) [6] = 3 // number of existing users (0, 10, 11) [7,8] = 0,1 // existingUser[0] (id=0, flags=SYSTEM) [9,10] = 10,8 // existingUser[1] (id=10, flags=ADMIN) [11,12] = 11,0 // existingUser[2] (id=11, flags=NONE) }
Przykład prośby o przesłanie starszego procesu
VehiclePropValue { // flattened from SwitchUserRequest prop: 299896584 // SWITCH_USER prop.values.int32Values: [0] = 2 // Request ID [1] = 1 // SwitchUserMessageType::LEGACY_ANDROID_SWITCH [2,3] = 10,8 // target user id (10) and flags (ADMIN) [4,5] = 0,1 // current user id (0) and flags (SYSTEM) [6] = 3 // number of existing users (0, 10, 11) [7,8] = 0,1 // existingUser[0] (id=0, flags=SYSTEM) [9,10] = 10,8 // existingUser[1] (id=10, flags=ADMIN) [11,12] = 11,0 // existingUser[2] (id=11, flags=NONE) }
Przykład żądania dotyczącego przepływu pracy związanego z pojazdem
VehiclePropValue { // flattened from SwitchUserRequest prop: 299896584 // SWITCH_USER prop.values.int32Values: [0] = -108 // Request ID (must be negative) [1] = 4 // SwitchUserMessageType::VEHICLE_REQUEST [2] = 11 // target user id }
Odpowiedź po zmianie starszego procesu
Ta odpowiedź zwykle występuje, gdy przełączenie na Androida zakończy się powodzeniem:
VehiclePropValue { // flattened from SwitchUserRequest prop: 299896584 // SWITCH_USER prop.values.int32Values: [0] = -108 // Request ID (must match from vehicle request ) [1] = 5 // SwitchUserMessageType::ANDROID_POST_SWITCH [2,3] = 11,0 // target user id (11) and flags (none in this case) [4,5] = 11,0 // current user id (11) and flags (none in this case) [6] = 3 // number of existing users (0, 10, 11) [7,8] = 0,1 // existingUser[0] (id=0, flags=SYSTEM) [9,10] = 10,8 // existingUser[1] (id=10, flags=ADMIN) [11,12] = 11,0 // existingUser[2] (id=11, flags=NONE) }
CREATE_USER
Przykład żądania
VehiclePropValue { // flattened from CreateUserRequest prop: 299896585 // CREATE_USER prop.values.int32Values: [0] = 42 // Request ID [1,2] = 11,6 // Android id of the created user and flags (id=11, flags=GUEST, EPHEMERAL) [3,4] = 10,0 // current user id (10) and flags (none in this case) [5] = 3 // number of existing users (0, 10, 11) [6,7] = 0,1 // existingUser[0] (id=0, flags=SYSTEM) [8,9] = 10,8 // existingUser[1] (id=10, flags=ADMIN) [10,11] = 11,6 // newUser[2] (id=11, flags=GUEST,EPHEMERAL) }
Przykład odpowiedzi
VehiclePropValue { // flattened from CreateUserResponse prop: 299896585 // CREATE_USER prop.values.int32Values: [0] = 42 // Request ID (must match request) [1] = 3 // CreateUserStatus::SUCCESS }
REMOVE_USER
Przykład żądania
VehiclePropValue { // flattened from RemoveUserRequest prop: 299896586 // REMOVE_USER prop.values.int32Values: [0] = 42 // Request ID [1,2] = 11,0 // Android id of the removed user and flags (none in this case) [3,4] = 10,0 // current user id (10) and flags (none in this case) [5] = 2 // number of existing users (0, 10) [6,7] = 0,1 // existingUser[0] (id=0, flags=SYSTEM) [8,9] = 10,8 // existingUser[1] (id=10, flags=ADMIN) }
USER_IDENTIFICATION_ASSOCIATION
Przykład ustawienia (kluczyk związany z użytkownikiem 10)
VehiclePropValue { // flattened from UserIdentificationSetRequest prop: 299896587 // USER_IDENTIFICATION_ASSOCIATION prop.values.int32Values: [0] = 43 // Request ID [1,2] = 10,0 // Android id (10) and flags (none in this case) [3] = 1 // number of associations being set [4] = 1 // 1st type: UserIdentificationAssociationType::KEY_FOB [5] = 1 // 1st value: UserIdentificationAssociationSetValue::ASSOCIATE_CURRENT_USER }