blob: 5fbf7495878207ecfa0ca797f937f818aee98725 [file] [log] [blame]
[email protected]de0fdca22014-08-19 05:26:091// Copyright 2014 The Chromium Authors. All rights reserved.
[email protected]e8f96ff2011-08-03 05:07:332// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]de0fdca22014-08-19 05:26:095#include "components/component_updater/component_updater_service.h"
[email protected]e8f96ff2011-08-03 05:07:336
7#include <algorithm>
sorin7c717622015-05-26 19:59:098#include <map>
9#include <string>
10#include <utility>
[email protected]e8f96ff2011-08-03 05:07:3311#include <vector>
12
[email protected]44da56e2011-11-21 19:59:1413#include "base/bind.h"
sorin395c2ac2014-09-16 21:31:0714#include "base/bind_helpers.h"
[email protected]78efe2e92014-08-08 15:53:2215#include "base/callback.h"
[email protected]57999812013-02-24 05:40:5216#include "base/files/file_path.h"
thestig819adcc82014-09-10 22:24:5317#include "base/files/file_util.h"
[email protected]e8f96ff2011-08-03 05:07:3318#include "base/logging.h"
sorin5cb1f5492014-09-23 04:07:4419#include "base/macros.h"
sorin85953dc2016-03-10 00:32:4820#include "base/metrics/histogram_macros.h"
waffles77255cc2016-08-02 17:25:1221#include "base/strings/utf_string_conversions.h"
[email protected]ed6fb982014-07-23 16:56:5222#include "base/threading/thread_checker.h"
gab7966d312016-05-11 20:35:0123#include "base/threading/thread_task_runner_handle.h"
sorin85953dc2016-03-10 00:32:4824#include "base/time/time.h"
[email protected]41a17c52013-06-28 00:27:5325#include "base/timer/timer.h"
sorin7c717622015-05-26 19:59:0926#include "components/component_updater/component_updater_service_internal.h"
27#include "components/component_updater/timer.h"
sorin52ac0882015-01-24 01:15:0028#include "components/update_client/configurator.h"
sorin52ac0882015-01-24 01:15:0029#include "components/update_client/crx_update_item.h"
sorin52ac0882015-01-24 01:15:0030#include "components/update_client/update_client.h"
sorin7b8650522016-11-02 18:23:4131#include "components/update_client/update_client_errors.h"
sorin52ac0882015-01-24 01:15:0032#include "components/update_client/utils.h"
[email protected]761fa4702013-07-02 15:25:1533#include "url/gurl.h"
[email protected]e8f96ff2011-08-03 05:07:3334
sorin7c717622015-05-26 19:59:0935using CrxInstaller = update_client::CrxInstaller;
36using UpdateClient = update_client::UpdateClient;
sorin52ac0882015-01-24 01:15:0037
sorin85953dc2016-03-10 00:32:4838namespace {
39
40enum UpdateType {
41 UPDATE_TYPE_MANUAL = 0,
42 UPDATE_TYPE_AUTOMATIC,
43 UPDATE_TYPE_COUNT,
44};
45
46} // namespace
47
[email protected]055981f2014-01-17 20:22:3248namespace component_updater {
[email protected]3a0092d2013-12-18 03:04:3549
Joshua Pawlicki0499ac82017-08-17 18:29:0750ComponentInfo::ComponentInfo(const std::string& id,
51 const std::string& fingerprint,
52 const base::string16& name,
wafflese7759f72016-10-10 23:41:2553 const base::Version& version)
Joshua Pawlicki0499ac82017-08-17 18:29:0754 : id(id), fingerprint(fingerprint), name(name), version(version) {}
55ComponentInfo::ComponentInfo(const ComponentInfo& other) = default;
56ComponentInfo::ComponentInfo(ComponentInfo&& other) = default;
waffles77255cc2016-08-02 17:25:1257ComponentInfo::~ComponentInfo() {}
58
Sorin Jianu49126332018-02-13 17:07:4259CrxUpdateService::CrxUpdateService(scoped_refptr<Configurator> config,
60 scoped_refptr<UpdateClient> update_client)
Sorin Jianuebd652462017-07-23 02:00:5861 : config_(config), update_client_(update_client) {
sorin7c717622015-05-26 19:59:0962 AddObserver(this);
[email protected]1ea21ad2013-09-02 04:20:3963}
[email protected]e8f96ff2011-08-03 05:07:3364
65CrxUpdateService::~CrxUpdateService() {
sorin7c717622015-05-26 19:59:0966 DCHECK(thread_checker_.CalledOnValidThread());
67
Sorin Jianua8ef73d2017-11-02 16:55:1768 for (auto& item : ready_callbacks_) {
69 std::move(item.second).Run();
sorin7c717622015-05-26 19:59:0970 }
71
72 RemoveObserver(this);
73
[email protected]e8f96ff2011-08-03 05:07:3374 Stop();
[email protected]1ea21ad2013-09-02 04:20:3975}
[email protected]e8f96ff2011-08-03 05:07:3376
[email protected]d3268fe2014-04-25 02:14:2377void CrxUpdateService::AddObserver(Observer* observer) {
[email protected]ed6fb982014-07-23 16:56:5278 DCHECK(thread_checker_.CalledOnValidThread());
sorin7c717622015-05-26 19:59:0979 update_client_->AddObserver(observer);
[email protected]d3268fe2014-04-25 02:14:2380}
81
82void CrxUpdateService::RemoveObserver(Observer* observer) {
[email protected]ed6fb982014-07-23 16:56:5283 DCHECK(thread_checker_.CalledOnValidThread());
sorin7c717622015-05-26 19:59:0984 update_client_->RemoveObserver(observer);
[email protected]d3268fe2014-04-25 02:14:2385}
86
sorin7c717622015-05-26 19:59:0987void CrxUpdateService::Start() {
88 DCHECK(thread_checker_.CalledOnValidThread());
89 VLOG(1) << "CrxUpdateService starting up. "
90 << "First update attempt will take place in "
91 << config_->InitialDelay() << " seconds. "
92 << "Next update attempt will take place in "
93 << config_->NextCheckDelay() << " seconds. ";
[email protected]e8f96ff2011-08-03 05:07:3394
sorin7c717622015-05-26 19:59:0995 timer_.Start(
96 base::TimeDelta::FromSeconds(config_->InitialDelay()),
97 base::TimeDelta::FromSeconds(config_->NextCheckDelay()),
98 base::Bind(base::IgnoreResult(&CrxUpdateService::CheckForUpdates),
99 base::Unretained(this)));
[email protected]e8f96ff2011-08-03 05:07:33100}
101
sorin7c717622015-05-26 19:59:09102// Stops the update loop. In flight operations will be completed.
103void CrxUpdateService::Stop() {
104 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]fb53e652014-04-30 11:27:19105 VLOG(1) << "CrxUpdateService stopping";
[email protected]e8f96ff2011-08-03 05:07:33106 timer_.Stop();
sorinecaad3e2015-11-13 19:15:52107 update_client_->Stop();
[email protected]e8f96ff2011-08-03 05:07:33108}
109
110// Adds a component to be checked for upgrades. If the component exists it
sorin7c717622015-05-26 19:59:09111// it will be replaced.
112bool CrxUpdateService::RegisterComponent(const CrxComponent& component) {
[email protected]ed6fb982014-07-23 16:56:52113 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]d0c8b8b42014-05-06 05:11:45114 if (component.pk_hash.empty() || !component.version.IsValid() ||
sorin7c717622015-05-26 19:59:09115 !component.installer) {
116 return false;
[email protected]e8f96ff2011-08-03 05:07:33117 }
118
sorin7c717622015-05-26 19:59:09119 // Update the registration data if the component has been registered before.
120 const std::string id(GetCrxComponentID(component));
121 auto it = components_.find(id);
122 if (it != components_.end()) {
123 it->second = component;
124 return true;
[email protected]10bc0222014-06-11 13:44:38125 }
[email protected]e8f96ff2011-08-03 05:07:33126
sorin7c717622015-05-26 19:59:09127 components_.insert(std::make_pair(id, component));
128 components_order_.push_back(id);
waffles77255cc2016-08-02 17:25:12129 for (const auto& mime_type : component.handled_mime_types)
130 component_ids_by_mime_type_[mime_type] = id;
sorin7c717622015-05-26 19:59:09131
132 // Create an initial state for this component. The state is mutated in
133 // response to events from the UpdateClient instance.
134 CrxUpdateItem item;
135 item.id = id;
136 item.component = component;
137 const auto inserted = component_states_.insert(std::make_pair(id, item));
138 DCHECK(inserted.second);
139
140 // Start the timer if this is the first component registered. The first timer
141 // event occurs after an interval defined by the component update
142 // configurator. The subsequent timer events are repeated with a period
143 // defined by the same configurator.
144 if (components_.size() == 1)
145 Start();
146
147 return true;
[email protected]e8f96ff2011-08-03 05:07:33148}
149
sorin7c717622015-05-26 19:59:09150bool CrxUpdateService::UnregisterComponent(const std::string& id) {
151 DCHECK(thread_checker_.CalledOnValidThread());
152 auto it = components_.find(id);
153 if (it == components_.end())
154 return false;
bauerb1f6657e72015-02-09 00:00:27155
sorin7c717622015-05-26 19:59:09156 DCHECK_EQ(id, it->first);
bauerb1f6657e72015-02-09 00:00:27157
sorin7c717622015-05-26 19:59:09158 // Delay the uninstall of the component if the component is being updated.
159 if (update_client_->IsUpdating(id)) {
160 components_pending_unregistration_.push_back(id);
161 return true;
162 }
163
164 return DoUnregisterComponent(it->second);
165}
166
167bool CrxUpdateService::DoUnregisterComponent(const CrxComponent& component) {
168 DCHECK(thread_checker_.CalledOnValidThread());
169
170 const auto id = GetCrxComponentID(component);
171 DCHECK(ready_callbacks_.find(id) == ready_callbacks_.end());
172
173 const bool result = component.installer->Uninstall();
174
175 const auto pos =
176 std::find(components_order_.begin(), components_order_.end(), id);
177 if (pos != components_order_.end())
178 components_order_.erase(pos);
179
180 components_.erase(id);
181 component_states_.erase(id);
182
183 return result;
bauerb1f6657e72015-02-09 00:00:27184}
185
[email protected]68bf09e2014-06-03 00:10:56186std::vector<std::string> CrxUpdateService::GetComponentIDs() const {
[email protected]ed6fb982014-07-23 16:56:52187 DCHECK(thread_checker_.CalledOnValidThread());
sorin7c717622015-05-26 19:59:09188 std::vector<std::string> ids;
189 for (const auto& it : components_)
190 ids.push_back(it.first);
191 return ids;
[email protected]68bf09e2014-06-03 00:10:56192}
193
waffles77255cc2016-08-02 17:25:12194std::unique_ptr<ComponentInfo> CrxUpdateService::GetComponentForMimeType(
195 const std::string& mime_type) const {
196 DCHECK(thread_checker_.CalledOnValidThread());
197 const auto it = component_ids_by_mime_type_.find(mime_type);
198 if (it == component_ids_by_mime_type_.end())
199 return nullptr;
vmpstr6d9996c82017-02-23 00:43:25200 auto* const component = GetComponent(it->second);
waffles77255cc2016-08-02 17:25:12201 if (!component)
202 return nullptr;
Gyuyoung Kim6afb5082018-01-19 13:35:57203 return std::make_unique<ComponentInfo>(
Joshua Pawlicki0499ac82017-08-17 18:29:07204 GetCrxComponentID(*component), component->fingerprint,
205 base::UTF8ToUTF16(component->name), component->version);
206}
207
208std::vector<ComponentInfo> CrxUpdateService::GetComponents() const {
209 DCHECK(thread_checker_.CalledOnValidThread());
210 std::vector<ComponentInfo> result;
211 for (const auto& it : components_) {
212 result.push_back(ComponentInfo(it.first, it.second.fingerprint,
213 base::UTF8ToUTF16(it.second.name),
214 it.second.version));
215 }
216 return result;
waffles77255cc2016-08-02 17:25:12217}
218
[email protected]78efe2e92014-08-08 15:53:22219OnDemandUpdater& CrxUpdateService::GetOnDemandUpdater() {
sorin7c717622015-05-26 19:59:09220 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]78efe2e92014-08-08 15:53:22221 return *this;
222}
223
sorin7c717622015-05-26 19:59:09224const CrxComponent* CrxUpdateService::GetComponent(
225 const std::string& id) const {
226 DCHECK(thread_checker_.CalledOnValidThread());
227 const auto it(components_.find(id));
Ivan Kotenkov75b1c3a2017-10-24 14:47:24228 return it != components_.end() ? &(it->second) : nullptr;
sorin7c717622015-05-26 19:59:09229}
230
231const CrxUpdateItem* CrxUpdateService::GetComponentState(
232 const std::string& id) const {
233 DCHECK(thread_checker_.CalledOnValidThread());
234 const auto it(component_states_.find(id));
Ivan Kotenkov75b1c3a2017-10-24 14:47:24235 return it != component_states_.end() ? &it->second : nullptr;
sorin7c717622015-05-26 19:59:09236}
237
238void CrxUpdateService::MaybeThrottle(const std::string& id,
Sorin Jianua8ef73d2017-11-02 16:55:17239 base::OnceClosure callback) {
[email protected]78efe2e92014-08-08 15:53:22240 DCHECK(thread_checker_.CalledOnValidThread());
Sorin Jianua8ef73d2017-11-02 16:55:17241 const auto it = components_.find(id);
sorin7c717622015-05-26 19:59:09242 if (it != components_.end()) {
243 DCHECK_EQ(it->first, id);
244 if (OnDemandUpdateWithCooldown(id)) {
Sorin Jianua8ef73d2017-11-02 16:55:17245 ready_callbacks_.insert(std::make_pair(id, std::move(callback)));
sorin7c717622015-05-26 19:59:09246 return;
247 }
[email protected]78efe2e92014-08-08 15:53:22248 }
sorin7c717622015-05-26 19:59:09249
Sorin Jianua8ef73d2017-11-02 16:55:17250 // Unblock the request if the request can't be throttled.
251 std::move(callback).Run();
sorin7c717622015-05-26 19:59:09252}
253
sorin4c520182016-08-19 17:27:44254void CrxUpdateService::OnDemandUpdate(const std::string& id,
Vladislav Kuzkokov12eca792017-10-20 12:45:38255 Callback callback) {
sorin7c717622015-05-26 19:59:09256 DCHECK(thread_checker_.CalledOnValidThread());
257
sorin4c520182016-08-19 17:27:44258 if (!GetComponent(id)) {
drbasic6d4d9ce2017-02-22 10:33:59259 if (!callback.is_null()) {
260 base::ThreadTaskRunnerHandle::Get()->PostTask(
Vladislav Kuzkokov12eca792017-10-20 12:45:38261 FROM_HERE, base::BindOnce(std::move(callback),
262 update_client::Error::INVALID_ARGUMENT));
drbasic6d4d9ce2017-02-22 10:33:59263 }
sorin4c520182016-08-19 17:27:44264 return;
265 }
sorin7c717622015-05-26 19:59:09266
Vladislav Kuzkokov12eca792017-10-20 12:45:38267 OnDemandUpdateInternal(id, std::move(callback));
sorin7c717622015-05-26 19:59:09268}
269
270bool CrxUpdateService::OnDemandUpdateWithCooldown(const std::string& id) {
271 DCHECK(thread_checker_.CalledOnValidThread());
272
273 DCHECK(GetComponent(id));
274
275 // Check if the request is too soon.
vmpstr2de366b2016-07-20 21:35:48276 const auto* component_state(GetComponentState(id));
Ivan Afanasyevec822ac2017-09-05 14:10:06277 if (component_state && !component_state->last_check.is_null()) {
sorin1827db12016-09-15 20:43:31278 base::TimeDelta delta =
279 base::TimeTicks::Now() - component_state->last_check;
sorin7c717622015-05-26 19:59:09280 if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay()))
281 return false;
282 }
283
sorin842703b2016-11-02 23:59:23284 OnDemandUpdateInternal(id, Callback());
sorin4c520182016-08-19 17:27:44285 return true;
sorin7c717622015-05-26 19:59:09286}
287
sorin4c520182016-08-19 17:27:44288void CrxUpdateService::OnDemandUpdateInternal(const std::string& id,
Vladislav Kuzkokov12eca792017-10-20 12:45:38289 Callback callback) {
sorin7c717622015-05-26 19:59:09290 DCHECK(thread_checker_.CalledOnValidThread());
291
sorin85953dc2016-03-10 00:32:48292 UMA_HISTOGRAM_ENUMERATION("ComponentUpdater.Calls", UPDATE_TYPE_MANUAL,
293 UPDATE_TYPE_COUNT);
sorin7c717622015-05-26 19:59:09294 update_client_->Install(
Sorin Jianua8ef73d2017-11-02 16:55:17295 id, base::BindOnce(&CrxUpdateService::OnUpdate, base::Unretained(this)),
Vladislav Kuzkokov12eca792017-10-20 12:45:38296 base::BindOnce(&CrxUpdateService::OnUpdateComplete,
297 base::Unretained(this), std::move(callback),
298 base::TimeTicks::Now()));
sorin7c717622015-05-26 19:59:09299}
300
301bool CrxUpdateService::CheckForUpdates() {
302 DCHECK(thread_checker_.CalledOnValidThread());
sorin85953dc2016-03-10 00:32:48303
304 UMA_HISTOGRAM_ENUMERATION("ComponentUpdater.Calls", UPDATE_TYPE_AUTOMATIC,
305 UPDATE_TYPE_COUNT);
306
sorinfccbf2d2016-04-04 20:34:34307 std::vector<std::string> secure_ids; // Requires HTTPS for update checks.
308 std::vector<std::string> unsecure_ids; // Can fallback to HTTP.
sorin7c717622015-05-26 19:59:09309 for (const auto id : components_order_) {
310 DCHECK(components_.find(id) != components_.end());
sorinfccbf2d2016-04-04 20:34:34311
vmpstr2de366b2016-07-20 21:35:48312 auto* component(GetComponent(id));
sorinfccbf2d2016-04-04 20:34:34313 if (!component || component->requires_network_encryption)
314 secure_ids.push_back(id);
315 else
316 unsecure_ids.push_back(id);
sorin7c717622015-05-26 19:59:09317 }
318
sorinfccbf2d2016-04-04 20:34:34319 if (!unsecure_ids.empty()) {
320 update_client_->Update(
321 unsecure_ids,
Sorin Jianua8ef73d2017-11-02 16:55:17322 base::BindOnce(&CrxUpdateService::OnUpdate, base::Unretained(this)),
Vladislav Kuzkokov12eca792017-10-20 12:45:38323 base::BindOnce(&CrxUpdateService::OnUpdateComplete,
324 base::Unretained(this), Callback(),
325 base::TimeTicks::Now()));
sorinfccbf2d2016-04-04 20:34:34326 }
327
328 if (!secure_ids.empty()) {
329 update_client_->Update(
330 secure_ids,
Sorin Jianua8ef73d2017-11-02 16:55:17331 base::BindOnce(&CrxUpdateService::OnUpdate, base::Unretained(this)),
Vladislav Kuzkokov12eca792017-10-20 12:45:38332 base::BindOnce(&CrxUpdateService::OnUpdateComplete,
333 base::Unretained(this), Callback(),
334 base::TimeTicks::Now()));
sorinfccbf2d2016-04-04 20:34:34335 }
sorin7c717622015-05-26 19:59:09336
337 return true;
[email protected]78efe2e92014-08-08 15:53:22338}
339
sorin7c717622015-05-26 19:59:09340bool CrxUpdateService::GetComponentDetails(const std::string& id,
[email protected]f392e372014-06-12 07:25:57341 CrxUpdateItem* item) const {
[email protected]ed6fb982014-07-23 16:56:52342 DCHECK(thread_checker_.CalledOnValidThread());
sorin7c717622015-05-26 19:59:09343
344 // First, if this component is currently being updated, return its state from
345 // the update client.
346 if (update_client_->GetCrxUpdateState(id, item))
347 return true;
348
349 // Otherwise, return the last seen state of the component, if such a
350 // state exists.
351 const auto component_states_it = component_states_.find(id);
352 if (component_states_it != component_states_.end()) {
353 *item = component_states_it->second;
354 return true;
355 }
356
357 return false;
[email protected]2e919ddd2013-08-21 05:05:17358}
359
sorin7c717622015-05-26 19:59:09360void CrxUpdateService::OnUpdate(const std::vector<std::string>& ids,
361 std::vector<CrxComponent>* components) {
362 DCHECK(thread_checker_.CalledOnValidThread());
363 DCHECK(components->empty());
364
365 for (const auto& id : ids) {
sorineae115a2016-08-26 02:27:20366 const update_client::CrxComponent* registered_component(GetComponent(id));
sorin97bd0292016-11-14 19:46:53367 if (registered_component)
sorin7c717622015-05-26 19:59:09368 components->push_back(*registered_component);
sorin7c717622015-05-26 19:59:09369 }
[email protected]ed6fb982014-07-23 16:56:52370}
371
sorin842703b2016-11-02 23:59:23372void CrxUpdateService::OnUpdateComplete(Callback callback,
sorin4c520182016-08-19 17:27:44373 const base::TimeTicks& start_time,
sorin7b8650522016-11-02 18:23:41374 update_client::Error error) {
sorin7c717622015-05-26 19:59:09375 DCHECK(thread_checker_.CalledOnValidThread());
sorin7b8650522016-11-02 18:23:41376 VLOG(1) << "Update completed with error " << static_cast<int>(error);
sorin7c717622015-05-26 19:59:09377
sorin7b8650522016-11-02 18:23:41378 UMA_HISTOGRAM_BOOLEAN("ComponentUpdater.UpdateCompleteResult",
379 error != update_client::Error::NONE);
sorin85953dc2016-03-10 00:32:48380 UMA_HISTOGRAM_LONG_TIMES_100("ComponentUpdater.UpdateCompleteTime",
381 base::TimeTicks::Now() - start_time);
382
sorin7c717622015-05-26 19:59:09383 for (const auto id : components_pending_unregistration_) {
384 if (!update_client_->IsUpdating(id)) {
vmpstr2de366b2016-07-20 21:35:48385 const auto* component = GetComponent(id);
sorin7c717622015-05-26 19:59:09386 if (component)
387 DoUnregisterComponent(*component);
388 }
389 }
sorin4c520182016-08-19 17:27:44390
391 if (!callback.is_null()) {
Sorin Jianuebd652462017-07-23 02:00:58392 base::ThreadTaskRunnerHandle::Get()->PostTask(
Vladislav Kuzkokov12eca792017-10-20 12:45:38393 FROM_HERE, base::BindOnce(std::move(callback), error));
sorin4c520182016-08-19 17:27:44394 }
sorin7c717622015-05-26 19:59:09395}
396
397void CrxUpdateService::OnEvent(Events event, const std::string& id) {
[email protected]ed6fb982014-07-23 16:56:52398 DCHECK(thread_checker_.CalledOnValidThread());
[email protected]93e8e2c2014-01-04 12:29:23399
sorin7c717622015-05-26 19:59:09400 // Unblock all throttles for the component.
401 if (event == Observer::Events::COMPONENT_UPDATED ||
Sorin Jianucbb10e12018-01-23 18:01:44402 event == Observer::Events::COMPONENT_NOT_UPDATED ||
403 event == Observer::Events::COMPONENT_UPDATE_ERROR) {
sorin7c717622015-05-26 19:59:09404 auto callbacks = ready_callbacks_.equal_range(id);
405 for (auto it = callbacks.first; it != callbacks.second; ++it) {
Sorin Jianua8ef73d2017-11-02 16:55:17406 std::move(it->second).Run();
sorin7c717622015-05-26 19:59:09407 }
408 ready_callbacks_.erase(id);
409 }
410
411 CrxUpdateItem update_item;
412 if (!update_client_->GetCrxUpdateState(id, &update_item))
[email protected]e8f96ff2011-08-03 05:07:33413 return;
[email protected]93e8e2c2014-01-04 12:29:23414
sorin7c717622015-05-26 19:59:09415 // Update the state of the item.
416 auto it = component_states_.find(id);
417 DCHECK(it != component_states_.end());
418 it->second = update_item;
bauerb1f6657e72015-02-09 00:00:27419
sorin7c717622015-05-26 19:59:09420 // Update the component registration with the new version.
421 if (event == Observer::Events::COMPONENT_UPDATED) {
vmpstr2de366b2016-07-20 21:35:48422 auto* component(const_cast<CrxComponent*>(GetComponent(id)));
sorin7c717622015-05-26 19:59:09423 if (component) {
424 component->version = update_item.next_version;
425 component->fingerprint = update_item.next_fp;
bauerb1f6657e72015-02-09 00:00:27426 }
427 }
[email protected]68bf09e2014-06-03 00:10:56428}
429
[email protected]00a77fa2013-11-02 04:18:46430///////////////////////////////////////////////////////////////////////////////
431
[email protected]e8f96ff2011-08-03 05:07:33432// The component update factory. Using the component updater as a singleton
433// is the job of the browser process.
sorin7c717622015-05-26 19:59:09434// TODO(sorin): consider making this a singleton.
dchenga0ee5fb82016-04-26 02:46:55435std::unique_ptr<ComponentUpdateService> ComponentUpdateServiceFactory(
Sorin Jianu49126332018-02-13 17:07:42436 scoped_refptr<Configurator> config) {
[email protected]e8f96ff2011-08-03 05:07:33437 DCHECK(config);
sorin7c717622015-05-26 19:59:09438 auto update_client = update_client::UpdateClientFactory(config);
Gyuyoung Kim6afb5082018-01-19 13:35:57439 return std::make_unique<CrxUpdateService>(config, std::move(update_client));
[email protected]e8f96ff2011-08-03 05:07:33440}
[email protected]2cddef42013-11-22 08:23:22441
[email protected]055981f2014-01-17 20:22:32442} // namespace component_updater