Esta página descreve como registrar e descobrir serviços e como enviar
dados para um serviço chamando métodos definidos nas interfaces em .hal
.
Registrar serviços
Servidores de interface HIDL (objetos que implementam a interface) podem ser registrados como serviços nomeados. O nome registrado não precisa estar relacionado à interface nem nome do pacote. Se nenhum nome for especificado, o nome "padrão" é usado. isso deveria ser usada para HALs que não precisam registrar duas implementações da mesma interface gráfica do usuário. Por exemplo, a chamada C++ para registro de serviço definido em cada interface é:
status_t status = myFoo->registerAsService(); status_t anotherStatus = anotherFoo->registerAsService("another_foo_service"); // if needed
A versão da interface HIDL está incluída na própria interface. É
associados automaticamente ao registro do serviço e podem ser recuperados por um
chamada de método (android::hardware::IInterface::getInterfaceVersion()
)
em todas as interfaces HIDL. Objetos de servidor não precisam ser registrados e podem ser passados
usando parâmetros do método HIDL para outro processo que faz chamadas desse método
no servidor.
Descobrir serviços
As solicitações por código do cliente são feitas para uma determinada interface por nome e por
própria versão, chamando getService
na classe HAL desejada:
// C++ sp<V1_1::IFooService> service = V1_1::IFooService::getService(); sp<V1_1::IFooService> alternateService = V1_1::IFooService::getService("another_foo_service"); // Java V1_1.IFooService service = V1_1.IFooService.getService(true /* retry */); V1_1.IFooService alternateService = V1_1.IFooService.getService("another", true /* retry */);
Cada versão de uma interface HIDL é tratada como uma interface separada. Assim,
IFooService
versão 1.1 e IFooService
versão 2.2
podem ser registrados como "foo_service" e
getService("foo_service")
em qualquer interface recebe o nome
para essa interface. É por isso que, na maioria dos casos, nenhum parâmetro de nome precisa
seja fornecido para registro ou descoberta (ou seja, nome "padrão").
O objeto da interface do fornecedor também desempenha um papel no método de transporte do
interface retornada. Para uma interface IFoo
no pacote
android.hardware.foo@1.0
, a interface retornada pelo
IFoo::getService
sempre usa o método de transporte declarado para
android.hardware.foo
no manifesto do dispositivo, se a entrada existir;
Se o método de transporte não estiver disponível, nullptr será retornado.
Em alguns casos, pode ser necessário continuar imediatamente, mesmo sem
de receber o serviço. Isso pode acontecer (por exemplo) quando um cliente quer
gerenciar notificações de serviço em si ou em um programa de diagnóstico (como
atrace
) que precisa receber todos os hwservices e recuperá-los. Em
Nesse caso, outras APIs são fornecidas, como tryGetService
em C++ ou
getService("instance-name", false)
em Java. A API legada
O getService
fornecido em Java também precisa ser usado com o serviço
notificações. O uso dessa API não evita a disputa em que um servidor
se registra depois da solicitação do cliente com uma dessas APIs de não repetição.
Notificações de interrupção do serviço
Os clientes que quiserem ser notificados sobre o encerramento de um serviço poderão ser encerrados e notificações entregues pelo framework. Para receber notificações, o cliente precisa:
- Criar uma subclasse da classe/interface HIDL
hidl_death_recipient
(em C++ não no HIDL). - Substitua o método
serviceDied()
. - Instancie um objeto da subclasse
hidl_death_recipient
. - Chame o método
linkToDeath()
no serviço a ser monitorado. transmitindo o objeto de interface doIDeathRecipient
. Observe que este não assume a propriedade do destinatário da morte ou do proxy no qual for chamado.
Um exemplo de pseudocódigo (C++ e Java são semelhantes):
class IMyDeathReceiver : hidl_death_recipient { virtual void serviceDied(uint64_t cookie, wp<IBase>& service) override { log("RIP service %d!", cookie); // Cookie should be 42 } }; .... IMyDeathReceiver deathReceiver = new IMyDeathReceiver(); m_importantService->linkToDeath(deathReceiver, 42);
O mesmo destinatário pode ser registrado em vários serviços diferentes.
Transferência de dados
Os dados podem ser enviados a um serviço chamando métodos definidos nas interfaces do
.hal
. Há dois tipos de métodos:
- Os métodos de bloqueio aguardam até que o servidor produza uma resultado.
- Métodos unidirecionais enviam dados em apenas uma direção e não bloco de recursos dependente. Se a quantidade de dados em trânsito em chamadas RPC exceder a implementação limites, as chamadas podem bloquear ou retornar uma indicação de erro (o comportamento é ainda não determinado).
um método que não retorna um valor, mas não é declarado como
oneway
ainda está bloqueando.
Todos os métodos declarados em uma interface HIDL são chamados em uma única direção, da HAL ou para a HAL. A interface não especifica qual em que direção é chamada. Arquiteturas que precisam de chamadas com origem a HAL deve fornecer duas (ou mais) interfaces no pacote HAL e disponibilizar a a interface apropriada de cada processo. As palavras client e server são usados em relação à direção de chamada da interface Ou seja, a HAL pode ser servidor de uma interface e cliente de outra, do BigQuery).
Callbacks
A palavra callback refere-se a dois conceitos diferentes, diferenciados por callback síncrono e assíncrono.
Callbacks síncronos são usados em alguns métodos HIDL que retornam dados. Um método HIDL que retorna mais de um valor (ou retorna um valor de tipo não primitivo) retorna os resultados por meio de uma função de callback. Se apenas um for retornado e for um tipo primitivo, um retorno de chamada não é usado e o valor é retornado do método. O servidor implementa os métodos HIDL e o cliente implementa os callbacks.
Callbacks assíncronos permitem que o servidor de uma interface HIDL
originar chamadas. Para isso, é preciso transmitir uma instância de uma segunda interface
na primeira interface. O cliente da primeira interface deve atuar como
servidor do segundo. O servidor da primeira interface pode chamar métodos no
segundo objeto da interface. Por exemplo, uma implementação de HAL pode enviar informações
de forma assíncrona ao processo que a está usando, chamando métodos em uma
objeto da interface criado e exibido por esse processo. Métodos em interfaces usadas
para o callback assíncrono pode estar bloqueando (e pode retornar valores para o autor da chamada)
ou oneway
. Para ver um exemplo, consulte "Callbacks assíncronos" no
HIDL C++.
Para simplificar a propriedade da memória, chamadas de método e callbacks levam apenas
in
e não oferecem suporte a out
ou
Parâmetros inout
.
Limites por transação
Os limites por transação não são impostos à quantidade de dados enviados no HIDL
e callbacks do sistema. No entanto, chamadas que excedem 4 KB por transação são
considerada excessiva. Se isso for observado, reestruturar a interface HIDL fornecida
é recomendado. Outra limitação são os recursos disponíveis para o HIDL
para lidar com várias transações simultâneas. Vários status
as transações podem estar em andamento simultaneamente devido a várias linhas de execução ou
processos que enviam chamadas para um processo ou várias chamadas oneway
que
não são tratados rapidamente pelo processo de recebimento. O espaço total máximo
disponível para todas as transações simultâneas é de 1 MB por padrão.
Em uma interface bem projetada, não deve exceder essas limitações de recursos aconteceram. em caso afirmativo, a chamada que os excedeu pode ser bloqueada até recursos ficam disponíveis ou sinalizam um erro de transporte. Cada ocorrência de exceder os limites por transação ou exceder os recursos de implementação de HIDL agregadas em andamento são registradas para facilitar a depuração.
Implementações de métodos
O HIDL gera arquivos de cabeçalho declarando os tipos, métodos e callbacks na linguagem de destino (C++ ou Java). O protótipo do conjunto de dados definido pelo HIDL e callbacks é o mesmo para o código do cliente e do servidor. O HIDL sistema fornece implementações de proxy dos métodos na lado do autor da chamada, que organizam os dados para o transporte IPC, e o stub o código no lado do recebedor da chamada que passa os dados para implementações de desenvolvedor do os métodos.
O autor da chamada de uma função (método HIDL ou callback) tem a propriedade dos dados passadas para a função e mantém a propriedade após a chamada. no em todos os casos em que o recebedor da chamada não precisar liberar ou liberar o armazenamento.
- Em C++, os dados podem ser somente leitura (tentativas de gravação neles podem causar uma falha de segmentação) e são válidos durante a chamada. O cliente pode copiar os dados em profundidade para propagá-los além da chamada.
- Em Java, o código recebe uma cópia local dos dados (um objeto Java normal), que ele pode manter, modificar ou permitir que sejam coletados por coleta de lixo.
Transferência de dados não RPC
O HIDL tem duas maneiras de transferir dados sem usar uma chamada RPC: compartilhada memória e uma Fila de mensagens rápidas (FMQ), ambos com suporte somente em C++.
- Memória compartilhada. O tipo de HIDL integrado
memory
é usada para transmitir um objeto que representa a memória compartilhada que foi alocada. Pode ser usado em um processo de recebimento para mapear a memória compartilhada. - Fila rápida de mensagens (FMQ, na sigla em inglês). O HIDL fornece uma mensagem modelo
tipo de fila que implementa a transmissão de mensagens sem espera. Ele não usa o kernel
ou programador em modo de passagem ou de binder (a comunicação entre dispositivos não
têm essas propriedades). Normalmente, a HAL configura o fim da fila,
criando um objeto que pode ser transmitido por RPC por meio de um parâmetro de
Tipo de HIDL
MQDescriptorSync
ouMQDescriptorUnsync
. Isso pode ser usado pelo processo de recebimento para configurar a outra extremidade da fila.- As filas de sincronização não podem estourar e só podem ter uma leitor de tela.
- As filas dessincronizadas podem ultrapassar o limite e ter muitos leitores, que precisam ler dados a tempo ou perdê-los.
Para mais detalhes sobre o FMQ, consulte Fila rápida de mensagens (FMQ, na sigla em inglês).