| // Copyright 2020 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/updater/persisted_data.h" |
| |
| #include "base/check_op.h" |
| #include "base/files/file_path.h" |
| #include "base/sequence_checker.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/values.h" |
| #include "base/version.h" |
| #include "build/build_config.h" |
| #include "chrome/updater/registration_data.h" |
| #include "components/prefs/pref_registry_simple.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/prefs/scoped_user_pref_update.h" |
| |
| namespace { |
| |
| // Uses the same pref as the update_client code. |
| constexpr char kPersistedDataPreference[] = "updateclientdata"; |
| |
| constexpr char kPV[] = "pv"; // Key for storing product version. |
| constexpr char kFP[] = "fp"; // Key for storing fingerprint. |
| constexpr char kECP[] = "ecp"; // Key for storing existence checker path. |
| constexpr char kBC[] = "bc"; // Key for storing brand code. |
| constexpr char kBP[] = "bp"; // Key for storing brand path. |
| constexpr char kAP[] = "ap"; // Key for storing ap. |
| |
| constexpr char kHadApps[] = "had_apps"; |
| |
| } // namespace |
| |
| namespace updater { |
| |
| PersistedData::PersistedData(PrefService* pref_service) |
| : pref_service_(pref_service) { |
| DCHECK(pref_service_); |
| DCHECK(pref_service_->FindPreference(kPersistedDataPreference)); |
| } |
| |
| PersistedData::~PersistedData() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| } |
| |
| base::Version PersistedData::GetProductVersion(const std::string& id) const { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| return base::Version(GetString(id, kPV)); |
| } |
| |
| void PersistedData::SetProductVersion(const std::string& id, |
| const base::Version& pv) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| DCHECK(pv.IsValid()); |
| SetString(id, kPV, pv.GetString()); |
| } |
| |
| std::string PersistedData::GetFingerprint(const std::string& id) const { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| return GetString(id, kFP); |
| } |
| |
| void PersistedData::SetFingerprint(const std::string& id, |
| const std::string& fingerprint) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| SetString(id, kFP, fingerprint); |
| } |
| |
| base::FilePath PersistedData::GetExistenceCheckerPath( |
| const std::string& id) const { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| return base::FilePath::FromUTF8Unsafe(GetString(id, kECP)); |
| } |
| |
| void PersistedData::SetExistenceCheckerPath(const std::string& id, |
| const base::FilePath& ecp) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| SetString(id, kECP, ecp.AsUTF8Unsafe()); |
| } |
| |
| std::string PersistedData::GetBrandCode(const std::string& id) const { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| return GetString(id, kBC); |
| } |
| |
| void PersistedData::SetBrandCode(const std::string& id, const std::string& bc) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| SetString(id, kBC, bc); |
| } |
| |
| base::FilePath PersistedData::GetBrandPath(const std::string& id) const { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| return base::FilePath::FromUTF8Unsafe(GetString(id, kBP)); |
| } |
| |
| void PersistedData::SetBrandPath(const std::string& id, |
| const base::FilePath& bp) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| SetString(id, kBP, bp.AsUTF8Unsafe()); |
| } |
| |
| std::string PersistedData::GetAP(const std::string& id) const { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| return GetString(id, kAP); |
| } |
| |
| void PersistedData::SetAP(const std::string& id, const std::string& ap) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| SetString(id, kAP, ap); |
| } |
| |
| void PersistedData::RegisterApp(const RegistrationRequest& rq) { |
| SetProductVersion(rq.app_id, rq.version); |
| SetExistenceCheckerPath(rq.app_id, rq.existence_checker_path); |
| SetBrandCode(rq.app_id, rq.brand_code); |
| SetBrandPath(rq.app_id, rq.brand_path); |
| SetAP(rq.app_id, rq.ap); |
| } |
| |
| bool PersistedData::RemoveApp(const std::string& id) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| if (!pref_service_) |
| return false; |
| |
| DictionaryPrefUpdate update(pref_service_, kPersistedDataPreference); |
| base::Value* apps = update->FindDictKey("apps"); |
| |
| return apps ? apps->RemoveKey(id) : false; |
| } |
| |
| std::vector<std::string> PersistedData::GetAppIds() const { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| |
| // The prefs is a dictionary of dictionaries, where each inner dictionary |
| // corresponds to an app: |
| // {"updateclientdata":{"apps":{"{44FC7FE2-65CE-487C-93F4-EDEE46EEAAAB}":{... |
| const auto* pref = pref_service_->GetDictionary(kPersistedDataPreference); |
| if (!pref) |
| return {}; |
| const auto* apps = pref->FindKey("apps"); |
| if (!apps || !apps->is_dict()) |
| return {}; |
| std::vector<std::string> app_ids; |
| for (auto kv : apps->DictItems()) { |
| const auto& app_id = kv.first; |
| const auto pv = GetProductVersion(app_id); |
| if (pv.IsValid()) |
| app_ids.push_back(app_id); |
| } |
| return app_ids; |
| } |
| |
| const base::Value* PersistedData::GetAppKey(const std::string& id) const { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| if (!pref_service_) |
| return nullptr; |
| const base::Value* dict = |
| pref_service_->GetDictionary(kPersistedDataPreference); |
| if (!dict) |
| return nullptr; |
| const base::Value* apps = dict->FindDictKey("apps"); |
| if (!apps) |
| return nullptr; |
| return apps->FindDictKey(id); |
| } |
| |
| std::string PersistedData::GetString(const std::string& id, |
| const std::string& key) const { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| const base::Value* app_key = GetAppKey(id); |
| if (!app_key) |
| return {}; |
| const std::string* value = app_key->FindStringKey(key); |
| if (!value) |
| return {}; |
| return *value; |
| } |
| |
| base::Value* PersistedData::GetOrCreateAppKey(const std::string& id, |
| base::Value* root) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| base::Value* apps = root->FindDictKey("apps"); |
| if (!apps) |
| apps = root->SetKey("apps", base::Value(base::Value::Type::DICTIONARY)); |
| base::Value* app = apps->FindDictKey(id); |
| if (!app) |
| app = apps->SetKey(id, base::Value(base::Value::Type::DICTIONARY)); |
| return app; |
| } |
| |
| void PersistedData::SetString(const std::string& id, |
| const std::string& key, |
| const std::string& value) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| if (!pref_service_) |
| return; |
| DictionaryPrefUpdate update(pref_service_, kPersistedDataPreference); |
| GetOrCreateAppKey(id, update.Get())->SetStringKey(key, value); |
| } |
| |
| bool PersistedData::GetHadApps() const { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| return pref_service_ && pref_service_->GetBoolean(kHadApps); |
| } |
| |
| void PersistedData::SetHadApps() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| if (pref_service_) |
| pref_service_->SetBoolean(kHadApps, true); |
| } |
| |
| // Register persisted data prefs, except for kPersistedDataPreference. |
| // kPersistedDataPreference is registered by update_client::RegisterPrefs. |
| void RegisterPersistedDataPrefs(scoped_refptr<PrefRegistrySimple> registry) { |
| registry->RegisterBooleanPref(kHadApps, false); |
| } |
| |
| } // namespace updater |