Renderscript

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

Os dispositivos que executam o Android 8.0 e superior usam a seguinte estrutura RenderScript e HALs de fornecedores:

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 criadas como parte da plataforma e são atualizadas à medida que o system.img é atualizado. No entanto, as libs em /system/lib/vndk-sp são criadas para o fornecedor e não são atualizadas quando o system.img é atualizado (embora possam ser atualizados 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 ) são vinculados às bibliotecas internas do RenderScript localizadas em /system/lib/vndk-sp . Eles não podem ser vinculados a libs em /system/lib porque libs 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 um OTA somente de estrutura impossível.

Projeto

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

Bibliotecas RenderScript disponíveis para fornecedores

Esta seção lista as bibliotecas do RenderScript (conhecidas como Vendor NDK para Same-Process HALs ou VNDK-SP) que estão disponíveis para o código do fornecedor e que 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 libs que não estejam no VNDK-SP sejam usadas pelo código do fornecedor é imposta 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 Same-Process HALs (SP-HALs) , exceto RenderScript , são carregados dentro do namespace do vinculador sphal . O RenderScript é carregado no namespace rs específico do RenderScript, um local que permite uma aplicação um pouco mais flexível para as 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 libs 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 de retorno 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 principal implementação do framework RS) é diretamente dlopen do namespace do vinculador padrão onde a versão da plataforma de libs 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 null mVendorDriverName . libRSDriver.so é (por padrão) dlopen ed e o driver lib é carregado do namespace default porque o chamador ( libRS_internal.so ) também é carregado no namespace default .

Figura 4. Caminho de reserva da CPU

Caminho da GPU

Para o caminho da GPU, o libRS_internal.so é carregado de forma diferente. Primeiro, libRS.so usa android.hardware.renderscript@1.0.so (e seu libhidltransport.so subjacente) 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 s 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 compilação OVERRIDE_RS_DRIVER , que é incorporado à implementação RS HAL ( hardware/interfaces/renderscript/1.0/default/Context.cpp ). Este nome de driver é então dlopen para o contexto RS para o caminho da GPU.

A criação do objeto RsContext é delegada à implementação do 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 então carrega o driver especificado quando o RsContext é inicializado. Nesse caso, a biblioteca de 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 substituto 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 puder ser encontrada/carregada do namespace sphal (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 bcc

bcc plugin é uma biblioteca fornecida pelo fornecedor carregada no compilador bcc . Como bcc é um processo do sistema no diretório /system/bin , a biblioteca de 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 um SP-HAL, a biblioteca bcc-plugin :

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

Essa restrição é imposta 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() por libLLVM.so . No Android 8.0 e superior, isso é especificado na opção -plugin e a lib é carregada diretamente pelo próprio bcc . Essa opção habilita um caminho não específico do Android para o projeto LLVM de código aberto.

Figura 6. Carregando plug-in bcc, Android 7.xe inferior


Figura 7. Carregando plug-in bcc, Android 8.0 e superior

Pesquisar caminhos para ld.mc

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

As bibliotecas de tempo de execução incluem:

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

Ao carregar o bitcode compilado no processo do aplicativo, forneça exatamente a mesma biblioteca que foi 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 do framework RS e usando dladdr() para obter o caminho do arquivo mapeado para o endereço.

Política SELinux

Como resultado das mudanças na política do SELinux no Android 8.0 e superior, você deve seguir regras específicas (impostas por neverallows ) ao rotular arquivos adicionais na partição do vendor :

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

Para obter detalhes sobre a política do 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 haverá aumento de versão HAL, as estruturas RS continuarão usando o driver GPU existente (HAL 1.0).

Para pequenas alterações de HAL (HAL 1.1) que não afetam o código de bits, as estruturas devem retornar à CPU para essas APIs recém-adicionadas e continuar usando o driver GPU (HAL 1.0) em outros lugares.

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

O consumo de bitcode RenderScript ocorre em três estágios:

Etapa 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 o bcc deve ser compatível com versões anteriores com aplicativos (herdados) existentes.
  • No entanto, os metadados em .bc podem mudar (pode 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 de fornecedor.
  • Novas funções de tempo de execução ou alterações de meta-dados importantes exigem o incremento do nível de API de código de bits. Como os drivers do fornecedor não poderão consumi-lo, a versão HAL também deve 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 para ld.mc também se aplica a eles.
Carga
  • libRSCpuRef carrega o objeto compartilhado. Se houver alterações nessa interface, é necessário um aumento da versão HAL.
  • Os fornecedores confiariam no libRSCpuRef para carregar o objeto compartilhado ou implementariam seus próprios.

Além do HAL, as APIs de tempo de execução e os símbolos exportados também são interfaces. Nenhuma das interfaces foi alterada 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 for alterada, 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 o driver da GPU funcione corretamente.

Módulos de driver

  • Os módulos de 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.
  • Implementação de 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 do RenderScript disponíveis para os fornecedores .
  2. Invoque system bcc: /system/bin/bcc com um bcc plugin fornecido pelo fornecedor; este plugin não pode depender de nenhuma biblioteca do 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 em 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 ) em partição /vendor .

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

Figura 8. Alterações 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 da implementação RS HAL.

Política SELinux

A política do SELinux afeta os executáveis ​​do driver e do compilador. Todos os módulos de driver devem ser rotulados 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 de 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 ao atualizar para o 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 fallback do tempo de execução do RenderScript para o 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 suspensão de uso incluem o seguinte: