Esta página fornece um método canônico para adicionar ou definir propriedades do sistema no Android, com diretrizes para refatorar propriedades do sistema. Use as diretrizes ao refatorar, a menos que você tenha uma forte problema de compatibilidade que determina o contrário.
Etapa 1: definir a propriedade do sistema
Ao adicionar uma propriedade do sistema, escolha um nome para ela e associe com um contexto de propriedade SELinux. Se não houver um contexto adequado, crie um novo. O nome é usado ao acessar a propriedade. a propriedade é usado para controlar a acessibilidade em termos de SELinux. Os nomes podem ser qualquer mas o AOSP recomenda que você siga um formato estruturado para torná-los claros.
Nome da propriedade
Use este formato com capitalização snake_case:
[{prefix}.]{group}[.{subgroup}]*.{name}[.{type}]
Use "" (omitido), ro
(para propriedades definidas apenas uma vez) ou persist
(para propriedades que persistem após reinicializações) para o elemento prefix
.
Avisos
Use ro
somente quando tiver certeza de que não precisará que prefix
seja gravável
no futuro. ** Não especifique o prefixo ro
.** Em vez disso, use o sepolicy para
tornam o prefix
somente leitura, ou seja, gravável apenas pelo init
.
Use persist
somente quando tiver certeza de que o valor precisa ser mantido
é reinicializado e usar as propriedades do sistema é a única opção.
O Google analisa estritamente as propriedades do sistema que têm propriedades ro
ou
persist
.
O termo group
é usado para agregar propriedades relacionadas. O objetivo é
ser um nome de subsistema semelhante em uso a audio
ou telephony
. Não use
termos ambíguos ou sobrecarregados, como sys
, system
, dev
, default
ou
config
.
É prática comum usar o nome do tipo de domínio de um
processo que tenha acesso exclusivo de leitura ou gravação às propriedades do sistema. Por
exemplo, para as propriedades do sistema em que o processo vold
tem acesso de gravação,
é comum usar vold
(o nome do tipo de domínio para o processo) como o
nome do grupo.
Se necessário, adicione subgroup
para categorizar ainda mais as propriedades, mas evite
termos ambíguos ou sobrecarregados para descrever esse elemento. Você também pode ter mais
de um subgroup
.
Muitos nomes de grupos já foram definidos. Consulte a
system/sepolicy/private/property_contexts
e usar nomes de grupos existentes
sempre que possível, em vez de criar novas. A tabela a seguir mostra
exemplos de nomes de grupos usados com frequência.
Domínio | Grupo (e subgrupo) |
---|---|
relacionado ao Bluetooth | bluetooth |
sysprops do cmdline do kernel | boot |
sysprop que identificam um build | build
|
serviços de telefonia | telephony |
relacionado a áudio | audio |
relacionados a gráficos | graphics |
relacionado ao vold | vold |
O seguinte comando define o uso de name
e type
no regex anterior
exemplo.
[{prefix}.]{group}[.{subgroup}]*.{name}[.{type}]
name
identifica uma propriedade do sistema dentro de um grupo.type
é um elemento opcional que esclarece o tipo ou a intenção do propriedade do sistema. Por exemplo, em vez de nomear um sysprop comoaudio.awesome_feature_enabled
ou apenasaudio.awesome_feature
, renomeie-o comoaudio.awesome_feature.enabled
para refletir o tipo e a intent da propriedade do sistema.
Não há uma regra específica sobre qual deve ser o tipo. são o uso recomendações:
enabled
: use se o tipo for uma propriedade de sistema booleano usada para transformar um recurso.config
: use se a intenção for esclarecer que a propriedade do sistema não representa um estado dinâmico do sistema. ele representa valor pré-configurado (por exemplo, algo somente leitura).List
: use se for uma propriedade do sistema com o valor de uma lista.Timeoutmillis
: use se for uma propriedade do sistema para um valor de tempo limite em unidades de ms.
Exemplos:
persist.radio.multisim.config
drm.service.enabled
Contexto da propriedade
O novo esquema de contexto de propriedade do SELinux permite uma granularidade mais refinada e mais e nomes descritivos. Semelhante ao que é usado para nomes de propriedades, o AOSP recomenda o seguinte formato:
{group}[_{subgroup}]*_prop
Os termos são definidos da seguinte maneira:
group
e subgroup
têm o mesmo significado definido nas opções anteriores
exemplo de regex. Por exemplo, vold_config_prop
significa
propriedades, que são configurações de um fornecedor e devem ser definidas pelo
vendor_init
, enquanto vold_status_prop
ou apenas vold_prop
significa propriedades
que têm o objetivo de expor o status atual de vold
.
Ao nomear um contexto de propriedade, escolha nomes que reflitam o uso geral da as propriedades. Evite os seguintes tipos de termos:
- Termos que parecem muito gerais e ambíguos, como
sys
,system
edefault
. - Termos que codificam diretamente a acessibilidade, como
exported
,apponly
ro
,public
eprivate
.
Prefira usos de nome, como vold_config_prop
a exported_vold_prop
,
ou vold_vendor_writable_prop
.
Tipo
O tipo de propriedade pode ser um dos seguintes, conforme listado na tabela.
Tipo | Definição |
---|---|
Booleano | true ou 1 para verdadeiro, false ou 0 para falso |
Número inteiro | Inteiro de 64 bits assinado |
Número inteiro sem sinal | inteiro de 64 bits não assinado |
Duplo | ponto flutuante de dupla precisão |
String | qualquer string UTF-8 válida |
enum | os valores podem ser qualquer string UTF-8 válida sem espaços em branco. |
Lista acima | Uma vírgula (, ) é usada como delimitadorA lista de números inteiros [1, 2, 3] é armazenada como 1,2,3 |
Internamente, todas as propriedades são armazenadas como strings. Para aplicar o tipo,
especificando-o como um arquivo property_contexts
. Para mais informações, consulte
property_contexts
na Etapa 3.
Etapa 2: determinar os níveis de acessibilidade necessários
Há quatro macros auxiliares que definem uma propriedade.
Tipo de acessibilidade | Significado |
---|---|
system_internal_prop |
Propriedades usadas somente em /system |
system_restricted_prop |
Propriedades que são lidas fora de /system , mas não gravadas |
system_vendor_config_prop |
Propriedades que são lidas fora de /system e gravadas apenas pelo vendor_init |
system_public_prop |
Propriedades que são lidas e gravadas fora de /system |
Definir o acesso às propriedades do sistema da forma mais restrita possível. Antes, o acesso amplo resultou em falhas de aplicativo e vulnerabilidades de segurança. Considere as seguintes perguntas na delimitação do escopo:
- Essa propriedade do sistema precisa ser mantida? (Se sim, por quê?)
- Qual processo precisa ter acesso de leitura a essa propriedade?
- Qual processo precisa ter acesso de gravação a essa propriedade?
Use as perguntas anteriores e a árvore de decisão a seguir como ferramentas para determinar um escopo apropriado para o acesso.
Figura 1. Árvore de decisão para determinar o escopo de acesso às propriedades do sistema
Etapa 3: adicionar ao system/sepolicy
Ao acessar o sysprop, o SELinux controla a acessibilidade dos processos. Depois
determina qual nível de acessibilidade é necessário, define contextos de propriedade
em system/sepolicy
, junto com as regras allow e Neverallow adicionais
sobre quais processos têm permissão para ler ou gravar.
Primeiro, defina o contexto da propriedade no arquivo
system/sepolicy/public/property.te
. Se a propriedade for interna do sistema, defina-a no
arquivo system/sepolicy/private/property.te
. Use uma destas opções:
as macros system_[accessibility]_prop([context])
que fornecem a
a acessibilidade exigida da propriedade do sistema. Confira um exemplo do
arquivo system/sepolicy/public/property.te
:
system_public_prop(audio_foo_prop)
system_vendor_config_prop(audio_bar_prop)
Exemplo para adicionar ao arquivo system/sepolicy/private/property.te
:
system_internal_prop(audio_baz_prop)
Depois conceda acesso de leitura e (ou gravação) ao contexto da propriedade. Use macros set_prop
e get_prop
para conceder acesso no arquivo
system/sepolicy/public/{domain}.te
ou system/sepolicy/private/{domain}.te
. Use private
sempre que possível. O public
é adequado apenas se a
macro set_prop
ou get_prop
afetar domínios fora do domínio principal.
Exemplo no arquivo system/sepolicy/private/audio.te
:
set_prop(audio, audio_foo_prop)
set_prop(audio, audio_bar_prop)
Exemplo no arquivo system/sepolicy/public/domain.te
:
get_prop(domain, audio_bar_prop)
Terceiro, adicione algumas regras de "nunca permitir" para reduzir ainda mais a acessibilidade
dentro do escopo da macro. Por exemplo, suponha que você usou
system_restricted_prop
porque as propriedades do sistema precisam ser lidas pelo fornecedor
processos de negócios. Se o acesso de leitura não for exigido por todos os processos do fornecedor e for
exigido apenas por um determinado conjunto de processos (como vendor_init
), proíbem
os processos do fornecedor que não precisam de acesso de leitura.
Use a seguinte sintaxe para restringir o acesso de leitura e gravação:
Para restringir o acesso de gravação:
neverallow [domain] [context]:property_service set;
Para restringir o acesso de leitura:
neverallow [domain] [context]:file no_rw_file_perms;
Coloque regras de nunca permitir no arquivo system/sepolicy/private/{domain}.te
se a
regra de nunca permitir estiver vinculada a um domínio específico. Para regras mais amplas de nunca permitir, use
domínios gerais, como estes, sempre que apropriado:
system/sepolicy/private/property.te
system/sepolicy/private/coredomain.te
system/sepolicy/private/domain.te
No arquivo system/sepolicy/private/audio.te
, coloque o seguinte:
neverallow {
domain -init -audio
} {audio_foo_prop audio_bar_prop}:property_service set;
No arquivo system/sepolicy/private/property.te
, coloque o seguinte:
neverallow {
domain -coredomain -vendor_init
} audio_prop:file no_rw_file_perms;
Observe que {domain -coredomain}
captura todos os processos do fornecedor. Portanto,
{domain -coredomain -vendor_init}
significa "todos os processos do fornecedor exceto
vendor_init
".
Por fim, associe uma propriedade do sistema ao contexto da propriedade. Isso garante
que o acesso concedido e as regras de nunca permitir aplicadas aos
contextos de propriedade sejam aplicados às propriedades reais. Para fazer isso, adicione uma entrada ao
arquivo property_contexts
, que descreve o mapeamento entre propriedades
do sistema e contextos de propriedade. Nesse arquivo, você pode especificar uma única propriedade ou um prefixo para que as propriedades sejam mapeadas para um contexto.
Esta é a sintaxe para mapear uma única propriedade:
[property_name] u:object_r:[context_name]:s0 exact [type]
Esta é a sintaxe para mapear um prefixo:
[property_name_prefix] u:object_r:[context_name]:s0 prefix [type]
Também é possível especificar o tipo de propriedade, que pode ser um dos seguintes:
bool
int
uint
double
enum [list of possible values...]
string
Usestring
para propriedades de lista.
Verifique se cada entrada tem seu tipo designado sempre que possível, já que type
é
aplicada ao definir property
. O exemplo a seguir mostra como gravar um mapeamento:
# binds a boolean property "ro.audio.status.enabled"
# to the context "audio_foo_prop"
ro.audio.status.enabled u:object_r:audio_foo_prop:s0 exact bool
# binds a boolean property "vold.decrypt.status"
# to the context "vold_foo_prop"
# The property can only be set to one of these: on, off, unknown
vold.decrypt.status u:object_r:vold_foo_prop:s0 exact enum on off unknown
# binds any properties starting with "ro.audio.status."
# to the context "audio_bar_prop", such as
# "ro.audio.status.foo", or "ro.audio.status.bar.baz", and so on.
ro.audio.status. u:object_r:audio_bar_prop:s0 prefix
Quando uma entrada exata e uma entrada de prefixo entram em conflito, a entrada exata assume o
precedência. Para mais exemplos, consulte system/sepolicy/private/property_contexts
.
Etapa 4: determinar os requisitos de estabilidade
A estabilidade é outro aspecto das propriedades do sistema e é diferente da acessibilidade. A estabilidade indica se uma propriedade do sistema pode ou não ser alterada (por exemplo, renomeada ou até mesmo removida) no futuro. Isso é particularmente importante à medida que o SO Android se torna modular. Com o Treble, o sistema, as partições de produto e fornecedor podem ser atualizadas independentemente umas das outras. Com No geral, algumas partes do SO são modularizadas como módulos atualizáveis (em APEXs). ou APKs).
Se uma propriedade do sistema for usada em softwares atualizáveis, por exemplo entre partições do sistema e do fornecedor, ele precisa ser estável. No entanto, se ele for usado apenas em um módulo Mainline específico, por exemplo, é possível mudar o nome, o tipo ou os contextos de propriedade e até mesmo removê-lo.
Faça as seguintes perguntas para determinar a estabilidade de uma propriedade do sistema:
- Esta propriedade do sistema deve ser configurada por parceiros (ou configurada) de maneira diferente por dispositivo)? Se sim, ele precisa ser estável.
- Essa propriedade do sistema definida pelo AOSP é destinada a ser gravada ou lida em
código (não em processo) que existe em partições que não são do sistema, como
vendor.img
ouproduct.img
? Se sim, ele precisa ser estável. - A propriedade do sistema é acessada nos módulos Mainline ou em um Mainline e a parte não atualizável da plataforma? Em caso afirmativo, ele precisa ser estável.
Para as propriedades estáveis do sistema, defina cada uma como uma API e use a API para acessar a propriedade do sistema, conforme explicado na Etapa 6.
Etapa 5: definir propriedades no momento da build
Defina propriedades no tempo de build com variáveis do makefile. Tecnicamente, os valores
são integrados ao {partition}/build.prop
. Depois, init
lê
{partition}/build.prop
para definir as propriedades. Há dois conjuntos de tais
variáveis: PRODUCT_{PARTITION}_PROPERTIES
e TARGET_{PARTITION}_PROP
.
PRODUCT_{PARTITION}_PROPERTIES
contém uma lista de valores de propriedade. A sintaxe
é {prop}={value}
ou {prop}?={value}
.
{prop}={value}
é uma atribuição normal que garante que {prop}
seja definido como
{value}
. Apenas uma atribuição desse tipo é possível por propriedade.
{prop}?={value}
é uma atividade opcional. {prop}
é definido como {value}
somente se
não houver nenhuma atividade {prop}={value}
. Se houver várias atribuições opcionais,
a primeira será usada.
# sets persist.traced.enable to 1 with system/build.prop
PRODUCT_SYSTEM_PROPERTIES += persist.traced.enable=1
# sets ro.zygote to zygote32 with system/build.prop
# but only when there are no other assignments to ro.zygote
# optional are useful when giving a default value to a property
PRODUCT_SYSTEM_PROPERTIES += ro.zygote?=zygote32
# sets ro.config.low_ram to true with vendor/build.prop
PRODUCT_VENDOR_PROPERTIES += ro.config.low_ram=true
TARGET_{PARTITION}_PROP
contém uma lista de arquivos, que é emitido diretamente para
{partition}/build.prop
. Cada arquivo contém uma lista de pares {prop}={value}
.
# example.prop
ro.cp_system_other_odex=0
ro.adb.secure=0
ro.control_privapp_permissions=disable
# emits example.prop to system/build.prop
TARGET_SYSTEM_PROP += example.prop
Para mais detalhes, consulte
build/make/core/sysprop.mk
.
Etapa 6: acessar propriedades no ambiente de execução
As propriedades podem ser lidas e gravadas no momento da execução.
Scripts de inicialização
Os arquivos de script de inicialização (geralmente arquivos *.rc) podem ler uma propriedade por ${prop}
ou
${prop:-default}
, pode definir uma ação que é executada sempre que uma propriedade se torna uma
valor específico e pode gravar as propriedades usando o comando setprop
.
# when persist.device_config.global_settings.sys_traced becomes 1,
# set persist.traced.enable to 1
on property:persist.device_config.global_settings.sys_traced=1
setprop persist.traced.enable 1
# when security.perf_harden becomes 0,
# write /proc/sys/kernel/sample_rate to the value of
# debug.sample_rate. If it's empty, write -100000 instead
on property:security.perf_harden=0
write /proc/sys/kernel/sample_rate ${debug.sample_rate:-100000}
Comandos do shell getprop e setprop
É possível usar os comandos do shell getprop
ou setprop
, respectivamente, para ler ou
gravar as propriedades. Para mais detalhes, invoque getprop --help
ou
setprop --help
.
$ adb shell getprop ro.vndk.version
$
$ adb shell setprop security.perf_harden 0
Sysprop como API para C++/Java/Rust
Com o sysprop como API, é possível definir propriedades do sistema e usar APIs geradas automaticamente
que são concretas e digitadas. Definir scope
com Public
também faz com que
APIs disponíveis para os módulos além dos limites e garante a estabilidade da API. Confira
exemplo de um arquivo .sysprop
, um módulo Android.bp
e códigos C++, Java e Rust.
usá-las.
# AudioProps.sysprop
# module becomes static class (Java) / namespace (C++) for serving API
module: "android.sysprop.AudioProps"
# owner can be Platform or Vendor or Odm
owner: Platform
# one prop defines one property
prop {
prop_name: "ro.audio.volume.level"
type: Integer
scope: Public
access: ReadWrite
api_name: "volume_level"
}
…
// Android.bp
sysprop_library {
name: "AudioProps",
srcs: ["android/sysprop/AudioProps.sysprop"],
property_owner: "Platform",
}
// Rust, Java and C++ modules can link against the sysprop_library
rust_binary {
rustlibs: ["libaudioprops_rust"],
…
}
java_library {
static_libs: ["AudioProps"],
…
}
cc_binary {
static_libs: ["libAudioProps"],
…
}
// Rust code accessing generated API.
// Get volume. Use 50 as the default value.
let vol = audioprops::volume_level()?.unwrap_or_else(50);
// Java codes accessing generated API
// get volume. use 50 as the default value.
int vol = android.sysprop.AudioProps.volume_level().orElse(50);
// add 10 to the volume level.
android.sysprop.AudioProps.volume_level(vol + 10);
// C++ codes accessing generated API
// get volume. use 50 as the default value.
int vol = android::sysprop::AudioProps::volume_level().value_or(50);
// add 10 to the volume level.
android::sysprop::AudioProps::volume_level(vol + 10);
Para mais informações, consulte Implementar propriedades do sistema como APIs.
Métodos e funções de propriedade de baixo nível do C/C++, Java e Rust
Quando possível, usar Sysprop como API, mesmo com funções C/C++ ou Rust de baixo nível ou métodos Java de baixo nível estão disponíveis para você.
libc
, libbase
e libcutils
oferecem funções de propriedade do sistema C++. libc
tem a API, enquanto as funções libbase
e libcutils
são
wrappers. Se possível, use as funções sysprop libbase
, que são as
mais convenientes, e os binários do host podem usar as funções libbase
. Para mais
detalhes, consulte sys/system_properties.h
(libc
), android-base/properties.h
(libbase
) e cutils/properties.h
(libcutils
).
A classe android.os.SystemProperties
oferece métodos de propriedade do sistema Java.
O módulo rustutils::system_properties
oferece funções de propriedade do sistema Rust.
e tipos.
Apêndice: adicionar propriedades específicas do fornecedor
Os parceiros (incluindo Googlers que trabalham no contexto de desenvolvimento do Pixel) querem
para definir propriedades do sistema específicas do hardware (ou do dispositivo).
As propriedades específicas do fornecedor são de propriedade do parceiro e exclusivas
próprio hardware ou dispositivo, não para a plataforma. Como eles dependem de hardware ou
dispositivo, eles devem ser usados nas partições /vendor
ou /odm
.
Desde o Project Treble, as propriedades da plataforma e do fornecedor foram divididas completamente para evitar conflitos. A seguir, descrevemos como definir as propriedades do fornecedor e quais delas precisam ser usadas sempre.
Namespace em nomes de propriedade e contexto
Todas as propriedades do fornecedor precisam começar com um dos prefixos a seguir para evitar colisão entre elas e as propriedades de outras partições.
ctl.odm.
ctl.vendor.
ctl.start$odm.
ctl.start$vendor.
ctl.stop$odm.
ctl.stop$vendor.
init.svc.odm.
init.svc.vendor.
ro.odm.
ro.vendor.
odm.
persist.odm.
persist.vendor.
vendor.
Observe que ro.hardware.
é permitido como prefixo, mas apenas para compatibilidade.
Não use para propriedades normais.
Os exemplos a seguir usam um dos prefixos listados anteriormente:
vendor.display.primary_red
persist.vendor.faceauth.use_disk_cache
ro.odm.hardware.platform
Todos os contextos de propriedade do fornecedor precisam começar com vendor_
. Isso também serve para
compatibilidade. Confira alguns exemplos:
vendor_radio_prop
.vendor_faceauth_prop
.vendor_usb_prop
.
É responsabilidade do fornecedor nomear e manter as propriedades, então siga as sugerido na Etapa 2, além do os requisitos de namespaces do fornecedor.
Regras SEPolicy específicas do fornecedor e property_contexts
As propriedades do fornecedor podem ser definidas pela macro vendor_internal_prop
. Coloque as
regras específicas do fornecedor que você define no diretório BOARD_VENDOR_SEPOLICY_DIRS
.
Por exemplo, suponha que você está definindo uma propriedade de faceauth do fornecedor em coral.
No arquivo BoardConfig.mk
(ou em qualquer inclusão de BoardConfig.mk
), coloque o
seguintes:
BOARD_VENDOR_SEPOLICY_DIRS := device/google/coral-sepolicy
No arquivo device/google/coral-sepolicy/private/property.te
, coloque o
seguinte:
vendor_internal_prop(vendor_faceauth_prop)
No arquivo device/google/coral-sepolicy/private/property_contexts
, coloque o
seguintes:
vendor.faceauth.trace u:object_r:vendor_faceauth_prop:s0 exact bool
Limitações das propriedades do fornecedor
Como as partições de sistema e produto não podem depender do fornecedor, nunca
Permitem que as propriedades do fornecedor sejam acessadas pelo system
, system-ext
ou
product
partições.
Apêndice: renomear propriedades existentes
Quando você precisar descontinuar uma propriedade e migrar para uma nova, use Sysprop como APIs
para renomear as propriedades atuais. Isso mantém a compatibilidade com versões anteriores ao
especificar o nome legado e o nome da nova propriedade. Especificamente, é possível
definir o nome legado pelo campo legacy_prop_name
no arquivo .sysprop
. A
API gerada tenta ler prop_name
e usa legacy_prop_name
se
prop_name
não existir.
Por exemplo, as etapas a seguir renomeiam awesome_feature_foo_enabled
.
para foo.awesome_feature.enabled
.
No arquivo foo.sysprop
module: "android.sysprop.foo"
owner: Platform
prop {
api_name: "is_awesome_feature_enabled"
type: Boolean
scope: Public
access: Readonly
prop_name: "foo.awesome_feature.enabled"
legacy_prop_name: "awesome_feature_foo_enabled"
}
No código C++
// is_awesome_feature_enabled() reads "foo.awesome_feature.enabled".
// If it doesn't exist, reads "awesome_feature_foo_enabled" instead
using android::sysprop::foo;
bool enabled = foo::is_awesome_feature_enabled().value_or(false);
Observe as seguintes ressalvas:
Primeiro, não é possível alterar o tipo do sysprop. Por exemplo, não é possível fazer uma propriedade
int
em umastring
. Só é possível mudar o nome.Em segundo lugar, apenas a API de leitura usa o nome legado. A API Write não recuperar o sistema. Se o sysprop for gravável, não será possível renomeá-lo.