Dodawanie właściwości systemowych

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 nametype.

[{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 prostu audio.awesome_feature, zmień jej nazwę na audio.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:

groupsubgroup 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_contextskroku 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.

Drzewo decyzyjne określające 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 allowneverallow 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_propget_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 symbolu string).

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 lub product.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}_PROPERTIESTARGET_{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, libbaselibcutils oferują funkcje właściwości systemu C++. libc ma bazowy interfejs API, a funkcje libbaselibcutils 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 rekwizyt string. 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.