blob: 8a727ae0e839cb18712701f976625d1a8277f04d [file] [log] [blame]
Alex Deymoaea4c1c2015-08-19 20:24:43 -07001//
2// Copyright (C) 2012 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//
Darin Petkov30030592010-07-27 13:53:20 -070016
Alex Deymo39910dc2015-11-09 17:04:30 -080017#include "update_engine/common/prefs.h"
Darin Petkov30030592010-07-27 13:53:20 -070018
Alex Deymod6f60072015-10-12 12:22:27 -070019#include <algorithm>
Daniel Zheng5eece042023-05-17 14:44:10 -070020#include <filesystem>
21#include <unistd.h>
Alex Deymod6f60072015-10-12 12:22:27 -070022
Kelvin Zhangc80d39b2023-10-25 09:30:16 -070023#include <android-base/file.h>
Kokoa Matsuda3357e272024-10-18 13:59:05 +090024#include <android-base/parseint.h>
Andrew065d78d2020-04-07 15:43:07 -070025#include <base/files/file_enumerator.h>
Ben Chan06c76a42014-09-05 08:21:06 -070026#include <base/files/file_util.h>
Darin Petkov36275772010-10-01 11:40:57 -070027#include <base/logging.h>
Alex Vakulenko75039d72014-03-25 12:36:28 -070028#include <base/strings/string_number_conversions.h>
Andrew065d78d2020-04-07 15:43:07 -070029#include <base/strings/string_split.h>
Alex Vakulenko75039d72014-03-25 12:36:28 -070030#include <base/strings/string_util.h>
Darin Petkov36275772010-10-01 11:40:57 -070031
Alex Deymo39910dc2015-11-09 17:04:30 -080032#include "update_engine/common/utils.h"
Darin Petkov30030592010-07-27 13:53:20 -070033
34using std::string;
Jae Hoon Kimc1f36922020-05-11 18:20:18 -070035using std::vector;
Darin Petkov30030592010-07-27 13:53:20 -070036
37namespace chromeos_update_engine {
38
Jae Hoon Kimc1f36922020-05-11 18:20:18 -070039namespace {
40
41void DeleteEmptyDirectories(const base::FilePath& path) {
42 base::FileEnumerator path_enum(
43 path, false /* recursive */, base::FileEnumerator::DIRECTORIES);
44 for (base::FilePath dir_path = path_enum.Next(); !dir_path.empty();
45 dir_path = path_enum.Next()) {
46 DeleteEmptyDirectories(dir_path);
47 if (base::IsDirectoryEmpty(dir_path))
hscham043355b2020-11-17 16:50:10 +090048#if BASE_VER < 800000
Jae Hoon Kimc1f36922020-05-11 18:20:18 -070049 base::DeleteFile(dir_path, false);
hscham043355b2020-11-17 16:50:10 +090050#else
51 base::DeleteFile(dir_path);
52#endif
Jae Hoon Kimc1f36922020-05-11 18:20:18 -070053 }
54}
55
56} // namespace
57
Kelvin Zhang1c86a922021-05-13 10:30:48 -040058bool PrefsBase::GetString(const std::string_view key, string* value) const {
Alex Deymoa0284ac2016-07-22 12:51:41 -070059 return storage_->GetKey(key, value);
Darin Petkov30030592010-07-27 13:53:20 -070060}
61
Kelvin Zhang1c86a922021-05-13 10:30:48 -040062bool PrefsBase::SetString(std::string_view key, std::string_view value) {
Alex Deymoa0284ac2016-07-22 12:51:41 -070063 TEST_AND_RETURN_FALSE(storage_->SetKey(key, value));
Alex Deymod6f60072015-10-12 12:22:27 -070064 const auto observers_for_key = observers_.find(key);
65 if (observers_for_key != observers_.end()) {
66 std::vector<ObserverInterface*> copy_observers(observers_for_key->second);
67 for (ObserverInterface* observer : copy_observers)
68 observer->OnPrefSet(key);
69 }
Darin Petkov30030592010-07-27 13:53:20 -070070 return true;
71}
72
Kelvin Zhang1c86a922021-05-13 10:30:48 -040073bool PrefsBase::GetInt64(const std::string_view key, int64_t* value) const {
Darin Petkov30030592010-07-27 13:53:20 -070074 string str_value;
Jay Srinivasan08fce042012-06-07 16:31:01 -070075 if (!GetString(key, &str_value))
76 return false;
Ben Chan736fcb52014-05-21 18:28:22 -070077 base::TrimWhitespaceASCII(str_value, base::TRIM_ALL, &str_value);
Kelvin Zhangc80d39b2023-10-25 09:30:16 -070078 if (str_value.empty()) {
79 LOG(ERROR) << "When reading pref " << key
80 << ", got an empty value after trim";
81 return false;
82 }
Kokoa Matsuda3357e272024-10-18 13:59:05 +090083 if (!android::base::ParseInt<int64_t>(str_value, value)) {
Kelvin Zhangc80d39b2023-10-25 09:30:16 -070084 LOG(ERROR) << "When reading pref " << key << ", failed to convert value "
85 << str_value << " to integer";
86 return false;
87 }
Darin Petkov30030592010-07-27 13:53:20 -070088 return true;
89}
90
Kelvin Zhang1c86a922021-05-13 10:30:48 -040091bool PrefsBase::SetInt64(std::string_view key, const int64_t value) {
hscham00b6aa22020-02-20 12:32:06 +090092 return SetString(key, base::NumberToString(value));
Darin Petkov30030592010-07-27 13:53:20 -070093}
94
Kelvin Zhang1c86a922021-05-13 10:30:48 -040095bool PrefsBase::GetBoolean(std::string_view key, bool* value) const {
Alex Deymoefb7c4c2013-07-09 14:34:00 -070096 string str_value;
97 if (!GetString(key, &str_value))
98 return false;
Ben Chan736fcb52014-05-21 18:28:22 -070099 base::TrimWhitespaceASCII(str_value, base::TRIM_ALL, &str_value);
Alex Deymoefb7c4c2013-07-09 14:34:00 -0700100 if (str_value == "false") {
101 *value = false;
102 return true;
103 }
104 if (str_value == "true") {
105 *value = true;
106 return true;
107 }
108 return false;
109}
110
Kelvin Zhang1c86a922021-05-13 10:30:48 -0400111bool PrefsBase::SetBoolean(std::string_view key, const bool value) {
Alex Deymoefb7c4c2013-07-09 14:34:00 -0700112 return SetString(key, value ? "true" : "false");
113}
114
Kelvin Zhang1c86a922021-05-13 10:30:48 -0400115bool PrefsBase::Exists(std::string_view key) const {
Alex Deymoa0284ac2016-07-22 12:51:41 -0700116 return storage_->KeyExists(key);
Jay Srinivasan480ddfa2012-06-01 19:15:26 -0700117}
118
Kelvin Zhang1c86a922021-05-13 10:30:48 -0400119bool PrefsBase::Delete(std::string_view key) {
Alex Deymoa0284ac2016-07-22 12:51:41 -0700120 TEST_AND_RETURN_FALSE(storage_->DeleteKey(key));
Alex Deymod6f60072015-10-12 12:22:27 -0700121 const auto observers_for_key = observers_.find(key);
122 if (observers_for_key != observers_.end()) {
123 std::vector<ObserverInterface*> copy_observers(observers_for_key->second);
124 for (ObserverInterface* observer : copy_observers)
125 observer->OnPrefDeleted(key);
126 }
127 return true;
128}
129
Kelvin Zhang1c86a922021-05-13 10:30:48 -0400130bool PrefsBase::Delete(std::string_view pref_key, const vector<string>& nss) {
Vyshu Khota4c5413d2020-11-04 16:17:25 -0800131 // Delete pref key for platform.
132 bool success = Delete(pref_key);
133 // Delete pref key in each namespace.
134 for (const auto& ns : nss) {
135 vector<string> namespace_keys;
136 success = GetSubKeys(ns, &namespace_keys) && success;
137 for (const auto& key : namespace_keys) {
138 auto last_key_seperator = key.find_last_of(kKeySeparator);
139 if (last_key_seperator != string::npos &&
140 pref_key == key.substr(last_key_seperator + 1)) {
141 success = Delete(key) && success;
142 }
143 }
144 }
145 return success;
146}
147
Kelvin Zhang1c86a922021-05-13 10:30:48 -0400148bool PrefsBase::GetSubKeys(std::string_view ns, vector<string>* keys) const {
Jae Hoon Kim29a80e02020-05-11 20:18:49 -0700149 return storage_->GetSubKeys(ns, keys);
150}
151
Kelvin Zhang1c86a922021-05-13 10:30:48 -0400152void PrefsBase::AddObserver(std::string_view key, ObserverInterface* observer) {
153 observers_[std::string{key}].push_back(observer);
Alex Deymod6f60072015-10-12 12:22:27 -0700154}
155
Kelvin Zhang1c86a922021-05-13 10:30:48 -0400156void PrefsBase::RemoveObserver(std::string_view key,
157 ObserverInterface* observer) {
158 std::vector<ObserverInterface*>& observers_for_key =
159 observers_[std::string{key}];
Alex Deymod6f60072015-10-12 12:22:27 -0700160 auto observer_it =
161 std::find(observers_for_key.begin(), observers_for_key.end(), observer);
162 if (observer_it != observers_for_key.end())
163 observers_for_key.erase(observer_it);
Jay Srinivasan480ddfa2012-06-01 19:15:26 -0700164}
165
Jae Hoon Kimc1f36922020-05-11 18:20:18 -0700166string PrefsInterface::CreateSubKey(const vector<string>& ns_and_key) {
167 return base::JoinString(ns_and_key, string(1, kKeySeparator));
Andrew065d78d2020-04-07 15:43:07 -0700168}
169
Alex Deymoa0284ac2016-07-22 12:51:41 -0700170// Prefs
171
172bool Prefs::Init(const base::FilePath& prefs_dir) {
173 return file_storage_.Init(prefs_dir);
174}
175
Daniel Zheng5eece042023-05-17 14:44:10 -0700176bool PrefsBase::StartTransaction() {
177 return storage_->CreateTemporaryPrefs();
178}
179
180bool PrefsBase::CancelTransaction() {
181 return storage_->DeleteTemporaryPrefs();
182}
183
184bool PrefsBase::SubmitTransaction() {
185 return storage_->SwapPrefs();
186}
187
188std::string Prefs::FileStorage::GetTemporaryDir() const {
189 return prefs_dir_.value() + "_tmp";
190}
191
192bool Prefs::FileStorage::CreateTemporaryPrefs() {
193 // Delete any existing prefs_tmp
194 DeleteTemporaryPrefs();
195 // Get the paths to the source and destination directories.
196 std::filesystem::path source_directory(prefs_dir_.value());
197 std::filesystem::path destination_directory(GetTemporaryDir());
198
199 if (!std::filesystem::exists(source_directory)) {
200 LOG(ERROR) << "prefs directory does not exist: " << source_directory;
201 return false;
202 }
203 // Copy the directory.
Daniel Zhenga77e6452024-08-13 13:52:55 -0700204 std::error_code e;
205 std::filesystem::copy(source_directory, destination_directory, e);
206 if (e) {
207 LOG(ERROR) << "failed to copy prefs to prefs_tmp: " << e.message();
208 return false;
209 }
Daniel Zheng5eece042023-05-17 14:44:10 -0700210
211 return true;
212}
213
214bool Prefs::FileStorage::DeleteTemporaryPrefs() {
215 std::filesystem::path destination_directory(GetTemporaryDir());
216
217 if (std::filesystem::exists(destination_directory)) {
Daniel Zhenga77e6452024-08-13 13:52:55 -0700218 std::error_code e;
219 std::filesystem::remove_all(destination_directory, e);
220 if (e) {
221 LOG(ERROR) << "failed to remove directory: " << e.message();
222 return false;
223 }
Daniel Zheng5eece042023-05-17 14:44:10 -0700224 }
225 return true;
226}
227
228bool Prefs::FileStorage::SwapPrefs() {
Kelvin Zhangc80d39b2023-10-25 09:30:16 -0700229 if (!utils::DeleteDirectory(prefs_dir_.value().c_str())) {
230 LOG(ERROR) << "Failed to remove prefs dir " << prefs_dir_;
231 return false;
Daniel Zheng5eece042023-05-17 14:44:10 -0700232 }
233 if (rename(GetTemporaryDir().c_str(), prefs_dir_.value().c_str()) != 0) {
234 LOG(ERROR) << "Error replacing prefs with prefs_tmp" << strerror(errno);
235 return false;
236 }
Kelvin Zhangc80d39b2023-10-25 09:30:16 -0700237 if (!utils::FsyncDirectory(
238 android::base::Dirname(prefs_dir_.value()).c_str())) {
239 PLOG(ERROR) << "Failed to fsync prefs parent dir after swapping prefs";
240 }
Daniel Zheng5eece042023-05-17 14:44:10 -0700241 return true;
242}
243
Alex Deymoa0284ac2016-07-22 12:51:41 -0700244bool Prefs::FileStorage::Init(const base::FilePath& prefs_dir) {
245 prefs_dir_ = prefs_dir;
Kelvin Zhangc80d39b2023-10-25 09:30:16 -0700246 if (!std::filesystem::exists(prefs_dir_.value())) {
247 LOG(INFO) << "Prefs dir does not exist, possibly due to an interrupted "
248 "transaction.";
249 if (std::filesystem::exists(GetTemporaryDir())) {
250 SwapPrefs();
251 }
252 }
Daniel Zheng5eece042023-05-17 14:44:10 -0700253
Daniel Zheng37f212d2024-08-13 12:38:13 -0700254 if (std::filesystem::exists(GetTemporaryDir())) {
255 LOG(INFO)
256 << "Deleting temporary prefs, checkpoint transaction was interrupted";
257 if (!utils::DeleteDirectory(GetTemporaryDir().c_str())) {
258 LOG(ERROR) << "Failed to delete temporary prefs";
259 return false;
260 }
261 }
262
Andrew065d78d2020-04-07 15:43:07 -0700263 // Delete empty directories. Ignore errors when deleting empty directories.
Jae Hoon Kimc1f36922020-05-11 18:20:18 -0700264 DeleteEmptyDirectories(prefs_dir_);
Alex Deymoa0284ac2016-07-22 12:51:41 -0700265 return true;
266}
267
Kelvin Zhang1c86a922021-05-13 10:30:48 -0400268bool Prefs::FileStorage::GetKey(std::string_view key, string* value) const {
Alex Deymoa0284ac2016-07-22 12:51:41 -0700269 base::FilePath filename;
270 TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
271 if (!base::ReadFileToString(filename, value)) {
Alex Deymoa0284ac2016-07-22 12:51:41 -0700272 return false;
273 }
274 return true;
275}
276
Kelvin Zhang1c86a922021-05-13 10:30:48 -0400277bool Prefs::FileStorage::GetSubKeys(std::string_view ns,
Jae Hoon Kim29a80e02020-05-11 20:18:49 -0700278 vector<string>* keys) const {
279 base::FilePath filename;
280 TEST_AND_RETURN_FALSE(GetFileNameForKey(ns, &filename));
281 base::FileEnumerator namespace_enum(
282 prefs_dir_, true, base::FileEnumerator::FILES);
283 for (base::FilePath f = namespace_enum.Next(); !f.empty();
284 f = namespace_enum.Next()) {
285 auto filename_str = filename.value();
286 if (f.value().compare(0, filename_str.length(), filename_str) == 0) {
287 // Only return the key portion excluding the |prefs_dir_| with slash.
288 keys->push_back(f.value().substr(
289 prefs_dir_.AsEndingWithSeparator().value().length()));
290 }
291 }
292 return true;
293}
294
Kelvin Zhang1c86a922021-05-13 10:30:48 -0400295bool Prefs::FileStorage::SetKey(std::string_view key, std::string_view value) {
Alex Deymoa0284ac2016-07-22 12:51:41 -0700296 base::FilePath filename;
297 TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
298 if (!base::DirectoryExists(filename.DirName())) {
299 // Only attempt to create the directory if it doesn't exist to avoid calls
300 // to parent directories where we might not have permission to write to.
301 TEST_AND_RETURN_FALSE(base::CreateDirectory(filename.DirName()));
302 }
Kelvin Zhang49170aa2022-11-28 10:55:16 -0800303 TEST_AND_RETURN_FALSE(
304 utils::WriteStringToFileAtomic(filename.value(), value));
Alex Deymoa0284ac2016-07-22 12:51:41 -0700305 return true;
306}
307
Kelvin Zhang1c86a922021-05-13 10:30:48 -0400308bool Prefs::FileStorage::KeyExists(std::string_view key) const {
Alex Deymoa0284ac2016-07-22 12:51:41 -0700309 base::FilePath filename;
310 TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
311 return base::PathExists(filename);
312}
313
Kelvin Zhang1c86a922021-05-13 10:30:48 -0400314bool Prefs::FileStorage::DeleteKey(std::string_view key) {
Alex Deymoa0284ac2016-07-22 12:51:41 -0700315 base::FilePath filename;
316 TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
hscham043355b2020-11-17 16:50:10 +0900317#if BASE_VER < 800000
Jae Hoon Kim29a80e02020-05-11 20:18:49 -0700318 TEST_AND_RETURN_FALSE(base::DeleteFile(filename, false));
hscham043355b2020-11-17 16:50:10 +0900319#else
320 TEST_AND_RETURN_FALSE(base::DeleteFile(filename));
321#endif
Alex Deymoa0284ac2016-07-22 12:51:41 -0700322 return true;
323}
324
Kelvin Zhang1c86a922021-05-13 10:30:48 -0400325bool Prefs::FileStorage::GetFileNameForKey(std::string_view key,
Alex Deymoa0284ac2016-07-22 12:51:41 -0700326 base::FilePath* filename) const {
Jae Hoon Kim29a80e02020-05-11 20:18:49 -0700327 // Allows only non-empty keys containing [A-Za-z0-9_-/].
Darin Petkov30030592010-07-27 13:53:20 -0700328 TEST_AND_RETURN_FALSE(!key.empty());
Jae Hoon Kim29a80e02020-05-11 20:18:49 -0700329 for (char c : key)
Alex Vakulenko0103c362016-01-20 07:56:15 -0800330 TEST_AND_RETURN_FALSE(base::IsAsciiAlpha(c) || base::IsAsciiDigit(c) ||
Andrew065d78d2020-04-07 15:43:07 -0700331 c == '_' || c == '-' || c == kKeySeparator);
Daniel Zheng5eece042023-05-17 14:44:10 -0700332 if (std::filesystem::exists(GetTemporaryDir())) {
333 *filename =
334 base::FilePath(GetTemporaryDir())
335 .Append(base::FilePath::StringPieceType(key.data(), key.size()));
336 } else {
337 *filename = prefs_dir_.Append(
338 base::FilePath::StringPieceType(key.data(), key.size()));
339 }
Darin Petkov30030592010-07-27 13:53:20 -0700340 return true;
341}
342
Alex Deymoa0284ac2016-07-22 12:51:41 -0700343// MemoryPrefs
344
Kelvin Zhang1c86a922021-05-13 10:30:48 -0400345bool MemoryPrefs::MemoryStorage::GetKey(std::string_view key,
Alex Deymoa0284ac2016-07-22 12:51:41 -0700346 string* value) const {
347 auto it = values_.find(key);
348 if (it == values_.end())
349 return false;
350 *value = it->second;
351 return true;
352}
353
Kelvin Zhang1c86a922021-05-13 10:30:48 -0400354bool MemoryPrefs::MemoryStorage::GetSubKeys(std::string_view ns,
Jae Hoon Kim29a80e02020-05-11 20:18:49 -0700355 vector<string>* keys) const {
Kelvin Zhang1c86a922021-05-13 10:30:48 -0400356 auto lower_comp = [](const auto& pr, const auto& ns) {
357 return std::string_view{pr.first.data(), ns.length()} < ns;
Jae Hoon Kim29a80e02020-05-11 20:18:49 -0700358 };
Kelvin Zhang1c86a922021-05-13 10:30:48 -0400359 auto upper_comp = [](const auto& ns, const auto& pr) {
360 return ns < std::string_view{pr.first.data(), ns.length()};
Jae Hoon Kim29a80e02020-05-11 20:18:49 -0700361 };
362 auto lower_it =
363 std::lower_bound(begin(values_), end(values_), ns, lower_comp);
364 auto upper_it = std::upper_bound(lower_it, end(values_), ns, upper_comp);
365 while (lower_it != upper_it)
366 keys->push_back((lower_it++)->first);
367 return true;
368}
369
Kelvin Zhang1c86a922021-05-13 10:30:48 -0400370bool MemoryPrefs::MemoryStorage::SetKey(std::string_view key,
Kelvin Zhangcf4600e2020-10-27 15:50:33 -0400371 std::string_view value) {
Kelvin Zhang1c86a922021-05-13 10:30:48 -0400372 values_[std::string{key}] = value;
Alex Deymoa0284ac2016-07-22 12:51:41 -0700373 return true;
374}
375
Kelvin Zhang1c86a922021-05-13 10:30:48 -0400376bool MemoryPrefs::MemoryStorage::KeyExists(std::string_view key) const {
Alex Deymoa0284ac2016-07-22 12:51:41 -0700377 return values_.find(key) != values_.end();
378}
379
Kelvin Zhang1c86a922021-05-13 10:30:48 -0400380bool MemoryPrefs::MemoryStorage::DeleteKey(std::string_view key) {
Alex Deymoa0284ac2016-07-22 12:51:41 -0700381 auto it = values_.find(key);
Andrew914f5542020-04-21 10:56:33 -0700382 if (it != values_.end())
383 values_.erase(it);
Alex Deymoa0284ac2016-07-22 12:51:41 -0700384 return true;
385}
386
Darin Petkov30030592010-07-27 13:53:20 -0700387} // namespace chromeos_update_engine