Добавить свойства системы

На этой странице представлен канонический метод добавления или определения системных свойств в Android с рекомендациями по рефакторингу существующих системных свойств. Убедитесь, что вы используете рекомендации при рефакторинге, если у вас нет серьезных проблем с совместимостью, которые диктуют иное.

Фон

Системные свойства используются для различных целей, потому что они просты в использовании. Хотя они похожи на глобальные переменные в языках программирования, не существует набора формализованных требований к процессам или соглашений об именах, которым вы должны следовать при их создании. Поэтому свойства системы могут быть трудными для понимания и обслуживания. Шаги на этой странице определяют системные свойства и предоставляют шаги для их добавления и обслуживания.

Подготовка: рассмотрите альтернативы

Определите, является ли системное свойство действительно тем, что вам нужно, и является ли это вашим единственным вариантом. Системные свойства — это общесистемные ресурсы, дающие определенные преимущества. Они просты в использовании, а их нединамические свойства имеют относительно низкую нагрузку на производительность. При использовании системных свойств вам не нужно использовать межпроцессное взаимодействие (IPC), даже если системное свойство совместно используется несколькими процессами. Однако они также могут быть вредными при неправильном использовании, подобно глобальным переменным. Неправильное использование системных свойств привело к таким проблемам, как недоступность приложений для пользователей и появление уязвимостей в системе безопасности.

Рассмотрите множество альтернатив системным свойствам, которые следуют, чтобы оценить, может ли одна из них предоставить вам необходимое решение.

Общие настройки

Для постоянной конфигурации, которая является локальной для приложения, используйте интерфейс Shared Preferences , а не системные свойства.

ХАЛ

Когда источником правды для конфигурации является аппаратный компонент на устройстве, HAL должен предоставить информацию для этого компонента. Не настраивайте HAL для записи системного свойства, чтобы другие процессы могли его прочитать (или наоборот). Вместо этого определите новый метод HAL для доступа к конфигурации. Другими словами, не используйте системные свойства в качестве механизма связи по побочному каналу для HAL.

Обратите внимание, что вам не нужен новый HAL для этого варианта использования, так как это дорогой вариант. Используйте это предложение, только если у вас есть существующий HAL для абстрагирования аппаратного компонента.

Конфигурационный файл

Если данные конфигурации являются статическими, но сложными (другими словами, структурированными), рассмотрите возможность использования XML или других подобных форматов для данных конфигурации. Убедитесь, что файловая схема остается стабильной. Для XML-файлов можно использовать xsd_config , чтобы сохранить стабильность схемы и воспользоваться преимуществами автоматически сгенерированного синтаксического анализатора XML.

Служба переплета

Системные свойства часто используются для совместного использования динамического состояния подсистемы с несколькими процессами. Такие состояния могут быть реализованы внутри службы связывателя (например, в поле объекта), а другие процессы могут считывать (или даже изменять) состояние, используя вызовы службы связывателя. Это предпочтительное решение, так как для превращения состояния в системное свойство и предоставления прямого доступа к нему требуется процесс, аналогичный этому:

  1. Выполните проверку работоспособности состояния.
  2. Выполните постобработку состояния, чтобы сделать его пригодным для использования.
  3. Выполните детальную функцию контроля доступа.
  4. Держите государство структурированным.

Успешное завершение этого процесса либо невозможно, либо, в лучшем случае, очень сложно, когда вы реализуете состояние как системное свойство. Поэтому используйте опцию службы связывания, когда читатели состояния уже имеют доступ к службе связывателя.

Шаг 1: Определение системного свойства

Когда вы добавляете системное свойство, выберите имя свойства и свяжите его с контекстом свойства SELinux. Если подходящего существующего контекста нет, создайте новый. Имя используется при доступе к свойству; контекст свойства используется для управления доступностью с точки зрения SELinux. Имена могут быть любой строкой, но AOSP рекомендует использовать структурированный формат, чтобы сделать их понятными.

Имя свойства

Используйте этот формат с регистром змейки_case:

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

Используйте «» (опущено), ro (для свойств, установленных только один раз) или persist (для свойств, которые сохраняются при перезагрузке) для prefix элемента.

Предостережения

Используйте ro только тогда, когда вы уверены, что вам не нужен prefix для записи в будущем. ** Не указывайте префикс ro .** Вместо этого полагайтесь на sepolicy, чтобы сделать prefix доступным только для чтения (другими словами, доступным для записи только init ).

Используйте persist только в том случае, если вы уверены, что значение должно сохраняться при перезагрузке, и что использование свойств системы — ваш единственный вариант. (Подробности см. в разделе « Подготовка ».)

Google строго проверяет системные свойства, которые имеют свойства ro или persist .

group терминов используется для объединения связанных свойств. Предполагается, что это имя подсистемы, похожее на audio или telephony . Не используйте двусмысленные или перегруженные термины, такие как sys , system , dev , default или config .

Общепринятой практикой является использование имени доменного типа процесса, который имеет монопольный доступ на чтение или запись к системным свойствам. Например, для системных свойств, к которым процесс vold имеет доступ для записи, обычно используется vold (имя типа домена для процесса) в качестве имени группы.

При необходимости добавьте subgroup для дальнейшей категоризации свойств, но избегайте двусмысленных или перегруженных терминов для описания этого элемента. (Вы также можете иметь более одной subgroup .)

Многие имена групп уже определены. Проверьте файл system/sepolicy/private/property_contexts и по возможности используйте существующие имена групп вместо создания новых. В следующей таблице приведены примеры часто используемых имен групп.

Домен Группа (и подгруппа)
связанные с Bluetooth bluetooth
sysprops из командной строки ядра boot
sysprops, которые идентифицируют сборку build
связанные с телефонией telephony
аудио связанные audio
связанные с графикой graphics
связанные с миром vold

Далее определяется использование name и type в предыдущем примере регулярного выражения .

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

  • name идентифицирует системное свойство в группе.

  • type — необязательный элемент, уточняющий тип или назначение системного свойства. Например, вместо того, чтобы называть sysprop как audio.awesome_feature_enabled или просто audio.awesome_feature , переименуйте его как audio.awesome_feature.enabled , чтобы отразить тип и назначение системного свойства.

Нет конкретного правила о том, каким должен быть тип; это рекомендации по использованию:

  • enabled : используйте, если тип является логическим системным свойством, которое используется для включения или выключения функции.
  • config : используйте, если цель состоит в том, чтобы уточнить, что системное свойство не представляет динамическое состояние системы; он представляет предварительно сконфигурированное значение (например, доступное только для чтения).
  • List : используйте, если это системное свойство, значением которого является список.
  • Timeoutmillis : используйте, если это системное свойство для значения времени ожидания в миллисекундах.

Примеры:

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

Контекст свойства

Новая схема контекста свойств SELinux обеспечивает более точную детализацию и более описательные имена. Подобно тому, что используется для имен свойств, AOSP рекомендует следующий формат:

{group}[_{subgroup}]*_prop

Термины определяются следующим образом:

group и subgroup имеют то же значение, что и в предыдущем примере регулярного выражения . Например, vold_config_prop означает свойства, которые являются конфигурациями от поставщика и предназначены для установки с помощью vendor_init , а vold_status_prop или просто vold_prop означает свойства, которые должны отображать текущий статус vold .

При именовании контекста свойства выбирайте имена, отражающие общее использование свойств. В частности, избегайте следующих типов терминов:

  • Термины, которые выглядят слишком общими и двусмысленными, например, sys , system , default .
  • Термины, непосредственно кодирующие доступность: например, exported , apponly , ro , public , private .

Предпочитайте использование имен, например vold_config_prop , вместо exported_vold_prop или vold_vendor_writable_prop и так далее.

Тип

Тип свойства может быть одним из следующих, перечисленных в таблице.

Тип Определение
логический true или 1 для true, false или 0 для false
Целое число 64-битное целое число со знаком
Беззнаковое целое беззнаковое 64-битное целое
Двойной с плавающей запятой двойной точности
Нить любая допустимая строка UTF-8
перечисление значения могут быть любой допустимой строкой UTF-8 без пробелов
Список выше Запятая ( , ) используется в качестве разделителя
Целочисленный список [1, 2, 3] хранится как 1,2,3

Внутри все свойства хранятся в виде строк. Вы можете применить тип, указав его как файл property_contexts . Дополнительные сведения см. в разделе property_contexts на шаге 3 .

Шаг 2. Определение необходимых уровней доступности

Есть четыре вспомогательных макроса, которые определяют свойство.

Тип доступности Значение
system_internal_prop Свойства, которые используются только в /system
system_restricted_prop Свойства, которые читаются снаружи /system , но не записываются
system_vendor_config_prop Свойства, которые читаются извне /system и записываются только с помощью vendor_init
system_public_prop Свойства, которые читаются и записываются вне /system

Ограничьте доступ к системным свойствам как можно более узко. В прошлом широкий доступ приводил к поломке приложений и уязвимостям в системе безопасности. При определении масштаба рассмотрите следующие вопросы:

  • Нужно ли сохранять это системное свойство? (если да, то почему?)
  • Какой процесс должен иметь доступ для чтения к этому свойству?
  • Какой процесс должен иметь доступ на запись к этому свойству?

Используйте предыдущие вопросы и следующее дерево решений в качестве инструментов для определения соответствующей области доступа.

Decision tree for determining the scope of access

Рисунок 1. Дерево решений для определения области доступа к системным свойствам

Шаг 3: Добавляем в system/sepolicy

При доступе к sysprop SELinux контролирует доступность процессов. После того, как вы определите, какой уровень доступа требуется, определите контексты свойств в system/sepolicy вместе с дополнительными правилами allow и neverallow о том, что процессам разрешено (и не разрешено) читать или писать.

Сначала определите контекст свойства в файле system/sepolicy/public/property.te . Если свойство является внутренним для системы, определите его в system/sepolicy/private/property.te . Используйте один из system_[accessibility]_prop([context]) , который обеспечивает доступность, необходимую для вашего системного свойства. Это пример для файла system/sepolicy/public/property.te :

system_public_prop(audio_foo_prop)
system_vendor_config_prop(audio_bar_prop)

Пример для добавления в файл system/sepolicy/private/property.te :

system_internal_prop(audio_baz_prop)

Во-вторых, предоставить доступ для чтения и (или) записи к контексту свойства. Используйте set_prop и get_prop для предоставления доступа либо к system/sepolicy/public/{domain}.te , либо к файлу system/sepolicy/private/{domain}.te . По возможности используйте private ; public подходит только в том случае, если set_prop или get_prop влияет на какие-либо домены за пределами основного домена.

Пример в system/sepolicy/private/audio.te :

set_prop(audio, audio_foo_prop)
set_prop(audio, audio_bar_prop)

Пример в system/sepolicy/public/domain.te :

get_prop(domain, audio_bar_prop)

В-третьих, добавьте несколько правил neverallow, чтобы еще больше уменьшить доступность, на которую распространяется макрос. Например, предположим, что вы использовали system_restricted_prop потому что ваши системные свойства должны быть прочитаны процессами поставщика. Если доступ на чтение не требуется для всех процессов поставщика, а требуется только для определенного набора процессов (например, vendor_init ), запретите процессы поставщика, которым не требуется доступ для чтения.

Используйте следующий синтаксис для ограничения доступа на запись и чтение:

Чтобы ограничить доступ для записи:

neverallow [domain] [context]:property_service set;

Чтобы ограничить доступ для чтения:

neverallow [domain] [context]:file no_rw_file_perms;

Поместите правила neverallow в файл system/sepolicy/private/{domain}.te , если правило neverallow привязано к определенному домену. Для более широких правил neverallow используйте общие домены, такие как эти, где это уместно:

  • system/sepolicy/private/property.te
  • system/sepolicy/private/coredomain.te
  • system/sepolicy/private/domain.te

В system/sepolicy/private/audio.te поместите следующее:

neverallow {
    domain -init -audio
} {audio_foo_prop audio_bar_prop}:property_service set;

В system/sepolicy/private/property.te поместите следующее:

neverallow {
    domain -coredomain -vendor_init
} audio_prop:file no_rw_file_perms;

Обратите внимание, что {domain -coredomain} захватывает все процессы поставщика. Таким образом {domain -coredomain -vendor_init} означает «все процессы поставщика, кроме vendor_init ».

Наконец, свяжите системное свойство с контекстом свойства. Это гарантирует, что предоставленный доступ и правила neverallow, применяемые к контекстам свойств, применяются к фактическим свойствам. Для этого добавьте запись в файл property_contexts , который описывает сопоставление системных свойств и контекстов свойств. В этом файле вы можете указать либо одно свойство, либо префикс для свойств, которые должны быть сопоставлены с контекстом.

Это синтаксис для сопоставления одного свойства:

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

Это синтаксис для сопоставления префикса:

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

Вы можете дополнительно указать тип свойства, который может быть одним из следующих:

  • bool
  • int
  • uint
  • double
  • enum [list of possible values...]
  • string (используйте string для свойств списка.)

Убедитесь, что каждая запись имеет назначенный тип, когда это возможно, так как type применяется при установке property . В следующем примере показано, как написать сопоставление:

# 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

Когда точная запись и префиксная запись конфликтуют, точная запись имеет приоритет. Дополнительные примеры см. в system/sepolicy/private/property_contexts .

Шаг 4: Определение требований к стабильности

Стабильность — еще один аспект системных свойств, отличающийся от доступности. Стабильность зависит от того, можно ли изменить системное свойство (например, переименовать или даже удалить) в будущем. Это особенно важно, поскольку ОС Android становится модульной. С Treble разделы системы, производителя и продукта можно обновлять независимо друг от друга. В Mainline некоторые части ОС представляют собой обновляемые модули (в APEX или APK).

Если системное свойство предназначено для использования в обновляемых частях программного обеспечения, например, в разделах системы и поставщика, оно должно быть стабильным. Однако, если он используется только внутри, например, определенного модуля Mainline, вы можете изменить его имя, тип или контекст свойств и даже удалить его.

Задайте следующие вопросы, чтобы определить стабильность системного свойства:

  • Предназначено ли это системное свойство для настройки партнерами (или настроено по-разному для каждого устройства)? Если да, то он должен быть стабильным.
  • Предназначено ли это системное свойство, определенное AOSP, для записи или чтения из кода (не процесса), который существует в несистемных разделах, таких как vendor.img или product.img ? Если да, то он должен быть стабильным.
  • Доступ к этому системному свойству осуществляется через модули Mainline или через модуль Mainline и необновляемую часть платформы? Если да, то он должен быть стабильным.

Для стабильных системных свойств формально определите каждое из них как API и используйте API для доступа к системному свойству, как описано в шаге 6 .

Шаг 5: Установка свойств во время сборки

Задайте свойства во время сборки с помощью переменных makefile. Технически значения запекаются в {partition}/build.prop . Затем init читает {partition}/build.prop , чтобы установить свойства. Существует два набора таких переменных: PRODUCT_{PARTITION}_PROPERTIES и TARGET_{PARTITION}_PROP .

PRODUCT_{PARTITION}_PROPERTIES содержит список значений свойств. Синтаксис: {prop}={value} или {prop}?={value} .

{prop}={value} — это обычное присваивание, которое гарантирует, что {prop} установлено в {value} ; для одного свойства возможно только одно такое присвоение.

{prop}?={value} — необязательное присваивание; {prop} устанавливается в {value} , только если нет никаких назначений {prop}={value} . Если существует несколько необязательных назначений, первое из них выигрывает.

# 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 содержит список файлов, который напрямую передается в {partition}/build.prop . Каждый файл содержит список пар {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

Дополнительные сведения см. в разделе build/make/core/sysprop.mk .

Шаг 6. Доступ к свойствам во время выполнения

Конечно, свойства можно читать и записывать во время выполнения.

Скрипты инициализации

Файлы сценария инициализации (обычно файлы *.rc) могут читать свойство с помощью ${prop} или ${prop:-default} , могут устанавливать действие, которое запускается всякий раз, когда свойство становится определенным значением, и могут записывать свойства с помощью 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}

Команды оболочки getprop и setprop

Вы можете использовать команды оболочки getprop или setprop соответственно для чтения или записи свойств. Для получения дополнительной информации вызовите getprop --help или setprop --help .

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

Sysprop как API для C++/Java

Используя sysprop в качестве API, вы можете определять системные свойства и использовать автоматически сгенерированные API, которые являются конкретными и типизированными. Установка scope с помощью Public также делает сгенерированные API доступными для модулей через границы и обеспечивает стабильность API. Вот пример файла .sysprop , модуля Android.bp и кода C++ и Java, использующего их.

# 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",
}

// Both java and cc module can link against sysprop_library
java_library {
    static_libs: ["AudioProps"],
    …
}

cc_binary {
    static_libs: ["AudioProps"],
    …
}

// 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);

Дополнительные сведения см. в разделе Реализация системных свойств в виде API .

Функции и методы низкоуровневых свойств C/C++ и Java

Используйте Sysprop как API, даже если вам доступны низкоуровневые функции C/C++ или низкоуровневые методы Java. По возможности отдавайте предпочтение использованию Sysprop.

libc , libbase и libcutils предлагают функции системных свойств C++. libc имеет базовый API, а функции libbase и libcutils являются оболочками. Если возможно, используйте функции libbase libbase; они наиболее удобны, и двоичные файлы хоста могут использовать функции libbase . Дополнительные сведения см. sys/system_properties.h ( libc ), android-base/properties.h ( libbase ) и cutils/properties.h ( libcutils ).

Класс android.os.SystemProperties предлагает методы системных свойств Java.

Приложение: Добавление свойств, зависящих от поставщика

Партнеры (в том числе сотрудники Google, работающие в контексте разработки Pixel) хотят определить аппаратно-зависимые (или специфичные для устройства) системные свойства. Свойства, специфичные для поставщика, — это свойства, принадлежащие партнерам, которые уникальны для их собственного оборудования или устройства, а не для платформы. Поскольку они зависят от оборудования или устройства, они предназначены для использования в разделах /vendor или /odm .

Начиная с Project Treble, свойства платформы и свойства поставщика были полностью разделены, чтобы предотвратить их конфликт. Далее описывается, как определить свойства поставщика, и сообщается, какие свойства поставщика должны использоваться всегда.

Пространство имен в именах свойств и контекстов

Все свойства поставщика должны начинаться с одного из следующих префиксов, чтобы предотвратить конфликт между ними и свойствами других разделов.

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

Обратите внимание, что ro.hardware. допускается в качестве префикса, но только для совместимости. Не используйте его для обычных свойств.

Во всех следующих примерах используется один из перечисленных выше префиксов:

  • vendor.display.primary_red
  • persist.vendor.faceauth.use_disk_cache
  • ro.odm.hardware.platform

Все контексты свойств поставщика должны начинаться с vendor_ . Это тоже для совместимости. Ниже приведены примеры:

  • vendor_radio_prop .
  • vendor_faceauth_prop .
  • vendor_usb_prop .

Поставщик несет ответственность за присвоение имен и поддержку свойств, поэтому следуйте формату, предложенному на шаге 2 , в дополнение к требованиям к пространствам имен поставщика.

Правила SEPolicy и property_contexts для конкретных поставщиков

Подобно свойствам платформы, свойства поставщика могут быть определены одним из следующих макросов.

Тип доступности Значение
vendor_internal_prop Свойства, которые используются только в /vendor
vendor_restricted_prop Свойства, которые читаются снаружи /vendor , но не записываются
vendor_public_prop Свойства, которые читаются и записываются вне /vendor

Поместите определяемые вами правила для конкретных поставщиков в каталог BOARD_VENDOR_SEPOLICY_DIRS . Например, предположим, что вы определяете свойство faceauth поставщика в Coral.

В файле BoardConfig.mk (или в любом другом файле BoardConfig.mk ) поместите следующее:

BOARD_VENDOR_SEPOLICY_DIRS := device/google/coral-sepolicy

В файле device/google/coral-sepolicy/private/property.te поместите следующее:

vendor_internal_prop(vendor_faceauth_prop)

В файле device/google/coral-sepolicy/private/property_contexts поместите следующее:

vendor.faceauth.trace u:object_r:vendor_faceauth_prop:s0 exact bool

Ограничения свойств поставщика

Поскольку разделы системы и продукта не могут зависеть от поставщика, никогда не разрешайте доступ к свойствам поставщика из раздела system , system-ext или product .

Приложение: переименование существующих свойств

Если вам необходимо объявить свойство устаревшим и перейти к новому, используйте Sysprop в качестве API -интерфейсов, чтобы переименовать существующие свойства. Это поддерживает обратную совместимость, указывая как устаревшее имя, так и новое имя свойства. В частности, вы можете установить устаревшее имя в поле legacy_prop_name в файле .sysprop . Сгенерированный API пытается прочитать prop_name и использует legacy_prop_name , если prop_name не существует.

Например, следующие шаги переименовывают awesome_feature_foo_enabled в foo.awesome_feature.enabled .

В файле foo.sysprop (на Java)

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"
}

В коде С++

// 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);

Обратите внимание на следующие предостережения:

  • Во-первых, вы не можете изменить тип sysprop. Например, вы не можете превратить свойство int в свойство string . Можно только изменить имя.

  • Во-вторых, только API чтения возвращается к устаревшему имени. API записи не отступает. Если sysprop доступен для записи, вы не можете его переименовать.