init: Replace property_set() with android::base::SetProperty()
Init is no longer a special case and talks to property service just
like every other client, therefore move it away from property_set()
and to android::base::SetProperty().
In doing so, this change moves the initial property set up from the
kernel command line and property files directly into PropertyInit().
This makes the responsibilities between init and property services
more clear.
Test: boot, unit test cases
Change-Id: I36b8c83e845d887f1b203355c2391ec123c3d05f
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 7d707cc..adf8929 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -97,8 +97,6 @@
static PropertyInfoAreaFile property_info_area;
-void CreateSerializedPropertyInfo();
-
struct PropertyAuditData {
const ucred* cr;
const char* name;
@@ -117,21 +115,6 @@
return 0;
}
-void property_init() {
- selinux_callback cb;
- cb.func_audit = PropertyAuditCallback;
- selinux_set_callback(SELINUX_CB_AUDIT, cb);
-
- mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH);
- CreateSerializedPropertyInfo();
- if (__system_property_area_init()) {
- LOG(FATAL) << "Failed to initialize property area";
- }
- if (!property_info_area.LoadDefaultPath()) {
- LOG(FATAL) << "Failed to load serialized property info file";
- }
-}
-
bool CanReadProperty(const std::string& source_context, const std::string& name) {
const char* target_context = nullptr;
property_info_area->GetPropertyInfo(name.c_str(), &target_context, nullptr);
@@ -527,20 +510,6 @@
return PropertySet(name, value, error);
}
-uint32_t InitPropertySet(const std::string& name, const std::string& value) {
- uint32_t result = 0;
- ucred cr = {.pid = 1, .uid = 0, .gid = 0};
- std::string error;
- result = HandlePropertySet(name, value, kInitContext, cr, nullptr, &error);
- if (result != PROP_SUCCESS) {
- LOG(ERROR) << "Init cannot set '" << name << "' to '" << value << "': " << error;
- }
-
- return result;
-}
-
-uint32_t (*property_set)(const std::string& name, const std::string& value) = InitPropertySet;
-
static void handle_property_set_fd() {
static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */
@@ -634,6 +603,18 @@
}
}
+uint32_t InitPropertySet(const std::string& name, const std::string& value) {
+ uint32_t result = 0;
+ ucred cr = {.pid = 1, .uid = 0, .gid = 0};
+ std::string error;
+ result = HandlePropertySet(name, value, kInitContext, cr, nullptr, &error);
+ if (result != PROP_SUCCESS) {
+ LOG(ERROR) << "Init cannot set '" << name << "' to '" << value << "': " << error;
+ }
+
+ return result;
+}
+
static bool load_properties_from_file(const char*, const char*,
std::map<std::string, std::string>*);
@@ -765,11 +746,11 @@
bool is_debuggable = android::base::GetBoolProperty("ro.debuggable", false);
std::string config = android::base::GetProperty("persist.sys.usb.config", "");
if (config.empty()) {
- property_set("persist.sys.usb.config", is_debuggable ? "adb" : "none");
+ InitPropertySet("persist.sys.usb.config", is_debuggable ? "adb" : "none");
} else if (is_debuggable && config.find("adb") == std::string::npos &&
config.length() + 4 < PROP_VALUE_MAX) {
config.append(",adb");
- property_set("persist.sys.usb.config", config);
+ InitPropertySet("persist.sys.usb.config", config);
}
}
@@ -890,7 +871,7 @@
}
}
-void property_load_boot_defaults(bool load_debug_prop) {
+void PropertyLoadBootDefaults() {
// TODO(b/117892318): merge prop.default and build.prop files into one
// We read the properties and their values into a map, in order to always allow properties
// loaded in the later property files to override the properties in loaded in the earlier
@@ -916,7 +897,7 @@
load_properties_from_file("/product/build.prop", nullptr, &properties);
load_properties_from_file("/factory/factory.prop", "ro.*", &properties);
- if (load_debug_prop) {
+ if (access(kDebugRamdiskProp, R_OK) == 0) {
LOG(INFO) << "Loading " << kDebugRamdiskProp;
load_properties_from_file(kDebugRamdiskProp, nullptr, &properties);
}
@@ -1009,6 +990,97 @@
selinux_android_restorecon(kPropertyInfosPath, 0);
}
+static void ExportKernelBootProps() {
+ constexpr const char* UNSET = "";
+ struct {
+ const char* src_prop;
+ const char* dst_prop;
+ const char* default_value;
+ } prop_map[] = {
+ // clang-format off
+ { "ro.boot.serialno", "ro.serialno", UNSET, },
+ { "ro.boot.mode", "ro.bootmode", "unknown", },
+ { "ro.boot.baseband", "ro.baseband", "unknown", },
+ { "ro.boot.bootloader", "ro.bootloader", "unknown", },
+ { "ro.boot.hardware", "ro.hardware", "unknown", },
+ { "ro.boot.revision", "ro.revision", "0", },
+ // clang-format on
+ };
+ for (const auto& prop : prop_map) {
+ std::string value = GetProperty(prop.src_prop, prop.default_value);
+ if (value != UNSET) InitPropertySet(prop.dst_prop, value);
+ }
+}
+
+static void ProcessKernelDt() {
+ if (!is_android_dt_value_expected("compatible", "android,firmware")) {
+ return;
+ }
+
+ std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(get_android_dt_dir().c_str()), closedir);
+ if (!dir) return;
+
+ std::string dt_file;
+ struct dirent* dp;
+ while ((dp = readdir(dir.get())) != NULL) {
+ if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible") ||
+ !strcmp(dp->d_name, "name")) {
+ continue;
+ }
+
+ std::string file_name = get_android_dt_dir() + dp->d_name;
+
+ android::base::ReadFileToString(file_name, &dt_file);
+ std::replace(dt_file.begin(), dt_file.end(), ',', '.');
+
+ InitPropertySet("ro.boot."s + dp->d_name, dt_file);
+ }
+}
+
+static void ProcessKernelCmdline() {
+ bool for_emulator = false;
+ ImportKernelCmdline([&](const std::string& key, const std::string& value) {
+ if (key == "qemu") {
+ for_emulator = true;
+ } else if (StartsWith(key, "androidboot.")) {
+ InitPropertySet("ro.boot." + key.substr(12), value);
+ }
+ });
+
+ if (for_emulator) {
+ ImportKernelCmdline([&](const std::string& key, const std::string& value) {
+ // In the emulator, export any kernel option with the "ro.kernel." prefix.
+ InitPropertySet("ro.kernel." + key, value);
+ });
+ }
+}
+
+void PropertyInit() {
+ selinux_callback cb;
+ cb.func_audit = PropertyAuditCallback;
+ selinux_set_callback(SELINUX_CB_AUDIT, cb);
+
+ mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH);
+ CreateSerializedPropertyInfo();
+ if (__system_property_area_init()) {
+ LOG(FATAL) << "Failed to initialize property area";
+ }
+ if (!property_info_area.LoadDefaultPath()) {
+ LOG(FATAL) << "Failed to load serialized property info file";
+ }
+
+ // If arguments are passed both on the command line and in DT,
+ // properties set in DT always have priority over the command-line ones.
+ ProcessKernelDt();
+ ProcessKernelCmdline();
+
+ // Propagate the kernel variables to internal variables
+ // used by init as well as the current required properties.
+ ExportKernelBootProps();
+
+ PropertyLoadBootDefaults();
+}
+
static void HandleInitSocket() {
auto message = ReadMessage(init_socket);
if (!message) {
@@ -1075,7 +1147,7 @@
}
void StartPropertyService(int* epoll_socket) {
- property_set("ro.property_service.version", "2");
+ InitPropertySet("ro.property_service.version", "2");
int sockets[2];
if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != 0) {
@@ -1095,11 +1167,6 @@
listen(property_set_fd, 8);
std::thread{PropertyServiceThread}.detach();
-
- property_set = [](const std::string& key, const std::string& value) -> uint32_t {
- android::base::SetProperty(key, value);
- return 0;
- };
}
} // namespace init