1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/component_updater/component_updater_service.h"
13 #include "base/check.h"
14 #include "base/files/file_path.h"
15 #include "base/files/file_util.h"
16 #include "base/functional/bind.h"
17 #include "base/functional/callback.h"
18 #include "base/functional/callback_helpers.h"
19 #include "base/logging.h"
20 #include "base/metrics/histogram_macros.h"
21 #include "base/ranges/algorithm.h"
22 #include "base/sequence_checker.h"
23 #include "base/strings/utf_string_conversions.h"
24 #include "base/task/sequenced_task_runner.h"
25 #include "base/time/time.h"
26 #include "base/timer/timer.h"
27 #include "components/component_updater/component_installer.h"
28 #include "components/component_updater/component_updater_service_internal.h"
29 #include "components/component_updater/component_updater_utils.h"
30 #include "components/component_updater/pref_names.h"
31 #include "components/prefs/pref_registry_simple.h"
32 #include "components/prefs/pref_service.h"
33 #include "components/update_client/configurator.h"
34 #include "components/update_client/crx_update_item.h"
35 #include "components/update_client/update_client.h"
36 #include "components/update_client/update_client_errors.h"
37 #include "components/update_client/utils.h"
38 #include "third_party/abseil-cpp/absl/types/optional.h"
41 using CrxInstaller = update_client::CrxInstaller;
42 using UpdateClient = update_client::UpdateClient;
47 UPDATE_TYPE_MANUAL = 0,
48 UPDATE_TYPE_AUTOMATIC,
54 namespace component_updater {
56 ComponentInfo::ComponentInfo(const std::string& id,
57 const std::string& fingerprint,
58 const std::u16string& name,
59 const base::Version& version,
60 const std::string& cohort_id)
62 fingerprint(fingerprint),
65 cohort_id(cohort_id) {}
66 ComponentInfo::ComponentInfo(const ComponentInfo& other) = default;
67 ComponentInfo& ComponentInfo::operator=(const ComponentInfo& other) = default;
68 ComponentInfo::ComponentInfo(ComponentInfo&& other) = default;
69 ComponentInfo& ComponentInfo::operator=(ComponentInfo&& other) = default;
70 ComponentInfo::~ComponentInfo() = default;
72 ComponentRegistration::ComponentRegistration(
73 const std::string& app_id,
74 const std::string& name,
75 std::vector<uint8_t> public_key_hash,
76 const base::Version& version,
77 const std::string& fingerprint,
78 std::map<std::string, std::string> installer_attributes,
79 scoped_refptr<update_client::ActionHandler> action_handler,
80 scoped_refptr<update_client::CrxInstaller> installer,
81 bool requires_network_encryption,
82 bool supports_group_policy_enable_component_updates)
85 public_key_hash(public_key_hash),
87 fingerprint(fingerprint),
88 installer_attributes(installer_attributes),
89 action_handler(action_handler),
91 requires_network_encryption(requires_network_encryption),
92 supports_group_policy_enable_component_updates(
93 supports_group_policy_enable_component_updates) {}
94 ComponentRegistration::ComponentRegistration(
95 const ComponentRegistration& other) = default;
96 ComponentRegistration& ComponentRegistration::operator=(
97 const ComponentRegistration& other) = default;
98 ComponentRegistration::ComponentRegistration(ComponentRegistration&& other) =
100 ComponentRegistration& ComponentRegistration::operator=(
101 ComponentRegistration&& other) = default;
102 ComponentRegistration::~ComponentRegistration() = default;
104 CrxUpdateService::CrxUpdateService(scoped_refptr<Configurator> config,
105 std::unique_ptr<UpdateScheduler> scheduler,
106 scoped_refptr<UpdateClient> update_client,
107 const std::string& brand)
109 scheduler_(std::move(scheduler)),
110 update_client_(update_client),
115 CrxUpdateService::~CrxUpdateService() {
116 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
118 for (auto& item : ready_callbacks_) {
119 std::move(item.second).Run();
122 RemoveObserver(this);
127 void CrxUpdateService::AddObserver(Observer* observer) {
128 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
129 update_client_->AddObserver(observer);
132 void CrxUpdateService::RemoveObserver(Observer* observer) {
133 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
134 update_client_->RemoveObserver(observer);
137 base::Version CrxUpdateService::GetRegisteredVersion(
138 const std::string& app_id) {
139 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
140 base::Version registered_version =
141 std::make_unique<update_client::PersistedData>(
142 config_->GetPrefService(), config_->GetActivityDataService())
143 ->GetProductVersion(app_id);
145 return (registered_version.IsValid()) ? registered_version
146 : base::Version(kNullVersion);
149 void CrxUpdateService::Start() {
150 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
151 VLOG(1) << "CrxUpdateService starting up. "
152 << "First update attempt will take place in "
153 << config_->InitialDelay() << " seconds. "
154 << "Next update attempt will take place in "
155 << config_->NextCheckDelay() << " seconds. ";
157 scheduler_->Schedule(
158 config_->InitialDelay(), config_->NextCheckDelay(),
160 base::IgnoreResult(&CrxUpdateService::CheckForUpdates),
161 base::Unretained(this)),
165 // Stops the update loop. In flight operations will be completed.
166 void CrxUpdateService::Stop() {
167 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
168 VLOG(1) << "CrxUpdateService stopping";
170 update_client_->Stop();
173 // Adds a component to be checked for upgrades. If the component exists it
174 // it will be replaced.
175 bool CrxUpdateService::RegisterComponent(
176 const ComponentRegistration& component) {
177 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
178 if (component.app_id.empty() || !component.version.IsValid() ||
179 !component.installer) {
183 // Update the registration data if the component has been registered before.
184 auto it = components_.find(component.app_id);
185 if (it != components_.end()) {
186 it->second = component;
190 components_.insert(std::make_pair(component.app_id, component));
191 components_order_.push_back(component.app_id);
193 // Create an initial state for this component. The state is mutated in
194 // response to events from the UpdateClient instance.
196 item.id = component.app_id;
197 item.component = ToCrxComponent(component);
198 const auto inserted =
199 component_states_.insert(std::make_pair(component.app_id, item));
200 DCHECK(inserted.second);
202 // Start the timer if this is the first component registered. The first timer
203 // event occurs after an interval defined by the component update
204 // configurator. The subsequent timer events are repeated with a period
205 // defined by the same configurator.
206 if (components_.size() == 1)
212 bool CrxUpdateService::UnregisterComponent(const std::string& id) {
213 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
214 auto it = components_.find(id);
215 if (it == components_.end())
218 DCHECK_EQ(id, it->first);
220 // Delay the uninstall of the component if the component is being updated.
221 if (update_client_->IsUpdating(id)) {
222 components_pending_unregistration_.push_back(id);
226 return DoUnregisterComponent(id);
229 bool CrxUpdateService::DoUnregisterComponent(const std::string& id) {
230 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
232 DCHECK(ready_callbacks_.find(id) == ready_callbacks_.end());
234 const bool result = components_.find(id)->second.installer->Uninstall();
236 const auto pos = base::ranges::find(components_order_, id);
237 if (pos != components_order_.end())
238 components_order_.erase(pos);
240 components_.erase(id);
241 component_states_.erase(id);
246 std::vector<std::string> CrxUpdateService::GetComponentIDs() const {
247 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
248 std::vector<std::string> ids;
249 for (const auto& it : components_)
250 ids.push_back(it.first);
254 std::vector<ComponentInfo> CrxUpdateService::GetComponents() const {
255 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
256 std::vector<ComponentInfo> result;
257 auto data = std::make_unique<update_client::PersistedData>(
258 config_->GetPrefService(), config_->GetActivityDataService());
259 for (const auto& it : components_) {
260 result.push_back(ComponentInfo(
261 it.first, it.second.fingerprint, base::UTF8ToUTF16(it.second.name),
262 it.second.version, data->GetCohort(it.second.app_id)));
267 OnDemandUpdater& CrxUpdateService::GetOnDemandUpdater() {
268 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
272 update_client::CrxComponent CrxUpdateService::ToCrxComponent(
273 const ComponentRegistration& component) const {
274 update_client::CrxComponent crx;
275 crx.pk_hash = component.public_key_hash;
276 crx.app_id = component.app_id;
277 crx.installer = component.installer;
278 crx.action_handler = component.action_handler;
279 crx.version = component.version;
280 crx.fingerprint = component.fingerprint;
281 crx.name = component.name;
282 crx.installer_attributes = component.installer_attributes;
283 crx.requires_network_encryption = component.requires_network_encryption;
286 crx.crx_format_requirement =
287 crx_file::VerifierFormat::CRX3_WITH_PUBLISHER_PROOF;
288 crx.updates_enabled =
289 !component.supports_group_policy_enable_component_updates ||
290 config_->GetPrefService()->GetBoolean(prefs::kComponentUpdatesEnabled);
295 absl::optional<ComponentRegistration> CrxUpdateService::GetComponent(
296 const std::string& id) const {
297 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
298 return component_updater::GetComponent(components_, id);
301 const CrxUpdateItem* CrxUpdateService::GetComponentState(
302 const std::string& id) const {
303 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
304 const auto it(component_states_.find(id));
305 return it != component_states_.end() ? &it->second : nullptr;
308 void CrxUpdateService::MaybeThrottle(const std::string& id,
309 base::OnceClosure callback) {
310 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
311 const auto it = components_.find(id);
312 if (it != components_.end()) {
313 DCHECK_EQ(it->first, id);
314 if (OnDemandUpdateWithCooldown(id)) {
315 ready_callbacks_.insert(std::make_pair(id, std::move(callback)));
320 // Unblock the request if the request can't be throttled.
321 std::move(callback).Run();
324 void CrxUpdateService::OnDemandUpdate(const std::string& id,
327 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
329 if (!GetComponent(id)) {
330 if (!callback.is_null()) {
331 base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
332 FROM_HERE, base::BindOnce(std::move(callback),
333 update_client::Error::INVALID_ARGUMENT));
338 OnDemandUpdateInternal(id, priority, std::move(callback));
341 bool CrxUpdateService::OnDemandUpdateWithCooldown(const std::string& id) {
342 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
344 DCHECK(GetComponent(id));
346 // Check if the request is too soon.
347 const auto* component_state(GetComponentState(id));
348 if (component_state && !component_state->last_check.is_null()) {
349 base::TimeDelta delta =
350 base::TimeTicks::Now() - component_state->last_check;
351 if (delta < config_->OnDemandDelay())
355 OnDemandUpdateInternal(id, Priority::FOREGROUND, Callback());
359 void CrxUpdateService::OnDemandUpdateInternal(const std::string& id,
362 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
364 UMA_HISTOGRAM_ENUMERATION("ComponentUpdater.Calls", UPDATE_TYPE_MANUAL,
367 auto crx_data_callback = base::BindOnce(&CrxUpdateService::GetCrxComponents,
368 base::Unretained(this));
369 auto update_complete_callback = base::BindOnce(
370 &CrxUpdateService::OnUpdateComplete, base::Unretained(this),
371 std::move(callback), base::TimeTicks::Now());
373 if (priority == Priority::FOREGROUND)
374 update_client_->Install(id, std::move(crx_data_callback), {},
375 std::move(update_complete_callback));
376 else if (priority == Priority::BACKGROUND)
377 update_client_->Update({id}, std::move(crx_data_callback), {}, false,
378 std::move(update_complete_callback));
383 bool CrxUpdateService::CheckForUpdates(
384 UpdateScheduler::OnFinishedCallback on_finished) {
385 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
387 UMA_HISTOGRAM_ENUMERATION("ComponentUpdater.Calls", UPDATE_TYPE_AUTOMATIC,
390 if (components_order_.empty()) {
391 base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
392 FROM_HERE, std::move(on_finished));
396 update_client_->Update(
398 base::BindOnce(&CrxUpdateService::GetCrxComponents,
399 base::Unretained(this)),
401 base::BindOnce(&CrxUpdateService::OnUpdateComplete,
402 base::Unretained(this),
404 [](UpdateScheduler::OnFinishedCallback on_finished,
405 update_client::Error /*error*/) {
406 std::move(on_finished).Run();
408 std::move(on_finished)),
409 base::TimeTicks::Now()));
413 bool CrxUpdateService::GetComponentDetails(const std::string& id,
414 CrxUpdateItem* item) const {
415 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
417 // First, if this component is currently being updated, return its state from
418 // the update client.
419 if (update_client_->GetCrxUpdateState(id, item))
422 // Otherwise, return the last seen state of the component, if such a
424 const auto component_states_it = component_states_.find(id);
425 if (component_states_it != component_states_.end()) {
426 *item = component_states_it->second;
433 void CrxUpdateService::GetCrxComponents(
434 const std::vector<std::string>& ids,
435 base::OnceCallback<void(const std::vector<absl::optional<CrxComponent>>&)>
437 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
438 std::vector<absl::optional<CrxComponent>> crxs;
439 for (absl::optional<ComponentRegistration> item :
440 component_updater::GetCrxComponents(components_, ids)) {
441 crxs.push_back(item ? absl::optional<CrxComponent>{ToCrxComponent(*item)}
444 std::move(callback).Run(crxs);
447 void CrxUpdateService::OnUpdateComplete(Callback callback,
448 const base::TimeTicks& start_time,
449 update_client::Error error) {
450 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
451 VLOG(1) << "Update completed with error " << static_cast<int>(error);
453 UMA_HISTOGRAM_BOOLEAN("ComponentUpdater.UpdateCompleteResult",
454 error != update_client::Error::NONE);
455 UMA_HISTOGRAM_ENUMERATION("ComponentUpdater.UpdateCompleteError", error,
456 update_client::Error::MAX_VALUE);
457 UMA_HISTOGRAM_LONG_TIMES_100("ComponentUpdater.UpdateCompleteTime",
458 base::TimeTicks::Now() - start_time);
460 for (const auto& id : components_pending_unregistration_) {
461 if (!update_client_->IsUpdating(id)) {
462 const auto component = GetComponent(id);
464 DoUnregisterComponent(id);
468 if (!callback.is_null()) {
469 base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
470 FROM_HERE, base::BindOnce(std::move(callback), error));
474 void CrxUpdateService::OnEvent(Events event, const std::string& id) {
475 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
477 // Unblock all throttles for the component.
478 if (event == Observer::Events::COMPONENT_UPDATED ||
479 event == Observer::Events::COMPONENT_ALREADY_UP_TO_DATE ||
480 event == Observer::Events::COMPONENT_UPDATE_ERROR) {
481 auto callbacks = ready_callbacks_.equal_range(id);
482 for (auto it = callbacks.first; it != callbacks.second; ++it) {
483 std::move(it->second).Run();
485 ready_callbacks_.erase(id);
488 CrxUpdateItem update_item;
489 if (!update_client_->GetCrxUpdateState(id, &update_item))
492 // Update the state of the item.
493 const auto state_it = component_states_.find(id);
494 if (state_it != component_states_.end())
495 state_it->second = update_item;
497 // Update the component registration with the new version.
498 if (event == Observer::Events::COMPONENT_UPDATED) {
499 const auto component_it = components_.find(id);
500 if (component_it != components_.end()) {
501 component_it->second.version = update_item.next_version;
502 component_it->second.fingerprint = update_item.next_fp;
507 ///////////////////////////////////////////////////////////////////////////////
509 // The component update factory. Using the component updater as a singleton
510 // is the job of the browser process.
511 std::unique_ptr<ComponentUpdateService> ComponentUpdateServiceFactory(
512 scoped_refptr<Configurator> config,
513 std::unique_ptr<UpdateScheduler> scheduler,
514 const std::string& brand) {
517 auto update_client = update_client::UpdateClientFactory(config);
518 return std::make_unique<CrxUpdateService>(config, std::move(scheduler),
519 std::move(update_client), brand);
522 // Register prefs required by the component update service.
523 void RegisterComponentUpdateServicePrefs(PrefRegistrySimple* registry) {
524 // The component updates are enabled by default, if the preference is not set.
525 registry->RegisterBooleanPref(prefs::kComponentUpdatesEnabled, true);
528 } // namespace component_updater