1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/metrics/structured/key_data_provider_ash.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "components/metrics/structured/key_data_provider_file.h"
#include "components/metrics/structured/structured_metrics_validator.h"
namespace metrics::structured {
namespace {
// Default delay period for the PersistentProto. This is the delay before a file
// write is triggered after a change has been made.
constexpr base::TimeDelta kSaveDelay = base::Milliseconds(1000);
// The path used to store per-profile keys. Relative to the user's
// cryptohome. This file is created by chromium.
constexpr char kProfileKeyPath[] = "structured_metrics/keys";
// The path used to store per-device keys. This file is created by tmpfiles.d
// on start and has its permissions and ownership set such that it is writable
// by chronos.
constexpr char kDeviceKeyPath[] = "/var/lib/metrics/structured/chromium/keys";
} // namespace
KeyDataProviderAsh::KeyDataProviderAsh()
: KeyDataProviderAsh(base::FilePath(kDeviceKeyPath), kSaveDelay) {}
KeyDataProviderAsh::KeyDataProviderAsh(const base::FilePath& device_key_path,
base::TimeDelta write_delay)
: device_key_path_(device_key_path), write_delay_(write_delay) {
device_key_ =
std::make_unique<KeyDataProviderFile>(device_key_path_, write_delay_);
device_key_->AddObserver(this);
}
KeyDataProviderAsh::~KeyDataProviderAsh() {
device_key_->RemoveObserver(this);
if (profile_key_) {
profile_key_->RemoveObserver(this);
}
}
bool KeyDataProviderAsh::IsReady() {
DCHECK(device_key_);
return device_key_->IsReady();
}
std::optional<uint64_t> KeyDataProviderAsh::GetId(
const std::string& project_name) {
KeyDataProvider* key_data_provider = GetKeyDataProvider(project_name);
if (!key_data_provider) {
return std::nullopt;
}
return key_data_provider->GetId(project_name);
}
std::optional<uint64_t> KeyDataProviderAsh::GetSecondaryId(
const std::string& project_name) {
const auto* project_validator =
validator::Validators::Get()->GetProjectValidator(project_name);
if (!project_validator) {
return std::nullopt;
}
// If |project_name| is not of type sequence, return std::nullopt as it
// should not have a corresponding secondary ID.
if (project_validator->event_type() != StructuredEventProto::SEQUENCE) {
return std::nullopt;
}
DCHECK(device_key_);
if (device_key_->IsReady()) {
return device_key_->GetId(project_name);
}
return std::nullopt;
}
KeyData* KeyDataProviderAsh::GetKeyData(const std::string& project_name) {
auto* key_data_provider = GetKeyDataProvider(project_name);
if (!key_data_provider || !key_data_provider->IsReady()) {
return nullptr;
}
return key_data_provider->GetKeyData(project_name);
}
void KeyDataProviderAsh::Purge() {
if (device_key_) {
device_key_->Purge();
}
if (profile_key_) {
profile_key_->Purge();
}
}
void KeyDataProviderAsh::OnKeyReady() {
NotifyKeyReady();
}
void KeyDataProviderAsh::ProfileAdded(const Profile& profile) {
// Only the primary user's keys should be loaded. If there is already is a
// profile key, no-op.
if (profile_key_) {
return;
}
const base::FilePath& profile_path = profile.GetPath();
profile_key_ = std::make_unique<KeyDataProviderFile>(
profile_path.Append(kProfileKeyPath), write_delay_);
profile_key_->AddObserver(this);
}
KeyDataProvider* KeyDataProviderAsh::GetKeyDataProvider(
const std::string& project_name) {
const auto* project_validator =
validator::Validators::Get()->GetProjectValidator(project_name);
if (!project_validator) {
return nullptr;
}
switch (project_validator->id_scope()) {
case IdScope::kPerProfile: {
if (profile_key_) {
return profile_key_.get();
}
break;
}
case IdScope::kPerDevice: {
// Retrieve the profile key if the type is a sequence.
if (project_validator->event_type() == StructuredEventProto::SEQUENCE) {
return profile_key_ ? profile_key_.get() : nullptr;
}
if (device_key_) {
return device_key_.get();
}
break;
}
default:
NOTREACHED();
}
return nullptr;
}
} // namespace metrics::structured
|