blob: 6bb32bd666e50f957f0c8c5cb9dba6142cbba48e [file] [log] [blame]
// Copyright 2016 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 "components/update_client/persisted_data.h"
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/callback.h"
#include "base/guid.h"
#include "base/strings/stringprintf.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/values.h"
#include "base/version.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "components/update_client/activity_data_service.h"
const char kPersistedDataPreference[] = "updateclientdata";
namespace update_client {
PersistedData::PersistedData(PrefService* pref_service,
ActivityDataService* activity_data_service)
: pref_service_(pref_service),
activity_data_service_(activity_data_service) {}
PersistedData::~PersistedData() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
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_->GetValue(kPersistedDataPreference);
if (dict.type() != base::Value::Type::DICTIONARY)
return nullptr;
const base::Value* apps = dict.FindDictKey("apps");
if (!apps)
return nullptr;
return apps->FindDictKey(id);
}
int PersistedData::GetInt(const std::string& id,
const std::string& key,
int fallback) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const base::Value* app_key = GetAppKey(id);
if (!app_key)
return fallback;
return app_key->FindIntKey(key).value_or(fallback);
}
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;
}
int PersistedData::GetDateLastRollCall(const std::string& id) const {
return GetInt(id, "dlrc", kDateUnknown);
}
int PersistedData::GetDateLastActive(const std::string& id) const {
return GetInt(id, "dla", kDateUnknown);
}
std::string PersistedData::GetPingFreshness(const std::string& id) const {
std::string result = GetString(id, "pf");
return !result.empty() ? base::StringPrintf("{%s}", result.c_str()) : result;
}
std::string PersistedData::GetCohort(const std::string& id) const {
return GetString(id, "cohort");
}
std::string PersistedData::GetCohortName(const std::string& id) const {
return GetString(id, "cohortname");
}
std::string PersistedData::GetCohortHint(const std::string& id) const {
return GetString(id, "cohorthint");
}
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::SetDateLastDataHelper(
const std::vector<std::string>& ids,
int datenum,
base::OnceClosure callback,
const std::set<std::string>& active_ids) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DictionaryPrefUpdate update(pref_service_, kPersistedDataPreference);
for (const auto& id : ids) {
base::Value* app_key = GetOrCreateAppKey(id, update.Get());
app_key->SetIntKey("dlrc", datenum);
app_key->SetStringKey("pf", base::GenerateGUID());
if (active_ids.find(id) != active_ids.end()) {
app_key->SetIntKey("dla", datenum);
}
}
std::move(callback).Run();
}
void PersistedData::SetDateLastData(const std::vector<std::string>& ids,
int datenum,
base::OnceClosure callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!pref_service_ || datenum < 0) {
base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
std::move(callback));
return;
}
if (!activity_data_service_) {
SetDateLastDataHelper(ids, datenum, std::move(callback), {});
return;
}
activity_data_service_->GetAndClearActiveBits(
ids, base::BindOnce(&PersistedData::SetDateLastDataHelper,
base::Unretained(this), ids, datenum,
std::move(callback)));
}
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);
}
void PersistedData::SetCohort(const std::string& id,
const std::string& cohort) {
SetString(id, "cohort", cohort);
}
void PersistedData::SetCohortName(const std::string& id,
const std::string& cohort_name) {
SetString(id, "cohortname", cohort_name);
}
void PersistedData::SetCohortHint(const std::string& id,
const std::string& cohort_hint) {
SetString(id, "cohorthint", cohort_hint);
}
void PersistedData::GetActiveBits(
const std::vector<std::string>& ids,
base::OnceCallback<void(const std::set<std::string>&)> callback) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!activity_data_service_) {
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback), std::set<std::string>{}));
return;
}
activity_data_service_->GetActiveBits(ids, std::move(callback));
}
int PersistedData::GetDaysSinceLastRollCall(const std::string& id) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return activity_data_service_
? activity_data_service_->GetDaysSinceLastRollCall(id)
: kDaysUnknown;
}
int PersistedData::GetDaysSinceLastActive(const std::string& id) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return activity_data_service_
? activity_data_service_->GetDaysSinceLastActive(id)
: kDaysUnknown;
}
base::Version PersistedData::GetProductVersion(const std::string& id) const {
return base::Version(GetString(id, "pv"));
}
void PersistedData::SetProductVersion(const std::string& id,
const base::Version& pv) {
DCHECK(pv.IsValid());
SetString(id, "pv", pv.GetString());
}
std::string PersistedData::GetFingerprint(const std::string& id) const {
return GetString(id, "fp");
}
void PersistedData::SetFingerprint(const std::string& id,
const std::string& fingerprint) {
SetString(id, "fp", fingerprint);
}
void PersistedData::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterDictionaryPref(kPersistedDataPreference);
}
} // namespace update_client