Las propiedades del sistema proporcionan una manera conveniente de compartir información, generalmente configuraciones, en todo el sistema. Cada partición puede utilizar sus propias propiedades del sistema internamente. Puede ocurrir un problema cuando se accede a las propiedades a través de particiones, como cuando /vendor
accede /system
. Desde Android 8.0, algunas particiones, como /system
, se pueden actualizar, mientras que /vendor
no se modifica. Debido a que las propiedades del sistema son solo un diccionario global de pares de clave/valor de cadena sin esquema, es difícil estabilizar las propiedades. La partición /system
podría cambiar o eliminar propiedades de las que depende la partición /vendor
sin previo aviso.
A partir de la versión de Android 10, las propiedades del sistema a las que se accede a través de particiones se esquematizan en archivos de descripción Sysprop, y las API para acceder a las propiedades se generan como funciones concretas para C++ y Rust, y clases para Java. Estas API son más cómodas de usar porque no se necesitan cadenas mágicas (como ro.build.date
) para acceder y porque se pueden escribir estáticamente. La estabilidad de ABI también se verifica en el momento de la compilación y la compilación se interrumpe si se producen cambios incompatibles. Esta verificación actúa como interfaces definidas explícitamente entre particiones. Estas API también pueden proporcionar coherencia entre Rust, Java y C++.
Definición de propiedades del sistema como API
Defina las propiedades del sistema como API con archivos de descripción Sysprop ( .sysprop
), que utilizan un formato de texto de protobuf, con el siguiente esquema:
// File: sysprop.proto
syntax = "proto3";
package sysprop;
enum Access {
Readonly = 0;
Writeonce = 1;
ReadWrite = 2;
}
enum Owner {
Platform = 0;
Vendor = 1;
Odm = 2;
}
enum Scope {
Public = 0;
Internal = 2;
}
enum Type {
Boolean = 0;
Integer = 1;
Long = 2;
Double = 3;
String = 4;
Enum = 5;
UInt = 6;
ULong = 7;
BooleanList = 20;
IntegerList = 21;
LongList = 22;
DoubleList = 23;
StringList = 24;
EnumList = 25;
UIntList = 26;
ULongList = 27;
}
message Property {
string api_name = 1;
Type type = 2;
Access access = 3;
Scope scope = 4;
string prop_name = 5;
string enum_values = 6;
bool integer_as_bool = 7;
string legacy_prop_name = 8;
}
message Properties {
Owner owner = 1;
string module = 2;
repeated Property prop = 3;
}
Un archivo de descripción Sysprop contiene un mensaje de propiedades, que describe un conjunto de propiedades. El significado de sus campos es el siguiente.
Campo | Significado |
---|---|
owner | Establezca la partición propietaria de las propiedades: Platform , Vendor u Odm . |
module | Se utiliza para crear un espacio de nombres (C++) o una clase final estática (Java) en la que se colocan las API generadas. Por ejemplo, com.android.sysprop.BuildProperties será el espacio de nombres com::android::sysprop::BuildProperties en C++ y la clase BuildProperties en el paquete en com.android.sysprop en Java. |
prop | Lista de propiedades. |
Los significados de los campos del mensaje Property
son los siguientes.
Campo | Significado |
---|---|
api_name | El nombre de la API generada. |
type | El tipo de esta propiedad. |
access | Readonly : genera solo API getter Nota: Propiedades con el prefijo |
scope | Internal : Sólo el propietario puede acceder. |
prop_name | El nombre de la propiedad del sistema subyacente, por ejemplo ro.build.date . |
enum_values | ( Enum , solo EnumList ) Una cadena separada por barras (|) que consta de posibles valores de enumeración. Por ejemplo, value1|value2 . |
integer_as_bool | ( Boolean , solo BooleanList ) Haga que los configuradores usen 0 y 1 en lugar de false y true . |
legacy_prop_name | (opcional, solo propiedades Readonly ) El nombre heredado de la propiedad del sistema subyacente. Al llamar a getter, la API getter intenta leer prop_name y usa legacy_prop_name si prop_name no existe. Utilice legacy_prop_name cuando deje obsoleta una propiedad existente y la traslade a una nueva propiedad. |
Cada tipo de propiedad se asigna a los siguientes tipos en C++, Java y Rust.
Tipo | C++ | Java | Óxido |
---|---|---|---|
Booleano | std::optional<bool> | Optional<Boolean> | bool |
Entero | std::optional<std::int32_t> | Optional<Integer> | i32 |
UInt | std::optional<std::uint32_t> | Optional<Integer> | u32 |
Largo | std::optional<std::int64_t> | Optional<Long> | i64 |
largo | std::optional<std::uint64_t> | Optional<Long> | u64 |
Doble | std::optional<double> | Optional<Double> | f64 |
Cadena | std::optional<std::string> | Optional<String> | String |
enumeración | std::optional<{api_name}_values> | Optional<{api_name}_values> | {ApiName}Values |
Lista T | std::vector<std::optional<T>> | List<T> | Vec<T> |
A continuación se muestra un ejemplo de un archivo de descripción Sysprop que define tres propiedades:
# File: android/sysprop/PlatformProperties.sysprop
owner: Platform
module: "android.sysprop.PlatformProperties"
prop {
api_name: "build_date"
type: String
prop_name: "ro.build.date"
scope: Public
access: Readonly
}
prop {
api_name: "date_utc"
type: Integer
prop_name: "ro.build.date_utc"
scope: Internal
access: Readonly
}
prop {
api_name: "device_status"
type: Enum
enum_values: "on|off|unknown"
prop_name: "device.status"
scope: Public
access: ReadWrite
}
Definición de bibliotecas de propiedades del sistema
Ahora puede definir módulos sysprop_library
con archivos de descripción Sysprop. sysprop_library
sirve como API para C++, Java y Rust. El sistema de compilación genera internamente un rust_library
, un java_library
y un cc_library
para cada instancia de sysprop_library
.
// File: Android.bp
sysprop_library {
name: "PlatformProperties",
srcs: ["android/sysprop/PlatformProperties.sysprop"],
property_owner: "Platform",
vendor_available: true,
}
Debe incluir archivos de listas de API en el origen para las comprobaciones de API. Para hacer esto, cree archivos API y un directorio api
. Coloque el directorio api
en el mismo directorio que Android.bp
. Los nombres de archivo API son <module_name>-current.txt
, <module_name>-latest.txt
. <module_name>-current.txt
contiene las firmas API de los códigos fuente actuales, y <module_name>-latest.txt
contiene las últimas firmas API congeladas. El sistema de compilación verifica si las API se cambiaron comparando estos archivos API con los archivos API generados en el momento de la compilación y emite un mensaje de error e instrucciones para actualizar el archivo current.txt
si current.txt
no coincide con los códigos fuente. A continuación se muestra un ejemplo de organización de directorios y archivos:
├── api
│ ├── PlatformProperties-current.txt
│ └── PlatformProperties-latest.txt
└── Android.bp
Los módulos cliente de Rust, Java y C++ pueden vincularse con sysprop_library
para utilizar las API generadas. El sistema de compilación crea enlaces desde los clientes a las bibliotecas C++, Java y Rust generadas, lo que brinda a los clientes acceso a las API generadas.
java_library {
name: "JavaClient",
srcs: ["foo/bar.java"],
libs: ["PlatformProperties"],
}
cc_binary {
name: "cc_client",
srcs: ["baz.cpp"],
shared_libs: ["PlatformProperties"],
}
rust_binary {
name: "rust_client",
srcs: ["src/main.rs"],
rustlibs: ["libplatformproperties_rust"],
}
Tenga en cuenta que el nombre de la biblioteca Rust se genera convirtiendo el nombre sysprop_library
a minúsculas, reemplazando .
y -
con _
, y luego anteponiendo lib
y agregando _rust
.
En el ejemplo anterior, podría acceder a las propiedades definidas de la siguiente manera.
Ejemplo de óxido:
use platformproperties::DeviceStatusValues;
fn foo() -> Result<(), Error> {
// Read "ro.build.date_utc". default value is -1.
let date_utc = platformproperties::date_utc()?.unwrap_or_else(-1);
// set "device.status" to "unknown" if "ro.build.date" is not set.
if platformproperties::build_date()?.is_none() {
platformproperties::set_device_status(DeviceStatusValues::UNKNOWN);
}
…
}
Ejemplo de Java:
import android.sysprop.PlatformProperties;
…
static void foo() {
…
// read "ro.build.date_utc". default value is -1
Integer dateUtc = PlatformProperties.date_utc().orElse(-1);
// set "device.status" to "unknown" if "ro.build.date" is not set
if (!PlatformProperties.build_date().isPresent()) {
PlatformProperties.device_status(
PlatformProperties.device_status_values.UNKNOWN
);
}
…
}
…
Ejemplo de C++:
#include <android/sysprop/PlatformProperties.sysprop.h>
using namespace android::sysprop;
…
void bar() {
…
// read "ro.build.date". default value is "(unknown)"
std::string build_date = PlatformProperties::build_date().value_or("(unknown)");
// set "device.status" to "on" if it's "unknown" or not set
using PlatformProperties::device_status_values;
auto status = PlatformProperties::device_status();
if (!status.has_value() || status.value() == device_status_values::UNKNOWN) {
PlatformProperties::device_status(device_status_values::ON);
}
…
}
…