diff options
author | Tom Cherry <tomcherry@google.com> | 2017-08-04 15:59:03 -0700 |
---|---|---|
committer | Tom Cherry <tomcherry@google.com> | 2017-08-29 17:45:06 -0700 |
commit | 16fad42007a7abbc3a1b5727e49c3aad1d8edb97 (patch) | |
tree | bbd3ca7fdb8e08b255e6b6fa42947baa88b2b06f /init | |
parent | 459aa1cac669b3bac6232e5906ceeacd33671b62 (diff) | |
download | core-16fad42007a7abbc3a1b5727e49c3aad1d8edb97.tar.gz core-16fad42007a7abbc3a1b5727e49c3aad1d8edb97.tar.bz2 core-16fad42007a7abbc3a1b5727e49c3aad1d8edb97.zip |
use a single file for storing persistent properties
We have seen that storing persistent properties in separate files
causes increased boot latency compared to if they were stored in a
single contiguous file.
This change creates a simple format for a contiguously stored property
file, and adds the support for arbitrary characters in the names of
persistent properties, which previously had been restricted. It has a
mechanism for converting older devices to the new format as well.
Bug: 64392887
Test: boot bullhead with new properties
Test: boot bullhead and verify old properties are converted to the new
property file
Test: corrupt property file and ensure that it gets recovered from memory
Test: new unit tests
Change-Id: I60d8201d655ce5c97b33faae81d5ca8dbbb21a14
Diffstat (limited to 'init')
-rw-r--r-- | init/Android.bp | 2 | ||||
-rw-r--r-- | init/persistent_properties.cpp | 341 | ||||
-rw-r--r-- | init/persistent_properties.h | 42 | ||||
-rw-r--r-- | init/persistent_properties_test.cpp | 173 | ||||
-rw-r--r-- | init/property_service.cpp | 91 |
5 files changed, 566 insertions, 83 deletions
diff --git a/init/Android.bp b/init/Android.bp index 33dfe566c..8737defae 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -72,6 +72,7 @@ cc_library_static { "import_parser.cpp", "log.cpp", "parser.cpp", + "persistent_properties.cpp", "property_service.cpp", "security.cpp", "selinux.cpp", @@ -162,6 +163,7 @@ cc_test { srcs: [ "devices_test.cpp", "init_test.cpp", + "persistent_properties_test.cpp", "property_service_test.cpp", "result_test.cpp", "rlimit_parser_test.cpp", diff --git a/init/persistent_properties.cpp b/init/persistent_properties.cpp new file mode 100644 index 000000000..66fa011b0 --- /dev/null +++ b/init/persistent_properties.cpp @@ -0,0 +1,341 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "persistent_properties.h" + +#include <dirent.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/system_properties.h> +#include <sys/types.h> + +#include <memory> + +#include <android-base/file.h> +#include <android-base/logging.h> +#include <android-base/strings.h> +#include <android-base/unique_fd.h> + +#include "util.h" + +using android::base::ReadFdToString; +using android::base::StartsWith; +using android::base::WriteStringToFd; +using android::base::unique_fd; + +namespace android { +namespace init { + +std::string persistent_property_filename = "/data/property/persistent_properties"; + +namespace { + +constexpr const uint32_t kMagic = 0x8495E0B4; +constexpr const char kLegacyPersistentPropertyDir[] = "/data/property"; + +Result<std::vector<std::pair<std::string, std::string>>> LoadLegacyPersistentProperties() { + std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(kLegacyPersistentPropertyDir), closedir); + if (!dir) { + return ErrnoError() << "Unable to open persistent property directory \"" + << kLegacyPersistentPropertyDir << "\""; + } + + std::vector<std::pair<std::string, std::string>> persistent_properties; + dirent* entry; + while ((entry = readdir(dir.get())) != nullptr) { + if (!StartsWith(entry->d_name, "persist.")) { + continue; + } + if (entry->d_type != DT_REG) { + continue; + } + + unique_fd fd(openat(dirfd(dir.get()), entry->d_name, O_RDONLY | O_NOFOLLOW)); + if (fd == -1) { + PLOG(ERROR) << "Unable to open persistent property file \"" << entry->d_name << "\""; + continue; + } + + struct stat sb; + if (fstat(fd, &sb) == -1) { + PLOG(ERROR) << "fstat on property file \"" << entry->d_name << "\" failed"; + continue; + } + + // File must not be accessible to others, be owned by root/root, and + // not be a hard link to any other file. + if (((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0) || sb.st_uid != 0 || sb.st_gid != 0 || + sb.st_nlink != 1) { + PLOG(ERROR) << "skipping insecure property file " << entry->d_name + << " (uid=" << sb.st_uid << " gid=" << sb.st_gid << " nlink=" << sb.st_nlink + << " mode=" << std::oct << sb.st_mode << ")"; + continue; + } + + std::string value; + if (ReadFdToString(fd, &value)) { + persistent_properties.emplace_back(entry->d_name, value); + } else { + PLOG(ERROR) << "Unable to read persistent property file " << entry->d_name; + } + } + return persistent_properties; +} + +void RemoveLegacyPersistentPropertyFiles() { + std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(kLegacyPersistentPropertyDir), closedir); + if (!dir) { + PLOG(ERROR) << "Unable to open persistent property directory \"" + << kLegacyPersistentPropertyDir << "\""; + return; + } + + dirent* entry; + while ((entry = readdir(dir.get())) != nullptr) { + if (!StartsWith(entry->d_name, "persist.")) { + continue; + } + if (entry->d_type != DT_REG) { + continue; + } + unlinkat(dirfd(dir.get()), entry->d_name, 0); + } +} + +std::vector<std::pair<std::string, std::string>> LoadPersistentPropertiesFromMemory() { + std::vector<std::pair<std::string, std::string>> properties; + __system_property_foreach( + [](const prop_info* pi, void* cookie) { + __system_property_read_callback( + pi, + [](void* cookie, const char* name, const char* value, unsigned serial) { + if (StartsWith(name, "persist.")) { + auto properties = + reinterpret_cast<std::vector<std::pair<std::string, std::string>>*>( + cookie); + properties->emplace_back(name, value); + } + }, + cookie); + }, + &properties); + return properties; +} + +class PersistentPropertyFileParser { + public: + PersistentPropertyFileParser(const std::string& contents) : contents_(contents), position_(0) {} + Result<std::vector<std::pair<std::string, std::string>>> Parse(); + + private: + Result<std::string> ReadString(); + Result<uint32_t> ReadUint32(); + + const std::string& contents_; + size_t position_; +}; + +Result<std::vector<std::pair<std::string, std::string>>> PersistentPropertyFileParser::Parse() { + std::vector<std::pair<std::string, std::string>> result; + + if (auto magic = ReadUint32(); magic) { + if (*magic != kMagic) { + return Error() << "Magic value '0x" << std::hex << *magic + << "' does not match expected value '0x" << kMagic << "'"; + } + } else { + return Error() << "Could not read magic value: " << magic.error(); + } + + if (auto version = ReadUint32(); version) { + if (*version != 1) { + return Error() << "Version '" << *version + << "' does not match any compatible version: (1)"; + } + } else { + return Error() << "Could not read version: " << version.error(); + } + + auto num_properties = ReadUint32(); + if (!num_properties) { + return Error() << "Could not read num_properties: " << num_properties.error(); + } + + while (position_ < contents_.size()) { + auto key = ReadString(); + if (!key) { + return Error() << "Could not read key: " << key.error(); + } + if (!StartsWith(*key, "persist.")) { + return Error() << "Property '" << *key << "' does not starts with 'persist.'"; + } + auto value = ReadString(); + if (!value) { + return Error() << "Could not read value: " << value.error(); + } + result.emplace_back(*key, *value); + } + + if (result.size() != *num_properties) { + return Error() << "Mismatch of number of persistent properties read, " << result.size() + << " and number of persistent properties expected, " << *num_properties; + } + + return result; +} + +Result<std::string> PersistentPropertyFileParser::ReadString() { + auto string_length = ReadUint32(); + if (!string_length) { + return Error() << "Could not read size for string"; + } + + if (position_ + *string_length > contents_.size()) { + return Error() << "String size would cause it to overflow the input buffer"; + } + auto result = std::string(contents_, position_, *string_length); + position_ += *string_length; + return result; +} + +Result<uint32_t> PersistentPropertyFileParser::ReadUint32() { + if (position_ + 3 > contents_.size()) { + return Error() << "Input buffer not large enough to read uint32_t"; + } + uint32_t result = *reinterpret_cast<const uint32_t*>(&contents_[position_]); + position_ += sizeof(uint32_t); + return result; +} + +} // namespace + +Result<std::vector<std::pair<std::string, std::string>>> LoadPersistentPropertyFile() { + const std::string temp_filename = persistent_property_filename + ".tmp"; + if (access(temp_filename.c_str(), F_OK) == 0) { + LOG(INFO) + << "Found temporary property file while attempting to persistent system properties" + " a previous persistent property write may have failed"; + unlink(temp_filename.c_str()); + } + auto file_contents = ReadFile(persistent_property_filename); + if (!file_contents) { + return Error() << "Unable to read persistent property file: " << file_contents.error(); + } + auto parsed_contents = PersistentPropertyFileParser(*file_contents).Parse(); + if (!parsed_contents) { + // If the file cannot be parsed, then we don't have any recovery mechanisms, so we delete + // it to allow for future writes to take place successfully. + unlink(persistent_property_filename.c_str()); + return Error() << "Unable to parse persistent property file: " << parsed_contents.error(); + } + return parsed_contents; +} + +std::string GenerateFileContents( + const std::vector<std::pair<std::string, std::string>>& persistent_properties) { + std::string result; + + uint32_t magic = kMagic; + result.append(reinterpret_cast<char*>(&magic), sizeof(uint32_t)); + + uint32_t version = 1; + result.append(reinterpret_cast<char*>(&version), sizeof(uint32_t)); + + uint32_t num_properties = persistent_properties.size(); + result.append(reinterpret_cast<char*>(&num_properties), sizeof(uint32_t)); + + for (const auto& [key, value] : persistent_properties) { + uint32_t key_length = key.length(); + result.append(reinterpret_cast<char*>(&key_length), sizeof(uint32_t)); + result.append(key); + uint32_t value_length = value.length(); + result.append(reinterpret_cast<char*>(&value_length), sizeof(uint32_t)); + result.append(value); + } + return result; +} + +Result<Success> WritePersistentPropertyFile( + const std::vector<std::pair<std::string, std::string>>& persistent_properties) { + auto file_contents = GenerateFileContents(persistent_properties); + + const std::string temp_filename = persistent_property_filename + ".tmp"; + unique_fd fd(TEMP_FAILURE_RETRY( + open(temp_filename.c_str(), O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC | O_CLOEXEC, 0600))); + if (fd == -1) { + return ErrnoError() << "Could not open temporary properties file"; + } + if (!WriteStringToFd(file_contents, fd)) { + return ErrnoError() << "Unable to write file contents"; + } + fsync(fd); + fd.reset(); + + if (rename(temp_filename.c_str(), persistent_property_filename.c_str())) { + int saved_errno = errno; + unlink(temp_filename.c_str()); + return Error(saved_errno) << "Unable to rename persistent property file"; + } + return Success(); +} + +// Persistent properties are not written often, so we rather not keep any data in memory and read +// then rewrite the persistent property file for each update. +void WritePersistentProperty(const std::string& name, const std::string& value) { + auto persistent_properties = LoadPersistentPropertyFile(); + if (!persistent_properties) { + LOG(ERROR) << "Recovering persistent properties from memory: " + << persistent_properties.error(); + persistent_properties = LoadPersistentPropertiesFromMemory(); + } + auto it = std::find_if(persistent_properties->begin(), persistent_properties->end(), + [&name](const auto& entry) { return entry.first == name; }); + if (it != persistent_properties->end()) { + *it = {name, value}; + } else { + persistent_properties->emplace_back(name, value); + } + + if (auto result = WritePersistentPropertyFile(*persistent_properties); !result) { + LOG(ERROR) << "Could not store persistent property: " << result.error(); + } +} + +std::vector<std::pair<std::string, std::string>> LoadPersistentProperties() { + auto persistent_properties = LoadPersistentPropertyFile(); + + if (!persistent_properties) { + LOG(ERROR) << "Could not load single persistent property file, trying legacy directory: " + << persistent_properties.error(); + persistent_properties = LoadLegacyPersistentProperties(); + if (!persistent_properties) { + LOG(ERROR) << "Unable to load legacy persistent properties: " + << persistent_properties.error(); + return {}; + } + if (auto result = WritePersistentPropertyFile(*persistent_properties); result) { + RemoveLegacyPersistentPropertyFiles(); + } else { + LOG(ERROR) << "Unable to write single persistent property file: " << result.error(); + // Fall through so that we still set the properties that we've read. + } + } + + return *persistent_properties; +} + +} // namespace init +} // namespace android diff --git a/init/persistent_properties.h b/init/persistent_properties.h new file mode 100644 index 000000000..d84d9db4f --- /dev/null +++ b/init/persistent_properties.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _INIT_PERSISTENT_PROPERTIES_H +#define _INIT_PERSISTENT_PROPERTIES_H + +#include <string> +#include <vector> + +#include "result.h" + +namespace android { +namespace init { + +std::vector<std::pair<std::string, std::string>> LoadPersistentProperties(); +void WritePersistentProperty(const std::string& name, const std::string& value); + +// Exposed only for testing +Result<std::vector<std::pair<std::string, std::string>>> LoadPersistentPropertyFile(); +std::string GenerateFileContents( + const std::vector<std::pair<std::string, std::string>>& persistent_properties); +Result<Success> WritePersistentPropertyFile( + const std::vector<std::pair<std::string, std::string>>& persistent_properties); +extern std::string persistent_property_filename; + +} // namespace init +} // namespace android + +#endif diff --git a/init/persistent_properties_test.cpp b/init/persistent_properties_test.cpp new file mode 100644 index 000000000..9ab5b229c --- /dev/null +++ b/init/persistent_properties_test.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "persistent_properties.h" + +#include <errno.h> + +#include <android-base/test_utils.h> +#include <gtest/gtest.h> + +#include "util.h" + +using namespace std::string_literals; + +namespace android { +namespace init { + +TEST(persistent_properties, GeneratedContents) { + const std::vector<std::pair<std::string, std::string>> persistent_properties = { + {"persist.abc", ""}, + {"persist.def", "test_success"}, + }; + auto generated_contents = GenerateFileContents(persistent_properties); + + // Manually serialized contents below: + std::string file_contents; + // All values below are written and read as little endian. + // Add magic value: 0x8495E0B4 + file_contents += "\xB4\xE0\x95\x84"s; + // Add version: 1 + file_contents += "\x01\x00\x00\x00"s; + // Add number of properties: 2 + file_contents += "\x02\x00\x00\x00"s; + + // Add first key: persist.abc + file_contents += "\x0B\x00\x00\x00persist.abc"s; + // Add first value: (empty string) + file_contents += "\x00\x00\x00\x00"s; + + // Add second key: persist.def + file_contents += "\x0B\x00\x00\x00persist.def"s; + // Add second value: test_success + file_contents += "\x0C\x00\x00\x00test_success"s; + + EXPECT_EQ(file_contents, generated_contents); +} + +TEST(persistent_properties, EndToEnd) { + TemporaryFile tf; + ASSERT_TRUE(tf.fd != -1); + persistent_property_filename = tf.path; + + std::vector<std::pair<std::string, std::string>> persistent_properties = { + {"persist.sys.locale", "en-US"}, + {"persist.sys.timezone", "America/Los_Angeles"}, + {"persist.test.empty.value", ""}, + {"persist.test.new.line", "abc\n\n\nabc"}, + {"persist.test.numbers", "1234567890"}, + {"persist.test.non.ascii", "\x00\x01\x02\xFF\xFE\xFD\x7F\x8F\x9F"}, + // We don't currently allow for non-ascii keys for system properties, but this is a policy + // decision, not a technical limitation. + {"persist.\x00\x01\x02\xFF\xFE\xFD\x7F\x8F\x9F", "non-ascii-key"}, + }; + + ASSERT_TRUE(WritePersistentPropertyFile(persistent_properties)); + + auto read_back_properties = LoadPersistentProperties(); + EXPECT_EQ(persistent_properties, read_back_properties); +} + +TEST(persistent_properties, BadMagic) { + TemporaryFile tf; + ASSERT_TRUE(tf.fd != -1); + persistent_property_filename = tf.path; + + ASSERT_TRUE(WriteFile(tf.path, "ab")); + + auto read_back_properties = LoadPersistentPropertyFile(); + + ASSERT_FALSE(read_back_properties); + EXPECT_EQ( + "Unable to parse persistent property file: Could not read magic value: Input buffer not " + "large enough to read uint32_t", + read_back_properties.error_string()); + + ASSERT_TRUE(WriteFile(tf.path, "\xFF\xFF\xFF\xFF")); + + read_back_properties = LoadPersistentPropertyFile(); + + ASSERT_FALSE(read_back_properties); + EXPECT_EQ( + "Unable to parse persistent property file: Magic value '0xffffffff' does not match " + "expected value '0x8495e0b4'", + read_back_properties.error_string()); +} + +TEST(persistent_properties, AddProperty) { + TemporaryFile tf; + ASSERT_TRUE(tf.fd != -1); + persistent_property_filename = tf.path; + + std::vector<std::pair<std::string, std::string>> persistent_properties = { + {"persist.sys.timezone", "America/Los_Angeles"}, + }; + ASSERT_TRUE(WritePersistentPropertyFile(persistent_properties)); + + WritePersistentProperty("persist.sys.locale", "pt-BR"); + + std::vector<std::pair<std::string, std::string>> persistent_properties_expected = { + {"persist.sys.timezone", "America/Los_Angeles"}, + {"persist.sys.locale", "pt-BR"}, + }; + + auto read_back_properties = LoadPersistentProperties(); + EXPECT_EQ(persistent_properties_expected, read_back_properties); +} + +TEST(persistent_properties, UpdateProperty) { + TemporaryFile tf; + ASSERT_TRUE(tf.fd != -1); + persistent_property_filename = tf.path; + + std::vector<std::pair<std::string, std::string>> persistent_properties = { + {"persist.sys.locale", "en-US"}, + {"persist.sys.timezone", "America/Los_Angeles"}, + }; + ASSERT_TRUE(WritePersistentPropertyFile(persistent_properties)); + + WritePersistentProperty("persist.sys.locale", "pt-BR"); + + std::vector<std::pair<std::string, std::string>> persistent_properties_expected = { + {"persist.sys.locale", "pt-BR"}, + {"persist.sys.timezone", "America/Los_Angeles"}, + }; + + auto read_back_properties = LoadPersistentProperties(); + EXPECT_EQ(persistent_properties_expected, read_back_properties); +} + +TEST(persistent_properties, UpdatePropertyBadParse) { + TemporaryFile tf; + ASSERT_TRUE(tf.fd != -1); + persistent_property_filename = tf.path; + + ASSERT_TRUE(WriteFile(tf.path, "ab")); + + WritePersistentProperty("persist.sys.locale", "pt-BR"); + + auto read_back_properties = LoadPersistentProperties(); + EXPECT_GT(read_back_properties.size(), 0U); + + auto it = std::find_if( + read_back_properties.begin(), read_back_properties.end(), [](const auto& entry) { + return entry.first == "persist.sys.locale" && entry.second == "pt-BR"; + }); + EXPECT_FALSE(it == read_back_properties.end()); +} + +} // namespace init +} // namespace android diff --git a/init/property_service.cpp b/init/property_service.cpp index f0e4d2e96..8c592cb41 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -17,7 +17,6 @@ #include "property_service.h" #include <ctype.h> -#include <dirent.h> #include <errno.h> #include <fcntl.h> #include <inttypes.h> @@ -54,17 +53,17 @@ #include <selinux/selinux.h> #include "init.h" +#include "persistent_properties.h" #include "util.h" using android::base::Timer; -#define PERSISTENT_PROPERTY_DIR "/data/property" #define RECOVERY_MOUNT_POINT "/recovery" namespace android { namespace init { -static int persistent_properties_loaded = 0; +static bool persistent_properties_loaded = false; static int property_set_fd = -1; @@ -120,29 +119,6 @@ static int check_control_mac_perms(const char *name, char *sctx, struct ucred *c return check_mac_perms(ctl_name, sctx, cr); } -static void write_persistent_property(const char *name, const char *value) -{ - char tempPath[PATH_MAX]; - char path[PATH_MAX]; - int fd; - - snprintf(tempPath, sizeof(tempPath), "%s/.temp.XXXXXX", PERSISTENT_PROPERTY_DIR); - fd = mkstemp(tempPath); - if (fd < 0) { - PLOG(ERROR) << "Unable to write persistent property to temp file " << tempPath; - return; - } - write(fd, value, strlen(value)); - fsync(fd); - close(fd); - - snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, name); - if (rename(tempPath, path)) { - PLOG(ERROR) << "Unable to rename persistent property file " << tempPath << " to " << path; - unlink(tempPath); - } -} - bool is_legal_property_name(const std::string& name) { size_t namelen = name.size(); @@ -204,7 +180,7 @@ static uint32_t PropertySetImpl(const std::string& name, const std::string& valu // Don't write properties to disk until after we have read all default // properties to prevent them from being overwritten by default values. if (persistent_properties_loaded && android::base::StartsWith(name, "persist.")) { - write_persistent_property(name.c_str(), value.c_str()); + WritePersistentProperty(name, value); } property_changed(name, value); return PROP_SUCCESS; @@ -599,61 +575,6 @@ static void load_properties_from_file(const char* filename, const char* filter) LOG(VERBOSE) << "(Loading properties from " << filename << " took " << t << ".)"; } -static void load_persistent_properties() { - persistent_properties_loaded = 1; - - std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(PERSISTENT_PROPERTY_DIR), closedir); - if (!dir) { - PLOG(ERROR) << "Unable to open persistent property directory \"" - << PERSISTENT_PROPERTY_DIR << "\""; - return; - } - - struct dirent* entry; - while ((entry = readdir(dir.get())) != NULL) { - if (strncmp("persist.", entry->d_name, strlen("persist."))) { - continue; - } - if (entry->d_type != DT_REG) { - continue; - } - - // Open the file and read the property value. - int fd = openat(dirfd(dir.get()), entry->d_name, O_RDONLY | O_NOFOLLOW); - if (fd == -1) { - PLOG(ERROR) << "Unable to open persistent property file \"" << entry->d_name << "\""; - continue; - } - - struct stat sb; - if (fstat(fd, &sb) == -1) { - PLOG(ERROR) << "fstat on property file \"" << entry->d_name << "\" failed"; - close(fd); - continue; - } - - // File must not be accessible to others, be owned by root/root, and - // not be a hard link to any other file. - if (((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0) || sb.st_uid != 0 || sb.st_gid != 0 || sb.st_nlink != 1) { - PLOG(ERROR) << "skipping insecure property file " << entry->d_name - << " (uid=" << sb.st_uid << " gid=" << sb.st_gid - << " nlink=" << sb.st_nlink << " mode=" << std::oct << sb.st_mode << ")"; - close(fd); - continue; - } - - char value[PROP_VALUE_MAX]; - int length = read(fd, value, sizeof(value) - 1); - if (length >= 0) { - value[length] = 0; - property_set(entry->d_name, value); - } else { - PLOG(ERROR) << "Unable to read persistent property file " << entry->d_name; - } - close(fd); - } -} - // persist.sys.usb.config values can't be combined on build-time when property // files are split into each partition. // So we need to apply the same rule of build/make/tools/post_process_props.py @@ -703,7 +624,11 @@ void load_persist_props(void) { load_override_properties(); /* Read persistent properties after all default values have been loaded. */ - load_persistent_properties(); + auto persistent_properties = LoadPersistentProperties(); + for (const auto& [name, value] : persistent_properties) { + property_set(name, value); + } + persistent_properties_loaded = true; property_set("ro.persistent_properties.ready", "true"); } |