Propriedades de HAL do usuário

Muitas arquiteturas atuais de veículos contêm várias unidades de controle eletrônico (ECUs) fora do sistema de infoentretenimento que controlam a ergonomia, como configurações de assento e ajustes de espelho. Com base nas arquiteturas atuais de hardware e energia, muitas ECUs são ativadas antes que o sistema de infoentretenimento baseado em Android seja ativado. Essas ECUs podem interagir com um sistema de infoentretenimento baseado no Android pela camada de abstração de hardware do veículo (VHAL, na sigla em inglês).

No Android 11 e versões mais recentes, o Android Automotive OS (AAOS) introduziu um novo conjunto de propriedades na VHAL para criar, alternar, remover e associar acessórios externos para identificar usuários. Por exemplo, essas novas propriedades permitem que um motorista vincule um acessório externo, como um chaveiro, ao usuário do Android. Em seguida, quando o motorista se aproxima do veículo, uma ECU é ativada e detecta o chaveiro. Essa ECU indica ao HAL qual usuário do Android o sistema de infoentretenimento precisa iniciar, o que reduz o tempo que o motorista espera para que o usuário do Android seja carregado.

Ativar a HAL do usuário

As propriedades da HAL do usuário precisam ser ativadas explicitamente, garantindo que a propriedade android.car.user_hal_enabled do sistema esteja definida como true. Você pode fazer isso no arquivo car.mk para que ele não precise ser definido manualmente. Verifique se o user_hal_enabled=true está ativado descartando o UserHalService:

$ adb shell dumpsys car_service --hal UserHalService|grep enabled
user_hal_enabled=true

Também é possível verificar o user_hal_enabled usando adb shell getprop android.car.user_hal_enabled ou adb logcat CarServiceHelper *:s. Se a propriedade estiver desativada, uma mensagem como esta será exibida quando system_server for iniciado:

I CarServiceHelper: Not using User HAL

Para ativar manualmente o user_hal_enabled, defina a propriedade do sistema android.car.user_hal_enabled e reinicie system_server:

$ adb shell setprop android.car.user_hal_enabled true
$ adb shell stop && adb shell start

A saída logcat aparece da seguinte maneira:

I CarServiceHelper: User HAL enabled with timeout of 5000ms
D CarServiceHelper: Got result from HAL: OK
I CarServiceHelper: User HAL returned DEFAULT behavior

Propriedades HAL do usuário

Propriedades do ciclo de vida do usuário

As propriedades a seguir fornecem as informações da HAL para os estados do ciclo de vida do usuário, que permitem a sincronização do ciclo de vida do usuário entre o sistema Android e uma ECU externa. Essas propriedades usam um protocolo de solicitação e resposta, em que o sistema Android faz uma solicitação definindo um valor de propriedade, e o HAL responde emitindo um evento de mudança de propriedade.

Observação:quando o HAL do usuário é compatível, todas as propriedades a seguir precisam ser implementadas.

Propriedade HAL Descrição
INITIAL_USER_INFO
(leitura/gravação)
Essa propriedade é chamada pelo sistema Android para determinar qual usuário o sistema inicia quando o dispositivo é inicializado ou retomado da suspensão para RAM (STR). Quando chamado, o HAL precisa responder com uma destas opções:
  • O comportamento padrão definido pelo Android (alternar para o último usuário usado ou criar um novo usuário se esta for a primeira inicialização).
  • Mudar para um usuário existente.
  • Crie um novo usuário (com as propriedades opcionais de nome, sinalizações, localidade do sistema e assim por diante) e mude para esse novo usuário.

Observação:se o HAL não responder, o comportamento padrão será a execução após um período de tempo limite (cinco segundos por padrão), o que atrasa a inicialização. Se o HAL responder, mas o sistema Android não conseguir executar a ação (por exemplo, se o número máximo de usuários tiver sido atingido), o comportamento padrão será usado.

Exemplo:por padrão, o sistema Android é iniciado no último usuário ativo na inicialização. Se um chaveiro para um usuário diferente for detectado, a ECU vai substituir a propriedade HAL e, durante a inicialização, o sistema Android vai mudar para a inicialização no usuário especificado.

SWITCH_USER
(leitura/gravação)
Essa propriedade é chamada ao alternar o usuário ativo do Android em primeiro plano. A propriedade pode ser chamada pelo sistema Android ou pelo HAL para solicitar uma troca de usuário. Os três fluxos de trabalho são:
  • Moderno. Mudança iniciada em CarUserManager.
  • Legado. Mudança iniciada em ActivityManager.
  • Veículo. Chamado pela HAL para solicitar uma troca de usuário.

O fluxo de trabalho moderno usa uma abordagem de confirmação de duas fases para garantir que o sistema Android e a ECU externa sejam sincronizados. Quando o Android inicia a troca:

  1. Verifique o HAL para determinar se o usuário pode ser trocado.

    O HAL responde com SUCCESS ou FAILURE, para que o Android saiba se deve continuar ou não.

  2. Conclua a troca de usuário do Android.

    O Android envia uma resposta ANDROID_POST_SWITCH para o HAL para indicar o sucesso ou a falha da troca.

O HAL precisa esperar até depois da resposta ANDROID_POST_SWITCH para atualizar o estado e sincronizar as ECUs ou atualizar outras propriedades do HAL.

Exemplo:durante o movimento, um motorista tenta alternar entre usuários do Android na interface de infoentretenimento. No entanto, como as configurações do assento do carro estão vinculadas ao usuário do Android, o assento se move durante a troca do usuário. Assim, a ECU que controla os assentos não confirma a troca, o HAL responde com uma falha e o usuário do Android não é trocado.

O fluxo de trabalho legado é uma chamada unidirecional enviada após a troca do usuário. Dessa forma, a HAL não pode bloquear a chave. Ele só é chamado na inicialização (após a troca inicial de usuário) ou para apps que chamam ActivityManager.switchUser() em vez de CarUserManager.switchUser(). Os apps de referência Settings e SystemUI já usam o segundo, mas, se um OEM fornecer os próprios apps de configurações para alternar usuários, ele precisará mudar o uso.

Exemplo:se um app usa ActivityManager.switchUser() para alternar usuários, uma chamada unidirecional é enviada para o HAL para informar que uma troca de usuário ocorreu.

O fluxo de trabalho do veículo tem origem no HAL, não no sistema Android:

  1. O HAL solicita uma troca de usuário.
  2. O sistema conclui a troca de usuário do Android.
  3. O Android envia uma resposta ANDROID_POST_SWITCH para o HAL para indicar sucesso ou falha da troca.

Exemplo:Bob usou o chaveiro de Alice para abrir o carro e o HAL respondeu à solicitação INITIAL_USER_INFO com o ID de usuário de Alice. Em seguida, uma ECU de sensor biométrico identificou o motorista como Bob, então o HAL do usuário enviou uma solicitação SWITCH_USER para trocar de usuário.

CREATE_USER
(leitura/gravação)
Essa propriedade é chamada pelo sistema Android quando um novo usuário do Android é criado (usando a API CarUserManager.createUser()).

O HAL responde com SUCCESS ou FAILURE. Se a HAL responder com uma falha, o sistema Android removerá o usuário.

Exemplo:um motorista toca em um ícone da interface de infoentretenimento para criar um novo usuário do Android. Isso envia uma solicitação para o HAL e o restante dos subsistemas do veículo. As ECUs são informadas sobre o usuário recém-criado. Outros subsistemas e ECUs associam os respectivos IDs do usuário interno ao ID do usuário do Android.

REMOVE_USER
(somente GRAVAÇÃO)
O sistema Android chama essa propriedade depois que um usuário do Android é removido (com o método CarUserManager.removeUser()).

Essa é uma chamada unidirecional, nenhuma resposta é esperada da HAL.

Exemplo:um motorista toca para remover um usuário do Android na interface do infoentretenimento. O HAL é informado, e outros subsistemas do veículo e ECUs são informados sobre a remoção do usuário para que possam remover o ID interno do usuário.

Propriedades adicionais

Confira a seguir outras propriedades não relacionadas aos estados do ciclo de vida do usuário. Cada uma pode ser implementada sem oferecer suporte ao HAL do usuário.

Propriedade da HAL Descrição
USER_IDENTIFICATION_ASSOCIATION
(leitura/gravação)
Use essa propriedade para associar qualquer usuário do Android a um mecanismo de identificação, como um chaveiro ou smartphone. Use essa mesma propriedade para associações get ou set.

Exemplo:um motorista toca em um ícone da interface de infoentretenimento para associar o chaveiro usado para abrir o veículo (KEY_123) ao usuário ativo do Android (USER_11).

Bibliotecas de ajuda

Todos os objetos usados nas mensagens de solicitação e resposta (como UserInfo, InitialUserInfoRequest, InitialUSerInfoResponse e assim por diante) têm uma representação de alto nível usando struct do C++, mas a remoção precisa ser agrupada em objetos VehiclePropValue padrão (confira os exemplos abaixo). Para facilitar o desenvolvimento, uma biblioteca auxiliar C++ é fornecida no AOSP para converter automaticamente a HAL de usuário structs em um VehiclePropValue (e vice-versa).

Exemplos

INITIAL_USER_INFO

Exemplo de solicitação (na primeira inicialização)

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
}

Exemplo de resposta (criar usuário administrador)

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

O nome real das classes e propriedades é um pouco diferente, mas o fluxo de trabalho geral é o mesmo, conforme ilustrado na figura:

Fluxo de trabalho

Figura 1. Fluxo de trabalho das propriedades de HAL do usuário.

Exemplo de solicitação de fluxo de trabalho moderno

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)
}

Exemplo de resposta de fluxo de trabalho moderno

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
}

Exemplo de resposta pós-mudança de fluxo de trabalho moderno

Essa resposta geralmente ocorre quando uma chave do Android é ativada:

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)
}

Resposta pós-chave do fluxo de trabalho moderno

Essa resposta normalmente ocorre quando uma chave do Android falha:

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)
}

Exemplo de solicitação de fluxo de trabalho legado

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)
}

Exemplo de solicitação de fluxo de trabalho do veículo

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
}

Resposta pós-mudança do fluxo de trabalho legado

Essa resposta normalmente ocorre quando uma troca do Android é concluída:

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

Exemplo de solicitação

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)
}

Exemplo de resposta

VehiclePropValue { // flattened from CreateUserResponse
prop: 299896585 // CREATE_USER
prop.values.int32Values:
 [0] = 42        // Request ID (must match request)
 [1] = 3         // CreateUserStatus::SUCCESS
}

REMOVE_USER

Exemplo de solicitação

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)
}

ASSOCIAÇÃO_DE_IDENTIFICAÇÃO_DO_USUÁRIO

Exemplo de conjunto (chaveiro associado ao usuário 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
}