Dodaj właściwości systemu

Na tej stronie przedstawiono kanoniczną metodę dodawania lub definiowania właściwości systemu w systemie Android wraz ze wskazówkami dotyczącymi refaktoryzacji istniejących właściwości systemu. Upewnij się, że używasz wytycznych podczas refaktoryzacji, chyba że masz poważny problem ze zgodnością, który nakazuje inaczej.

Krok 1: Zdefiniowanie właściwości systemu

Kiedy dodajesz właściwość systemową, zdecyduj o nazwie tej właściwości i powiąż ją z kontekstem właściwości SELinux. Jeśli nie ma odpowiedniego istniejącego kontekstu, utwórz nowy. Nazwa jest używana podczas uzyskiwania dostępu do nieruchomości; kontekst właściwości służy do kontrolowania dostępności w kontekście SELinux. Nazwy mogą być dowolnym ciągiem znaków, ale AOSP zaleca stosowanie ustrukturyzowanego formatu, aby były jasne.

Nazwa właściwości

Użyj tego formatu z wielkością wężową:

[{prefix}.]{group}[.{subgroup}]*.{name}[.{type}]

Użyj „” (pominięte), ro (dla właściwości ustawionych tylko raz) lub persist (dla właściwości, które utrzymują się po ponownym uruchomieniu) dla prefix elementu.

Zastrzeżenia

Używaj ro tylko wtedy, gdy masz pewność, że w przyszłości nie będziesz potrzebować prefix , aby można było go zapisać. ** Nie podawaj prefiksu ro .** Zamiast tego polegaj na sepolicy, aby ustawić prefix tylko do odczytu (innymi słowy, zapisywalny tylko przez init ).

Użyj opcji persist tylko wtedy, gdy masz pewność, że wartość musi zostać utrwalona po ponownym uruchomieniu komputera i że jedyną opcją jest użycie właściwości systemu. (Szczegółowe informacje można znaleźć w części Przygotowanie .)

Google ściśle 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. Ma to być nazwa podsystemu podobna w użyciu do audio lub telephony . Nie używaj niejednoznacznych lub przeciążonych terminów, takich jak sys , system , dev , default lub config .

Powszechną praktyką jest używanie nazwy typu domeny procesu, który ma wyłączny dostęp do odczytu i zapisu właściwości systemu. Na przykład w przypadku właściwości systemu, do których proces vold ma prawo zapisu, często używa się vold (nazwy typu domeny procesu) jako nazwy grupy.

W razie potrzeby dodaj subgroup , aby dalej kategoryzować właściwości, ale unikaj niejednoznacznych lub przeciążonych terminów opisujących ten element. (Możesz także mieć więcej niż jedną subgroup .)

Wiele nazw grup zostało już zdefiniowanych. Sprawdź plik system/sepolicy/private/property_contexts i tam, gdzie to możliwe, użyj istniejących nazw grup, zamiast tworzyć nowe. Poniższa tabela zawiera przykłady często używanych nazw grup.

Domena Grupa (i podgrupa)
związane z Bluetoothem bluetooth
sysprops z linii cmd jądra boot
sysprops, które identyfikują kompilację build
związane z telefonią telephony
związane z dźwiękiem audio
związane z grafiką graphics
związane z Voldem vold

Poniżej zdefiniowano użycie name i type w poprzednim przykładzie wyrażenia regularnego .

[{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 systemowej. Na przykład zamiast nazywać obiekt sysprop audio.awesome_feature_enabled lub po prostu audio.awesome_feature , zmień jego nazwę na audio.awesome_feature.enabled , aby odzwierciedlić typ i przeznaczenie właściwości systemu.

Nie ma konkretnej reguły określającej, jaki musi być typ; oto zalecenia dotyczące użytkowania:

  • enabled : Użyj, jeśli typ jest boolowską właściwością systemową używaną do włączania lub wyłączania funkcji.
  • config : Użyj, jeśli zamierzeniem jest wyjaśnienie, że właściwość systemowa nie reprezentuje dynamicznego stanu systemu; reprezentuje wstępnie skonfigurowaną wartość (na przykład opcję 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 jednostkach ms.

Przykłady:

  • persist.radio.multisim.config
  • drm.service.enabled

Kontekst właściwości

Nowy schemat kontekstu właściwości SELinux pozwala na większą szczegółowość i bardziej opisowe nazwy. Podobnie jak w przypadku nazw właściwości, AOSP zaleca następujący format:

{group}[_{subgroup}]*_prop

Terminy definiuje się w następujący sposób:

group i subgroup mają takie samo znaczenie, jak zdefiniowano dla poprzedniego przykładowego wyrażenia regularnego . Na przykład vold_config_prop oznacza właściwości, które są konfiguracjami od dostawcy i które mają być ustawione przez vendor_init , podczas gdy vold_status_prop lub po prostu vold_prop oznacza właściwości, które mają ukazać bieżący stan vold .

Nazywając kontekst właściwości, wybierz nazwy, które odzwierciedlają ogólne użycie właściwości. W szczególności należy unikać następujących typów terminów:

  • Terminy, które wydają się zbyt ogólne i niejednoznaczne, takie jak sys , system , default .
  • Terminy, które bezpośrednio kodują dostępność: takie jak exported , apponly , ro , public , private .

Preferuj użycie nazw, takie jak vold_config_prop do exported_vold_prop lub vold_vendor_writable_prop i tak dalej.

Typ

Typ właściwości może być jednym z następujących typów wymienionych w tabeli.

Typ Definicja
Wartość logiczna true lub 1 dla prawdy, false lub 0 dla fałszu
Liczba całkowita 64-bitowa liczba całkowita ze znakiem
Liczba całkowita bez znaku 64-bitowa liczba całkowita bez znaku
Podwójnie zmiennoprzecinkowy podwójnej precyzji
Strunowy dowolny prawidłowy ciąg UTF-8
wyliczenie wartościami mogą być dowolne prawidłowe ciągi znaków w formacie UTF-8 bez białych znaków
Lista powyżej Jako ogranicznik 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żna wymusić typ, określając go jako plik property_contexts . Aby uzyskać więcej informacji, zobacz property_contexts w kroku 3 .

Krok 2: Określenie wymaganych poziomów dostępności

Istnieją cztery makra pomocnicze, które definiują właściwość.

Typ dostępności Oznaczający
system_internal_prop Właściwości używane tylko w /system
system_restricted_prop Właściwości, które są odczytywane poza /system , ale nie zapisywane
system_vendor_config_prop Właściwości odczytywane poza /system i zapisywane tylko przez vendor_init
system_public_prop Właściwości, które są odczytywane i zapisywane poza /system

Zawęź zakres dostępu do właściwości systemu tak wąsko, jak to możliwe. W przeszłości szeroki dostęp powodował awarie aplikacji i luki w zabezpieczeniach. Podczas określania zakresu należy wziąć pod uwagę następujące pytania:

  • Czy ta właściwość systemu musi zostać utrwalona? (jeśli tak, dlaczego?)
  • Który proces powinien mieć dostęp do odczytu tej właściwości?
  • Który proces powinien mieć prawo zapisu do tej właściwości?

Wykorzystaj powyższe pytania i poniższe drzewo decyzyjne jako narzędzia do określenia odpowiedniego zakresu dostępu.

Decision tree for determining the scope of access

Rysunek 1. Drzewo decyzyjne określające zakres dostępu do właściwości systemu

Krok 3: Dodanie go do systemu/sepolicy

Podczas uzyskiwania dostępu do sysprop SELinux kontroluje dostępność procesów. Po ustaleniu, jaki poziom dostępności jest wymagany, zdefiniuj konteksty właściwości w system/sepolicy wraz z dodatkowymi regułami zezwalającymi i nigdy zezwalającymi określającymi, które procesy mogą (a nie mogą) czytać i zapisywać.

Najpierw zdefiniuj 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 makr system_[accessibility]_prop([context]) , które zapewnia dostępność wymaganą 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 dodania pliku system/sepolicy/private/property.te :

system_internal_prop(audio_baz_prop)

Po drugie, przyznaj dostęp do odczytu i (lub) zapisu do kontekstu właściwości. Użyj makr set_prop i get_prop , aby przyznać dostęp do pliku system/sepolicy/public/{domain}.te lub system/sepolicy/private/{domain}.te . Jeśli to możliwe, używaj private ; public jest odpowiednie tylko wtedy, gdy makro set_prop lub get_prop wpływa na dowolne domeny poza domeną podstawową.

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 kilka reguł Neverallow, aby jeszcze bardziej ograniczyć dostępność objętą zakresem makra. Załóżmy na przykład, że użyłeś system_restricted_prop , ponieważ właściwości systemu muszą zostać odczytane przez procesy dostawcy. Jeśli dostęp do odczytu nie jest wymagany przez wszystkie procesy dostawcy i jest wymagany tylko przez określony zestaw procesów (taki jak vendor_init ), zablokuj procesy dostawcy, które nie potrzebują dostępu do odczytu.

Aby ograniczyć dostęp do zapisu i odczytu, użyj następującej 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;

Jeśli reguła Neverallow jest powiązana z konkretną domeną, umieść reguły Neverallow w pliku system/sepolicy/private/{domain}.te . W przypadku szerszych zasad „nigdy nie zezwalaj” w stosownych przypadkach użyj domen ogólnych, takich jak poniższe:

  • 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 dostawców. Zatem {domain -coredomain -vendor_init} oznacza „wszystkie procesy dostawców z wyjątkiem vendor_init ”.

Na koniec powiąż właściwość systemową z kontekstem właściwości. Dzięki temu przyznany dostęp i reguły Neverallow stosowane do kontekstów właściwości zostaną zastosowane do rzeczywistych właściwości. Aby to zrobić, dodaj wpis do pliku property_contexts , pliku opisującego mapowanie pomiędzy właściwościami systemu i kontekstami właściwości. W tym pliku można określić pojedynczą właściwość lub przedrostek właściwości, które mają być mapowane w kontekście.

Oto składnia mapowania pojedynczej właściwości:

[property_name] u:object_r:[context_name]:s0 exact [type]

Oto składnia mapowania przedrostka:

[property_name_prefix] u:object_r:[context_name]:s0 prefix [type]

Opcjonalnie możesz określić typ właściwości, który może być jednym z poniższych:

  • bool
  • int
  • uint
  • double
  • enum [list of possible values...]
  • string (Użyj string dla właściwości listy.)

Jeśli to możliwe, upewnij się, że każdy wpis ma swój wyznaczony typ, ponieważ type jest wymuszany 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

W przypadku konfliktu wpisu dokładnego i wpisu z przedrostkiem, pierwszeństwo ma wpis dokładny. Więcej przykładów można znaleźć w artykule system/sepolicy/private/property_contexts .

Krok 4: Określenie wymagań stabilności

Stabilność to kolejny aspekt właściwości systemu, różniący się od dostępności. Stabilność dotyczy tego, czy właściwość systemu będzie mogła zostać zmieniona (na przykład zmieniona nazwa lub nawet usunięta) w przyszłości. Jest to szczególnie ważne, ponieważ system operacyjny Android staje się modułowy. Dzięki Treble partycje systemu, dostawcy i produktu mogą być aktualizowane niezależnie od siebie. W przypadku Mainline niektóre części systemu operacyjnego są modułowe w postaci modułów z możliwością aktualizacji (w plikach APEX lub APK).

Jeśli właściwość systemu ma być używana w aktualizowalnych fragmentach oprogramowania, na przykład na partycjach systemu i dostawcy, musi być stabilna. Jeśli jednak jest używany tylko w obrębie, na przykład, określonego modułu Mainline, możesz zmienić jego nazwę, typ lub kontekst właściwości, a nawet go usunąć.

Zadaj następujące pytania, aby określić stabilność właściwości systemu:

  • Czy ta właściwość systemu ma być konfigurowana przez partnerów (czy może konfigurowana inaczej w zależności od urządzenia)? Jeśli tak, to musi być stabilne.
  • Czy ta właściwość systemowa zdefiniowana przez AOSP jest przeznaczona do zapisu lub odczytu z kodu (nie procesu), który istnieje na partycjach niesystemowych, takich jak vendor.img lub product.img ? Jeśli tak, to musi być stabilne.
  • Czy dostęp do tej właściwości systemu można uzyskać w modułach Mainline, czy w module Mainline i nieaktualizowanej części platformy? Jeśli tak, to musi być stabilne.

W przypadku stabilnych właściwości systemu formalnie zdefiniuj każdą z nich jako API i użyj API, aby uzyskać dostęp do właściwości systemu, jak wyjaśniono w kroku 6 .

Krok 5: Ustawianie 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ą zapisywane w {partition}/build.prop . Następnie init odczytuje {partition}/build.prop aby ustawić właściwości. Istnieją dwa zestawy 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 zapewnia, że {prop} jest ustawione na {value} ; na jedną nieruchomość możliwe jest tylko jedno takie przypisanie.

{prop}?={value} jest przypisaniem opcjonalnym; {prop} ustawia się na {value} tylko wtedy, gdy nie ma żadnych przypisań {prop}={value} . Jeśli istnieje wiele opcjonalnych zadań, pierwsze z nich wygrywa.

# 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 szczegółów znajdziesz w build/make/core/sysprop.mk .

Krok 6: Uzyskaj dostęp do właściwości w czasie wykonywania

Oczywiście właściwości można odczytywać i zapisywać w czasie wykonywania.

Skrypty inicjujące

Pliki skryptów inicjujących (zwykle pliki *.rc) mogą odczytywać właściwości za pomocą ${prop} lub ${prop:-default} , mogą ustawiać akcję, która będzie uruchamiana za każdym razem, gdy właściwość osiągnie określoną wartość i mogą zapisywać właściwości za pomocą setprop Komenda.

# 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

Do odczytu lub zapisu właściwości można użyć odpowiednio poleceń powłoki getprop lub setprop . Aby uzyskać więcej informacji, wywołaj getprop --help lub setprop --help .

$ adb shell getprop ro.vndk.version
$
$ adb shell setprop security.perf_harden 0

Sysprop jako API dla C++/Java/Rust

Dzięki sysprop jako API możesz definiować właściwości systemu i korzystać z automatycznie generowanego API, które jest konkretne i wpisane. Ustawienie scope za pomocą opcji Public powoduje również, że wygenerowane interfejsy API są dostępne dla modułów ponad granicami i zapewniają stabilność interfejsu API. Oto przykład pliku .sysprop , modułu Android.bp oraz kodu 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);

Aby uzyskać więcej informacji, zobacz Implementowanie właściwości systemu jako interfejsów API .

Funkcje i metody właściwości niskiego poziomu w językach C/C++, Java i Rust

Jeśli to możliwe, używaj Sysprop jako API, nawet jeśli masz dostępne niskopoziomowe funkcje C/C++ lub Rust albo niskopoziomowe metody Java.

libc , libbase i libcutils oferują funkcje właściwości systemowych C++. libc zawiera podstawowy interfejs API, natomiast funkcje libbase i libcutils są opakowaniami. Jeśli to możliwe, użyj funkcji sysprop libbase ; są najwygodniejsze, a pliki binarne hosta mogą korzystać z funkcji libbase . Aby uzyskać więcej informacji, zobacz sys/system_properties.h ( libc ), android-base/properties.h ( libbase ) i cutils/properties.h ( libcutils ).

Klasa android.os.SystemProperties oferuje metody właściwości systemu Java.

Moduł rustutils::system_properties oferuje funkcje i typy właściwości systemu Rust.

Dodatek: Dodawanie właściwości specyficznych dla dostawcy

Partnerzy (w tym pracownicy Google pracujący w kontekście rozwoju 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 własnego sprzętu lub urządzenia, a nie platformy. Ponieważ są one zależne od sprzętu lub urządzenia, należy ich używać w partycjach /vendor lub /odm .

Od czasu Projektu Treble właściwości platformy i właściwości dostawcy zostały całkowicie rozdzielone, aby zapobiec konfliktom. Poniżej opisano sposób definiowania właściwości dostawcy i wskazano, które właściwości dostawcy muszą być zawsze używane.

Przestrzeń nazw dla nazw właściwości i kontekstów

Wszystkie właściwości dostawcy muszą zaczynać się od jednego z następujących przedrostków, aby zapobiec kolizjom między nimi a 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.

Należy pamiętać, że ro.hardware. jest dozwolony jako przedrostek, ale tylko w celu zapewnienia zgodności. Nie używaj go do normalnych właściwości.

Wszystkie poniższe przykłady wykorzystują jeden z wymienionych wcześniej przedrostkó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 również kompatybilności. Oto przykłady:

  • vendor_radio_prop .
  • vendor_faceauth_prop .
  • vendor_usb_prop .

Nadawanie nazw i utrzymywanie właściwości jest obowiązkiem dostawcy, dlatego należy postępować zgodnie z formatem sugerowanym w kroku 2 , oprócz wymagań dotyczących przestrzeni nazw dostawcy.

Reguły SEPolicy i kontekst_właściwości specyficzne dla dostawcy

Właściwości dostawcy można zdefiniować za pomocą makra vendor_internal_prop . Umieść zdefiniowane przez siebie reguły specyficzne dla dostawcy 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 innym pliku BoardConfig.mk ) umieść następujące informacje:

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 systemowe i produktowe nie mogą zależeć od dostawcy, nigdy nie zezwalaj na dostęp do właściwości dostawcy z partycji system , system-ext lub partycji product .

Dodatek: Zmiana nazw istniejących właściwości

Jeśli musisz wycofać właściwość i przejść na nową, użyj Sysprop jako interfejsów API , aby zmienić nazwę istniejących właściwości. Pozwala to zachować kompatybilność wsteczną poprzez określenie zarówno starszej nazwy, jak i nowej nazwy właściwości. W szczególnoś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 poniższe kroki 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);

Zwróć uwagę na następujące zastrzeżenia:

  • Po pierwsze, nie można zmienić typu pliku sysprop. Na przykład nie możesz przekształcić właściwości int w właściwość string . Możesz zmienić tylko nazwę.

  • Po drugie, tylko interfejs API odczytu powraca do starszej nazwy. Interfejs API zapisu nie wraca. Jeśli plik sysprop jest zapisywalny, nie można zmienić jego nazwy.