Na tej stronie znajdziesz kanoniczną metodę dodawania lub definiowania właściwości systemu Android wraz z wytycznymi dotyczącymi refaktoryzacji istniejących właściwości systemu. Podczas refaktoryzacji postępuj zgodnie z wytycznymi, chyba że masz poważny problem ze zgodnością, który wymaga innego podejścia.
Krok 1. Zdefiniuj właściwość systemu
Gdy dodajesz właściwość systemową, wybierz jej nazwę i powiąż ją z kontekstem właściwości SELinux. Jeśli nie ma odpowiedniego kontekstu, utwórz nowy. Nazwa jest używana podczas uzyskiwania dostępu do właściwości, a kontekst właściwości służy do kontrolowania dostępności w kontekście SELinux. Nazwy mogą być dowolnymi ciągami znaków, ale AOSP zaleca stosowanie uporządkowanego formatu, aby były czytelne.
Nazwa właściwości
Użyj tego formatu z notacją snake_case:
[{prefix}.]{group}[.{subgroup}]*.{name}[.{type}]
W przypadku elementu prefix
użyj wartości „” (pominięto), ro
(w przypadku właściwości ustawianych tylko raz) lub persist
(w przypadku właściwości, które są zachowywane po ponownym uruchomieniu).
Uwagi
Używaj ro
tylko wtedy, gdy masz pewność, że w przyszłości nie będziesz potrzebować możliwości zapisywania w prefix
. ** Nie podawaj prefiksu ro
. Zamiast tego polegaj na sepolicy, aby ustawić prefix
jako tylko do odczytu (czyli zapisywalny tylko przez init
).
Używaj persist
tylko wtedy, gdy masz pewność, że wartość musi być zachowywana po ponownym uruchomieniu i że używanie właściwości systemu jest jedyną opcją.
Google dokładnie sprawdza właściwości systemu, które mają właściwości ro
lub persist
.
Termin group
służy do agregowania powiązanych właściwości. Jest to nazwa podsystemu podobna w użyciu do audio
lub telephony
. Nie używaj niejednoznacznych lub nadużywanych terminów, takich jak sys
, system
, dev
, default
czy config
.
Zwykle używa się nazwy typu domeny procesu, który ma wyłączny dostęp do odczytu lub zapisu właściwości systemu. Na przykład w przypadku właściwości systemu, do których proces vold
ma dostęp do zapisu, często używa się vold
(nazwy typu domeny dla procesu) jako nazwy grupy.
W razie potrzeby dodaj subgroup
, aby dokładniej sklasyfikować usługi, ale unikaj niejednoznacznych lub nadmiernie obciążonych terminów do opisywania tego elementu. (Możesz mieć więcej niż 1 subgroup
).
Wiele nazw grup zostało już zdefiniowanych. Sprawdź pliksystem/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 Bluetooth, | bluetooth |
sysprops z linii poleceń jądra | boot |
właściwości systemu, które identyfikują kompilację; | build
|
związane z telefonią, | telephony |
związane z dźwiękiem, | audio |
związane z grafiką, | graphics |
vold related | vold |
Poniżej wyjaśniamy, jak w poprzednim przykładzie wyrażenia regularnego użyto znaków name
i type
.
[{prefix}.]{group}[.{subgroup}]*.{name}[.{type}]
name
identyfikuje właściwość systemu w grupie.type
to opcjonalny element, który wyjaśnia typ lub przeznaczenie właściwości systemu. Na przykład zamiast nazywać właściwość systemowąaudio.awesome_feature_enabled
lub po prostuaudio.awesome_feature
, zmień jej nazwę naaudio.awesome_feature.enabled
, aby odzwierciedlała typ i przeznaczenie właściwości systemowej.
Nie ma konkretnej reguły dotyczącej tego, jaki typ musi być użyty. Oto rekomendacje dotyczące użycia:
enabled
: użyj, jeśli typem jest właściwość systemowa o wartości logicznej, która służy do włączania i wyłączania funkcji.config
: użyj, jeśli chcesz wyjaśnić, że właściwość systemu nie reprezentuje dynamicznego stanu systemu, ale wstępnie skonfigurowaną wartość (np. obiekt tylko do odczytu).List
: użyj, jeśli jest to właściwość systemowa, której wartością jest lista.Timeoutmillis
: użyj, jeśli jest to właściwość systemowa dla wartości limitu czasu w milisekundach.
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 stosowanie tego formatu:
{group}[_{subgroup}]*_prop
Terminy te są zdefiniowane w ten sposób:
group
i subgroup
mają takie samo znaczenie jak w przypadku poprzedniego przykładowego wyrażenia regularnego. Na przykład vold_config_prop
oznacza właściwości, które są konfiguracjami dostawcy i mają być ustawiane przez vendor_init
, a vold_status_prop
lub po prostu vold_prop
oznacza właściwości, które mają ujawniać bieżący stan vold
.
Nadając kontekstowi usługi nazwę, wybieraj takie nazwy, które odzwierciedlają ogólne zastosowanie właściwości. Unikaj w szczególności tych typów słów:
- słowa, które są zbyt ogólne i niejednoznaczne, np.
sys
,system
,default
; - Terminy, które bezpośrednio kodują dostępność, np.
exported
,apponly
,ro
,public
,private
.
Preferuj użycie nazwy w formie vold_config_prop
zamiast exported_vold_prop
lub vold_vendor_writable_prop
.
Typ
Typ usługi może być jednym z tych typów (patrz tabela).
Typ | Definicja |
---|---|
Wartość logiczna | true lub 1 w przypadku odpowiedzi „prawda”, false lub 0 w przypadku odpowiedzi „fałsz”. |
Liczba całkowita | 64-bitowa liczba całkowita ze znakiem |
Liczba całkowita bez znaku | niepodpisana 64-bitowa liczba całkowita, |
Podwójny | liczba zmiennoprzecinkowa podwójnej precyzji |
Ciąg znaków | dowolny prawidłowy ciąg znaków UTF-8, |
enum | wartości mogą być dowolnym prawidłowym ciągiem znaków UTF-8 bez spacji. |
Lista powyższych | Jako ogranicznika używany jest przecinek (, ).Lista liczb całkowitych [1, 2, 3] jest przechowywana jako 1,2,3 |
Wszystkie właściwości są wewnętrznie przechowywane jako ciągi tekstowe. Możesz wymusić typ, określając go jako property_contexts
. Więcej informacji znajdziesz w property_contexts
w kroku 3.
Krok 2. Określ wymagane poziomy dostępności
Właściwość definiują 4 makra 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 /system , a 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 niezbędnego minimum. W przeszłości szeroki dostęp powodował awarie aplikacji i luki w zabezpieczeniach. Podczas określania zakresu projektu weź pod uwagę te pytania:
- Czy ta właściwość systemu musi być zachowywana? (jeśli tak, to 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?
Użyj powyższych pytań i poniższego drzewa decyzyjnego, aby określić odpowiedni zakres dostępu.
Rysunek 1. Schemat decyzyjny określający zakres 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
wraz z dodatkowymi regułami allow i neverallow
określającymi, co procesy mogą (a czego nie mogą) odczytywać i zapisywać.
Najpierw zdefiniuj kontekst usługi 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 makr system_[accessibility]_prop([context])
, które zapewnia dostępność wymaganą przez właściwość 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 dodania do pliku system/sepolicy/private/property.te
:
system_internal_prop(audio_baz_prop)
Po drugie, przyznaj uprawnienia do odczytu i (lub) zapisu kontekstu usługi. Użyj makr set_prop
i get_prop
, aby przyznać dostęp w pliku system/sepolicy/public/{domain}.te
lub system/sepolicy/private/{domain}.te
. W miarę możliwości używaj tagu private
. Tag public
jest odpowiedni tylko wtedy, gdy makro set_prop
lub get_prop
wpływa na domeny inne niż domena podstawowa.
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 trzecie dodaj reguły neverallow, aby jeszcze bardziej ograniczyć dostępność określoną przez makro. Załóżmy na przykład, że używasz system_restricted_prop
, ponieważ właściwości systemu muszą być odczytywane przez procesy dostawcy. Jeśli dostęp do odczytu nie jest wymagany przez wszystkie procesy dostawcy, a jest potrzebny tylko w przypadku określonego zestawu procesów (np. vendor_init
), zabroń dostawcy korzystania z procesów, które nie wymagają dostępu do odczytu.
Aby ograniczyć uprawnienia do zapisu i odczytu, użyj tej składni:
Aby ograniczyć uprawnienia 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 bardziej ogólnych reguł neverallow używaj w odpowiednich miejscach domen ogólnych, 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ść ten kod:
neverallow {
domain -init -audio
} {audio_foo_prop audio_bar_prop}:property_service set;
W pliku system/sepolicy/private/property.te
umieść ten kod:
neverallow {
domain -coredomain -vendor_init
} audio_prop:file no_rw_file_perms;
Pamiętaj, że {domain -coredomain}
obejmuje wszystkie procesy dostawców. So
{domain -coredomain -vendor_init}
oznacza „wszystkie procesy dostawcy z wyjątkiem
vendor_init
”.
Na koniec powiąż właściwość systemową z kontekstem usługi. Dzięki temu dostęp, który jest przyznawany, i reguły neverallow, które są stosowane w kontekstach usług, są stosowane w przypadku 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 określić pojedynczą właściwość lub prefiks właściwości, które mają być mapowane na kontekst.
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 typów:
bool
int
uint
double
enum [list of possible values...]
string
(W przypadku właściwości listy użyj symbolustring
).
W miarę możliwości upewnij się, że każdy wpis ma przypisany typ, ponieważ type
jest wymuszane podczas ustawiania property
. Poniższy przykład pokazuje, jak napisać 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
Gdy dokładny wpis i wpis z prefiksem są sprzeczne, pierwszeństwo ma dokładny wpis. Więcej przykładów znajdziesz w sekcji system/sepolicy/private/property_contexts
.
Krok 4. Określ wymagania dotyczące stabilności
Stabilność to kolejny aspekt właściwości systemu, który różni się od dostępności. Stabilność określa, czy właściwość systemu może zostać zmieniona (np. jej nazwa) lub usunięta w przyszłości. Jest to szczególnie ważne, ponieważ system operacyjny Android staje się modułowy. Dzięki Treble partycje systemowe, dostawcy i produktu można aktualizować niezależnie od siebie. W przypadku Mainline niektóre części systemu operacyjnego są podzielone na moduły, które można aktualizować (w postaci plików APEX lub APK).
Jeśli właściwość systemowa ma być używana w aktualizowanych elementach oprogramowania, np. w partycjach systemowych i partycjach dostawcy, musi być stabilna. Jeśli jednak jest on używany tylko w określonym module Mainline, możesz zmienić jego nazwę, typ lub konteksty właściwości, a nawet go usunąć.
Aby określić stabilność właściwości systemu, zadaj sobie te pytania:
- Czy to ustawienie systemowe ma być konfigurowane przez partnerów (lub konfigurowane inaczej na poszczególnych urządzeniach)? Jeśli tak, musi być stabilny.
- Czy ta właściwość systemowa zdefiniowana w AOSP ma być zapisywana lub odczytywana przez kod (nie proces) znajdujący się w partycjach innych niż systemowe, np.
vendor.img
lubproduct.img
? Jeśli tak, musi być stabilny. - Czy dostęp do tej właściwości systemowej jest uzyskiwany w modułach Mainline lub w module Mainline i nieaktualizowanej części platformy? Jeśli tak, musi być stabilny.
W przypadku stabilnych właściwości systemu formalnie zdefiniuj każdą z nich jako interfejs API i używaj go do uzyskiwania 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 pliku makefile. Wartości są technicznie 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 zwykłe przypisanie, które zapewnia, że {prop}
ma wartość {value}
. W przypadku jednej właściwości możliwe jest tylko jedno takie przypisanie.
{prop}?={value}
to opcjonalne przypisanie; {prop}
przyjmuje wartość {value}
tylko wtedy, gdy nie ma przypisań {prop}={value}
. Jeśli istnieje kilka opcjonalnych przypisań, pierwsze z nich ma pierwszeństwo.
# 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ę par {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
Więcej informacji znajdziesz w sekcji build/make/core/sysprop.mk
.
Krok 6. Uzyskiwanie dostępu do właściwości w czasie działania
Właściwości można odczytywać i zapisywać w czasie działania programu.
Skrypty inicjujące
Pliki skryptu inicjującego (zwykle pliki *.rc) mogą odczytywać właściwość za pomocą polecenia ${prop}
lub
${prop:-default}
, mogą ustawiać działanie, które jest uruchamiane, gdy właściwość przyjmuje określoną wartość, i mogą 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ć odpowiednio poleceń powłoki getprop
lub setprop
. Więcej informacji znajdziesz w opisie funkcji getprop --help
lub setprop --help
.
$ adb shell getprop ro.vndk.version
$
$ adb shell setprop security.perf_harden 0
Sysprop jako interfejs API dla C++/Javy/Rusta
Dzięki sysprop jako interfejsowi API możesz definiować właściwości systemu i korzystać z automatycznie generowanego interfejsu API, który jest konkretny i ma określony typ. Ustawienie scope
z parametrem Public
sprawia też, że wygenerowane interfejsy API są dostępne dla modułów w różnych granicach i zapewnia stabilność interfejsu API. Oto przykładowy plik .sysprop
, moduł Android.bp
oraz kod w językach C++, Java i Rust, który ich używa.
# 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 niskiego poziomu w językach C/C++, Java i Rust
Jeśli to możliwe, używaj Sysprop jako interfejsu API, nawet jeśli masz dostęp do funkcji niskiego poziomu w C/C++ lub Rust albo do metod niskiego poziomu w Javie.
libc
, libbase
i libcutils
oferują funkcje właściwości systemu C++. libc
ma bazowy interfejs API, a funkcje libbase
i libcutils
są
otoczkami. Jeśli to możliwe, używaj funkcji libbase
sysprop. Są one najwygodniejsze, a binarne pliki hosta mogą korzystać z funkcji libbase
. Więcej informacji znajdziesz w sekcjach 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 systemu Java.
Moduł rustutils::system_properties
oferuje funkcje i typy właściwości systemowych Rust.
Dodatek: dodawanie właściwości specyficznych dla dostawcy
Partnerzy (w tym pracownicy Google zaangażowani w rozwój Pixela) chcą zdefiniować właściwości systemu specyficzne dla sprzętu (lub urządzenia).
Właściwości specyficzne dla dostawcy to właściwości należące do partnera, które są unikalne dla jego sprzętu lub urządzenia, a nie dla platformy. Ponieważ są one zależne od sprzętu lub urządzenia, powinny być używane w partycjach /vendor
lub /odm
.
Od czasu wprowadzenia Project Treble właściwości platformy i właściwości dostawcy są całkowicie rozdzielone, aby uniknąć konfliktów. Poniżej znajdziesz opis sposobu definiowania właściwości dostawcy oraz informacje o tym, które właściwości dostawcy muszą być zawsze używane.
Przestrzeń nazw we właściwości i nazwach kontekstu
Aby zapobiec kolizji między właściwościami dostawcy a właściwościami innych partycji, wszystkie właściwości dostawcy muszą zaczynać się od jednego z tych prefiksów:
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 zwykłych usług.
Wszystkie podane niżej przykłady korzystają z jednego z wymienionych wcześniej 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_
. Służy to również zapewnieniu zgodności. Przykłady:
vendor_radio_prop
.vendor_faceauth_prop
.vendor_usb_prop
.
Nazwy właściwości i ich utrzymywanie należy do obowiązków dostawcy, dlatego postępuj zgodnie z formatem sugerowanym w kroku 2 oraz z wymaganiami dotyczącymi przestrzeni nazw dostawcy.
Reguły SEPolicy i pliki property_contexts specyficzne dla dostawcy
Właściwości dostawcy można zdefiniować za pomocą makra vendor_internal_prop
. Umieść zdefiniowane przez siebie reguły dotyczące konkretnego dostawcy w katalogu BOARD_VENDOR_SEPOLICY_DIRS
.
Załóżmy na przykład, że definiujesz właściwość dostawcy faceauth w przypadku koralowca.
W pliku BoardConfig.mk
(lub w dowolnym pliku BoardConfig.mk
) umieść ten kod:
BOARD_VENDOR_SEPOLICY_DIRS := device/google/coral-sepolicy
W pliku device/google/coral-sepolicy/private/property.te
umieść ten kod:
vendor_internal_prop(vendor_faceauth_prop)
W pliku device/google/coral-sepolicy/private/property_contexts
umieść ten kod:
vendor.faceauth.trace u:object_r:vendor_faceauth_prop:s0 exact bool
Ograniczenia dotyczące usług dostawców
Partycje systemowe i produktu nie mogą zależeć od dostawcy, dlatego nigdy nie zezwalaj na dostęp do właściwości dostawcy z partycji system
, system-ext
ani product
.
Dodatek: zmiana nazw dotychczasowych usług
Jeśli musisz wycofać usługę i przejść na nową, użyj Sysprop jako interfejsów API, aby zmienić nazwy dotychczasowych usług. Zapewnia to zgodność wsteczną, ponieważ określa zarówno starą nazwę, jak i nową nazwę właściwości. Możesz ustawić starszą nazwę za pomocą pola legacy_prop_name
w pliku .sysprop
. Wygenerowany interfejs API próbuje odczytać prop_name
i używa legacy_prop_name
, jeśli prop_name
nie istnieje.
Na przykład te czynności zmieniają nazwę 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 kwestiach:
Po pierwsze, nie możesz zmienić typu sysprop. Nie możesz na przykład zmienić rekwizytu
int
na rekwizytstring
. Możesz tylko zmienić nazwę.Po drugie, tylko interfejs API do odczytu wraca do starszej nazwy. Interfejs API do zapisu nie wraca do poprzedniej wersji. Jeśli właściwość systemowa jest zapisywalna, nie można zmienić jej nazwy.