Na tej stronie znajdziesz kanoniczną metodę dodawania i definiowania właściwości systemowych w Androidzie oraz wskazówki dotyczące refaktoryzacji dotychczasowych właściwości systemowych. Podczas refaktoryzacji kieruj się tymi wskazówkami, chyba że masz poważny problem ze zgodnością, który nakazuje inaczej.
Krok 1. Zdefiniuj właściwość systemu
Podczas dodawania właściwości systemowej określ jej nazwę i połącz ją z kontekstem usługi SELinux. Jeśli nie ma odpowiedniego kontekstu, utwórz nowy. Nazwa jest używana podczas uzyskiwania dostępu do usługi, a kontekst usługi jest używany do kontrolowania dostępności w ramach SELinux. Nazwy mogą być dowolnymi ciągami znaków, ale AOSP zaleca, aby były one uporządkowane w jasny sposób.
Nazwa właściwości
Użyj tego formatu z wielkimi literami w sposób snake_case:
[{prefix}.]{group}[.{subgroup}]*.{name}[.{type}]
Użyj wartości „” (pominiętej), ro
(dla właściwości ustawianych tylko raz) lub persist
(dla właściwości, które są zachowywane po ponownym uruchomieniu) dla elementu prefix
.
Ograniczenia
Używaj elementu ro
tylko wtedy, gdy masz pewność, że w przyszłości nie będziesz potrzebować możliwości zapisu do elementu prefix
. ** Nie podawaj prefiksu ro
.** Zamiast tego użyj sepolicy, aby ustawić prefix
w trybie tylko do odczytu (czyli tylko do zapisu przez init
).
Użyj właściwości persist
tylko wtedy, gdy masz pewność, że wartość musi być zachowana po ponownym uruchomieniu, i że użycie właściwości systemowych jest jedyną opcją.
Google ściśle sprawdza właściwości systemowe z właściwościami ro
lub persist
.
Termin group
służy do agregowania powiązanych usług. Ma to być nazwa podsystemu podobna do audio
lub telephony
. Nie używaj niejednoznacznych lub przeciążonych terminów, takich jak sys
, system
, dev
, default
lub config
.
Zwykle używa się nazwy typu domeny procesu, który ma wyłączny dostęp do odczytu lub zapisu do właściwości systemu. Na przykład w przypadku właściwości systemowych, do których proces vold
ma uprawnienia do zapisu, jako nazwy grupy często używa się nazwy vold
(nazwa typu domeny procesu).
W razie potrzeby dodaj subgroup
, aby jeszcze bardziej skategoryzować usługi. Unikaj jednak niejednoznacznych lub nadmiernie obciążonych terminach. (Możesz też mieć więcej niż jeden subgroup
).
Wiele nazw grup jest już zdefiniowanych. Sprawdź plik system/sepolicy/private/property_contexts
i w miarę możliwości używaj istniejących nazw grup zamiast tworzyć nowe. W tabeli poniżej znajdziesz przykłady często używanych nazw grup.
Domena | Grupa (i podgrupa) |
---|---|
Związane z Bluetoothem | bluetooth |
sysprops z cmdline jądra | boot |
syspropów, które identyfikują wersję. | build
|
związane z telefonią | telephony |
związane z dźwiękiem | audio |
grafika | graphics |
vold | vold |
Poniżej znajdziesz definicje użycia name
i type
w poprzednim przykładzie wyrażenia regularnego.
[{prefix}.]{group}[.{subgroup}]*.{name}[.{type}]
name
identyfikuje właściwość systemową w grupie.type
to opcjonalny element, który wyjaśnia typ lub intencję właściwości systemowej. Na przykład zamiast nadawać nazwęaudio.awesome_feature_enabled
lub po prostuaudio.awesome_feature
, nadaj nazwęaudio.awesome_feature.enabled
, aby odzwierciedlała typ i zamierzenie właściwości systemowej.
Nie ma konkretnej reguły określającej jego typ. Oto zalecenia dotyczące użytkowania:
enabled
: użyj, jeśli typ jest właściwością systemową typu logicznego, która służy do włączania i wyłączania funkcji.config
: użyj, jeśli chcesz wyjaśnić, że właściwość systemowa nie reprezentuje dynamicznego stanu systemu, lecz skonfigurowaną wartość (np. element tylko do odczytu).List
: użyj, jeśli jest to właściwość systemowa, której wartość jest listą.Timeoutmillis
: użyj, jeśli jest to właściwość systemowa wartości limitu czasu w ms.
Przykłady:
persist.radio.multisim.config
drm.service.enabled
Kontekst usługi
Nowy schemat kontekstu właściwości SELinux zapewnia większą szczegółowość i bardziej opisowe nazwy. Podobnie jak w przypadku nazw właściwości, AOSP zaleca używanie tego formatu:
{group}[_{subgroup}]*_prop
Terminy są zdefiniowane w następujący sposób:
group
i subgroup
mają takie samo znaczenie jak w poprzednim przykładzie wyrażenia regularnego. Na przykład vold_config_prop
oznacza właściwości, które są konfiguracjami od dostawcy i mają być ustawiane przez vendor_init
, a vold_status_prop
lub tylko vold_prop
oznaczają właściwości, które mają wyświetlać bieżący stan vold
.
Nadając nazwy kontekstom właściwości, wybierz takie, które odzwierciedlają ogólne zastosowanie tych właściwości. Unikaj w szczególności tych rodzajów haseł:
- Terminy, które wyglądają na zbyt ogólne i niejednoznaczne, np.
sys
,system
,default
. - Hasła bezpośrednio związane z dostępnością:
exported
,apponly
,ro
,public
,private
.
Preferuj nazwy takie jak vold_config_prop
zamiast exported_vold_prop
lub vold_vendor_writable_prop
.
Typ
Typ usługi może być jednym z tych typów podanych w tabeli.
Typ | Definicja |
---|---|
Wartość logiczna | true lub 1 oznacza prawdę, false lub 0 – fałsz. |
Liczba całkowita | 64-bitowa liczba całkowita ze znakiem |
liczba całkowita bez znaku | bez znaku 64-bitowy |
Podwójny | podwójna precyzja zmiennoprzecinkowa |
Ciąg znaków | dowolny prawidłowy ciąg UTF-8 |
enum | wartości mogą być dowolnym prawidłowym ciągiem znaków UTF-8 bez spacji |
Lista powyżej | Jako separator używany jest przecinek (, ).Lista liczb całkowitych [1, 2, 3] jest przechowywana jako 1,2,3 |
Wewnętrznie wszystkie właściwości są przechowywane jako ciągi znaków. Możesz wymusić typ, określając go jako plik property_contexts
. Więcej informacji znajdziesz w sekcji property_contexts
w kroku 3.
Krok 2. Określ wymagane poziomy ułatwień dostępu
Właściwość definiują 4 makro pomocnicze.
Typ ułatwień dostępu | Znaczenie |
---|---|
system_internal_prop |
Właściwości używane tylko w /system |
system_restricted_prop |
Właściwości odczytywane poza /system , ale nie zapisywane |
system_vendor_config_prop |
Właściwości, które są odczytywane poza domeną /system i zapisywane tylko przez vendor_init |
system_public_prop |
Właściwości odczytywane i zapisywane poza /system |
Ogranicz dostęp do właściwości systemu do jak najmniejszego zakresu. W przeszłości szeroki dostęp powodował awarie aplikacji i luki w zabezpieczeniach. Podczas określania zakresu projektu zastanów się nad tymi pytaniami:
- Czy ta właściwość systemu musi być zapisywana? (jeśli tak, dlaczego?)
- Który proces powinien mieć dostęp do odczytu tej usługi?
- Który proces powinien mieć uprawnienia do zapisu w tej usłudze?
Aby określić odpowiedni zakres dostępu, użyj podanych wyżej pytań i tabeli.
Rysunek 1. Schemat decyzyjny służący do określania zakresu dostępu do właściwości systemu
Krok 3. Dodaj do system/sepolicy
Podczas uzyskiwania dostępu do sysprop SELinux kontroluje dostępność procesów. Po określeniu wymaganego poziomu dostępności zdefiniuj konteksty właściwości w sekcji system/sepolicy
, a także dodatkowe reguły allow i neverallow dotyczące tego, które procesy mogą (lub nie) odczytywać lub zapisywać dane.
Najpierw określ kontekst właściwości w pliku system/sepolicy/public/property.te
. Jeśli właściwość jest wewnętrzna, zdefiniuj ją w pliku system/sepolicy/private/property.te
. Użyj jednego z makro system_[accessibility]_prop([context])
, które zapewnia wymaganą dostępność dla właściwości systemu. Oto przykład pliku system/sepolicy/public/property.te
:
system_public_prop(audio_foo_prop)
system_vendor_config_prop(audio_bar_prop)
Przykład do dodania w pliku system/sepolicy/private/property.te
:
system_internal_prop(audio_baz_prop)
Po drugie, przyznaj uprawnienia do odczytu lub zapisu w kontekście usługi. Aby przyznać dostęp w pliku system/sepolicy/public/{domain}.te
lub system/sepolicy/private/{domain}.te
, użyj makr set_prop
i get_prop
. W miarę możliwości używaj private
. public
jest odpowiedni tylko wtedy, gdy makro set_prop
lub get_prop
ma wpływ na domeny spoza domeny podstawowej.
Przykład w pliku system/sepolicy/private/audio.te
:
set_prop(audio, audio_foo_prop)
set_prop(audio, audio_bar_prop)
Przykład w pliku system/sepolicy/public/domain.te
:
get_prop(domain, audio_bar_prop)
Po trzeciej dodaj reguły neverallow, aby jeszcze bardziej ograniczyć dostępność, którą ma makro. Załóżmy na przykład, że używasz metody system_restricted_prop
, ponieważ właściwości systemowe muszą być odczytywane przez procesy dostawcy. Jeśli dostęp do odczytu nie jest wymagany przez wszystkie procesy dostawcy, a tylko przez określony zestaw procesów (takich jak vendor_init
), zablokuj procesy dostawcy, które nie wymagają dostępu do odczytu.
Aby ograniczyć dostęp do zapisu i odczytu, użyj tej składni:
Aby ograniczyć dostęp do zapisu:
neverallow [domain] [context]:property_service set;
Aby ograniczyć dostęp do odczytu:
neverallow [domain] [context]:file no_rw_file_perms;
Umieść reguły neverallow w pliku system/sepolicy/private/{domain}.te
, jeśli reguła neverallow jest powiązana z konkretną domeną. W przypadku szerszych reguł typu nigdy nie zezwalaj używaj ogólnych domen takich jak te:
system/sepolicy/private/property.te
system/sepolicy/private/coredomain.te
system/sepolicy/private/domain.te
W pliku system/sepolicy/private/audio.te
umieść:
neverallow {
domain -init -audio
} {audio_foo_prop audio_bar_prop}:property_service set;
W pliku system/sepolicy/private/property.te
umieść:
neverallow {
domain -coredomain -vendor_init
} audio_prop:file no_rw_file_perms;
Pamiętaj, że {domain -coredomain}
obejmuje wszystkie procesy dostawcy. W związku z tym {domain -coredomain -vendor_init}
oznacza „wszystkie procesy dostawcy z wyjątkiem
vendor_init
”.
Na koniec powiążesz właściwość systemową z kontekstem usługi. Dzięki temu przyznany dostęp i reguły nigdy nie zezwalaj stosowane do kontekstów usług są stosowane do rzeczywistych usług. Aby to zrobić, dodaj wpis do pliku property_contexts
, który opisuje mapowanie między właściwościami systemu a kontekstami właściwości. W tym pliku możesz podać jedną właściwość lub prefiks właściwości, które mają zostać zmapowane w kontekście.
Oto składnia mapowania pojedynczej usługi:
[property_name] u:object_r:[context_name]:s0 exact [type]
Oto składnia mapowania prefiksu:
[property_name_prefix] u:object_r:[context_name]:s0 prefix [type]
Opcjonalnie możesz określić typ usługi, który może być jednym z tych:
bool
int
uint
double
enum [list of possible values...]
string
(użyjstring
w przypadku właściwości listy).
Upewnij się, że każdy wpis ma określony typ, o ile to możliwe, ponieważ type
jest wymagane podczas ustawiania property
. Poniższy przykład pokazuje, jak utworzyć mapowanie:
# 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
W przypadku konfliktu wpisu dokładnego i wpisu z prefiksem pierwszeństwo ma wpis dokładny. Więcej przykładów znajdziesz w artykule system/sepolicy/private/property_contexts
.
Krok 4. Określ wymagania dotyczące stabilności
Stabilność to kolejny aspekt właściwości systemowych, który różni się od dostępności. Stabilność oznacza, czy w przyszłości można zmienić (np. zmienić nazwę lub nawet usunąć) daną właściwość systemu. Jest to szczególnie ważne, ponieważ system operacyjny Android staje się modułowy. W Treble podziały systemowe, dostawcy i produkty można aktualizować niezależnie. W Mainline niektóre części systemu operacyjnego są modułowe w postaci modułów możliwych do aktualizacji (w APEX lub plikach APK).
Jeśli właściwość systemowa jest przeznaczona do użytku w aktualizacjach oprogramowania, np. w ramach partycji systemu i dostawcy, musi być stabilna. Jeśli jednak jest używany tylko w ramach konkretnego modułu Mainline, możesz zmienić jego nazwę, typ lub konteksty usługi, a nawet usunąć.
Aby określić stabilność właściwości systemu, zadaj te pytania:
- Czy ta właściwość systemu ma być konfigurowana przez partnerów (lub konfigurowana inaczej na poszczególnych urządzeniach)? Jeśli tak, musi być stabilny.
- Czy ta określona przez AOSP właściwość systemu ma być zapisywana lub odczytywana przez kod (a nie proces), który znajduje się w partycjach niesystemowych, takich jak
vendor.img
lubproduct.img
? Jeśli tak, musi być stabilna. - Czy do tej właściwości systemu uzyskuje się dostęp w ramach modułów Mainline, czy w ramach modułu Mainline i nieaktualizowanej części platformy? Jeśli tak, musi być stabilna.
W przypadku stabilnych właściwości systemu formalnie zdefiniuj je jako interfejs API i użyj go do uzyskania dostępu do właściwości systemu, zgodnie z opisem w kroku 6.
Krok 5. Ustaw właściwości w czasie kompilacji
Ustaw właściwości w czasie kompilacji za pomocą zmiennych makefile. Technicznie rzecz biorąc, wartości są wbudowane w {partition}/build.prop
. Następnie init
odczytuje {partition}/build.prop
, aby ustawić właściwości. Istnieją 2 zbiory takich zmiennych: PRODUCT_{PARTITION}_PROPERTIES
i TARGET_{PARTITION}_PROP
.
PRODUCT_{PARTITION}_PROPERTIES
zawiera listę wartości właściwości. Składnia to {prop}={value}
lub {prop}?={value}
.
{prop}={value}
to normalne przypisanie, które gwarantuje, że {prop}
ma wartość {value}
. W przypadku pojedynczej usługi możliwe jest tylko jedno takie przypisanie.
{prop}?={value}
to przypisanie opcjonalne. {prop}
ustawia wartość {value}
tylko wtedy, gdy nie ma żadnych przypisań {prop}={value}
. Jeśli istnieje kilka opcjonalnych przypisań, pierwszeństwo ma pierwsze z nich.
# 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
zawiera listę plików, która jest bezpośrednio emitowana do {partition}/build.prop
. Każdy plik zawiera listę {prop}={value}
par.
# 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
Więcej informacji znajdziesz w sekcji build/make/core/sysprop.mk
.
Krok 6. Uzyskaj dostęp do właściwości w czasie działania
Właściwości można odczytywać i zapisywać w czasie działania.
Skrypty init
Pliki skryptów init (zwykle pliki *.rc) mogą odczytywać właściwość za pomocą polecenia ${prop}
lub ${prop:-default}
, ustawiać działanie wywoływane za każdym razem, gdy właściwość staje się określoną wartością, oraz zapisywać właściwości za pomocą polecenia 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}
polecenia powłoki getprop i setprop
Aby odczytać lub zapisać właściwości, możesz użyć poleceń getprop
lub setprop
. Aby dowiedzieć się więcej, wywołaj getprop --help
lub setprop --help
.
$ adb shell getprop ro.vndk.version
$
$ adb shell setprop security.perf_harden 0
Sysprop jako interfejs API dla C++/Java/Rust
Dzięki interfejsowi sysprop możesz definiować właściwości systemu i korzystać z automatycznie generowanych interfejsów API, które są konkretne i typowe. Ustawienie wartości scope
z wartością Public
powoduje również, że wygenerowane interfejsy API są dostępne dla modułów w ramach granic i zapewnia stabilność interfejsów API. Oto przykład pliku .sysprop
, modułu Android.bp
oraz kodu w językach C++, Java i Rust, który z nich korzysta.
# 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);
Więcej informacji znajdziesz w artykule Implementowanie właściwości systemu jako interfejsów API.
funkcje i metody właściwości na niskim poziomie w językach C/C++, Java i Rust;
Jeśli to możliwe, używaj interfejsu Sysprop jako interfejsu API, mimo że masz dostęp do funkcji niskiego poziomu w C/C++ lub Rust albo do niskiego poziomu metod Java.
Biblioteki libc
, libbase
i libcutils
udostępniają funkcje właściwości systemowych C++. libc
ma interfejs API, podczas gdy funkcje libbase
i libcutils
są obudową. Jeśli to możliwe, używaj funkcji libbase
sysprop; są one najbardziej wygodne, a binarne pliki hosta mogą korzystać z funkcji libbase
. Więcej informacji znajdziesz w artykułach sys/system_properties.h
(libc
), android-base/properties.h
(libbase
) i cutils/properties.h
(libcutils
).
Klasa android.os.SystemProperties
udostępnia metody właściwości systemowych Javy.
Moduł rustutils::system_properties
zawiera funkcje i typy właściwości systemowych Rust.
Załącznik: dodawanie właściwości dostawcy
Partnerzy (w tym pracownicy Google zajmujący się opracowywaniem telefonów Pixel) chcą zdefiniować właściwości systemowe związane ze sprzętem (lub urządzeniem).
Usługi specyficzne dla dostawców to należące do partnerów usługi, które są unikalne dla ich sprzętu lub urządzenia, a nie dla platformy. Ponieważ są one zależne od sprzętu lub urządzenia, należy ich używać w ramach partycji /vendor
lub /odm
.
Od czasu projektu Treble właściwości platformy i właściwości dostawcy zostały całkowicie rozdzielone, aby uniknąć konfliktów. Poniżej opisujemy, jak definiować właściwości dostawcy i których właściwości dostawcy należy zawsze używać.
Przestrzeń nazw w nazwach właściwości i kontekstów
Wszystkie właściwości dostawcy muszą zaczynać się od jednego z tych prefiksów, aby zapobiec kolizji z właściwościami innych partycji.
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.
Pamiętaj, że znak ro.hardware.
jest dozwolony jako prefiks, ale tylko ze względu na zgodność.
Nie używaj go w przypadku usług zwykłych.
W poniższych przykładach używany jest jeden z wymienionych wyżej prefiksów:
vendor.display.primary_red
persist.vendor.faceauth.use_disk_cache
ro.odm.hardware.platform
Wszystkie konteksty właściwości dostawcy muszą zaczynać się od vendor_
. Dotyczy to też zgodności. Oto kilka przykładów:
vendor_radio_prop
.vendor_faceauth_prop
.vendor_usb_prop
.
Nazewnictwo i utrzymywanie usług należy do sprzedawcy, dlatego stosuj format sugerowany w kroku 2, a także wymagania dotyczące przestrzeni nazw sprzedawcy.
Reguły SEPolicy i konteksty property_contexts specyficzne dla dostawcy
Właściwości dostawcy można zdefiniować za pomocą makra vendor_internal_prop
. Zdefiniowane przez Ciebie reguły dotyczące dostawcy umieść w katalogu BOARD_VENDOR_SEPOLICY_DIRS
.
Załóżmy na przykład, że definiujesz właściwość Faceauth dostawcy w koralu.
W pliku BoardConfig.mk
(lub w dowolnym elemencie BoardConfig.mk
) umieść:
BOARD_VENDOR_SEPOLICY_DIRS := device/google/coral-sepolicy
W pliku device/google/coral-sepolicy/private/property.te
umieść:
vendor_internal_prop(vendor_faceauth_prop)
W pliku device/google/coral-sepolicy/private/property_contexts
umieść:
vendor.faceauth.trace u:object_r:vendor_faceauth_prop:s0 exact bool
Ograniczenia właściwości dostawcy
Ponieważ partycje systemu i usług nie mogą zależeć od dostawcy, nigdy nie zezwalaj na dostęp do właściwości dostawcy z partycji system
, system-ext
lub product
.
Dodatek: zmiana nazw istniejących usług
Jeśli musisz wycofać usługę i przejść na nową, użyj interfejsów Sysprop jako interfejsów API, aby zmienić nazwy dotychczasowych usług. Dzięki temu zachowana jest zgodność wsteczna, ponieważ określana jest zarówno nazwa starszej, jak i nowoczesnej wersji usługi. Starszą nazwę możesz ustawić w polu legacy_prop_name
w pliku .sysprop
. Wygenerowany interfejs API próbuje odczytać parametr prop_name
i używa parametru legacy_prop_name
, jeśli parametr prop_name
nie istnieje.
W poniższych krokach na przykład zmień nazwę z awesome_feature_foo_enabled
na foo.awesome_feature.enabled
.
W pliku 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"
}
W kodzie 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);
Pamiętaj o tych ograniczeniach:
Po pierwsze, nie można zmienić typu właściwości sysprop. Nie możesz na przykład przekształcić rekwizytu
int
w rekwizytstring
. Możesz zmienić tylko nazwę.Po drugie, tylko interfejs API odczytu używa starszej nazwy. Interfejs API do zapisu nie korzysta z tego rozwiązania. Jeśli jest to obiekt sysprop z możliwością zapisu, nie możesz zmienić jego nazwy.