1aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
2aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Copyright (C) 2012 The Android Open Source Project
3aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
4aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Licensed under the Apache License, Version 2.0 (the "License");
5aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// you may not use this file except in compliance with the License.
6aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// You may obtain a copy of the License at
7aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
8aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//      http://www.apache.org/licenses/LICENSE-2.0
9aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
10aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Unless required by applicable law or agreed to in writing, software
11aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// distributed under the License is distributed on an "AS IS" BASIS,
12aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// See the License for the specific language governing permissions and
14aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// limitations under the License.
15aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
163003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov
1739910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/prefs.h"
183003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov
19d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo#include <algorithm>
20d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo
2106c76a49bfd29c8abdb8abd5b646a6583783191aBen Chan#include <base/files/file_util.h>
22362757765e7697dd93e8de05fa0a59f29242eb89Darin Petkov#include <base/logging.h>
2375039d7397f03dff77bdf4e26398049ff88edc4cAlex Vakulenko#include <base/strings/string_number_conversions.h>
2475039d7397f03dff77bdf4e26398049ff88edc4cAlex Vakulenko#include <base/strings/string_util.h>
25362757765e7697dd93e8de05fa0a59f29242eb89Darin Petkov
2639910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/utils.h"
273003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov
283003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkovusing std::string;
293003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov
303003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkovnamespace chromeos_update_engine {
313003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov
32e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymobool PrefsBase::GetString(const string& key, string* value) const {
33e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  return storage_->GetKey(key, value);
343003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov}
353003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov
36e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymobool PrefsBase::SetString(const string& key, const string& value) {
37e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  TEST_AND_RETURN_FALSE(storage_->SetKey(key, value));
38d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo  const auto observers_for_key = observers_.find(key);
39d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo  if (observers_for_key != observers_.end()) {
40d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo    std::vector<ObserverInterface*> copy_observers(observers_for_key->second);
41d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo    for (ObserverInterface* observer : copy_observers)
42d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo      observer->OnPrefSet(key);
43d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo  }
443003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov  return true;
453003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov}
463003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov
47e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymobool PrefsBase::GetInt64(const string& key, int64_t* value) const {
483003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov  string str_value;
4908fce04e5341c99f308ee7462b1f351f5232eacdJay Srinivasan  if (!GetString(key, &str_value))
5008fce04e5341c99f308ee7462b1f351f5232eacdJay Srinivasan    return false;
51736fcb57ca2dcf09710a797e4c23a64f6cd64e16Ben Chan  base::TrimWhitespaceASCII(str_value, base::TRIM_ALL, &str_value);
52790e62e2d8114647b0785574bea361cf931c482bChris Masone  TEST_AND_RETURN_FALSE(base::StringToInt64(str_value, value));
533003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov  return true;
543003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov}
553003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov
56e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymobool PrefsBase::SetInt64(const string& key, const int64_t value) {
57790e62e2d8114647b0785574bea361cf931c482bChris Masone  return SetString(key, base::Int64ToString(value));
583003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov}
593003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov
60e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymobool PrefsBase::GetBoolean(const string& key, bool* value) const {
61efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo  string str_value;
62efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo  if (!GetString(key, &str_value))
63efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo    return false;
64736fcb57ca2dcf09710a797e4c23a64f6cd64e16Ben Chan  base::TrimWhitespaceASCII(str_value, base::TRIM_ALL, &str_value);
65efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo  if (str_value == "false") {
66efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo    *value = false;
67efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo    return true;
68efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo  }
69efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo  if (str_value == "true") {
70efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo    *value = true;
71efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo    return true;
72efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo  }
73efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo  return false;
74efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo}
75efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo
76e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymobool PrefsBase::SetBoolean(const string& key, const bool value) {
77efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo  return SetString(key, value ? "true" : "false");
78efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo}
79efb7c4c605440fdc6297deed8fa9d1aecb77235eAlex Deymo
80e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymobool PrefsBase::Exists(const string& key) const {
81e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  return storage_->KeyExists(key);
82480ddfa079ebd01ed87e495332dec121d9ae781fJay Srinivasan}
83480ddfa079ebd01ed87e495332dec121d9ae781fJay Srinivasan
84e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymobool PrefsBase::Delete(const string& key) {
85e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  TEST_AND_RETURN_FALSE(storage_->DeleteKey(key));
86d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo  const auto observers_for_key = observers_.find(key);
87d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo  if (observers_for_key != observers_.end()) {
88d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo    std::vector<ObserverInterface*> copy_observers(observers_for_key->second);
89d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo    for (ObserverInterface* observer : copy_observers)
90d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo      observer->OnPrefDeleted(key);
91d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo  }
92d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo  return true;
93d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo}
94d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo
95e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymovoid PrefsBase::AddObserver(const string& key, ObserverInterface* observer) {
96d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo  observers_[key].push_back(observer);
97d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo}
98d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo
99e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymovoid PrefsBase::RemoveObserver(const string& key, ObserverInterface* observer) {
100d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo  std::vector<ObserverInterface*>& observers_for_key = observers_[key];
101d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo  auto observer_it =
102d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo      std::find(observers_for_key.begin(), observers_for_key.end(), observer);
103d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo  if (observer_it != observers_for_key.end())
104d6f60079258fa385b583dac9e770afd2ea3c9aebAlex Deymo    observers_for_key.erase(observer_it);
105480ddfa079ebd01ed87e495332dec121d9ae781fJay Srinivasan}
106480ddfa079ebd01ed87e495332dec121d9ae781fJay Srinivasan
107e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo// Prefs
108e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo
109e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymobool Prefs::Init(const base::FilePath& prefs_dir) {
110e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  return file_storage_.Init(prefs_dir);
111e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo}
112e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo
113e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymobool Prefs::FileStorage::Init(const base::FilePath& prefs_dir) {
114e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  prefs_dir_ = prefs_dir;
115e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  return true;
116e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo}
117e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo
118e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymobool Prefs::FileStorage::GetKey(const string& key, string* value) const {
119e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  base::FilePath filename;
120e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
121e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  if (!base::ReadFileToString(filename, value)) {
122e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo    LOG(INFO) << key << " not present in " << prefs_dir_.value();
123e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo    return false;
124e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  }
125e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  return true;
126e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo}
127e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo
128e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymobool Prefs::FileStorage::SetKey(const string& key, const string& value) {
129e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  base::FilePath filename;
130e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
131e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  if (!base::DirectoryExists(filename.DirName())) {
132e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo    // Only attempt to create the directory if it doesn't exist to avoid calls
133e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo    // to parent directories where we might not have permission to write to.
134e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo    TEST_AND_RETURN_FALSE(base::CreateDirectory(filename.DirName()));
135e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  }
136e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  TEST_AND_RETURN_FALSE(base::WriteFile(filename, value.data(), value.size()) ==
137e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo                        static_cast<int>(value.size()));
138e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  return true;
139e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo}
140e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo
141e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymobool Prefs::FileStorage::KeyExists(const string& key) const {
142e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  base::FilePath filename;
143e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
144e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  return base::PathExists(filename);
145e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo}
146e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo
147e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymobool Prefs::FileStorage::DeleteKey(const string& key) {
148e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  base::FilePath filename;
149e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
150e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  TEST_AND_RETURN_FALSE(base::DeleteFile(filename, false));
151e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  return true;
152e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo}
153e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo
154e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymobool Prefs::FileStorage::GetFileNameForKey(const string& key,
155e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo                                           base::FilePath* filename) const {
1563003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov  // Allows only non-empty keys containing [A-Za-z0-9_-].
1573003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov  TEST_AND_RETURN_FALSE(!key.empty());
1583003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov  for (size_t i = 0; i < key.size(); ++i) {
1593003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov    char c = key.at(i);
160a3cf75a1d01aeb03d2341600ebff3db0a8316200Alex Vakulenko    TEST_AND_RETURN_FALSE(base::IsAsciiAlpha(c) || base::IsAsciiDigit(c) ||
1613003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov                          c == '_' || c == '-');
1623003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov  }
1633003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov  *filename = prefs_dir_.Append(key);
1643003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov  return true;
1653003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov}
1663003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov
167e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo// MemoryPrefs
168e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo
169e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymobool MemoryPrefs::MemoryStorage::GetKey(const string& key,
170e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo                                        string* value) const {
171e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  auto it = values_.find(key);
172e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  if (it == values_.end())
173e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo    return false;
174e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  *value = it->second;
175e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  return true;
176e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo}
177e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo
178e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymobool MemoryPrefs::MemoryStorage::SetKey(const string& key,
179e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo                                        const string& value) {
180e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  values_[key] = value;
181e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  return true;
182e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo}
183e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo
184e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymobool MemoryPrefs::MemoryStorage::KeyExists(const string& key) const {
185e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  return values_.find(key) != values_.end();
186e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo}
187e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo
188e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymobool MemoryPrefs::MemoryStorage::DeleteKey(const string& key) {
189e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  auto it = values_.find(key);
190e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  if (it == values_.end())
191e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo    return false;
192e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  values_.erase(it);
193e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo  return true;
194e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo}
195e6eef83c63a50f043b2c4a85175030b6d8b6b91dAlex Deymo
1963003059032a7ac8a49f1bdd9fda2d58becec8374Darin Petkov}  // namespace chromeos_update_engine
197