In android: read/write system properties, we discuss how to read/write system properties. This post further discussing how to system properties are loaded by init process at boot time.
testing environment
[ro.build.version.release]: [5.1]
where are system propertied stored
System properties are stored in tmpfs /dev/__properties__ whose backend is memory.
default system properties after boot
System properties are stored in memory which is released before shutdown. Thus, there are no properties initially in memory after boot. Then, init process loads properties from below files into /dev/__properties__.
#define PROP_PATH_RAMDISK_DEFAULT "/default.prop"
#define PROP_PATH_SYSTEM_BUILD "/system/build.prop"
#define PROP_PATH_SYSTEM_DEFAULT "/system/default.prop"
#define PROP_PATH_VENDOR_BUILD "/vendor/build.prop"
#define PROP_PATH_LOCAL_OVERRIDE "/data/local.prop"
#define PROP_PATH_FACTORY "/factory/factory.prop"
#define PERSISTENT_PROPERTY_DIR "/data/property"
how init process loads properties from ramdisk
- Init process will will load /default.prop at first anyway.
- These properties are loaded in all boot modes, including recovery mode.
- /default.prop are determined at compile time.
INFO("property init\n");
property_load_boot_defaults();
INFO("reading config file\n");
init_parse_config_file("/init.rc");
action_for_each_trigger("early-init", action_add_queue_tail);
queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
queue_builtin_action(keychord_init_action, "keychord_init");
queue_builtin_action(console_init_action, "console_init");
/* execute all the boot actions to get us started */
action_for_each_trigger("init", action_add_queue_tail);
void property_load_boot_defaults(void)
{
load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT, NULL);
}
how init process loads properties from system partition
In below context, to trigger an action means to add an action to the action queue of init process.
- init process reads config file such as init.rc or init.project.rc.
- init process triggers actions, such as early-init, and late-init
- In late-init action, init process triggers file system related actions, then load_all_props_action action, and then android boot related actions.
- load_all_props_action action is executed after file system related actions. Thus, system partition has already been mounted.
- In load_all_props_action action, init process loads properties from /system/build.prop, /system/default.prop, /vendor/build.prop.
- *.prop files in system partition are determined at compile time.
INFO("property init\n");
property_load_boot_defaults();
INFO("reading config file\n");
init_parse_config_file("/init.rc");
action_for_each_trigger("early-init", action_add_queue_tail);
queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
queue_builtin_action(keychord_init_action, "keychord_init");
queue_builtin_action(console_init_action, "console_init");
/* execute all the boot actions to get us started */
action_for_each_trigger("init", action_add_queue_tail);
# Mount filesystems and start core system services.
on late-init
trigger early-fs
trigger fs
trigger post-fs
trigger post-fs-data
# Load properties from /system/ + /factory after fs mount. Place
# this in another action so that the load will be scheduled after the prior
# issued fs triggers have completed.
trigger load_all_props_action
# Remove a file to wake up anything waiting for firmware.
trigger firmware_mounts_complete
trigger early-boot
trigger boot
void load_persist_props(void)
{
load_override_properties();
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties();
}
void load_all_props(void)
{
load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);
load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT, NULL);
load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL);
load_properties_from_file(PROP_PATH_FACTORY, "ro.*");
load_override_properties();
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties();
}
how init process loads properties from data partition
- load_all_props_action action is executed after file system related actions. Thus, data partition has already been mounted.
- In load_all_props_action action, init process loads properties from /data/local.prop and persist properties in /data/property/
- /data/local.prop is load when ro.debuggable property are true. Thus, it is only loaded for debug build.
- /data/local.prop and persist properties in /data/property/ could be updated at runtime
void load_persist_props(void)
{
load_override_properties();
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties();
}
void load_all_props(void)
{
load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);
load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT, NULL);
load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL);
load_properties_from_file(PROP_PATH_FACTORY, "ro.*");
load_override_properties();
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties();
}
static void load_override_properties() {
#ifdef ALLOW_LOCAL_PROP_OVERRIDE
char debuggable[PROP_VALUE_MAX];
int ret;
ret = property_get("ro.debuggable", debuggable);
if (ret && (strcmp(debuggable, "1") == 0)) {
load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE, NULL);
}
#endif /* ALLOW_LOCAL_PROP_OVERRIDE */
}
conclusion
This post discuss how init process loads properties from different places at boot time.