Skip to content

Commit a97faba

Browse files
author
Tom Cherry
committed
init: use protobuf for serialization of persistent properties
I probably should have done this from the start... There's a shim to convert my manually serialized format to protobuf, and since that has not yet shipped, it'll be reverted in a short period of time. Test: init unit tests Test: upgrade from legacy and intermediate property formats successfully Change-Id: Iad25f6c30d0b44d294230a53dd6876222d1c785b
1 parent 2fb5fa3 commit a97faba

File tree

7 files changed

+159
-148
lines changed

7 files changed

+159
-148
lines changed

init/Android.bp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ cc_library_static {
7373
"log.cpp",
7474
"parser.cpp",
7575
"persistent_properties.cpp",
76+
"persistent_properties.proto",
7677
"property_service.cpp",
7778
"security.cpp",
7879
"selinux.cpp",
@@ -90,11 +91,15 @@ cc_library_static {
9091
"liblog",
9192
"libprocessgroup",
9293
"libfs_mgr",
94+
"libprotobuf-cpp-lite",
9395
],
9496
include_dirs: [
9597
"system/core/mkbootimg",
9698
],
97-
99+
proto: {
100+
type: "lite",
101+
export_proto_headers: true,
102+
},
98103
}
99104

100105
/*
@@ -179,6 +184,7 @@ cc_test {
179184
"libinit",
180185
"libselinux",
181186
"libcrypto",
187+
"libprotobuf-cpp-lite",
182188
],
183189
}
184190

init/Android.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ LOCAL_STATIC_LIBRARIES := \
8282
libprocessgroup \
8383
libavb \
8484
libkeyutils \
85+
libprotobuf-cpp-lite \
8586

8687
LOCAL_REQUIRED_MODULES := \
8788
e2fsdroid \

init/persistent_properties.cpp

Lines changed: 67 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,21 @@ namespace {
4646
constexpr const uint32_t kMagic = 0x8495E0B4;
4747
constexpr const char kLegacyPersistentPropertyDir[] = "/data/property";
4848

49-
Result<std::vector<std::pair<std::string, std::string>>> LoadLegacyPersistentProperties() {
49+
void AddPersistentProperty(const std::string& name, const std::string& value,
50+
PersistentProperties* persistent_properties) {
51+
auto persistent_property_record = persistent_properties->add_properties();
52+
persistent_property_record->set_name(name);
53+
persistent_property_record->set_value(value);
54+
}
55+
56+
Result<PersistentProperties> LoadLegacyPersistentProperties() {
5057
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(kLegacyPersistentPropertyDir), closedir);
5158
if (!dir) {
5259
return ErrnoError() << "Unable to open persistent property directory \""
5360
<< kLegacyPersistentPropertyDir << "\"";
5461
}
5562

56-
std::vector<std::pair<std::string, std::string>> persistent_properties;
63+
PersistentProperties persistent_properties;
5764
dirent* entry;
5865
while ((entry = readdir(dir.get())) != nullptr) {
5966
if (!StartsWith(entry->d_name, "persist.")) {
@@ -87,7 +94,7 @@ Result<std::vector<std::pair<std::string, std::string>>> LoadLegacyPersistentPro
8794

8895
std::string value;
8996
if (ReadFdToString(fd, &value)) {
90-
persistent_properties.emplace_back(entry->d_name, value);
97+
AddPersistentProperty(entry->d_name, value, &persistent_properties);
9198
} else {
9299
PLOG(ERROR) << "Unable to read persistent property file " << entry->d_name;
93100
}
@@ -115,30 +122,28 @@ void RemoveLegacyPersistentPropertyFiles() {
115122
}
116123
}
117124

118-
std::vector<std::pair<std::string, std::string>> LoadPersistentPropertiesFromMemory() {
119-
std::vector<std::pair<std::string, std::string>> properties;
125+
PersistentProperties LoadPersistentPropertiesFromMemory() {
126+
PersistentProperties persistent_properties;
120127
__system_property_foreach(
121128
[](const prop_info* pi, void* cookie) {
122129
__system_property_read_callback(
123130
pi,
124131
[](void* cookie, const char* name, const char* value, unsigned serial) {
125132
if (StartsWith(name, "persist.")) {
126-
auto properties =
127-
reinterpret_cast<std::vector<std::pair<std::string, std::string>>*>(
128-
cookie);
129-
properties->emplace_back(name, value);
133+
auto properties = reinterpret_cast<PersistentProperties*>(cookie);
134+
AddPersistentProperty(name, value, properties);
130135
}
131136
},
132137
cookie);
133138
},
134-
&properties);
135-
return properties;
139+
&persistent_properties);
140+
return persistent_properties;
136141
}
137142

138143
class PersistentPropertyFileParser {
139144
public:
140145
PersistentPropertyFileParser(const std::string& contents) : contents_(contents), position_(0) {}
141-
Result<std::vector<std::pair<std::string, std::string>>> Parse();
146+
Result<PersistentProperties> Parse();
142147

143148
private:
144149
Result<std::string> ReadString();
@@ -148,9 +153,7 @@ class PersistentPropertyFileParser {
148153
size_t position_;
149154
};
150155

151-
Result<std::vector<std::pair<std::string, std::string>>> PersistentPropertyFileParser::Parse() {
152-
std::vector<std::pair<std::string, std::string>> result;
153-
156+
Result<PersistentProperties> PersistentPropertyFileParser::Parse() {
154157
if (auto magic = ReadUint32(); magic) {
155158
if (*magic != kMagic) {
156159
return Error() << "Magic value '0x" << std::hex << *magic
@@ -174,24 +177,20 @@ Result<std::vector<std::pair<std::string, std::string>>> PersistentPropertyFileP
174177
return Error() << "Could not read num_properties: " << num_properties.error();
175178
}
176179

180+
PersistentProperties result;
177181
while (position_ < contents_.size()) {
178-
auto key = ReadString();
179-
if (!key) {
180-
return Error() << "Could not read key: " << key.error();
182+
auto name = ReadString();
183+
if (!name) {
184+
return Error() << "Could not read name: " << name.error();
181185
}
182-
if (!StartsWith(*key, "persist.")) {
183-
return Error() << "Property '" << *key << "' does not starts with 'persist.'";
186+
if (!StartsWith(*name, "persist.")) {
187+
return Error() << "Property '" << *name << "' does not starts with 'persist.'";
184188
}
185189
auto value = ReadString();
186190
if (!value) {
187191
return Error() << "Could not read value: " << value.error();
188192
}
189-
result.emplace_back(*key, *value);
190-
}
191-
192-
if (result.size() != *num_properties) {
193-
return Error() << "Mismatch of number of persistent properties read, " << result.size()
194-
<< " and number of persistent properties expected, " << *num_properties;
193+
AddPersistentProperty(*name, *value, &result);
195194
}
196195

197196
return result;
@@ -220,9 +219,7 @@ Result<uint32_t> PersistentPropertyFileParser::ReadUint32() {
220219
return result;
221220
}
222221

223-
} // namespace
224-
225-
Result<std::vector<std::pair<std::string, std::string>>> LoadPersistentPropertyFile() {
222+
Result<std::string> ReadPersistentPropertyFile() {
226223
const std::string temp_filename = persistent_property_filename + ".tmp";
227224
if (access(temp_filename.c_str(), F_OK) == 0) {
228225
LOG(INFO)
@@ -234,51 +231,47 @@ Result<std::vector<std::pair<std::string, std::string>>> LoadPersistentPropertyF
234231
if (!file_contents) {
235232
return Error() << "Unable to read persistent property file: " << file_contents.error();
236233
}
237-
auto parsed_contents = PersistentPropertyFileParser(*file_contents).Parse();
238-
if (!parsed_contents) {
239-
// If the file cannot be parsed, then we don't have any recovery mechanisms, so we delete
240-
// it to allow for future writes to take place successfully.
241-
unlink(persistent_property_filename.c_str());
242-
return Error() << "Unable to parse persistent property file: " << parsed_contents.error();
243-
}
244-
return parsed_contents;
234+
return *file_contents;
245235
}
246236

247-
std::string GenerateFileContents(
248-
const std::vector<std::pair<std::string, std::string>>& persistent_properties) {
249-
std::string result;
250-
251-
uint32_t magic = kMagic;
252-
result.append(reinterpret_cast<char*>(&magic), sizeof(uint32_t));
237+
} // namespace
253238

254-
uint32_t version = 1;
255-
result.append(reinterpret_cast<char*>(&version), sizeof(uint32_t));
239+
Result<PersistentProperties> LoadPersistentPropertyFile() {
240+
auto file_contents = ReadPersistentPropertyFile();
241+
if (!file_contents) return file_contents.error();
256242

257-
uint32_t num_properties = persistent_properties.size();
258-
result.append(reinterpret_cast<char*>(&num_properties), sizeof(uint32_t));
243+
// Check the intermediate "I should have used protobufs from the start" format.
244+
// TODO: Remove this.
245+
auto parsed_contents = PersistentPropertyFileParser(*file_contents).Parse();
246+
if (parsed_contents) {
247+
LOG(INFO) << "Intermediate format persistent property file found, converting to protobuf";
259248

260-
for (const auto& [key, value] : persistent_properties) {
261-
uint32_t key_length = key.length();
262-
result.append(reinterpret_cast<char*>(&key_length), sizeof(uint32_t));
263-
result.append(key);
264-
uint32_t value_length = value.length();
265-
result.append(reinterpret_cast<char*>(&value_length), sizeof(uint32_t));
266-
result.append(value);
249+
// Update to the protobuf format
250+
WritePersistentPropertyFile(*parsed_contents);
251+
return parsed_contents;
267252
}
268-
return result;
269-
}
270253

271-
Result<Success> WritePersistentPropertyFile(
272-
const std::vector<std::pair<std::string, std::string>>& persistent_properties) {
273-
auto file_contents = GenerateFileContents(persistent_properties);
254+
PersistentProperties persistent_properties;
255+
if (persistent_properties.ParseFromString(*file_contents)) return persistent_properties;
256+
257+
// If the file cannot be parsed in either format, then we don't have any recovery
258+
// mechanisms, so we delete it to allow for future writes to take place successfully.
259+
unlink(persistent_property_filename.c_str());
260+
return Error() << "Unable to parse persistent property file: " << parsed_contents.error();
261+
}
274262

263+
Result<Success> WritePersistentPropertyFile(const PersistentProperties& persistent_properties) {
275264
const std::string temp_filename = persistent_property_filename + ".tmp";
276265
unique_fd fd(TEMP_FAILURE_RETRY(
277266
open(temp_filename.c_str(), O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC | O_CLOEXEC, 0600)));
278267
if (fd == -1) {
279268
return ErrnoError() << "Could not open temporary properties file";
280269
}
281-
if (!WriteStringToFd(file_contents, fd)) {
270+
std::string serialized_string;
271+
if (!persistent_properties.SerializeToString(&serialized_string)) {
272+
return Error() << "Unable to serialize properties";
273+
}
274+
if (!WriteStringToFd(serialized_string, fd)) {
282275
return ErrnoError() << "Unable to write file contents";
283276
}
284277
fsync(fd);
@@ -295,26 +288,30 @@ Result<Success> WritePersistentPropertyFile(
295288
// Persistent properties are not written often, so we rather not keep any data in memory and read
296289
// then rewrite the persistent property file for each update.
297290
void WritePersistentProperty(const std::string& name, const std::string& value) {
298-
auto persistent_properties = LoadPersistentPropertyFile();
299-
if (!persistent_properties) {
291+
auto file_contents = ReadPersistentPropertyFile();
292+
PersistentProperties persistent_properties;
293+
294+
if (!file_contents || !persistent_properties.ParseFromString(*file_contents)) {
300295
LOG(ERROR) << "Recovering persistent properties from memory: "
301-
<< persistent_properties.error();
296+
<< (!file_contents ? file_contents.error_string() : "Could not parse protobuf");
302297
persistent_properties = LoadPersistentPropertiesFromMemory();
303298
}
304-
auto it = std::find_if(persistent_properties->begin(), persistent_properties->end(),
305-
[&name](const auto& entry) { return entry.first == name; });
306-
if (it != persistent_properties->end()) {
307-
*it = {name, value};
299+
auto it = std::find_if(persistent_properties.mutable_properties()->begin(),
300+
persistent_properties.mutable_properties()->end(),
301+
[&name](const auto& record) { return record.name() == name; });
302+
if (it != persistent_properties.mutable_properties()->end()) {
303+
it->set_name(name);
304+
it->set_value(value);
308305
} else {
309-
persistent_properties->emplace_back(name, value);
306+
AddPersistentProperty(name, value, &persistent_properties);
310307
}
311308

312-
if (auto result = WritePersistentPropertyFile(*persistent_properties); !result) {
309+
if (auto result = WritePersistentPropertyFile(persistent_properties); !result) {
313310
LOG(ERROR) << "Could not store persistent property: " << result.error();
314311
}
315312
}
316313

317-
std::vector<std::pair<std::string, std::string>> LoadPersistentProperties() {
314+
PersistentProperties LoadPersistentProperties() {
318315
auto persistent_properties = LoadPersistentPropertyFile();
319316

320317
if (!persistent_properties) {

init/persistent_properties.h

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,19 @@
1818
#define _INIT_PERSISTENT_PROPERTIES_H
1919

2020
#include <string>
21-
#include <vector>
2221

2322
#include "result.h"
23+
#include "system/core/init/persistent_properties.pb.h"
2424

2525
namespace android {
2626
namespace init {
2727

28-
std::vector<std::pair<std::string, std::string>> LoadPersistentProperties();
28+
PersistentProperties LoadPersistentProperties();
2929
void WritePersistentProperty(const std::string& name, const std::string& value);
3030

3131
// Exposed only for testing
32-
Result<std::vector<std::pair<std::string, std::string>>> LoadPersistentPropertyFile();
33-
std::string GenerateFileContents(
34-
const std::vector<std::pair<std::string, std::string>>& persistent_properties);
35-
Result<Success> WritePersistentPropertyFile(
36-
const std::vector<std::pair<std::string, std::string>>& persistent_properties);
32+
Result<PersistentProperties> LoadPersistentPropertyFile();
33+
Result<Success> WritePersistentPropertyFile(const PersistentProperties& persistent_properties);
3734
extern std::string persistent_property_filename;
3835

3936
} // namespace init

init/persistent_properties.proto

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright (C) 2017 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
syntax = "proto2";
18+
option optimize_for = LITE_RUNTIME;
19+
20+
message PersistentProperties {
21+
message PersistentPropertyRecord {
22+
optional string name = 1;
23+
optional string value = 2;
24+
}
25+
26+
repeated PersistentPropertyRecord properties = 1;
27+
}

0 commit comments

Comments
 (0)