Renderscript

RenderScript é uma estrutura para executar tarefas computacionalmente intensivas com alto desempenho no Android. Ele foi projetado para uso com computação paralela de dados, embora cargas de trabalho seriais também possam se beneficiar. O tempo de execução do RenderScript paraleliza o trabalho entre processadores disponíveis em um dispositivo, como CPUs e GPUs multi-core, permitindo que os desenvolvedores se concentrem em expressar algoritmos em vez de agendar o trabalho. RenderScript é especialmente útil para aplicativos que realizam processamento de imagens, fotografia computacional ou visão computacional.

Dispositivos que executam o Android 8.0 e superior usam a seguinte estrutura RenderScript e HALs de fornecedor:

Figura 1. Código do fornecedor vinculado a bibliotecas internas

As diferenças do RenderScript no Android 7.xe inferior incluem:

  • Duas instâncias de bibliotecas internas do RenderScript em um processo. Um conjunto é para o caminho de fallback da CPU e vem diretamente de /system/lib ; o outro conjunto é para o caminho da GPU e é de /system/lib/vndk-sp .
  • As bibliotecas internas do RS em /system/lib são construídas como parte da plataforma e são atualizadas à medida que system.img é atualizado. No entanto, as bibliotecas em /system/lib/vndk-sp são criadas para o fornecedor e não são atualizadas quando system.img é atualizado (embora possam ser atualizadas para uma correção de segurança, sua ABI permanece a mesma).
  • O código do fornecedor (RS HAL, driver RS ​​e o bcc plugin ) estão vinculados às bibliotecas internas do RenderScript localizadas em /system/lib/vndk-sp . Eles não podem vincular-se a bibliotecas em /system/lib porque as bibliotecas nesse diretório são construídas para a plataforma e, portanto, podem não ser compatíveis com o código do fornecedor (ou seja, os símbolos podem ser removidos). Fazer isso tornaria impossível uma OTA apenas de estrutura.

Projeto

As seções a seguir detalham o design do RenderScript no Android 8.0 e versões posteriores.

Bibliotecas RenderScript disponíveis para fornecedores

Esta seção lista as bibliotecas RenderScript (conhecidas como Vendor NDK para Same-Process HALs ou VNDK-SP) que estão disponíveis para o código do fornecedor e às quais podem ser vinculadas. Ele também detalha bibliotecas adicionais que não estão relacionadas ao RenderScript, mas que também são fornecidas ao código do fornecedor.

Embora a lista de bibliotecas a seguir possa diferir entre as versões do Android, ela é imutável para uma versão específica do Android; para obter uma lista atualizada de bibliotecas disponíveis, consulte /system/etc/ld.config.txt .

Bibliotecas RenderScript Bibliotecas não RenderScript
  • android.hardware.graphics.renderscript@1.0.so
  • libRS_internal.so
  • libRSCpuRef.so
  • libblas.so
  • libbcinfo.so
  • libcompiler_rt.so
  • libRSDriver.so
  • libc.so
  • libm.so
  • libdl.so
  • libstdc++.so
  • liblog.so
  • libnativewindow.so
  • libsync.so
  • libvndksupport.so
  • libbase.so
  • libc++.so
  • libcutils.so
  • libutils.so
  • libhardware.so
  • libhidlbase.so
  • libhidltransport.so
  • libhwbinder.so
  • liblzma.so
  • libz.so
  • libEGL.so
  • libGLESv1_CM.so
  • libGLESv2.so

Configuração do namespace do vinculador

A restrição de vinculação que impede que bibliotecas que não estão no VNDK-SP sejam usadas pelo código do fornecedor é aplicada em tempo de execução usando o namespace do vinculador. (Para obter detalhes, consulte a apresentação do VNDK Design .)

Em um dispositivo com Android 8.0 e superior, todos os HALs do mesmo processo (SP-HALs), exceto RenderScript, são carregados dentro do namespace do vinculador sphal . O RenderScript é carregado no namespace específico do RenderScript rs , um local que permite uma aplicação um pouco mais flexível para bibliotecas do RenderScript. Como a implementação RS precisa carregar o bitcode compilado, /data/*/*.so é adicionado ao caminho do namespace rs (outros SP-HALs não têm permissão para carregar bibliotecas da partição de dados).

Além disso, o namespace rs permite mais bibliotecas do que as fornecidas por outros namespaces. libmediandk.so e libft2.so são expostos ao namespace rs porque libRS_internal.so tem uma dependência interna dessas bibliotecas.

Figura 2. Configuração de namespace para vinculador

Carregando drivers

Caminho alternativo da CPU

Dependendo da existência do bit RS_CONTEXT_LOW_LATENCY ao criar um contexto RS, o caminho da CPU ou da GPU é selecionado. Quando o caminho da CPU é selecionado, libRS_internal.so (a implementação principal da estrutura RS) é diretamente dlopen a partir do namespace do vinculador padrão onde a versão da plataforma das bibliotecas RS é fornecida.

A implementação RS HAL do fornecedor não é usada quando o caminho de fallback da CPU é usado e um objeto RsContext é criado com mVendorDriverName nulo. libRSDriver.so é (por padrão) dlopen ed e o driver lib é carregado a partir do namespace default porque o chamador ( libRS_internal.so ) também é carregado no namespace default .

Figura 4. Caminho de fallback da CPU

Caminho da GPU

Para o caminho da GPU, libRS_internal.so é carregado de forma diferente. Primeiro, libRS.so usa android.hardware.renderscript@1.0.so (e seu subjacente libhidltransport.so ) para carregar android.hardware.renderscript@1.0-impl.so (uma implementação de fornecedor de RS HAL) em um namespace de vinculador diferente chamado sphal . O RS HAL então dlopen libRS_internal.so em outro namespace do vinculador chamado rs .

Os fornecedores podem fornecer seu próprio driver RS ​​definindo o sinalizador de tempo de construção OVERRIDE_RS_DRIVER , que está incorporado na implementação RS HAL ( hardware/interfaces/renderscript/1.0/default/Context.cpp ). Este nome de driver é então dlopen para o contexto RS do caminho da GPU.

A criação do objeto RsContext é delegada à implementação RS HAL. O HAL chama de volta para a estrutura RS usando a função rsContextCreateVendor() com o nome do driver a ser usado como argumento. A estrutura RS carrega o driver especificado quando o RsContext é inicializado. Nesse caso, a biblioteca do driver é carregada no namespace rs porque o objeto RsContext é criado dentro do namespace rs e /vendor/lib está no caminho de pesquisa do namespace.

Figura 5. Caminho de fallback da GPU

Ao fazer a transição do namespace default para o namespace sphal , libhidltransport.so usa a função android_load_sphal_library() para ordenar explicitamente que o vinculador dinâmico carregue a biblioteca -impl.so do namespace sphal .

Ao fazer a transição do namespace sphal para o namespace rs , o carregamento é feito indiretamente pela seguinte linha em /system/etc/ld.config.txt :

namespace.sphal.link.rs.shared_libs = libRS_internal.so

Esta linha especifica que o vinculador dinâmico deve carregar libRS_internal.so do namespace rs quando a lib não pode ser encontrada/carregada do namespace sphal (o que é sempre o caso porque o namespace sphal não pesquisa /system/lib/vndk-sp onde libRS_internal.so reside). Com esta configuração, uma simples chamada dlopen() para libRS_internal.so é suficiente para fazer a transição do namespace.

Carregando plug-in Cco

bcc plugin é uma biblioteca fornecida pelo fornecedor carregada no compilador bcc . Como bcc é um processo do sistema no diretório /system/bin , a biblioteca bcc plugin pode ser considerada um SP-HAL (ou seja, um HAL de fornecedor que pode ser carregado diretamente no processo do sistema sem ser vinculado). Como SP-HAL, a biblioteca bcc-plugin :

  • Não é possível vincular bibliotecas somente de estrutura, como libLLVM.so .
  • Pode vincular apenas às bibliotecas VNDK-SP disponíveis para o fornecedor.

Esta restrição é aplicada carregando o bcc plugin no namespace sphal usando a função android_sphal_load_library() . Nas versões anteriores do Android, o nome do plugin era especificado usando a opção -load e a lib era carregada usando o simples dlopen() de libLLVM.so . No Android 8.0 e superior, isso é especificado na opção -plugin e a lib é carregada diretamente pelo próprio bcc . Esta opção permite um caminho não específico do Android para o projeto LLVM de código aberto.

Figura 6. Carregando o plugin Cco, Android 7.xe inferior


Figura 7. Carregando o plugin Cco, Android 8.0 e superior

Caminhos de pesquisa para ld.mc

Ao executar ld.mc , algumas bibliotecas de tempo de execução RS são fornecidas como entradas para o vinculador. O bitcode RS do aplicativo é vinculado às bibliotecas de tempo de execução e quando o bitcode convertido é carregado em um processo do aplicativo, as bibliotecas de tempo de execução são novamente vinculadas dinamicamente a partir do bitcode convertido.

As bibliotecas de tempo de execução incluem:

  • libcompiler_rt.so
  • libm.so
  • libc.so
  • Driver RS ​​( libRSDriver.so ou OVERRIDE_RS_DRIVER )

Ao carregar o bitcode compilado no processo do aplicativo, forneça exatamente a mesma biblioteca usada por ld.mc . Caso contrário, o bitcode compilado pode não encontrar um símbolo que estava disponível quando foi vinculado.

Para fazer isso, a estrutura RS usa diferentes caminhos de pesquisa para as bibliotecas de tempo de execução ao executar ld.mc , dependendo se a própria estrutura RS é carregada de /system/lib ou de /system/lib/vndk-sp . Isso pode ser determinado lendo o endereço de um símbolo arbitrário de uma biblioteca de estrutura RS e usando dladdr() para obter o caminho do arquivo mapeado para o endereço.

Política SELinux

Como resultado das alterações na política do SELinux no Android 8.0 e versões posteriores, você deve seguir regras específicas (aplicadas por meio de neverallows ) ao rotular arquivos adicionais na partição vendor :

  • vendor_file deve ser o rótulo padrão para todos os arquivos na partição vendor . A política da plataforma exige isso para acessar implementações HAL de passagem.
  • Todos os novos exec_types adicionados na partição vendor por meio do SEPolicy do fornecedor devem ter o atributo vendor_file_type . Isso é aplicado por meio neverallows .
  • Para evitar conflitos com futuras atualizações de plataforma/estrutura, evite rotular arquivos que não sejam exec_types na partição vendor .
  • Todas as dependências de biblioteca para HALs do mesmo processo identificados pelo AOSP devem ser rotuladas como same_process_hal_file .

Para obter detalhes sobre a política SELinux, consulte Linux com segurança aprimorada no Android .

Compatibilidade ABI para bitcode

Se nenhuma nova API for adicionada, o que significa que não há aumento de versão do HAL, as estruturas RS continuarão usando o driver GPU (HAL 1.0) existente.

Para pequenas alterações de HAL (HAL 1.1) que não afetem o bitcode, as estruturas devem recorrer à CPU para essas APIs recém-adicionadas e continuar usando o driver GPU (HAL 1.0) em outro lugar.

Para grandes alterações de HAL (HAL 2.0) que afetam a compilação/vinculação de código de bits, as estruturas RS devem optar por não carregar drivers de GPU fornecidos pelo fornecedor e, em vez disso, usar a CPU ou o caminho Vulkan para aceleração.

O consumo do bitcode RenderScript ocorre em três etapas:

Estágio Detalhes
Compilar
  • O código de bits de entrada (.bc) para bcc deve estar no formato de código de bits LLVM 3.2 e bcc deve ser compatível com versões anteriores de aplicativos existentes (herdados).
  • Entretanto, os metadados em .bc podem mudar (podem haver novas funções de tempo de execução, por exemplo, setters de alocação ∓ getters, funções matemáticas, etc.). Parte das funções de tempo de execução reside em libclcore.bc , parte delas reside em LibRSDriver ou equivalente do fornecedor.
  • Novas funções de tempo de execução ou alterações significativas nos metadados exigem o incremento do nível da API do bitcode. Como os drivers do fornecedor não poderão consumi-lo, a versão HAL também deverá ser incrementada.
  • Os fornecedores podem ter seus próprios compiladores, mas as conclusões/requisitos para bcc também se aplicam a esses compiladores.
Link
  • O .o compilado será vinculado ao driver do fornecedor, por exemplo, libRSDriver_foo.so e libcompiler_rt.so . O caminho da CPU será vinculado a libRSDriver.so .
  • Se o .o exigir uma nova API de tempo de execução de libRSDriver_foo , o driver do fornecedor deverá ser atualizado para suportá-lo.
  • Certos fornecedores podem ter seus próprios linkers, mas o argumento a favor ld.mc também se aplica a eles.
Carregar
  • libRSCpuRef carrega o objeto compartilhado. Se houver alterações nesta interface, será necessário um aumento na versão do HAL.
  • Os fornecedores confiariam no libRSCpuRef para carregar o objeto compartilhado ou implementariam o seu próprio.

Além do HAL, as APIs de tempo de execução e os símbolos exportados também são interfaces. Nenhuma das interfaces mudou desde o Android 7.0 (API 24) e não há planos imediatos para alterá-la no Android 8.0 e posteriores. No entanto, se a interface mudar, a versão HAL também será incrementada.

Implementações de fornecedores

O Android 8.0 e superior requer algumas alterações no driver da GPU para que ele funcione corretamente.

Módulos de driver

  • Os módulos do driver não devem depender de nenhuma biblioteca do sistema que não esteja na lista .
  • O driver deve fornecer seu próprio android.hardware.renderscript@1.0-impl_{NAME} ou declarar a implementação padrão android.hardware.renderscript@1.0-impl como sua dependência.
  • A implementação da CPU libRSDriver.so é um bom exemplo de como remover dependências não VNDK-SP.

Compilador de código de bits

Você pode compilar o bitcode RenderScript para o driver do fornecedor de duas maneiras:

  1. Invoque o compilador RenderScript específico do fornecedor em /vendor/bin/ (método preferencial de compilação de GPU). Semelhante a outros módulos de driver, o binário do compilador do fornecedor não pode depender de nenhuma biblioteca do sistema que não esteja na lista de bibliotecas RenderScript disponíveis para os fornecedores .
  2. Invoque o sistema bcc: /system/bin/bcc com um bcc plugin fornecido pelo fornecedor; este plugin não pode depender de nenhuma biblioteca de sistema que não esteja na lista de bibliotecas RenderScript disponíveis para fornecedores .

Se o bcc plugin do fornecedor precisar interferir na compilação da CPU e sua dependência de libLLVM.so não puder ser facilmente removida, o fornecedor deverá copiar bcc (e todas as dependências não LL-NDK, incluindo libLLVM.so , libbcc.so ) para /vendor .

Além disso, os fornecedores precisam fazer as seguintes alterações:

Figura 8. Mudanças no driver do fornecedor
  1. Copie libclcore.bc para a partição /vendor . Isso garante libclcore.bc , libLLVM.so e libbcc.so estejam sincronizados.
  2. Altere o caminho para o executável bcc definindo RsdCpuScriptImpl::BCC_EXE_PATH na implementação RS HAL.

Política SELinux

A política SELinux afeta o driver e os executáveis ​​do compilador. Todos os módulos de driver devem ser rotulados como same_process_hal_file no file_contexts do dispositivo. Por exemplo:

/vendor/lib(64)?/libRSDriver_EXAMPLE\.so     u:object_r:same_process_hal_file:s0

O executável do compilador deve poder ser invocado por um processo de aplicativo, assim como a cópia do fornecedor do bcc ( /vendor/bin/bcc ). Por exemplo:

device/vendor_foo/device_bar/sepolicy/file_contexts:
/vendor/bin/bcc                    u:object_r:same_process_hal_file:s0

Dispositivos legados

Dispositivos legados são aqueles que atendem às seguintes condições:

  1. PRODUCT_SHIPPING_API_LEVEL é inferior a 26.
  2. PRODUCT_FULL_TREBLE_OVERRIDE não está definido.

Para dispositivos legados, as restrições não são aplicadas durante a atualização para Android 8.0 e superior, o que significa que os drivers podem continuar vinculados a bibliotecas em /system/lib[64] . No entanto, devido à mudança de arquitetura relacionada a OVERRIDE_RS_DRIVER , android.hardware.renderscript@1.0-impl deve ser instalado na partição /vendor ; não fazer isso força o retorno do tempo de execução do RenderScript ao caminho da CPU.

Para obter informações sobre a motivação para a descontinuação do Renderscript, consulte o Android Developers Blog: Android GPU Compute Going Forward . As informações de recursos para esta descontinuação incluem o seguinte: