1 // Copyright (c) 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/chromeos/settings/stats_reporting_controller.h"
6 
7 #include <string>
8 
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h"
12 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h"
13 #include "chrome/browser/chromeos/settings/cros_settings.h"
14 #include "chrome/browser/chromeos/settings/device_settings_service.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chromeos/settings/cros_settings_names.h"
17 #include "components/ownership/owner_settings_service.h"
18 #include "components/prefs/pref_registry_simple.h"
19 #include "components/prefs/pref_service.h"
20 
21 namespace {
22 
23 constexpr char kPendingPref[] = "pending.cros.metrics.reportingEnabled";
24 
25 }  // namespace
26 
27 namespace chromeos {
28 
29 static StatsReportingController* g_stats_reporting_controller = nullptr;
30 
31 // static
Initialize(PrefService * local_state)32 void StatsReportingController::Initialize(PrefService* local_state) {
33   CHECK(!g_stats_reporting_controller);
34   g_stats_reporting_controller = new StatsReportingController(local_state);
35 }
36 
37 // static
IsInitialized()38 bool StatsReportingController::IsInitialized() {
39   return g_stats_reporting_controller;
40 }
41 
42 // static
Shutdown()43 void StatsReportingController::Shutdown() {
44   DCHECK(g_stats_reporting_controller);
45   delete g_stats_reporting_controller;
46   g_stats_reporting_controller = nullptr;
47 }
48 
49 // static
Get()50 StatsReportingController* StatsReportingController::Get() {
51   CHECK(g_stats_reporting_controller);
52   return g_stats_reporting_controller;
53 }
54 
55 // static
RegisterLocalStatePrefs(PrefRegistrySimple * registry)56 void StatsReportingController::RegisterLocalStatePrefs(
57     PrefRegistrySimple* registry) {
58   registry->RegisterBooleanPref(kPendingPref, false,
59                                 PrefRegistry::NO_REGISTRATION_FLAGS);
60 }
61 
SetEnabled(Profile * profile,bool enabled)62 void StatsReportingController::SetEnabled(Profile* profile, bool enabled) {
63   DCHECK(profile);
64   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
65   VLOG(1) << "SetEnabled(" << std::boolalpha << enabled << ")";
66 
67   if (GetOwnershipStatus() == DeviceSettingsService::OWNERSHIP_TAKEN) {
68     // The device has an owner. If the current profile is that owner, we will
69     // write the value on their behalf, otherwise no action is taken.
70     VLOG(1) << "Already has owner";
71     SetWithServiceAsync(GetOwnerSettingsService(profile), enabled);
72   } else {
73     // The device has no owner, or we do not know yet whether the device has an
74     // owner. We write a pending value that will be persisted when ownership is
75     // taken (if that has not already happened).
76     // We store the new value in the local state, so that even if Chrome is
77     // restarted before ownership is taken, we will still persist it eventually.
78     // See OnOwnershipTaken.
79     VLOG(1) << "Pending owner; setting kPendingPref";
80     local_state_->SetBoolean(kPendingPref, enabled);
81     NotifyObservers();
82   }
83 }
84 
IsEnabled()85 bool StatsReportingController::IsEnabled() {
86   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
87   bool value = false;
88   if (GetOwnershipStatus() == DeviceSettingsService::OWNERSHIP_NONE &&
89       GetPendingValue(&value)) {
90     // Return the pending value if it exists and we are sure there is no owner:
91     return value;
92   }
93   // Otherwise, always return the value from the signed store.
94   GetSignedStoredValue(&value);
95   return value;
96 }
97 
98 std::unique_ptr<CrosSettings::ObserverSubscription>
AddObserver(const base::RepeatingClosure & callback)99 StatsReportingController::AddObserver(const base::RepeatingClosure& callback) {
100   DCHECK(!callback.is_null());
101   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
102   return callback_list_.Add(callback);
103 }
104 
OnOwnershipTaken(ownership::OwnerSettingsService * service)105 void StatsReportingController::OnOwnershipTaken(
106     ownership::OwnerSettingsService* service) {
107   DCHECK_EQ(GetOwnershipStatus(), DeviceSettingsService::OWNERSHIP_TAKEN);
108   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
109   VLOG(1) << "OnOwnershipTaken";
110 
111   bool pending_value;
112   if (GetPendingValue(&pending_value)) {
113     // At the time ownership is taken, there is a value waiting to be written.
114     // Use the OwnerSettingsService of the new owner to write the setting.
115     SetWithServiceAsync(service, pending_value);
116   }
117 }
118 
StatsReportingController(PrefService * local_state)119 StatsReportingController::StatsReportingController(PrefService* local_state)
120     : local_state_(local_state) {
121   setting_subscription_ = CrosSettings::Get()->AddSettingsObserver(
122       kStatsReportingPref,
123       base::BindRepeating(&StatsReportingController::NotifyObservers,
124                           this->as_weak_ptr()));
125   value_notified_to_observers_ = IsEnabled();
126 }
127 
~StatsReportingController()128 StatsReportingController::~StatsReportingController() {
129   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
130 }
131 
SetWithServiceAsync(ownership::OwnerSettingsService * service,bool enabled)132 void StatsReportingController::SetWithServiceAsync(
133     ownership::OwnerSettingsService* service,  // Can be null for non-owners.
134     bool enabled) {
135   VLOG(1) << "SetWithServiceAsync(" << std::boolalpha << enabled << ")";
136   bool not_yet_ready = service && !service->IsReady();
137   if (not_yet_ready) {
138     VLOG(1) << "Service not yet ready. Adding listener.";
139     // Service is not yet ready. Listen for changes in its readiness so we can
140     // write the value once it is ready. Uses weak pointers, so if everything
141     // is shutdown and deleted in the meantime, this callback isn't run.
142     service->IsOwnerAsync(
143         base::BindOnce(&StatsReportingController::SetWithServiceCallback,
144                        this->as_weak_ptr(), service->as_weak_ptr(), enabled));
145   } else {
146     // Service is either null, or ready - use it right now.
147     SetWithService(service, enabled);
148   }
149 }
150 
SetWithServiceCallback(const base::WeakPtr<ownership::OwnerSettingsService> & service,bool enabled,bool is_owner)151 void StatsReportingController::SetWithServiceCallback(
152     const base::WeakPtr<ownership::OwnerSettingsService>& service,
153     bool enabled,
154     bool is_owner) {
155   VLOG(1) << "SetWithServiceCallback(" << std::boolalpha << enabled << ")";
156   if (service)  // Make sure service wasn't deleted in the meantime.
157     SetWithService(service.get(), enabled);
158 }
159 
SetWithService(ownership::OwnerSettingsService * service,bool enabled)160 void StatsReportingController::SetWithService(
161     ownership::OwnerSettingsService* service,  // Can be null for non-owners.
162     bool enabled) {
163   VLOG(1) << "SetWithService(" << std::boolalpha << enabled << ")";
164   if (service && service->IsOwner()) {
165     service->SetBoolean(kStatsReportingPref, enabled);
166     ClearPendingValue();
167     NotifyObservers();
168   } else {
169     // Do nothing since we are not the owner.
170     LOG(WARNING) << "Changing settings from non-owner, setting="
171                  << kStatsReportingPref;
172   }
173 }
174 
NotifyObservers()175 void StatsReportingController::NotifyObservers() {
176   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
177   bool current_value = IsEnabled();
178   VLOG(1) << "Maybe notifying observers of " << std::boolalpha << current_value;
179   if (current_value != value_notified_to_observers_) {
180     VLOG(1) << "Notifying observers";
181     value_notified_to_observers_ = current_value;
182     callback_list_.Notify();
183   } else {
184     VLOG(1) << "Not notifying (already notified)";
185   }
186 }
187 
188 DeviceSettingsService::OwnershipStatus
GetOwnershipStatus()189 StatsReportingController::GetOwnershipStatus() {
190   return DeviceSettingsService::Get()->GetOwnershipStatus();
191 }
192 
193 ownership::OwnerSettingsService*
GetOwnerSettingsService(Profile * profile)194 StatsReportingController::GetOwnerSettingsService(Profile* profile) {
195   return OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(profile);
196 }
197 
GetPendingValue(bool * result)198 bool StatsReportingController::GetPendingValue(bool* result) {
199   if (local_state_->HasPrefPath(kPendingPref)) {
200     *result = local_state_->GetBoolean(kPendingPref);
201     return true;
202   }
203   return false;
204 }
205 
ClearPendingValue()206 void StatsReportingController::ClearPendingValue() {
207   VLOG(1) << "ClearPendingValue";
208   local_state_->ClearPref(kPendingPref);
209 }
210 
GetSignedStoredValue(bool * result)211 bool StatsReportingController::GetSignedStoredValue(bool* result) {
212   return CrosSettings::Get()->GetBoolean(kStatsReportingPref, result);
213 }
214 
215 }  // namespace chromeos
216