Systemeigenschaften bieten eine praktische Möglichkeit, Informationen, in der Regel Konfigurationen, systemweit freizugeben. Jede Partition kann intern eigene Systemeigenschaften verwenden. Probleme können auftreten, wenn über Partitionen hinweg auf Properties zugegriffen wird, z. B. wenn /vendor
auf von /system
definierte Properties zugreift. Seit Android 8.0 können einige Partitionen wie /system
aktualisiert werden, während /vendor
unverändert bleibt. Da Systemeigenschaften nur ein globales Wörterbuch mit String-Schlüssel/Wert-Paaren ohne Schema sind, ist es schwierig, Properties zu stabilisieren. Die Partition /system
kann Eigenschaften, von denen die Partition /vendor
abhängt, ohne vorherige Ankündigung ändern oder entfernen.
Ab der Android 10-Version werden Systemeigenschaften, auf die über Partitionen hinweg zugegriffen wird, in Sysprop-Beschreibungsdateien schematisiert. APIs zum Zugriff auf Eigenschaften werden als konkrete Funktionen für C++ und Rust sowie als Klassen für Java generiert. Diese APIs sind praktischer, da für den Zugriff keine magischen Strings wie ro.build.date
erforderlich sind und sie statisch typisiert werden können. Die ABI-Stabilität wird auch zum Zeitpunkt des Builds geprüft. Der Build wird abgebrochen, wenn inkompatible Änderungen vorgenommen werden. Diese Prüfung fungiert als explizit definierte Schnittstellen zwischen Partitionen. Diese APIs können auch für Einheitlichkeit zwischen Rust, Java und C++ sorgen.
Systemeigenschaften als APIs definieren
Definieren Sie Systemeigenschaften als APIs mit Sysprop-Beschreibungsdateien (.sysprop
), die ein Textformat von protobuf mit dem folgenden Schema verwenden:
// 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;
}
Eine Sysprop-Beschreibungsdatei enthält eine Eigenschaftennachricht, die eine Reihe von Eigenschaften beschreibt. Die Bedeutung der Felder ist folgende:
Feld | Bedeutung |
---|---|
owner
|
Legt die Partition fest, der die Properties zugewiesen sind: Platform , Vendor oder Odm .
|
module
|
Wird zum Erstellen eines Namespace (C++) oder einer statischen finalen Klasse (Java) verwendet, in dem generierte APIs platziert werden. Zum Beispiel ist com.android.sysprop.BuildProperties der Namespace com::android::sysprop::BuildProperties in C++ und die Klasse BuildProperties im Paket in com.android.sysprop in Java.
|
prop
|
Liste der Unterkünfte. |
Die Bedeutung der Felder in Property
-Nachrichten ist:
Feld | Bedeutung |
---|---|
api_name
|
Der Name der generierten API. |
type
|
Der Typ dieser Property. |
access
|
Readonly : Generiert nur Getter-APIs
Writeonce , ReadWrite : Generiert Getter- und Setter-APIs
Hinweis: Für Properties mit dem Präfix ro. kann kein ReadWrite -Zugriff verwendet werden.
|
scope
|
Internal : Nur der Inhaber kann darauf zugreifen.
Public : Alle können darauf zugreifen, mit Ausnahme von NDK-Modulen.
|
prop_name
|
Der Name der zugrunde liegenden Systemeigenschaft, z. B. ro.build.date .
|
enum_values
|
(Nur Enum , EnumList ) Ein durch Balken(|) getrennter String, der aus möglichen Aufzählungswerten besteht. Beispiel: value1|value2 .
|
integer_as_bool
|
(Nur Boolean , BooleanList ) Verwenden Sie für Setter 0 und 1 anstelle von false und true .
|
legacy_prop_name
|
(optional, nur Readonly -Attribute) Der alte Name des zugrunde liegenden Systemattributs. Beim Aufrufen des Getters versucht die Getter-API, prop_name zu lesen, und verwendet legacy_prop_name , wenn prop_name nicht vorhanden ist. Verwenden Sie legacy_prop_name , wenn Sie eine vorhandene Property einstellen und zu einer neuen Property wechseln.
|
Jeder Property-Typ wird den folgenden Typen in C++, Java und Rust zugeordnet.
Eingeben | C++ | Java | Rust |
---|---|---|---|
Boolesch | std::optional<bool>
|
Optional<Boolean>
|
bool
|
Ganzzahl | std::optional<std::int32_t>
|
Optional<Integer>
|
i32
|
UInt | std::optional<std::uint32_t>
|
Optional<Integer>
|
u32
|
Lang | std::optional<std::int64_t>
|
Optional<Long>
|
i64
|
ULong | std::optional<std::uint64_t>
|
Optional<Long>
|
u64
|
Double | std::optional<double>
|
Optional<Double>
|
f64
|
String | std::optional<std::string>
|
Optional<String>
|
String
|
Aufzählung | std::optional<{api_name}_values>
|
Optional<{api_name}_values>
|
{ApiName}Values
|
T-Liste | std::vector<std::optional<T>>
|
List<T>
|
Vec<T>
|
Hier ein Beispiel für eine Sysprop-Beschreibungsdatei, in der drei Eigenschaften definiert sind:
# 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
}
Bibliotheken für Systemeigenschaften definieren
Sie können jetzt sysprop_library
-Module mit Sysprop-Beschreibungsdateien definieren.
sysprop_library
dient als API für C++, Java und Rust. Das Build-System generiert intern eine rust_library
, eine java_library
und eine cc_library
für jede Instanz von sysprop_library
.
// File: Android.bp
sysprop_library {
name: "PlatformProperties",
srcs: ["android/sysprop/PlatformProperties.sysprop"],
property_owner: "Platform",
vendor_available: true,
}
Sie müssen Dateien mit API-Listen in die Quelle für API-Prüfungen aufnehmen. Erstellen Sie dazu API-Dateien und ein api
-Verzeichnis. Platzieren Sie das Verzeichnis api
im selben Verzeichnis wie Android.bp
. Die API-Dateinamen lauten <module_name>-current.txt
und <module_name>-latest.txt
. <module_name>-current.txt
enthält die API-Signaturen der aktuellen Quellcodes und <module_name>-latest.txt
die neuesten eingefrorenen API-Signaturen. Das Build-System prüft, ob die APIs geändert wurden, indem es diese API-Dateien zum Zeitpunkt des Builds mit generierten API-Dateien vergleicht. Wenn current.txt
nicht mit den Quellcodes übereinstimmt, wird eine Fehlermeldung ausgegeben und eine Anleitung zum Aktualisieren der Datei current.txt
. Hier ein Beispiel für die Verzeichnis- und Dateiorganisation:
├── api
│ ├── PlatformProperties-current.txt
│ └── PlatformProperties-latest.txt
└── Android.bp
Rust-, Java- und C++-Clientmodule können mit sysprop_library
verknüpft werden, um generierte APIs zu verwenden. Das Build-System erstellt Links von Clients zu generierten C++-, Java- und Rust-Bibliotheken, sodass Clients Zugriff auf generierte APIs erhalten.
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"],
}
Der Name der Rust-Bibliothek wird generiert, indem der Name sysprop_library
in Kleinbuchstaben umgewandelt wird. Dabei werden .
und -
durch _
ersetzt, lib
vorangestellt und _rust
angehängt.
Im vorherigen Beispiel könnten Sie auf definierte Properties so zugreifen:
Rust-Beispiel:
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);
}
…
}
Java-Beispiel:
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
);
}
…
}
…
C++-Beispiel:
#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);
}
…
}
…