Usar IPC de vinculação

Esta página descreve as alterações no driver de vinculação no Android 8, fornece detalhes sobre o uso de IPC de vinculação e lista a política SELinux exigida.

Mudanças no driver de vinculação

A partir do Android 8, o framework e as HALs do Android se comunicam com uns aos outros usando o binder. Como essa comunicação aumenta drasticamente o binder tráfego, o Android 8 inclui várias melhorias projetadas para manter a IPC do binder rápido. Fornecedores de SoC e OEMs devem se fundir diretamente das filiais relevantes da android-4.4, android-4.9 e posteriores do kernel/common.

Vários domínios de vinculação (contextos)

Common-4.4 e mais recentes, incluindo upstream

Para dividir de maneira clara o tráfego do binder entre o framework (independente de dispositivo) e o código de fornecedor (específico do dispositivo), o Android 8 introduziu o conceito de um binder contexto. Cada contexto de vinculação tem o próprio nó de dispositivo e contexto (serviço). Só é possível acessar o gerenciador de contexto pelo dispositivo nó ao qual pertence e, ao passar um nó de vinculação por um determinado ele seja acessível a partir desse mesmo contexto somente por outro processo, assim isolando completamente os domínios uns dos outros. Para mais detalhes sobre o uso, consulte vndbinder e vndservicemanager.

Agrupamento por dispersão

Common-4.4 e mais recentes, incluindo upstream

Nas versões anteriores do Android, todos os dados em uma chamada de vinculação eram copiados três vezes:

  • Uma vez para serializá-lo em um Parcel no processo de chamada.
  • Uma vez no driver do kernel para copiar o Parcel para o destino processo
  • Uma vez para desserializar o Parcel no processo de destino

Usos do Android 8 dispersão otimização para reduzir o número de cópias de três para um. Em vez de serializando dados em um Parcel primeiro, os dados permanecem no estado original; e o layout da memória e o driver copia imediatamente para o destino de desenvolvimento de software. Depois que os dados estão no processo de destino, a estrutura e a memória e o layout é o mesmo e os dados podem ser lidos sem precisar de outra cópia.

Bloqueio granular

Common-4.4 e mais recentes, incluindo upstream

Nas versões anteriores do Android, o driver de vinculação usava um bloqueio global para proteger contra o acesso simultâneo a estruturas de dados críticas. Apesar de ter sido muito contenção para o bloqueio, o principal problema era que, se uma linha de execução de baixa prioridade o bloqueio e a interrupção forçada, pode atrasar muito linhas de execução de maior prioridade que precisem ter o mesmo bloqueio. Isso causou instabilidade de plataforma.

As tentativas iniciais de resolver esse problema envolveram a desativação da preempção enquanto manter o bloqueio global. No entanto, isso foi mais um truque do que uma verdadeira solução, e depois foi rejeitada pelo upstream e descartada. Tentativas seguintes focado em tornar o bloqueio mais refinado, uma versão da qual foi executada em dispositivos Pixel desde janeiro de 2017. A maioria dessas mudanças publicadas melhorias substanciais foram feitas nas versões subsequentes.

Após identificar pequenos problemas na implementação de bloqueio detalhado, idealizou uma solução aprimorada com uma arquitetura de bloqueio diferente e enviou as mudanças em todas as ramificações comuns do kernel. Continuamos testando implementação em um grande número de dispositivos diferentes. pois não sabemos das problemas pendentes, esta é a implementação recomendada para envio de dispositivos com o Android 8.

Herança de prioridade em tempo real

Common-4.4 e common-4.9 (upstream em breve)

O driver de vinculação sempre foi compatível com uma herança de prioridade boa. Como aumento no número de processos no Android executados com prioridade em tempo real, em alguns casos, faz sentido que, se uma linha de execução em tempo real fizer uma chamada de vinculação, o linha de execução no processo que processa essa chamada também é executada com prioridade em tempo real. Para oferecer suporte a esses casos de uso, o Android 8 agora implementa herança de prioridade em tempo real no driver de vinculação.

Além da herança de prioridade no nível da transação, a prioridade do nó herança permite que um nó (objeto de serviço de binder) especifique um valor mínimo prioridade na qual as chamadas para esse nó devem ser executadas. Versões anteriores do O Android já oferecia suporte à herança de prioridade de nó com bons valores, mas O Android 8 adiciona suporte à herança de nós de políticas de programação em tempo real.

Mudanças no espaço do usuário

O Android 8 inclui todas as mudanças de espaço do usuário necessárias para trabalhar com o no kernel comum, com uma exceção: o driver implementação para desativar a herança de prioridade em tempo real para /dev/binder usou um ioctl (em inglês). O desenvolvimento subsequente mudou o controle de prioridade herança para um método mais detalhado, por modo de binder (e não por contexto). Assim, a ioctl não está na ramificação comum do Android, enviadas nos nossos kernels comuns.

O efeito dessa mudança é que a herança de prioridade em tempo real é desabilitada pela padrão para todos os nós. A equipe de desempenho do Android descobriu é benéfico ativar a herança de prioridade em tempo real para todos os nós da hwbinder. Para conseguir o mesmo efeito, dessa mudança no espaço do usuário.

SHAs para kernels comuns

Para fazer as mudanças necessárias no driver de vinculação, sincronize com o SHA adequado:

  • Comum-3,18
    cc8b90c121de ANDROID: binder: não verifica permissões anteriores na restauração.
  • Comum-4,4
    76b376eac7a2 ANDROID: binder: não verifica permissões anteriores na restauração.
  • Comum-4,9
    ecd972d4f9b5 ANDROID: binder: não verifica permissões anteriores na restauração.

Trabalhar com um binder IPC

Historicamente, os processos do fornecedor usavam a comunicação entre processos do binder. IPC) para se comunicar. No Android 8, o nó de dispositivo /dev/binder se torna exclusivo dos processos do framework, ou seja, os processos do fornecedor tenham acesso a ele. Os processos do fornecedor podem acessar /dev/hwbinder, mas precisam converter as interfaces AIDL para usar HIDL. Para os fornecedores que querem continuar usando interfaces AIDL entre processos do fornecedor, o Android aceita binder IPC como descritas abaixo. No Android 10, a AIDL estável permite que todos processos para usar /dev/binder e, ao mesmo tempo, resolver a estabilidade garante que HIDL e /dev/hwbinder sejam resolvidos. Para saber como usar o Stable AIDL, consulte AIDL para HALs:

Vndbinder

O Android 8 oferece suporte a um novo domínio binder para uso pelos serviços do fornecedor, acessado usando /dev/vndbinder em vez de /dev/binder. Com o adição de /dev/vndbinder, o Android agora tem as três Domínios com IPC:

Domínio de IPC Descrição
/dev/binder IPC entre processos de framework/app com interfaces AIDL
/dev/hwbinder IPC entre processos do fornecedor/framework com interfaces HIDL
IPC entre processos do fornecedor com interfaces HIDL
/dev/vndbinder IPC entre processos de fornecedor/fornecedor com interfaces AIDL

Para que /dev/vndbinder apareça, verifique se a configuração do kernel o item CONFIG_ANDROID_BINDER_DEVICES está definido como "binder,hwbinder,vndbinder", que é o padrão no árvores de kernel comuns).

Normalmente, os processos do fornecedor não abrem o driver de vinculação diretamente. da biblioteca de espaço do usuário libbinder, que abre a driver de vinculação. Adicionar um método para ::android::ProcessState() seleciona o driver de vinculação para libbinder. Os processos do fornecedor devem chamar esse método antes de chamar ProcessState, IPCThreadState ou antes de fazer chamadas de vinculação em geral. Para uso, faça a seguinte chamada após o main() do processo de um fornecedor (cliente e servidor):

ProcessState::initWithDriver("/dev/vndbinder");

vndservicemanager

Antes, os serviços de vinculação eram registrados com servicemanager, onde poderiam ser recuperados por outros processos. No Android 8, O servicemanager agora é usado exclusivamente por framework e app e os processos do fornecedor não podem mais acessá-lo.

No entanto, os serviços do fornecedor agora podem usar vndservicemanager, um novo instância de servicemanager que usa /dev/vndbinder em vez de /dev/binder e que é criado a partir das mesmas origens que framework servicemanager. Os processos do fornecedor não precisam fazer muda para falar com vndservicemanager; quando um processo do fornecedor é iniciado /dev/vndbinder, as pesquisas de serviço vão automaticamente para vndservicemanager:

O binário vndservicemanager está incluído no padrão do Android. makefiles de dispositivos.

Política do SELinux

Os processos do fornecedor que querem usar a funcionalidade de vinculação para se comunicar com precisam do seguinte:

  1. Acesso a /dev/vndbinder.
  2. Os ganchos de vinculação {transfer, call} são inseridos vndservicemanager.
  3. binder_call(A, B) para qualquer domínio A do fornecedor que queira chamar no domínio B do fornecedor, sobre a interface de vinculação do fornecedor.
  4. Permissão para {add, find} serviços em vndservicemanager.

Para cumprir os requisitos 1 e 2, use o vndbinder_use() :

vndbinder_use(some_vendor_process_domain);

Para atender ao requisito 3, a binder_call(A, B) do fornecedor Os processos A e B que precisam se comunicar por um binder podem permanecer ativos e não precisam ser renomeadas.

Para cumprir o requisito 4, é preciso fazer alterações na forma como os nomes dos serviços, rótulos de serviço e regras são tratados.

Para saber mais sobre o SELinux, consulte Segurança reforçada Linux no Android. Para mais detalhes sobre o SELinux no Android 8.0, consulte SELinux para Android 8.0.

Nomes de serviço

Anteriormente, o fornecedor processa nomes de serviço registrados em um service_contexts e adicionamos regras correspondentes para acessar esse arquivo. Exemplo de arquivo service_contexts de device/google/marlin/sepolicy:

AtCmdFwd                              u:object_r:atfwd_service:s0
cneservice                            u:object_r:cne_service:s0
qti.ims.connectionmanagerservice      u:object_r:imscm_service:s0
rcs                                   u:object_r:radio_service:s0
uce                                   u:object_r:uce_service:s0
vendor.qcom.PeripheralManager         u:object_r:per_mgr_service:s0

No Android 8, o vndservicemanager carrega a arquivo vndservice_contexts. Migração dos serviços do fornecedor para vndservicemanager (e que já estão na versão antiga) service_contexts) devem ser adicionadas à nova arquivo vndservice_contexts.

Rótulos de serviço

Antes, os rótulos de serviço, como u:object_r:atfwd_service:s0 foram definidas em um arquivo service.te. Exemplo:

type atfwd_service,      service_manager_type;

No Android 8, você precisa alterar o tipo para vndservice_manager_type e mover a regra para arquivo vndservice.te. Exemplo:

type atfwd_service,      vndservice_manager_type;

Regras do servicemanager

Antes, as regras concedevam acesso aos domínios para adicionar ou encontrar serviços servicemanager: Exemplo:

allow atfwd atfwd_service:service_manager find;
allow some_vendor_app atfwd_service:service_manager add;

No Android 8, essas regras podem permanecer em vigor e usar a mesma classe. Exemplo:

allow atfwd atfwd_service:service_manager find;
allow some_vendor_app atfwd_service:service_manager add;