Właściwości HAL użytkownika

Wiele obecnych architektur pojazdów zawiera wiele elektronicznych jednostek sterujących (ECU) poza systemem informacyjno-rozrywkowym, które kontrolują ergonomię, np. ustawienia siedzeń i regulację lusterek. Na podstawie obecnych architektur sprzętu i zasilania wiele ECU uruchamia się przed uruchomieniem 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) wprowadził nowy zestaw właściwości w 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. Ten sterownik ECU wskazuje HAL, który powinien uruchomić użytkownika Androida, co skraca czas oczekiwania na załadowanie danych użytkownika Androida.

Włączanie interfejsu HAL użytkownika

Właściwości HAL użytkownika muszą być włączone w sposób jawny. W tym celu należy ustawić wartość 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ę 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 system ma uruchomić po uruchomieniu urządzenia lub wznowieniu z pamięci podręcznej (STR). Po wywołaniu HAL musi odpowiedzieć jedną z tych opcji:
  • Domyślne zachowanie ustawione przez Androida (przełączenie na ostatnio używanego użytkownika lub utworzenie nowego użytkownika, jeśli jest to pierwszy rozruch).
  • Przełącz się na istniejącego użytkownika.
  • Utwórz nowego użytkownika (z opcjonalnymi właściwościami, takimi jak nazwa, flagi, locale systemu itp.) i przełącz się na tego użytkownika.

Uwaga: jeśli interfejs HAL nie odpowiada, domyślnie jest wykonywany po upływie czasu oczekiwania (domyślnie 5 sekund), co opóźnia uruchamianie. Jeśli HAL odpowie, ale system Android nie wykona działania (na przykład jeśli osiągnięto maksymalną liczbę użytkowników), zostanie użyte domyślne działanie.

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 konkretnego 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 być wywoływana przez system Android lub przez HAL w celu poproszenia o przełączenie użytkownika. Te 3 procesy to:
  • Nowoczesny. Przejście rozpoczęte z CarUserManager.
  • Starsza wersja. Przejście rozpoczęte z ActivityManager.
  • Pojazd. Wywoływany przez HAL, aby poprosić o przełączenie użytkownika.

Nowoczesny przepływ pracy wykorzystuje dwufazowe zatwierdzanie, aby zapewnić synchronizację systemu Android i zewnętrznego ECU. Gdy Android inicjuje przełączenie:

  1. Sprawdź HAL, aby określić, czy można zmienić użytkownika.

    HAL odpowiada za pomocą SUCCESS lub FAILURE, aby Android wiedział, czy kontynuować, czy nie.

  2. Przełącz użytkownika na Androidzie.

    Android wysyła do HAL odpowiedź ANDROID_POST_SWITCH, aby wskazać, czy przełączenie się powiodło.

HAL powinien poczekać na odpowiedź ANDROID_POST_SWITCH, aby zaktualizować swój stan w celu zsynchronizowania ECU lub zaktualizowania innych właściwości HAL.

Przykład: podczas jazdy kierowca próbuje przełączyć użytkowników Androida w interfejsie systemu informacyjno-rozrywkowego. Ustawienia fotelika samochodowego są jednak powiązane z użytkownikiem Androida, więc fotel zmienia pozycję podczas przełączania użytkowników. 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ę ActivityManager.switchUser() zamiast CarUserManager.switchUser(). Aplikacje referencyjne SettingsSystemUI korzystają już z tego pierwszego, ale jeśli OEM udostępnia własne aplikacje Ustawienia, OEM powinien zmienić sposób ich używania.

Przykład: jeśli aplikacja używa interfejsu ActivityManager.switchUser() do przełączania użytkowników, wysyłana jest do HAL-a jednokierunkowa wywołania, aby poinformować o zmianie użytkownika.

Proces dotyczący pojazdu pochodzi z interfejsu HAL, a nie z systemu Android:

  1. HAL prosi o przełączenie użytkownika.
  2. System przełączy użytkownika Androida.
  3. Android wysyła do HAL odpowiedź ANDROID_POST_SWITCH, aby wskazać, czy przełącznik został włączony, czy nie.

Przykład: Bob używa kluczyka Alice, aby otworzyć samochód, a HAL odpowiada na żądanie INITIAL_USER_INFO z identyfikatorem użytkownika Alice. Następnie czujnik biometryczny ECU zidentyfikował kierowcę jako Boba, więc HAL użytkownika wysłał żądanie SWITCH_USER, aby przełączyć użytkowników.

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ą SUCCESS lub FAILURE. Jeśli HAL odpowie błędem, system Android usuwa użytkownika.

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 swoje wewnętrzne identyfikatory użytkowników 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 wywołanie jednokierunkowe, dlatego nie oczekuj odpowiedzi od HAL.

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.

Właściwości dodatkowe

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żywaj tej samej właściwości do tworzenia powiązań get lub set.

Przykład: kierowca klika ikonę w interfejsie systemu multimedialnego, aby powiązać kluczyk samochodowy służący do otwierania pojazdu (KEY_123) z obecnym aktywnym użytkownikiem Androida (USER_11).

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ą w C++, która automatycznie konwertuje HAL użytkownika structs 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ład odpowiedzi (tworzenie konta użytkownika o roli 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

Rzeczywiste nazwy klas i właściwości różnią się nieznacznie, ale ogólny przepływ pracy jest taki sam, jak pokazano na rysunku:

Workflow

Rysunek 1. Proces właściwości HAL użytkownika.

Przykład żądania w ramach nowoczesnego procesu

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 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]     = 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 żądania w ramach 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
}