En esta página, se proporciona un método canónico para agregar o definir propiedades del sistema en Android, con lineamientos para refactorizar las propiedades existentes del sistema. Asegúrate de usar los lineamientos cuando reestructures, a menos que tengas una de compatibilidad que dicte lo contrario.
Paso 1: Define la propiedad del sistema
Cuando agregues una propiedad del sistema, decide un nombre para ella y asóciala con un contexto de propiedad SELinux. Si no hay un contexto adecuado, crear una nueva. El nombre se usa cuando se accede a la propiedad. la propiedad el contexto se usa para controlar la accesibilidad en términos de SELinux. Los nombres pueden ser cualquiera pero el AOSP recomienda seguir un formato estructurado para que sean claras.
Nombre de la propiedad
Usa este formato con mayúsculas y minúsculas:
[{prefix}.]{group}[.{subgroup}]*.{name}[.{type}]
Usa "" (omitida), ro
(para propiedades establecidas solo una vez) o persist
(para las propiedades que persisten después de los reinicios) para el elemento prefix
.
Advertencias
Usa ro
solo cuando estés seguro de que no necesitas que prefix
admita escritura.
en el futuro. ** No especifiques el prefijo ro
.** En su lugar, confía en la política para
hacer que prefix
sea de solo lectura (en otras palabras, solo que init
pueda escribir).
Usa persist
solo cuando estés seguro de que el valor debe persistir en
y que el uso de las propiedades del sistema es la única opción.
Google revisa estrictamente las propiedades del sistema que tienen ro
o persist
.
propiedades.
El término group
se usa para agregar propiedades relacionadas. Está diseñada para
ser un nombre de subsistema similar al uso de audio
o telephony
No utilizar
términos ambiguos o sobrecargados, como sys
, system
, dev
, default
o
config
Es una práctica común usar el nombre del tipo de dominio de un
que tiene acceso exclusivo de lectura o escritura a las propiedades del sistema. Para
Por ejemplo, para las propiedades del sistema a las que el proceso vold
tiene acceso de escritura,
es común usar vold
(el nombre del tipo de dominio para el proceso) como el
nombre del grupo.
Si es necesario, agrega subgroup
para categorizar aún más las propiedades, pero evita
términos ambiguos o sobrecargados para describir este elemento. (También puedes tener más
de un subgroup
).
Ya se definieron muchos nombres de grupos. Consulta el
system/sepolicy/private/property_contexts
archivo y usar nombres de grupos existentes
siempre que sea posible, en lugar de hacer nuevos. En la siguiente tabla, se proporciona
ejemplos de nombres de grupos de uso frecuente.
Dominio | Grupo (y subgrupo) |
---|---|
Relacionado con Bluetooth | bluetooth |
sysprops de cmdline del kernel | boot |
sysprops que identifican una compilación | build
|
relacionada con la telefonía | telephony |
audio | audio |
gráficos relacionados | graphics |
relacionado con vold | vold |
A continuación, se define el uso de name
y type
en la regex anterior
ejemplo.
[{prefix}.]{group}[.{subgroup}]*.{name}[.{type}]
name
identifica una propiedad del sistema dentro de un grupo.type
es un elemento opcional que aclara el tipo o el intent del del sistema. Por ejemplo, en lugar de nombrar a una sysprop comoaudio.awesome_feature_enabled
o soloaudio.awesome_feature
, cámbiale el nombre aaudio.awesome_feature.enabled
para reflejar el tipo de propiedad del sistema y el intent.
No existe una regla específica sobre cuál debe ser el tipo; uso recomendaciones:
enabled
: Se usa si el tipo es una propiedad booleana del sistema que se usa para convertir activar o desactivar una función.config
: Úsalo si la intención es aclarar que la propiedad del sistema no representa un estado dinámico del sistema. representa un un valor preconfigurado (por ejemplo, un elemento de solo lectura).List
: Se usa si es una propiedad del sistema cuyo valor es una lista.Timeoutmillis
: Se usa si es una propiedad del sistema para un valor de tiempo de espera en unidades. de ms.
Ejemplos:
persist.radio.multisim.config
drm.service.enabled
Contexto de la propiedad
El nuevo esquema de contexto de propiedades de SELinux permite un mayor nivel de detalle y más nombres descriptivos. De manera similar a lo que se usa para los nombres de propiedades, el AOSP recomienda el siguiente formato:
{group}[_{subgroup}]*_prop
Los términos se definen de la siguiente manera:
group
y subgroup
tienen el mismo significado que se definió en la configuración anterior
regex de muestra. Por ejemplo, vold_config_prop
significa
Propiedades que son configuraciones de un proveedor y que debe establecer
vendor_init
, mientras que vold_status_prop
o solo vold_prop
significa propiedades
que expondrán el estado actual de vold
.
Cuando asigne un nombre al contexto de una propiedad, elija nombres que reflejen el uso general de las propiedades. En particular, evita los siguientes tipos de términos:
- Términos que parecen demasiado generales y ambiguos, como
sys
,system
ydefault
- Términos que codifican directamente la accesibilidad, como
exported
,apponly
,ro
,public
yprivate
.
Prefiere el uso de nombres, como vold_config_prop
a exported_vold_prop
,
o vold_vendor_writable_prop
.
Tipo
Un tipo de propiedad puede ser uno de los que se enumeran en la tabla.
Tipo | Definición |
---|---|
Booleano | true o 1 para verdadero, false o 0 para falso |
Entero | Número entero de 64 bits con firma |
Número entero sin firma | Número entero de 64 bits sin firma |
Double | punto flotante de doble precisión |
String | cualquier cadena UTF-8 válida |
enum | los valores pueden ser cualquier cadena UTF-8 válida sin espacios en blanco |
Lista anterior | Se utiliza una coma (, ) como delimitadorLa lista de números enteros [1, 2, 3] se almacena como 1,2,3 |
Internamente, todas las propiedades se almacenan como cadenas. Puedes aplicar el tipo
y lo especificas como un archivo property_contexts
. Para obtener más información, consulta
property_contexts
en el paso 3.
Paso 2: Determina los niveles de accesibilidad necesarios
Hay cuatro macros de ayuda que definen una propiedad.
Tipo de accesibilidad | Significado |
---|---|
system_internal_prop |
Propiedades que solo se usan en /system |
system_restricted_prop |
Propiedades que se leen fuera de /system , pero no se escriben |
system_vendor_config_prop |
Propiedades que se leen fuera de /system y que solo escribe vendor_init |
system_public_prop |
Propiedades que se leen y escriben fuera de /system |
Limitar el acceso a las propiedades del sistema de la manera más específica posible En el pasado, un acceso amplio generó fallas en la app y vulnerabilidades de seguridad. Reflexiona las siguientes preguntas al determinar el alcance:
- ¿Es necesario mantener esta propiedad del sistema? (Si es así, ¿por qué?)
- ¿Qué proceso debería tener acceso de lectura a esta propiedad?
- ¿Qué proceso debería tener acceso de escritura a esta propiedad?
Usa las preguntas anteriores y el siguiente árbol de decisiones como herramientas para determinar un alcance apropiado para el acceso.
Figura 1: Árbol de decisión para determinar el alcance del acceso a las propiedades del sistema
Paso 3: Agrega la cuenta al sistema o a la política
Cuando se accede a sysprop, SELinux controla la accesibilidad de los procesos. Después del
determinas qué nivel de accesibilidad se requiere y defines los contextos de las propiedades
en system/sepolicy
, junto con las reglas allow y neverallow adicionales
sobre qué pueden leer o escribir los procesos (y cuáles no).
Primero, define el contexto de la propiedad en system/sepolicy/public/property.te
. Si la propiedad es interna del sistema, defínela en el
system/sepolicy/private/property.te
. Usa uno de
las macros system_[accessibility]_prop([context])
que proporciona la
la accesibilidad requerida de la propiedad del sistema. Este es un ejemplo de
Archivo system/sepolicy/public/property.te
:
system_public_prop(audio_foo_prop)
system_vendor_config_prop(audio_bar_prop)
Ejemplo para agregar el archivo system/sepolicy/private/property.te
:
system_internal_prop(audio_baz_prop)
Segundo, otorga acceso de lectura o escritura al contexto de la propiedad. Usa set_prop
y get_prop
para otorgar acceso, en el
system/sepolicy/public/{domain}.te
o system/sepolicy/private/{domain}.te
. Usa private
siempre que sea posible. public
es adecuado solo si el elemento
Las macro set_prop
o get_prop
afectan a cualquier dominio fuera del dominio principal.
Por ejemplo, en el archivo system/sepolicy/private/audio.te
:
set_prop(audio, audio_foo_prop)
set_prop(audio, audio_bar_prop)
Por ejemplo, en el archivo system/sepolicy/public/domain.te
:
get_prop(domain, audio_bar_prop)
Tercero, agrega algunas reglas de “Neverallow” para reducir aún más la accesibilidad
el alcance de la macro. Por ejemplo, supongamos que usaste
system_restricted_prop
porque el proveedor debe leer las propiedades de tu sistema
procesos. Si todos los procesos del proveedor no requieren acceso de lectura y
que solo requieran un conjunto determinado de procesos (como vendor_init
), prohíben
los procesos del proveedor
que no necesitan acceso de lectura.
Usa la siguiente sintaxis para restringir el acceso de escritura y lectura:
Para restringir el acceso de escritura, sigue estos pasos:
neverallow [domain] [context]:property_service set;
Para restringir el acceso de lectura, haz lo siguiente:
neverallow [domain] [context]:file no_rw_file_perms;
Coloca reglas de “Neverallow” en el archivo system/sepolicy/private/{domain}.te
si el elemento
La regla keepallow está vinculada a un dominio específico. Para reglas de “Neverallow más” más amplias, usa
dominios generales como los siguientes cuando corresponda:
system/sepolicy/private/property.te
system/sepolicy/private/coredomain.te
system/sepolicy/private/domain.te
En el archivo system/sepolicy/private/audio.te
, coloca lo siguiente:
neverallow {
domain -init -audio
} {audio_foo_prop audio_bar_prop}:property_service set;
En el archivo system/sepolicy/private/property.te
, coloca lo siguiente:
neverallow {
domain -coredomain -vendor_init
} audio_prop:file no_rw_file_perms;
Ten en cuenta que {domain -coredomain}
captura todos los procesos del proveedor. De esta manera,
{domain -coredomain -vendor_init}
significa "todos los procesos del proveedor, excepto".
vendor_init
".
Por último, asocia una propiedad del sistema con el contexto de la propiedad. Esto garantiza
que el acceso que se otorga y las reglas keepallow que se aplican
se aplican a las propiedades reales. Para hacer esto, agrega una entrada a
el archivo property_contexts
, que describe la asignación entre sistemas
y contextos de propiedades. En este archivo, puedes especificar un único
propiedad o un prefijo para que se asignen propiedades a un contexto.
Esta es la sintaxis para asignar una sola propiedad:
[property_name] u:object_r:[context_name]:s0 exact [type]
Esta es la sintaxis para asignar un prefijo:
[property_name_prefix] u:object_r:[context_name]:s0 prefix [type]
De forma opcional, puedes especificar el tipo de propiedad, que puede ser uno de los lo siguiente:
bool
int
uint
double
enum [list of possible values...]
string
(usastring
para las propiedades de lista).
Asegúrate de que cada entrada tenga su tipo designado siempre que sea posible, ya que type
es
se aplicará de manera forzosa cuando se configure property
. En el siguiente ejemplo, se muestra cómo escribir un
mapeo:
# 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
Cuando una entrada exacta y una de prefijo entran en conflicto, la entrada exacta tarda
prioridad. Para obtener más ejemplos, consulta system/sepolicy/private/property_contexts
.
Paso 4: Determina los requisitos de estabilidad
La estabilidad es otro aspecto de las propiedades del sistema y se diferencia de accesibilidad. La estabilidad es si una propiedad del sistema puede o no cambian (por ejemplo, se les cambió el nombre o incluso se quitaron) en el futuro. Este es sobre todo a medida que el SO Android se vuelve modular. Con Treble, el sistema proveedor y las particiones de producto pueden actualizarse de forma independiente. Con Principal, algunas partes del SO están modularizadas como módulos actualizables (en APEXes) o APKs).
Si la propiedad de un sistema es para usar en software que se puede actualizar, por ejemplo, entre las particiones del sistema y el proveedor, debe ser estable. Sin embargo, si se usa solo dentro de, por ejemplo, un módulo Mainline específico, puedes cambiar su nombre tipo o de propiedad, y hasta quitarlo.
Haz las siguientes preguntas para determinar la estabilidad de una propiedad del sistema:
- ¿Esta propiedad del sistema está pensada para que la configuren los socios (o se configuró de manera diferente según el dispositivo)? Si es así, debe ser estable.
- ¿Esta propiedad del sistema definida por el AOSP se usa para escribir o leer en ellos?
código (no el proceso) que existe en particiones que no son del sistema, como
vendor.img
o ¿product.img
? Si es así, debe ser estable. - ¿Se puede acceder a esta propiedad del sistema en los módulos de línea principal o en una línea principal? y la parte de la plataforma que no se puede actualizar? Si es así, debe ser estable.
Para las propiedades estables del sistema, define formalmente cada una como una API y usa la API para acceder a la propiedad del sistema, como se explica Paso 6:
Paso 5: Configura propiedades en el tiempo de compilación
Configura propiedades durante el tiempo de compilación con variables de archivo makefile. Técnicamente, los valores
están integradas en {partition}/build.prop
. Luego, init
lee
{partition}/build.prop
para configurar las propiedades. Hay dos conjuntos de tales
variables: PRODUCT_{PARTITION}_PROPERTIES
y TARGET_{PARTITION}_PROP
.
PRODUCT_{PARTITION}_PROPERTIES
contiene una lista de valores de propiedades. La sintaxis
es {prop}={value}
o {prop}?={value}
.
{prop}={value}
es una asignación normal que garantiza que {prop}
se establezca en
{value}
; solo es posible una de estas asignaciones por cada propiedad.
{prop}?={value}
es una tarea opcional. {prop}
se establece en {value}
solo si
no hay ninguna tarea {prop}={value}
. Si hay varias asignaciones opcionales
existen, gana el primero.
# 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
contiene una lista de archivos que se emiten directamente a
{partition}/build.prop
Cada archivo contiene una 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 obtener más detalles, consulta
build/make/core/sysprop.mk
Paso 6: Accede a las propiedades en el entorno de ejecución
Las propiedades se pueden leer y escribir durante el tiempo de ejecución.
Secuencias de comandos Init
Los archivos de secuencia de comandos Init (por lo general, archivos *.rc) pueden leer una propiedad mediante ${prop}
.
${prop:-default}
, puede establecer una acción que se ejecute cada vez que una propiedad se convierta en
valor específico y puedes escribir las propiedades con el 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 de shell getprop y setprop
Puedes usar los comandos de shell getprop
o setprop
, respectivamente, para leer o
escribir las propiedades. Para obtener más detalles, invoca a getprop --help
o
setprop --help
$ adb shell getprop ro.vndk.version
$
$ adb shell setprop security.perf_harden 0
Sysprop como API para C++/Java/Rust
Con sysprop como API, puedes definir las propiedades del sistema y usar la API generada automáticamente
concretos y escritos. Configurar scope
con Public
también hace que las imágenes
APIs disponibles para los módulos más allá de los límites y garantiza la estabilidad de las APIs. Este es un
ejemplo de un archivo .sysprop
, un módulo Android.bp
y código de C++, Java y Rust
para usarlas.
# 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 obtener más información, consulta Cómo implementar propiedades del sistema como APIs.
Funciones y métodos de propiedades de bajo nivel de C/C++, Java y Rust
Cuando sea posible, usa Sysprop como API, aunque funciones de C/C++ o Rust de bajo nivel o de bajo nivel de Java disponibles.
libc
, libbase
y libcutils
ofrecen funciones de propiedad del sistema C++. libc
tiene la API subyacente, mientras que las funciones libbase
y libcutils
son
wrappers. Si es posible, usa las funciones sysprop libbase
. son
y los objetos binarios del host pueden usar las funciones libbase
. Para ver más
detalles, consulta sys/system_properties.h
(libc
), android-base/properties.h
(libbase
) y cutils/properties.h
(libcutils
).
La clase android.os.SystemProperties
ofrece métodos de propiedad del sistema Java.
El módulo rustutils::system_properties
ofrece funciones de propiedad del sistema Rust
y tipos de datos.
Apéndice: Cómo agregar propiedades específicas del proveedor
Los socios (incluidos los Googlers que trabajan en el contexto del desarrollo de Pixel) quieren
para definir propiedades del sistema específicas de hardware (o de dispositivos).
Las propiedades específicas del proveedor son propiedad de los socios que son exclusivas de su
su propio hardware o dispositivo, no a la plataforma. Como se trata de hardware o dispositivos
dependientes, están diseñados para usarse dentro de las particiones /vendor
o /odm
.
Desde Project Treble, las propiedades de la plataforma y de los proveedores se han completamente divididos para evitar conflictos. A continuación, se describe cómo definir las propiedades del proveedor y determinar qué propiedades del proveedor deben usarse siempre.
Espacio de nombres en los nombres de propiedades y contextos
Todas las propiedades del proveedor deben comenzar con uno de los siguientes prefijos para evitar colisión entre ellos y las propiedades de otras particiones.
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.
Ten en cuenta que ro.hardware.
se permite como prefijo, pero solo por compatibilidad.
No lo uses para propiedades normales.
En todos los siguientes ejemplos, se usa uno de los prefijos enumerados anteriormente:
vendor.display.primary_red
persist.vendor.faceauth.use_disk_cache
ro.odm.hardware.platform
Todos los contextos de propiedades del proveedor deben comenzar con vendor_
. Esto también es para
compatibilidad. Estos son algunos ejemplos:
vendor_radio_prop
.vendor_faceauth_prop
.vendor_usb_prop
.
Es responsabilidad del proveedor nombrar y mantener propiedades, por lo que debes seguir la formato sugerido en el Paso 2, además del los requisitos de los espacios de nombres del proveedor.
Reglas de SEPolicy específicas del proveedor y property_contexts
Las propiedades del proveedor se pueden definir con la macro vendor_internal_prop
. Coloca el
reglas específicas del proveedor que definas en el directorio BOARD_VENDOR_SEPOLICY_DIRS
Por ejemplo, supongamos que estás definiendo una propiedad faceauth del proveedor en coral.
En el archivo BoardConfig.mk
(o en cualquier inclusión BoardConfig.mk
), coloca el
lo siguiente:
BOARD_VENDOR_SEPOLICY_DIRS := device/google/coral-sepolicy
En el archivo device/google/coral-sepolicy/private/property.te
, coloca el
lo siguiente:
vendor_internal_prop(vendor_faceauth_prop)
En el archivo device/google/coral-sepolicy/private/property_contexts
, coloca el
lo siguiente:
vendor.faceauth.trace u:object_r:vendor_faceauth_prop:s0 exact bool
Limitaciones de las propiedades del proveedor
Debido a que las particiones del sistema y del producto no pueden depender del proveedor, nunca
permitir el acceso a las propiedades del proveedor desde system
, system-ext
o
product
particiones.
Apéndice: Cómo cambiar el nombre de las propiedades existentes
Usa Sysprop como APIs cuando debas dar de baja una propiedad y migrarla a una nueva.
para cambiar el nombre de tus propiedades existentes. Esto mantiene la retrocompatibilidad
que especifica el nombre heredado y el nuevo de la propiedad. Específicamente, puedes
Establece el nombre heredado por el campo legacy_prop_name
del archivo .sysprop
. El
La API generada intenta leer prop_name
y usa legacy_prop_name
si
prop_name
no existe.
Por ejemplo, en los siguientes pasos, se cambia el nombre de awesome_feature_foo_enabled
a foo.awesome_feature.enabled
.
En el archivo 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"
}
En 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);
Ten en cuenta las siguientes advertencias:
Primero, no se puede cambiar el tipo de sysprop. Por ejemplo, no puedes hacer un prop
int
en un propstring
Solo puedes cambiar el nombre.Segundo, solo la API de lectura recurre al nombre heredado. La API de escritura no se revierte. Si sysprop admite escritura, no se puede cambiar el nombre.