Serviços e transferência de dados

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:

  1. Criar uma subclasse da classe/interface HIDL hidl_death_recipient (em C++ não no HIDL).
  2. Substitua o método serviceDied().
  3. Instancie um objeto da subclasse hidl_death_recipient.
  4. Chame o método linkToDeath() no serviço a ser monitorado. transmitindo o objeto de interface do IDeathRecipient. 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 ou MQDescriptorUnsync. 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.
    . Nenhum dos tipos tem permissão para estourar (a leitura de uma fila vazia falha) e cada tipo só pode ter um gravador.

Para mais detalhes sobre o FMQ, consulte Fila rápida de mensagens (FMQ, na sigla em inglês).