O RenderScript é um framework para executar tarefas intensivas em termos de computação 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 trabalha em paralelo em todos 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 programar o trabalho. O RenderScript é especialmente útil para apps que realizam processamento de imagens, fotografia computacional ou visão computacional.
Dispositivos com o Android 8.0 e versões mais recentes usam o seguinte framework RenderScript e HALs do fornecedor:
Figura 1. Link do código do fornecedor para bibliotecas internas.
As diferenças do RenderScript no Android 7.x e versões anteriores incluem:
- Duas instâncias de libs internas do RenderScript em um processo. Um conjunto é para
o caminho de fallback da CPU e é diretamente de
/system/lib
. O outro conjunto é para o caminho da GPU e é de/system/lib/vndk-sp
. - As libs internas do RS no
/system/lib
são criadas como parte da plataforma e são atualizadas conforme osystem.img
é atualizado. No entanto, as bibliotecas em/system/lib/vndk-sp
são criadas para o fornecedor e não são atualizadas quando osystem.img
é atualizado. Embora elas possam ser atualizadas para uma correção de segurança, a ABI delas permanece a mesma. - O código do fornecedor (HAL do RS, driver do RS e
bcc plugin
) são vinculados às libs internas do RenderScript localizadas em/system/lib/vndk-sp
. Elas não podem se vincular a bibliotecas em/system/lib
porque as bibliotecas nesse diretório são criadas 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). Isso tornaria impossível uma OTA somente de framework.
Design
As seções abaixo detalham o design do RenderScript no Android 8.0 e versões mais recentes.
Bibliotecas do RenderScript disponíveis para fornecedores
Esta seção lista as bibliotecas do RenderScript (conhecidas como NDK do fornecedor para HALs do mesmo processo ou VNDK-SP) que estão disponíveis para o código do fornecedor e que podem ser vinculadas. Ele também detalha outras bibliotecas 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 variar entre as versões do Android,
ela é imutável para uma versão específica do Android. Para conferir uma lista atualizada das
bibliotecas disponíveis, consulte /system/etc/ld.config.txt
.
Bibliotecas do RenderScript | Bibliotecas que não são do RenderScript |
---|---|
|
|
Configuração de namespace do vinculador
A restrição de vinculação que impede que as bibliotecas que não estão no VNDK-SP sejam usadas pelo código do fornecedor é aplicada no momento da execução usando o namespace do vinculador. Para mais detalhes, consulte a apresentação VNDK Design.
Em um dispositivo com o Android 8.0 e versões mais recentes, todas as HALs do mesmo processo (SP-HALs, na sigla em inglês)
exceto RenderScript são carregadas 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 de RS precisa carregar
o código de bits compilado, /data/*/*.so
é adicionado ao caminho do
namespace rs
. Outros SP-HALs não podem 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 o vinculador.
Carregar drivers
Caminho de fallback da CPU
Dependendo da existência do bit RS_CONTEXT_LOW_LATENCY
ao criar um contexto de RS, o caminho da CPU ou da GPU é selecionado. Quando o
caminho da CPU é selecionado, libRS_internal.so
(a implementação principal
do framework RS) é diretamente dlopen
ed do namespace de vinculador padrão
em que a versão da plataforma das bibliotecas RS é fornecida.
A implementação do HAL do RS do fornecedor não é usada quando o caminho de fallback
da CPU é usado e um objeto RsContext
é criado com
mVendorDriverName
nulo. libRSDriver.so
é dlopen
ado (por
padrão) e a biblioteca do driver é carregada do
namespace default
porque o autor da chamada
(libRS_internal.so
) também é carregado no namespace
default
.
Figura 3. Caminho de fallback da CPU.
Caminho da GPU
Para o caminho da GPU, o libRS_internal.so
é carregado de maneira diferente.
Primeiro, libRS.so
usa
android.hardware.renderscript@1.0.so
(e o
libhidltransport.so
) para carregar
android.hardware.renderscript@1.0-impl.so
(uma implementação
do fornecedor do RS HAL) em um namespace de linker diferente chamado
sphal
. O HAL
RS dlopen
s libRS_internal.so
em outro
namespace de vinculação chamado rs
.
Os fornecedores podem fornecer o próprio driver RS definindo a flag
OVERRIDE_RS_DRIVER
, que é incorporada à implementação
HAL do RS
(hardware/interfaces/renderscript/1.0/default/Context.cpp
). Esse
nome de driver é dlopen
ed para o contexto RS do caminho da GPU.
A criação do objeto RsContext
é delegada à implementação da HAL de RS. O HAL chama de volta para a estrutura RS usando
a função rsContextCreateVendor()
com o nome do driver para
usar como um argumento. O framework RS carrega o driver especificado quando o
RsContext
é inicializado. Nesse caso, a biblioteca de drivers é
carregada no namespace rs
porque o objeto RsContext
é criado dentro do namespace rs
e
/vendor/lib
está no caminho de pesquisa do namespace.
Figura 4. Caminho alternativo 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
rs
, o carregamento é feito indiretamente pela linha a seguir em
/system/etc/ld.config.txt
:
namespace.sphal.link.rs.shared_libs = libRS_internal.so
Essa linha especifica que o vinculador dinâmico precisa carregar
libRS_internal.so
do namespace rs
quando a biblioteca
não pode ser encontrada/carregada do namespace sphal
(o que sempre
acontece porque o namespace sphal
não pesquisa
/system/lib/vndk-sp
em que libRS_internal.so
reside). Com essa configuração, uma chamada dlopen()
simples para
libRS_internal.so
é suficiente para fazer a transição de namespace.
Carregar plug-in Cco
bcc plugin
é uma biblioteca fornecida pelo fornecedor e carregada no
compilador bcc
. Como bcc
é um processo do sistema no
diretório /system/bin
, a biblioteca bcc plugin
pode ser
considerada um HAL do fornecedor, que pode ser carregado diretamente no
processo do sistema sem ser vinculado. Como uma SP-HAL, a biblioteca bcc-plugin
:
- Não é possível vincular bibliotecas exclusivas do framework, como
libLLVM.so
. - Pode ser vinculado apenas às bibliotecas do VNDK-SP disponíveis para o fornecedor.
Essa restrição é aplicada ao carregar o bcc plugin
no
namespace sphal
usando a
função android_sphal_load_library()
. Nas versões anteriores do
Android, o nome do plug-in era especificado usando a opção -load
e
a biblioteca era carregada usando o dlopen()
simples por
libLLVM.so
. No Android 8.0 e versões mais recentes, isso é especificado na
opção -plugin
, e a biblioteca é carregada diretamente pelo
bcc
. Essa opção ativa um caminho não específico do Android para
o projeto LLVM de código aberto.
Figura 5. Carregamento do plug-in bcc, Android 7.x e versões anteriores.
Figura 6. Carregamento do plug-in bcc, Android 8.0 e versões mais recentes.
Pesquisar caminhos para ld.mc
Ao executar ld.mc
, algumas bibliotecas de execução do RS são fornecidas como entradas
para o vinculador. O bitcode RS do app é vinculado às bibliotecas de execução
e, quando o bitcode convertido é carregado em um processo do app, as bibliotecas de execução
são vinculadas dinamicamente do bitcode convertido.
As bibliotecas de execução incluem:
libcompiler_rt.so
libm.so
libc.so
- Driver RS (
libRSDriver.so
ouOVERRIDE_RS_DRIVER
)
Ao carregar o bitcode compilado no processo do app, forneça 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, o framework de RS usa diferentes caminhos de pesquisa para as bibliotecas de ambiente de execução ao
executar ld.mc
, dependendo se o próprio framework do RS é
carregado de /system/lib
ou /system/lib/vndk-sp
.
Isso pode ser determinado lendo o endereço de um símbolo arbitrário de uma lib de framework de RS e usando dladdr()
para ter o caminho de arquivo mapeado para o endereço.
Política do SELinux
Como resultado das mudanças na política do SELinux no Android 8.0 e versões mais recentes, é necessário
seguir regras específicas (aplicadas pelo neverallows
) ao
rotular outros arquivos na partição vendor
:
vendor_file
precisa ser o rótulo padrão para todos os arquivos na partiçãovendor
. A política da plataforma exige isso para acessar implementações de HAL de passagem.- Todos os novos
exec_types
adicionados na partiçãovendor
usando a SEPolicy do fornecedor precisam ter o atributovendor_file_type
. Isso é aplicado porneverallows
. - Para evitar conflitos com futuras atualizações de plataforma/framework, evite rotular
arquivos diferentes de
exec_types
na partiçãovendor
. - Todas as dependências de biblioteca para HALs de mesmo processo identificados pelo AOSP precisam ser
marcadas como
same_process_hal_file
.
Para mais detalhes sobre a política do SELinux, consulte Security-Enhanced Linux no Android.
Compatibilidade com ABI para bitcode
Se nenhuma API nova for adicionada, ou seja, sem promoção de versão da HAL, os frameworks de RS continuarão usando o driver da GPU (HAL 1.0) existente.
Para mudanças menores do HAL (HAL 1.1) que não afetam o bitcode, os frameworks precisam usar a CPU para essas APIs recém-adicionadas e continuar usando o driver de GPU (HAL 1.0) em outro lugar.
Para mudanças importantes no HAL (HAL 2.0) que afetam a vinculação/compilação de bitcode, os frameworks do RS precisam escolher 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 do bitcode do RenderScript ocorre em três etapas:
Etapa | Detalhes |
---|---|
Compilar |
|
Link |
|
Carregamento |
|
Além do HAL, as APIs 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 mudá-la no Android 8.0 e em versões mais recentes. No entanto, se a interface mudar, a versão do HAL também vai aumentar.
Implementações do fornecedor
O Android 8.0 e versões mais recentes exigem algumas mudanças de driver da GPU para que ele funcione corretamente.
Módulos de driver
- Os módulos de driver não podem depender de nenhuma biblioteca do sistema que não esteja na lista.
- O driver precisa fornecer o próprio
android.hardware.renderscript@1.0-impl_{NAME}
ou declarar a implementação padrãoandroid.hardware.renderscript@1.0-impl
como dependência. - A implementação de CPU
libRSDriver.so
é um bom exemplo de como remover dependências que não são do VNDK-SP.
Compilador de bitcode
Você pode compilar bitcode do RenderScript para o driver do fornecedor de duas maneiras:
- Invocar o compilador do RenderScript específico do fornecedor em
/vendor/bin/
(método preferido de compilação de GPU). Assim como 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 fornecedores. - Chamar o bcc do sistema:
/system/bin/bcc
com umbcc plugin
fornecido pelo fornecedor. Esse plug-in não pode depender de nenhuma biblioteca do sistema que não esteja na lista de bibliotecas do RenderScript disponíveis para fornecedores.
Se o bcc plugin
do fornecedor precisar interferir na compilação da
CPU e a dependência de libLLVM.so
não puder ser removida
facilmente, o fornecedor precisará copiar bcc
(e todas as dependências que não sejam
LL-NDK, incluindo libLLVM.so
, libbcc.so
) para
a partição /vendor
.
Além disso, os fornecedores precisam fazer as seguintes mudanças:
Figura 7. Alterações no driver do fornecedor.
- Copie
libclcore.bc
para a partição/vendor
. Isso garante quelibclcore.bc
,libLLVM.so
elibbcc.so
estejam sincronizados. - Mude o caminho para o executável
bcc
definindoRsdCpuScriptImpl::BCC_EXE_PATH
da implementação da HAL do RS.
Política do SELinux
A política do SELinux afeta os executáveis do driver e do compilador. Todos
os módulos do driver precisam ser rotulados como same_process_hal_file
no
file_contexts
do dispositivo. Exemplo:
/vendor/lib(64)?/libRSDriver_EXAMPLE\.so u:object_r:same_process_hal_file:s0
O executável do compilador precisa ser invocado por um processo do app, 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
Os dispositivos legados são aqueles que atendem às seguintes condições:
- PRODUCT_SHIPPING_API_LEVEL é inferior a 26.
- PRODUCT_FULL_TREBLE_OVERRIDE não está definido.
Para dispositivos legados, as restrições não são aplicadas ao fazer upgrade para
o Android 8.0 e versões mais recentes, o que significa que os drivers podem continuar vinculando às bibliotecas
em /system/lib[64]
. No entanto, devido à mudança de arquitetura
relacionada a OVERRIDE_RS_DRIVER
,
android.hardware.renderscript@1.0-impl
precisa ser instalado na
partição /vendor
. Se isso não for feito, o tempo de execução do RenderScript
será substituído pelo caminho da CPU.
Para informações sobre o motivo da descontinuação do Renderscript, consulte o Blog de desenvolvedores Android: Android GPU Compute Going Forward (link em inglês). As informações de recursos para essa descontinuação incluem o seguinte:
- Migrar do Renderscript
- Exemplo de RenderScriptMigration
- README do kit de ferramentas de substituição de intrínsecos
- Toolkit.kt de substituição de intrínsecos