Esta página descreve as mudanças no driver de vinculação no Android 8, fornece detalhes sobre o uso do IPC de vinculação e lista a política SELinux necessária.
Mudanças no driver de vinculação
A partir do Android 8, o framework do Android e as HALs agora se comunicam entre si usando o binder. Como essa comunicação aumenta drasticamente o tráfego de vinculação, o Android 8 inclui várias melhorias projetadas para manter o IPC de vinculação rápido. Os fornecedores de SoC e OEMs precisam mesclar diretamente das ramificações relevantes de android-4.4, android-4.9 e versões mais recentes do projeto kernel/common.
Vários domínios de vinculação (contextos)
Common-4.4 e versões mais recentes, incluindo upstreamPara dividir o tráfego do binder entre o framework (independente do dispositivo) e o código do fornecedor (específico do dispositivo), o Android 8 introduziu o conceito de um contexto de binder. Cada contexto de vinculação tem o próprio nó de dispositivo e o próprio gerenciador de contexto (serviço). Só é possível acessar o gerenciador de contexto pelo nó do dispositivo ao qual ele pertence. Quando um nó de vinculação é transmitido por um determinado contexto, ele só pode ser acessado por outro processo nesse mesmo contexto, isolando completamente os domínios uns dos outros. Para saber mais sobre o uso, consulte vndbinder e vndservicemanager.
Dispersão e reunião
Common-4.4 e versões mais recentes, incluindo upstreamNas versões anteriores do Android, cada parte de dados em uma chamada de vinculação era copiada três vezes:
- Uma vez para serializar em um
Parcel
no processo de chamada - No driver do kernel, copie o
Parcel
para o processo alvo. - Uma vez para desserializar o
Parcel
no processo de destino
O Android 8 usa a
otimização de
dispersão-coleção para reduzir o número de cópias de 3 para 1. Em vez de
serializar os dados em um Parcel
primeiro, os dados permanecem na estrutura
original e no layout de memória, e o driver os copia imediatamente para o processo
de destino. Depois que os dados estão no processo de destino, a estrutura e o layout
da memória são os mesmos, e os dados podem ser lidos sem exigir outra cópia.
Bloqueio granular
Common-4.4 e versões mais recentes, incluindo upstreamEm versões anteriores do Android, o driver de vinculação usava uma trava global para proteger contra acessos simultâneos a estruturas de dados importantes. Embora houvesse uma disputa mínima pelo bloqueio, o problema principal era que, se uma linha de execução de baixa prioridade recebeu o bloqueio e foi interrompida, isso poderia atrasar seriamente linhas de execução de alta prioridade que precisavam receber o mesmo bloqueio. Isso causou instabilidade na plataforma.
As tentativas iniciais para resolver esse problema envolviam desativar a preempção enquanto mantinha a trava global. No entanto, isso foi mais um hack do que uma solução real, e acabou sendo rejeitado pela upstream e descartado. As tentativas seguintes se concentraram em tornar o bloqueio mais refinado, uma versão que está sendo executada em dispositivos Pixel desde janeiro de 2017. Embora a maioria dessas mudanças tenha sido publicada, melhorias substanciais foram feitas nas versões seguintes.
Depois de identificar pequenos problemas na implementação de bloqueio de granularidade fina, criamos uma solução melhorada com uma arquitetura de bloqueio diferente e enviamos as mudanças em todos os ramos comuns do kernel. Continuamos testando essa implementação em um grande número de dispositivos diferentes. Como não temos conhecimento de problemas pendentes, essa é a implementação recomendada para dispositivos enviados 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 ofereceu uma boa herança de prioridade. Como um número cada vez maior de processos no Android é executado com prioridade em tempo real, em alguns casos, agora faz sentido que, se uma linha de execução em tempo real fizer uma chamada de vinculação, a linha de execução no processo que processa essa chamada também será executada com prioridade em tempo real. Para oferecer suporte a esses casos de uso, o Android 8 agora implementa a 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 herança de prioridade de nó permite que um nó (objeto de serviço de vinculação) especifique uma prioridade mínima em que as chamadas para esse nó precisam ser executadas. As versões anteriores do Android já ofereciam suporte à herança de prioridade de nó com valores adequados, mas o Android 8 adiciona suporte à herança de nó 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 no espaço do usuário necessárias para trabalhar com o driver
de vinculação atual no kernel comum, com uma exceção: a implementação
original para desativar a herança de prioridade em tempo real para
/dev/binder
usava um
ioctl. O desenvolvimento subsequente mudou o controle da herança de prioridade
para um método mais refinado que é por modo de vinculação (e não por
contexto). Portanto, o ioctl não está na ramificação comum do Android e é
enviado nos nossos kernels comuns.
O efeito dessa mudança é que a herança de prioridade em tempo real é desativada por
padrão para todos os nós. A equipe de desempenho do Android descobriu que
é benéfico ativar a herança de prioridade em tempo real para todos os nós no
domínio hwbinder
. Para conseguir o mesmo efeito, escolha
essa 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 apropriado:
- Common-3.18
cc8b90c121de ANDROID: binder: não verifica as permissões de prio na restauração. - Common-4.4
76b376eac7a2 ANDROID: binder: não verifica as permissões de prio na restauração. - Common-4.9
ecd972d4f9b5 ANDROID: binder: não verifica as permissões de prio na restauração.
Trabalhar com IPC de vinculação
Historicamente, os processos do fornecedor usavam a comunicação interprocesso de vinculação
(IPC, na sigla em inglês) para se comunicar. No Android 8, o nó de dispositivo /dev/binder
passa a ser exclusivo para processos de framework, o que significa que os processos do fornecedor não
têm mais acesso a ele. Os processos do fornecedor podem acessar /dev/hwbinder
, mas
precisam converter as interfaces AIDL para usar a HIDL. Para fornecedores que querem continuar
usando interfaces AIDL entre processos do fornecedor, o Android oferece suporte ao IPC de vinculação, conforme
descrito abaixo. No Android 10, a AIDL estável permite que todos
os processos usem /dev/binder
, além de resolver as garantias de estabilidade
HIDL e /dev/hwbinder
. Para saber como usar o AIDL
estável, consulte
AIDL para HALs.
vndbinder
O Android 8 oferece suporte a um novo domínio de vinculação para uso por serviços do fornecedor, acessado
usando /dev/vndbinder
em vez de /dev/binder
. Com a
adição de /dev/vndbinder
, o Android agora tem os três domínios
IPC a seguir:
Domínio do IPC | Descrição |
---|---|
/dev/binder |
IPC entre processos de framework/app com interfaces AIDL |
/dev/hwbinder |
IPC entre processos de framework/fornecedor com interfaces HIDL
IPC entre processos de fornecedor com interfaces HIDL |
/dev/vndbinder |
IPC entre processos de fornecedor/fornecedor com interfaces AIDL |
Para que /dev/vndbinder
apareça, verifique se o item de configuração
do kernel CONFIG_ANDROID_BINDER_DEVICES
está definido como
"binder,hwbinder,vndbinder"
(este é o padrão nas árvores de kernel
comuns do Android).
Normalmente, os processos do fornecedor não abrem o driver de vinculação diretamente, mas
fazem a vinculação com a biblioteca de espaço do usuário libbinder
, que abre o
driver de vinculação. Adicionar um método para ::android::ProcessState()
seleciona o driver de vinculação para libbinder
. Os processos do fornecedor precisam
chamar esse método antes de chamar ProcessState,
IPCThreadState
ou de fazer qualquer chamada de vinculação em geral. Para
usar, faça a seguinte chamada após o main()
de um processo do fornecedor
(cliente e servidor):
ProcessState::initWithDriver("/dev/vndbinder");
vndservicemanager
Antes, os serviços de vinculação eram registrados com servicemanager
,
onde podiam ser recuperados por outros processos. No Android 8,
servicemanager
agora é usado exclusivamente por processos de 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
, uma nova
instância de servicemanager
que usa /dev/vndbinder
em vez de /dev/binder
e que é criada com as mesmas origens do
framework servicemanager
. Os processos do fornecedor não precisam fazer
mudanças para se comunicar com vndservicemanager
. Quando um processo do fornecedor abre
/dev/vndbinder
, as pesquisas de serviço vão automaticamente para
vndservicemanager
.
O binário vndservicemanager
está incluído nos makefiles
padrão do dispositivo do Android.
Política do SELinux
Os processos do fornecedor que querem usar a funcionalidade de vinculação para se comunicar entre si precisam do seguinte:
- Acesso a
/dev/vndbinder
. - O binder
{transfer, call}
se conecta avndservicemanager
. binder_call(A, B)
para qualquer domínio de fornecedor A que queira chamar o domínio de fornecedor B pela interface de vinculação de fornecedores.- Permissão para serviços
{add, find}
emvndservicemanager
.
Para atender aos requisitos 1 e 2, use a macro
vndbinder_use()
:
vndbinder_use(some_vendor_process_domain);
Para atender ao requisito 3, o binder_call(A, B)
para os processos
do fornecedor A e B que precisam se comunicar por meio de um binder pode permanecer no lugar e não
precisa ser renomeado.
Para atender ao requisito 4, você precisa fazer mudanças na forma como os nomes de serviço, os rótulos de serviço e as regras são processados.
Para mais detalhes sobre o SELinux, consulte Security-Enhanced Linux no Android. Para saber mais sobre o SELinux no Android 8.0, consulte SELinux para Android 8.0.
Nomes de serviços
Anteriormente, o fornecedor processava nomes de serviço registrados em um
arquivo service_contexts
e adicionava 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 o
arquivo vndservice_contexts
. Os serviços do fornecedor que estão migrando para
vndservicemanager
(e que já estão no arquivo
service_contexts
antigo) precisam ser adicionados ao novo
arquivo vndservice_contexts
.
Rótulos de serviço
Anteriormente, os rótulos de serviço, como u:object_r:atfwd_service:s0
,
eram definidos em um arquivo service.te
. Exemplo:
type atfwd_service, service_manager_type;
No Android 8, é necessário mudar o tipo para
vndservice_manager_type
e mover a regra para o
arquivo vndservice.te
. Exemplo:
type atfwd_service, vndservice_manager_type;
regras do servicemanager
Antes, as regras davam aos domínios acesso para adicionar ou encontrar serviços do
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 no lugar e usar a mesma classe. Exemplo:
allow atfwd atfwd_service:service_manager find; allow some_vendor_app atfwd_service:service_manager add;