blob: 3800d1926e54f6571a699b548a3db800a04f6112 [file] [log] [blame]
sorin30474f02017-04-27 00:45:481// Copyright 2017 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 "components/update_client/component.h"
6
7#include <algorithm>
8#include <utility>
9
10#include "base/bind.h"
sorin30474f02017-04-27 00:45:4811#include "base/files/file_util.h"
Sorin Jianuf40ab4b32017-10-06 22:53:4112#include "base/files/scoped_temp_dir.h"
sorin30474f02017-04-27 00:45:4813#include "base/location.h"
14#include "base/logging.h"
sorin30474f02017-04-27 00:45:4815#include "base/single_thread_task_runner.h"
Sorin Jianu039032b2018-10-12 21:48:1316#include "base/strings/string_number_conversions.h"
Gabriel Charette44db1422018-08-06 11:19:3317#include "base/task/post_task.h"
sorin30474f02017-04-27 00:45:4818#include "base/threading/thread_task_runner_handle.h"
Sorin Jianu039032b2018-10-12 21:48:1319#include "base/values.h"
Sorin Jianu4ab7c292017-06-15 18:40:2120#include "components/update_client/action_runner.h"
sorincca1c122017-05-11 17:43:2221#include "components/update_client/component_unpacker.h"
sorin30474f02017-04-27 00:45:4822#include "components/update_client/configurator.h"
Sorin Jianu75e6bf22019-02-12 16:07:1223#include "components/update_client/network.h"
Joshua Pawlickid5409e12019-04-06 00:23:1124#include "components/update_client/patcher.h"
Sorin Jianub9258672020-02-19 16:52:1725#include "components/update_client/persisted_data.h"
Sorin Jianu55587d32018-11-14 21:43:2726#include "components/update_client/protocol_definition.h"
Sorin Jianu039032b2018-10-12 21:48:1327#include "components/update_client/protocol_serializer.h"
Sorin Jianuebd652462017-07-23 02:00:5828#include "components/update_client/task_traits.h"
Joshua Pawlickid5409e12019-04-06 00:23:1129#include "components/update_client/unzipper.h"
sorin30474f02017-04-27 00:45:4830#include "components/update_client/update_client.h"
31#include "components/update_client/update_client_errors.h"
32#include "components/update_client/update_engine.h"
33#include "components/update_client/utils.h"
34
35// The state machine representing how a CRX component changes during an update.
36//
Sorin Jianu7c22795b2018-04-26 22:16:5237// +------------------------- kNew
38// | |
39// | V
40// | kChecking
41// | |
42// V error V no no
Sorin Jianu4ab7c292017-06-15 18:40:2143// kUpdateError <------------- [update?] -> [action?] -> kUpToDate kUpdated
44// ^ | | ^ ^
45// | yes | | yes | |
46// | V | | |
47// | kCanUpdate +--------> kRun |
48// | | |
49// | no V |
50// | +-<- [differential update?] |
51// | | | |
52// | | yes | |
53// | | error V |
54// | +-<----- kDownloadingDiff kRun---->-+
55// | | | ^ |
56// | | | yes | |
57// | | error V | |
58// | +-<----- kUpdatingDiff ---------> [action?] ->-+
59// | | ^ no
60// | error V |
61// +-<-------- kDownloading |
62// | | |
63// | | |
64// | error V |
65// +-<-------- kUpdating --------------------------------+
sorin30474f02017-04-27 00:45:4866
67namespace update_client {
68
69namespace {
70
Sorin Jianua8ef73d2017-11-02 16:55:1771using InstallOnBlockingTaskRunnerCompleteCallback = base::OnceCallback<
Minh X. Nguyena4640cb2018-05-23 21:29:1072 void(ErrorCategory error_category, int error_code, int extra_code1)>;
sorin30474f02017-04-27 00:45:4873
Sorin Jianuf40ab4b32017-10-06 22:53:4174void InstallComplete(
Sorin Jianu49126332018-02-13 17:07:4275 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
Sorin Jianua8ef73d2017-11-02 16:55:1776 InstallOnBlockingTaskRunnerCompleteCallback callback,
sorin30474f02017-04-27 00:45:4877 const base::FilePath& unpack_path,
Sorin Jianuf40ab4b32017-10-06 22:53:4178 const CrxInstaller::Result& result) {
Sami Kyostila14ca7642019-08-01 17:52:2579 base::PostTask(
80 FROM_HERE,
81 {base::ThreadPool(), base::TaskPriority::BEST_EFFORT, base::MayBlock()},
Sorin Jianuf40ab4b32017-10-06 22:53:4182 base::BindOnce(
Sorin Jianu49126332018-02-13 17:07:4283 [](scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
Sorin Jianua8ef73d2017-11-02 16:55:1784 InstallOnBlockingTaskRunnerCompleteCallback callback,
Sorin Jianuf40ab4b32017-10-06 22:53:4185 const base::FilePath& unpack_path,
86 const CrxInstaller::Result& result) {
Lei Zhang091d4232019-10-15 21:12:5187 base::DeleteFileRecursively(unpack_path);
Sorin Jianuf40ab4b32017-10-06 22:53:4188 const ErrorCategory error_category =
Sorin Jianuafcb70dd2018-05-16 20:14:1589 result.error ? ErrorCategory::kInstall : ErrorCategory::kNone;
Sorin Jianuf40ab4b32017-10-06 22:53:4190 main_task_runner->PostTask(
Minh X. Nguyena4640cb2018-05-23 21:29:1091 FROM_HERE, base::BindOnce(std::move(callback), error_category,
Sorin Jianua8ef73d2017-11-02 16:55:1792 static_cast<int>(result.error),
93 result.extended_error));
Sorin Jianuf40ab4b32017-10-06 22:53:4194 },
Sorin Jianua8ef73d2017-11-02 16:55:1795 main_task_runner, std::move(callback), unpack_path, result));
sorin30474f02017-04-27 00:45:4896}
97
98void InstallOnBlockingTaskRunner(
Sorin Jianu49126332018-02-13 17:07:4299 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
sorin30474f02017-04-27 00:45:48100 const base::FilePath& unpack_path,
Minh X. Nguyenaafd7632017-10-19 21:12:35101 const std::string& public_key,
sorin30474f02017-04-27 00:45:48102 const std::string& fingerprint,
Sorin Jianu9d64af672020-02-05 19:14:34103 std::unique_ptr<CrxInstaller::InstallParams> install_params,
Sorin Jianu49126332018-02-13 17:07:42104 scoped_refptr<CrxInstaller> installer,
Sorin Jianua8ef73d2017-11-02 16:55:17105 InstallOnBlockingTaskRunnerCompleteCallback callback) {
Sorin Jianu23f70f752017-05-30 16:21:58106 DCHECK(base::DirectoryExists(unpack_path));
sorin30474f02017-04-27 00:45:48107
Sorin Jianuf40ab4b32017-10-06 22:53:41108 // Acquire the ownership of the |unpack_path|.
109 base::ScopedTempDir unpack_path_owner;
110 ignore_result(unpack_path_owner.Set(unpack_path));
111
112 if (static_cast<int>(fingerprint.size()) !=
113 base::WriteFile(
114 unpack_path.Append(FILE_PATH_LITERAL("manifest.fingerprint")),
115 fingerprint.c_str(), base::checked_cast<int>(fingerprint.size()))) {
116 const CrxInstaller::Result result(InstallError::FINGERPRINT_WRITE_FAILED);
117 main_task_runner->PostTask(
118 FROM_HERE,
Minh X. Nguyena4640cb2018-05-23 21:29:10119 base::BindOnce(std::move(callback), ErrorCategory::kInstall,
Sorin Jianuf40ab4b32017-10-06 22:53:41120 static_cast<int>(result.error), result.extended_error));
121 return;
122 }
123
Sorin Jianua8ef73d2017-11-02 16:55:17124 installer->Install(
Sorin Jianu9d64af672020-02-05 19:14:34125 unpack_path, public_key, std::move(install_params),
Sorin Jianua8ef73d2017-11-02 16:55:17126 base::BindOnce(&InstallComplete, main_task_runner, std::move(callback),
127 unpack_path_owner.Take()));
sorin30474f02017-04-27 00:45:48128}
129
130void UnpackCompleteOnBlockingTaskRunner(
Sorin Jianu49126332018-02-13 17:07:42131 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
sorin30474f02017-04-27 00:45:48132 const base::FilePath& crx_path,
133 const std::string& fingerprint,
Sorin Jianu9d64af672020-02-05 19:14:34134 std::unique_ptr<CrxInstaller::InstallParams> install_params,
Sorin Jianu49126332018-02-13 17:07:42135 scoped_refptr<CrxInstaller> installer,
Sorin Jianua8ef73d2017-11-02 16:55:17136 InstallOnBlockingTaskRunnerCompleteCallback callback,
sorin30474f02017-04-27 00:45:48137 const ComponentUnpacker::Result& result) {
sorin30474f02017-04-27 00:45:48138 update_client::DeleteFileAndEmptyParentDirectory(crx_path);
139
140 if (result.error != UnpackerError::kNone) {
141 main_task_runner->PostTask(
142 FROM_HERE,
Minh X. Nguyena4640cb2018-05-23 21:29:10143 base::BindOnce(std::move(callback), ErrorCategory::kUnpack,
Sorin Jianuebd652462017-07-23 02:00:58144 static_cast<int>(result.error), result.extended_error));
sorin30474f02017-04-27 00:45:48145 return;
146 }
147
Sami Kyostila14ca7642019-08-01 17:52:25148 base::PostTask(FROM_HERE, kTaskTraits,
149 base::BindOnce(&InstallOnBlockingTaskRunner, main_task_runner,
150 result.unpack_path, result.public_key,
Sorin Jianu9d64af672020-02-05 19:14:34151 fingerprint, std::move(install_params),
152 installer, std::move(callback)));
sorin30474f02017-04-27 00:45:48153}
154
155void StartInstallOnBlockingTaskRunner(
Sorin Jianu49126332018-02-13 17:07:42156 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
sorin30474f02017-04-27 00:45:48157 const std::vector<uint8_t>& pk_hash,
158 const base::FilePath& crx_path,
159 const std::string& fingerprint,
Sorin Jianu9d64af672020-02-05 19:14:34160 std::unique_ptr<CrxInstaller::InstallParams> install_params,
Sorin Jianu49126332018-02-13 17:07:42161 scoped_refptr<CrxInstaller> installer,
Joshua Pawlickid5409e12019-04-06 00:23:11162 std::unique_ptr<Unzipper> unzipper_,
163 scoped_refptr<Patcher> patcher_,
Joshua Pawlickif4b33f382018-08-17 17:36:51164 crx_file::VerifierFormat crx_format,
Sorin Jianua8ef73d2017-11-02 16:55:17165 InstallOnBlockingTaskRunnerCompleteCallback callback) {
Taiju Tsuiki36c517d2017-05-18 06:45:43166 auto unpacker = base::MakeRefCounted<ComponentUnpacker>(
Joshua Pawlickid5409e12019-04-06 00:23:11167 pk_hash, crx_path, installer, std::move(unzipper_), std::move(patcher_),
168 crx_format);
sorin30474f02017-04-27 00:45:48169
Sorin Jianu9d64af672020-02-05 19:14:34170 unpacker->Unpack(base::BindOnce(
171 &UnpackCompleteOnBlockingTaskRunner, main_task_runner, crx_path,
172 fingerprint, std::move(install_params), installer, std::move(callback)));
sorin30474f02017-04-27 00:45:48173}
174
Sorin Jianu039032b2018-10-12 21:48:13175// Returns a string literal corresponding to the value of the downloader |d|.
176const char* DownloaderToString(CrxDownloader::DownloadMetrics::Downloader d) {
177 switch (d) {
178 case CrxDownloader::DownloadMetrics::kUrlFetcher:
179 return "direct";
180 case CrxDownloader::DownloadMetrics::kBits:
181 return "bits";
182 default:
183 return "unknown";
184 }
185}
186
sorin30474f02017-04-27 00:45:48187} // namespace
188
189Component::Component(const UpdateContext& update_context, const std::string& id)
190 : id_(id),
Jinho Bangda4e4282018-01-03 13:21:23191 state_(std::make_unique<StateNew>(this)),
sorin30474f02017-04-27 00:45:48192 update_context_(update_context) {}
193
194Component::~Component() {}
195
Sorin Jianub3296162017-12-13 20:26:32196scoped_refptr<Configurator> Component::config() const {
197 return update_context_.config;
198}
199
Sorin Jianud69d4372018-02-07 19:44:22200std::string Component::session_id() const {
201 return update_context_.session_id;
202}
203
Sorin Jianub41a592a2018-03-02 16:30:27204bool Component::is_foreground() const {
205 return update_context_.is_foreground;
206}
207
Sorin Jianuee5c0db2018-04-12 23:38:47208void Component::Handle(CallbackHandleComplete callback_handle_complete) {
sorin30474f02017-04-27 00:45:48209 DCHECK(thread_checker_.CalledOnValidThread());
210 DCHECK(state_);
211
Sorin Jianuee5c0db2018-04-12 23:38:47212 callback_handle_complete_ = std::move(callback_handle_complete);
sorin30474f02017-04-27 00:45:48213
Sorin Jianua8ef73d2017-11-02 16:55:17214 state_->Handle(
215 base::BindOnce(&Component::ChangeState, base::Unretained(this)));
sorin30474f02017-04-27 00:45:48216}
217
218void Component::ChangeState(std::unique_ptr<State> next_state) {
219 DCHECK(thread_checker_.CalledOnValidThread());
220
Sorin Jianu4ab7c292017-06-15 18:40:21221 previous_state_ = state();
sorin30474f02017-04-27 00:45:48222 if (next_state)
223 state_ = std::move(next_state);
Sorin Jianuee5c0db2018-04-12 23:38:47224 else
225 is_handled_ = true;
sorin30474f02017-04-27 00:45:48226
Sorin Jianua8ef73d2017-11-02 16:55:17227 base::ThreadTaskRunnerHandle::Get()->PostTask(
228 FROM_HERE, std::move(callback_handle_complete_));
sorin30474f02017-04-27 00:45:48229}
230
231CrxUpdateItem Component::GetCrxUpdateItem() const {
232 DCHECK(thread_checker_.CalledOnValidThread());
233
234 CrxUpdateItem crx_update_item;
235 crx_update_item.state = state_->state();
236 crx_update_item.id = id_;
Sorin Jianu7c22795b2018-04-26 22:16:52237 if (crx_component_)
238 crx_update_item.component = *crx_component_;
sorin30474f02017-04-27 00:45:48239 crx_update_item.last_check = last_check_;
240 crx_update_item.next_version = next_version_;
241 crx_update_item.next_fp = next_fp_;
Sorin Jianuafcb70dd2018-05-16 20:14:15242 crx_update_item.error_category = error_category_;
243 crx_update_item.error_code = error_code_;
244 crx_update_item.extra_code1 = extra_code1_;
Joshua Pawlickica4f8fa12020-02-25 23:46:06245 crx_update_item.custom_updatecheck_data = custom_attrs_;
sorin30474f02017-04-27 00:45:48246
247 return crx_update_item;
248}
249
sorin7cff6e52017-05-17 16:37:23250void Component::SetParseResult(const ProtocolParser::Result& result) {
sorin30474f02017-04-27 00:45:48251 DCHECK(thread_checker_.CalledOnValidThread());
252
253 DCHECK_EQ(0, update_check_error_);
254
255 status_ = result.status;
sorin519656c2017-04-28 22:39:34256 action_run_ = result.action_run;
Joshua Pawlickica4f8fa12020-02-25 23:46:06257 custom_attrs_ = result.custom_attributes;
sorin30474f02017-04-27 00:45:48258
259 if (result.manifest.packages.empty())
260 return;
261
262 next_version_ = base::Version(result.manifest.version);
263 const auto& package = result.manifest.packages.front();
264 next_fp_ = package.fingerprint;
265
266 // Resolve the urls by combining the base urls with the package names.
267 for (const auto& crx_url : result.crx_urls) {
268 const GURL url = crx_url.Resolve(package.name);
269 if (url.is_valid())
270 crx_urls_.push_back(url);
271 }
272 for (const auto& crx_diffurl : result.crx_diffurls) {
273 const GURL url = crx_diffurl.Resolve(package.namediff);
274 if (url.is_valid())
275 crx_diffurls_.push_back(url);
276 }
277
278 hash_sha256_ = package.hash_sha256;
279 hashdiff_sha256_ = package.hashdiff_sha256;
Sorin Jianu9d64af672020-02-05 19:14:34280
281 if (!result.manifest.run.empty()) {
282 install_params_ = base::make_optional(CrxInstaller::InstallParams(
283 result.manifest.run, result.manifest.arguments));
284 }
sorin30474f02017-04-27 00:45:48285}
286
287void Component::Uninstall(const base::Version& version, int reason) {
288 DCHECK(thread_checker_.CalledOnValidThread());
289
290 DCHECK_EQ(ComponentState::kNew, state());
291
Sorin Jianu73900242018-08-17 01:11:53292 crx_component_ = CrxComponent();
Sorin Jianu7c22795b2018-04-26 22:16:52293 crx_component_->version = version;
294
sorin30474f02017-04-27 00:45:48295 previous_version_ = version;
296 next_version_ = base::Version("0");
297 extra_code1_ = reason;
298
Jinho Bangda4e4282018-01-03 13:21:23299 state_ = std::make_unique<StateUninstalled>(this);
sorin30474f02017-04-27 00:45:48300}
301
Sorin Jianu888ec292018-06-01 15:35:42302void Component::SetUpdateCheckResult(
303 const base::Optional<ProtocolParser::Result>& result,
304 ErrorCategory error_category,
305 int error) {
sorin30474f02017-04-27 00:45:48306 DCHECK(thread_checker_.CalledOnValidThread());
sorin30474f02017-04-27 00:45:48307 DCHECK_EQ(ComponentState::kChecking, state());
308
Sorin Jianu888ec292018-06-01 15:35:42309 error_category_ = error_category;
310 error_code_ = error;
Joshua Pawlickica4f8fa12020-02-25 23:46:06311
Sorin Jianu888ec292018-06-01 15:35:42312 if (result)
313 SetParseResult(result.value());
314
Sorin Jianua8ef73d2017-11-02 16:55:17315 base::ThreadTaskRunnerHandle::Get()->PostTask(
316 FROM_HERE, std::move(update_check_complete_));
sorin30474f02017-04-27 00:45:48317}
318
319bool Component::CanDoBackgroundDownload() const {
Sorin Jianub41a592a2018-03-02 16:30:27320 // Foreground component updates are always downloaded in foreground.
Sorin Jianu7c22795b2018-04-26 22:16:52321 return !is_foreground() &&
322 (crx_component() && crx_component()->allows_background_download) &&
sorin30474f02017-04-27 00:45:48323 update_context_.config->EnabledBackgroundDownloader();
324}
325
Sorin Jianu039032b2018-10-12 21:48:13326void Component::AppendEvent(base::Value event) {
327 events_.push_back(std::move(event));
sorin30474f02017-04-27 00:45:48328}
329
330void Component::NotifyObservers(UpdateClient::Observer::Events event) const {
331 DCHECK(thread_checker_.CalledOnValidThread());
332 update_context_.notify_observers_callback.Run(event, id_);
333}
334
335base::TimeDelta Component::GetUpdateDuration() const {
336 DCHECK(thread_checker_.CalledOnValidThread());
337
338 if (update_begin_.is_null())
339 return base::TimeDelta();
340
341 const base::TimeDelta update_cost(base::TimeTicks::Now() - update_begin_);
342 DCHECK_GE(update_cost, base::TimeDelta());
343 const base::TimeDelta max_update_delay =
344 base::TimeDelta::FromSeconds(update_context_.config->UpdateDelay());
345 return std::min(update_cost, max_update_delay);
346}
347
Sorin Jianu039032b2018-10-12 21:48:13348base::Value Component::MakeEventUpdateComplete() const {
349 base::Value event(base::Value::Type::DICTIONARY);
350 event.SetKey("eventtype", base::Value(3));
351 event.SetKey(
352 "eventresult",
353 base::Value(static_cast<int>(state() == ComponentState::kUpdated)));
354 if (error_category() != ErrorCategory::kNone)
355 event.SetKey("errorcat", base::Value(static_cast<int>(error_category())));
356 if (error_code())
357 event.SetKey("errorcode", base::Value(error_code()));
358 if (extra_code1())
359 event.SetKey("extracode1", base::Value(extra_code1()));
360 if (HasDiffUpdate(*this)) {
361 const int diffresult = static_cast<int>(!diff_update_failed());
362 event.SetKey("diffresult", base::Value(diffresult));
363 }
364 if (diff_error_category() != ErrorCategory::kNone) {
365 const int differrorcat = static_cast<int>(diff_error_category());
366 event.SetKey("differrorcat", base::Value(differrorcat));
367 }
368 if (diff_error_code())
369 event.SetKey("differrorcode", base::Value(diff_error_code()));
370 if (diff_extra_code1())
371 event.SetKey("diffextracode1", base::Value(diff_extra_code1()));
372 if (!previous_fp().empty())
373 event.SetKey("previousfp", base::Value(previous_fp()));
374 if (!next_fp().empty())
375 event.SetKey("nextfp", base::Value(next_fp()));
376 DCHECK(previous_version().IsValid());
377 event.SetKey("previousversion", base::Value(previous_version().GetString()));
378 if (next_version().IsValid())
379 event.SetKey("nextversion", base::Value(next_version().GetString()));
380 return event;
381}
382
383base::Value Component::MakeEventDownloadMetrics(
384 const CrxDownloader::DownloadMetrics& dm) const {
385 base::Value event(base::Value::Type::DICTIONARY);
386 event.SetKey("eventtype", base::Value(14));
387 event.SetKey("eventresult", base::Value(static_cast<int>(dm.error == 0)));
388 event.SetKey("downloader", base::Value(DownloaderToString(dm.downloader)));
389 if (dm.error)
390 event.SetKey("errorcode", base::Value(dm.error));
391 event.SetKey("url", base::Value(dm.url.spec()));
392
393 // -1 means that the byte counts are not known.
Sorin Jianu55587d32018-11-14 21:43:27394 if (dm.total_bytes != -1 && dm.total_bytes < kProtocolMaxInt)
395 event.SetKey("total", base::Value(static_cast<double>(dm.total_bytes)));
396 if (dm.downloaded_bytes != -1 && dm.total_bytes < kProtocolMaxInt) {
Sorin Jianu039032b2018-10-12 21:48:13397 event.SetKey("downloaded",
Sorin Jianu55587d32018-11-14 21:43:27398 base::Value(static_cast<double>(dm.downloaded_bytes)));
Sorin Jianu039032b2018-10-12 21:48:13399 }
Sorin Jianu55587d32018-11-14 21:43:27400 if (dm.download_time_ms && dm.total_bytes < kProtocolMaxInt) {
Sorin Jianu039032b2018-10-12 21:48:13401 event.SetKey("download_time_ms",
Sorin Jianu55587d32018-11-14 21:43:27402 base::Value(static_cast<double>(dm.download_time_ms)));
Sorin Jianu039032b2018-10-12 21:48:13403 }
404 DCHECK(previous_version().IsValid());
405 event.SetKey("previousversion", base::Value(previous_version().GetString()));
406 if (next_version().IsValid())
407 event.SetKey("nextversion", base::Value(next_version().GetString()));
408 return event;
409}
410
411base::Value Component::MakeEventUninstalled() const {
412 DCHECK(state() == ComponentState::kUninstalled);
413 base::Value event(base::Value::Type::DICTIONARY);
414 event.SetKey("eventtype", base::Value(4));
415 event.SetKey("eventresult", base::Value(1));
416 if (extra_code1())
417 event.SetKey("extracode1", base::Value(extra_code1()));
418 DCHECK(previous_version().IsValid());
419 event.SetKey("previousversion", base::Value(previous_version().GetString()));
420 DCHECK(next_version().IsValid());
421 event.SetKey("nextversion", base::Value(next_version().GetString()));
422 return event;
423}
424
425base::Value Component::MakeEventActionRun(bool succeeded,
426 int error_code,
427 int extra_code1) const {
428 base::Value event(base::Value::Type::DICTIONARY);
429 event.SetKey("eventtype", base::Value(42));
430 event.SetKey("eventresult", base::Value(static_cast<int>(succeeded)));
431 if (error_code)
432 event.SetKey("errorcode", base::Value(error_code));
433 if (extra_code1)
434 event.SetKey("extracode1", base::Value(extra_code1));
435 return event;
436}
437
438std::vector<base::Value> Component::GetEvents() const {
439 std::vector<base::Value> events;
440 for (const auto& event : events_)
441 events.push_back(event.Clone());
442 return events;
443}
444
Sorin Jianu9d64af672020-02-05 19:14:34445std::unique_ptr<CrxInstaller::InstallParams> Component::install_params() const {
446 return install_params_
447 ? std::make_unique<CrxInstaller::InstallParams>(*install_params_)
448 : nullptr;
449}
450
sorin30474f02017-04-27 00:45:48451Component::State::State(Component* component, ComponentState state)
452 : state_(state), component_(*component) {}
453
454Component::State::~State() {}
455
Sorin Jianuee5c0db2018-04-12 23:38:47456void Component::State::Handle(CallbackNextState callback_next_state) {
sorin30474f02017-04-27 00:45:48457 DCHECK(thread_checker_.CalledOnValidThread());
458
Sorin Jianuee5c0db2018-04-12 23:38:47459 callback_next_state_ = std::move(callback_next_state);
sorin30474f02017-04-27 00:45:48460
sorin30474f02017-04-27 00:45:48461 DoHandle();
462}
463
464void Component::State::TransitionState(std::unique_ptr<State> next_state) {
Sorin Jianuee5c0db2018-04-12 23:38:47465 DCHECK(thread_checker_.CalledOnValidThread());
466 DCHECK(next_state);
sorin30474f02017-04-27 00:45:48467
468 base::ThreadTaskRunnerHandle::Get()->PostTask(
Sorin Jianuee5c0db2018-04-12 23:38:47469 FROM_HERE,
470 base::BindOnce(std::move(callback_next_state_), std::move(next_state)));
471}
472
473void Component::State::EndState() {
474 DCHECK(thread_checker_.CalledOnValidThread());
475
476 base::ThreadTaskRunnerHandle::Get()->PostTask(
477 FROM_HERE, base::BindOnce(std::move(callback_next_state_), nullptr));
sorin30474f02017-04-27 00:45:48478}
479
480Component::StateNew::StateNew(Component* component)
481 : State(component, ComponentState::kNew) {}
482
483Component::StateNew::~StateNew() {
484 DCHECK(thread_checker_.CalledOnValidThread());
485}
486
487void Component::StateNew::DoHandle() {
488 DCHECK(thread_checker_.CalledOnValidThread());
489
490 auto& component = State::component();
Sorin Jianucb4431a2018-04-30 20:59:24491 if (component.crx_component()) {
492 TransitionState(std::make_unique<StateChecking>(&component));
493 } else {
494 component.error_code_ = static_cast<int>(Error::CRX_NOT_FOUND);
Minh X. Nguyena4640cb2018-05-23 21:29:10495 component.error_category_ = ErrorCategory::kService;
Sorin Jianucb4431a2018-04-30 20:59:24496 TransitionState(std::make_unique<StateUpdateError>(&component));
497 }
sorin30474f02017-04-27 00:45:48498}
499
500Component::StateChecking::StateChecking(Component* component)
501 : State(component, ComponentState::kChecking) {}
502
503Component::StateChecking::~StateChecking() {
504 DCHECK(thread_checker_.CalledOnValidThread());
505}
506
507// Unlike how other states are handled, this function does not change the
508// state right away. The state transition happens when the UpdateChecker
509// calls Component::UpdateCheckComplete and |update_check_complete_| is invoked.
510// This is an artifact of how multiple components must be checked for updates
511// together but the state machine defines the transitions for one component
512// at a time.
513void Component::StateChecking::DoHandle() {
514 DCHECK(thread_checker_.CalledOnValidThread());
515
516 auto& component = State::component();
Sorin Jianu7c22795b2018-04-26 22:16:52517 DCHECK(component.crx_component());
sorin30474f02017-04-27 00:45:48518
519 component.last_check_ = base::TimeTicks::Now();
Sorin Jianua8ef73d2017-11-02 16:55:17520 component.update_check_complete_ = base::BindOnce(
sorin30474f02017-04-27 00:45:48521 &Component::StateChecking::UpdateCheckComplete, base::Unretained(this));
522
523 component.NotifyObservers(Events::COMPONENT_CHECKING_FOR_UPDATES);
524}
525
526void Component::StateChecking::UpdateCheckComplete() {
527 DCHECK(thread_checker_.CalledOnValidThread());
528 auto& component = State::component();
Sorin Jianuafcb70dd2018-05-16 20:14:15529 if (!component.error_code_) {
sorin30474f02017-04-27 00:45:48530 if (component.status_ == "ok") {
Jinho Bangda4e4282018-01-03 13:21:23531 TransitionState(std::make_unique<StateCanUpdate>(&component));
sorin30474f02017-04-27 00:45:48532 return;
533 }
534
535 if (component.status_ == "noupdate") {
Sorin Jianu4ab7c292017-06-15 18:40:21536 if (component.action_run_.empty())
Jinho Bangda4e4282018-01-03 13:21:23537 TransitionState(std::make_unique<StateUpToDate>(&component));
Sorin Jianu4ab7c292017-06-15 18:40:21538 else
Jinho Bangda4e4282018-01-03 13:21:23539 TransitionState(std::make_unique<StateRun>(&component));
sorin30474f02017-04-27 00:45:48540 return;
541 }
542 }
543
Jinho Bangda4e4282018-01-03 13:21:23544 TransitionState(std::make_unique<StateUpdateError>(&component));
sorin30474f02017-04-27 00:45:48545}
546
547Component::StateUpdateError::StateUpdateError(Component* component)
548 : State(component, ComponentState::kUpdateError) {}
549
550Component::StateUpdateError::~StateUpdateError() {
551 DCHECK(thread_checker_.CalledOnValidThread());
552}
553
554void Component::StateUpdateError::DoHandle() {
555 DCHECK(thread_checker_.CalledOnValidThread());
556
557 auto& component = State::component();
sorin117334f2017-05-19 02:36:25558
Sorin Jianu888ec292018-06-01 15:35:42559 DCHECK_NE(ErrorCategory::kNone, component.error_category_);
560 DCHECK_NE(0, component.error_code_);
561
sorin117334f2017-05-19 02:36:25562 // Create an event only when the server response included an update.
563 if (component.IsUpdateAvailable())
Sorin Jianu039032b2018-10-12 21:48:13564 component.AppendEvent(component.MakeEventUpdateComplete());
sorin117334f2017-05-19 02:36:25565
Sorin Jianuee5c0db2018-04-12 23:38:47566 EndState();
Sorin Jianucbb10e12018-01-23 18:01:44567 component.NotifyObservers(Events::COMPONENT_UPDATE_ERROR);
sorin30474f02017-04-27 00:45:48568}
569
570Component::StateCanUpdate::StateCanUpdate(Component* component)
571 : State(component, ComponentState::kCanUpdate) {}
572
573Component::StateCanUpdate::~StateCanUpdate() {
574 DCHECK(thread_checker_.CalledOnValidThread());
575}
576
577void Component::StateCanUpdate::DoHandle() {
578 DCHECK(thread_checker_.CalledOnValidThread());
579
580 auto& component = State::component();
Sorin Jianu7c22795b2018-04-26 22:16:52581 DCHECK(component.crx_component());
sorin30474f02017-04-27 00:45:48582
583 component.is_update_available_ = true;
584 component.NotifyObservers(Events::COMPONENT_UPDATE_FOUND);
585
Sorin Jianu7c22795b2018-04-26 22:16:52586 if (component.crx_component()
587 ->supports_group_policy_enable_component_updates &&
sorin30474f02017-04-27 00:45:48588 !component.update_context_.enabled_component_updates) {
Minh X. Nguyena4640cb2018-05-23 21:29:10589 component.error_category_ = ErrorCategory::kService;
sorin30474f02017-04-27 00:45:48590 component.error_code_ = static_cast<int>(ServiceError::UPDATE_DISABLED);
591 component.extra_code1_ = 0;
Jinho Bangda4e4282018-01-03 13:21:23592 TransitionState(std::make_unique<StateUpdateError>(&component));
sorin30474f02017-04-27 00:45:48593 return;
594 }
595
596 // Start computing the cost of the this update from here on.
597 component.update_begin_ = base::TimeTicks::Now();
598
599 if (CanTryDiffUpdate())
Jinho Bangda4e4282018-01-03 13:21:23600 TransitionState(std::make_unique<StateDownloadingDiff>(&component));
sorin30474f02017-04-27 00:45:48601 else
Jinho Bangda4e4282018-01-03 13:21:23602 TransitionState(std::make_unique<StateDownloading>(&component));
sorin30474f02017-04-27 00:45:48603}
604
605// Returns true if a differential update is available, it has not failed yet,
606// and the configuration allows this update.
607bool Component::StateCanUpdate::CanTryDiffUpdate() const {
608 const auto& component = Component::State::component();
609 return HasDiffUpdate(component) && !component.diff_error_code_ &&
610 component.update_context_.config->EnabledDeltas();
611}
612
613Component::StateUpToDate::StateUpToDate(Component* component)
614 : State(component, ComponentState::kUpToDate) {}
615
616Component::StateUpToDate::~StateUpToDate() {
617 DCHECK(thread_checker_.CalledOnValidThread());
618}
619
620void Component::StateUpToDate::DoHandle() {
621 DCHECK(thread_checker_.CalledOnValidThread());
622
623 auto& component = State::component();
Sorin Jianu7c22795b2018-04-26 22:16:52624 DCHECK(component.crx_component());
sorin30474f02017-04-27 00:45:48625
sorin30474f02017-04-27 00:45:48626 component.NotifyObservers(Events::COMPONENT_NOT_UPDATED);
Sorin Jianuee5c0db2018-04-12 23:38:47627 EndState();
sorin30474f02017-04-27 00:45:48628}
629
630Component::StateDownloadingDiff::StateDownloadingDiff(Component* component)
631 : State(component, ComponentState::kDownloadingDiff) {}
632
633Component::StateDownloadingDiff::~StateDownloadingDiff() {
634 DCHECK(thread_checker_.CalledOnValidThread());
635}
636
637void Component::StateDownloadingDiff::DoHandle() {
638 DCHECK(thread_checker_.CalledOnValidThread());
639
640 const auto& component = Component::State::component();
641 const auto& update_context = component.update_context_;
642
Sorin Jianu7c22795b2018-04-26 22:16:52643 DCHECK(component.crx_component());
644
sorin30474f02017-04-27 00:45:48645 crx_downloader_ = update_context.crx_downloader_factory(
646 component.CanDoBackgroundDownload(),
Sorin Jianu75e6bf22019-02-12 16:07:12647 update_context.config->GetNetworkFetcherFactory());
sorin30474f02017-04-27 00:45:48648
649 const auto& id = component.id_;
650 crx_downloader_->set_progress_callback(
Ken Rockot942a6382019-12-18 21:31:41651 base::BindRepeating(&Component::StateDownloadingDiff::DownloadProgress,
652 base::Unretained(this), id));
sorin30474f02017-04-27 00:45:48653 crx_downloader_->StartDownload(
654 component.crx_diffurls_, component.hashdiff_sha256_,
Sorin Jianua8ef73d2017-11-02 16:55:17655 base::BindOnce(&Component::StateDownloadingDiff::DownloadComplete,
656 base::Unretained(this), id));
sorin30474f02017-04-27 00:45:48657
658 component.NotifyObservers(Events::COMPONENT_UPDATE_DOWNLOADING);
659}
660
Antonio Gomes31237fb2018-08-27 19:11:03661// Called when progress is being made downloading a CRX. Can be called multiple
662// times due to how the CRX downloader switches between different downloaders
663// and fallback urls.
664void Component::StateDownloadingDiff::DownloadProgress(const std::string& id) {
sorin30474f02017-04-27 00:45:48665 DCHECK(thread_checker_.CalledOnValidThread());
666
667 component().NotifyObservers(Events::COMPONENT_UPDATE_DOWNLOADING);
668}
669
670void Component::StateDownloadingDiff::DownloadComplete(
671 const std::string& id,
672 const CrxDownloader::Result& download_result) {
673 DCHECK(thread_checker_.CalledOnValidThread());
674
675 auto& component = Component::State::component();
Sorin Jianu039032b2018-10-12 21:48:13676 for (const auto& download_metrics : crx_downloader_->download_metrics())
677 component.AppendEvent(component.MakeEventDownloadMetrics(download_metrics));
sorin30474f02017-04-27 00:45:48678
679 crx_downloader_.reset();
680
681 if (download_result.error) {
Sorin Jianu52de5fa2017-10-09 23:19:33682 DCHECK(download_result.response.empty());
Minh X. Nguyena4640cb2018-05-23 21:29:10683 component.diff_error_category_ = ErrorCategory::kDownload;
sorin30474f02017-04-27 00:45:48684 component.diff_error_code_ = download_result.error;
685
Jinho Bangda4e4282018-01-03 13:21:23686 TransitionState(std::make_unique<StateDownloading>(&component));
sorin30474f02017-04-27 00:45:48687 return;
688 }
689
690 component.crx_path_ = download_result.response;
691
Jinho Bangda4e4282018-01-03 13:21:23692 TransitionState(std::make_unique<StateUpdatingDiff>(&component));
sorin30474f02017-04-27 00:45:48693}
694
695Component::StateDownloading::StateDownloading(Component* component)
696 : State(component, ComponentState::kDownloading) {}
697
698Component::StateDownloading::~StateDownloading() {
699 DCHECK(thread_checker_.CalledOnValidThread());
700}
701
702void Component::StateDownloading::DoHandle() {
703 DCHECK(thread_checker_.CalledOnValidThread());
704
705 const auto& component = Component::State::component();
706 const auto& update_context = component.update_context_;
707
Sorin Jianu7c22795b2018-04-26 22:16:52708 DCHECK(component.crx_component());
709
sorin30474f02017-04-27 00:45:48710 crx_downloader_ = update_context.crx_downloader_factory(
711 component.CanDoBackgroundDownload(),
Sorin Jianu75e6bf22019-02-12 16:07:12712 update_context.config->GetNetworkFetcherFactory());
sorin30474f02017-04-27 00:45:48713
714 const auto& id = component.id_;
715 crx_downloader_->set_progress_callback(
Ken Rockot942a6382019-12-18 21:31:41716 base::BindRepeating(&Component::StateDownloading::DownloadProgress,
717 base::Unretained(this), id));
sorin30474f02017-04-27 00:45:48718 crx_downloader_->StartDownload(
719 component.crx_urls_, component.hash_sha256_,
Sorin Jianua8ef73d2017-11-02 16:55:17720 base::BindOnce(&Component::StateDownloading::DownloadComplete,
721 base::Unretained(this), id));
sorin30474f02017-04-27 00:45:48722
723 component.NotifyObservers(Events::COMPONENT_UPDATE_DOWNLOADING);
724}
725
Antonio Gomes31237fb2018-08-27 19:11:03726// Called when progress is being made downloading a CRX. Can be called multiple
727// times due to how the CRX downloader switches between different downloaders
728// and fallback urls.
729void Component::StateDownloading::DownloadProgress(const std::string& id) {
sorin30474f02017-04-27 00:45:48730 DCHECK(thread_checker_.CalledOnValidThread());
731
732 component().NotifyObservers(Events::COMPONENT_UPDATE_DOWNLOADING);
733}
734
735void Component::StateDownloading::DownloadComplete(
736 const std::string& id,
737 const CrxDownloader::Result& download_result) {
738 DCHECK(thread_checker_.CalledOnValidThread());
739
740 auto& component = Component::State::component();
741
Sorin Jianu039032b2018-10-12 21:48:13742 for (const auto& download_metrics : crx_downloader_->download_metrics())
743 component.AppendEvent(component.MakeEventDownloadMetrics(download_metrics));
sorin30474f02017-04-27 00:45:48744
745 crx_downloader_.reset();
746
747 if (download_result.error) {
Sorin Jianu52de5fa2017-10-09 23:19:33748 DCHECK(download_result.response.empty());
Minh X. Nguyena4640cb2018-05-23 21:29:10749 component.error_category_ = ErrorCategory::kDownload;
sorin30474f02017-04-27 00:45:48750 component.error_code_ = download_result.error;
751
Jinho Bangda4e4282018-01-03 13:21:23752 TransitionState(std::make_unique<StateUpdateError>(&component));
sorin30474f02017-04-27 00:45:48753 return;
754 }
755
756 component.crx_path_ = download_result.response;
757
Jinho Bangda4e4282018-01-03 13:21:23758 TransitionState(std::make_unique<StateUpdating>(&component));
sorin30474f02017-04-27 00:45:48759}
760
761Component::StateUpdatingDiff::StateUpdatingDiff(Component* component)
762 : State(component, ComponentState::kUpdatingDiff) {}
763
764Component::StateUpdatingDiff::~StateUpdatingDiff() {
765 DCHECK(thread_checker_.CalledOnValidThread());
766}
767
768void Component::StateUpdatingDiff::DoHandle() {
769 DCHECK(thread_checker_.CalledOnValidThread());
770
771 const auto& component = Component::State::component();
772 const auto& update_context = component.update_context_;
773
Sorin Jianu7c22795b2018-04-26 22:16:52774 DCHECK(component.crx_component());
775
sorin30474f02017-04-27 00:45:48776 component.NotifyObservers(Events::COMPONENT_UPDATE_READY);
777
Sami Kyostila14ca7642019-08-01 17:52:25778 base::CreateSequencedTaskRunner(kTaskTraits)
Sorin Jianua8ef73d2017-11-02 16:55:17779 ->PostTask(
780 FROM_HERE,
781 base::BindOnce(
782 &update_client::StartInstallOnBlockingTaskRunner,
783 base::ThreadTaskRunnerHandle::Get(),
Sorin Jianu7c22795b2018-04-26 22:16:52784 component.crx_component()->pk_hash, component.crx_path_,
Sorin Jianu9d64af672020-02-05 19:14:34785 component.next_fp_, component.install_params(),
786 component.crx_component()->installer,
Joshua Pawlickid5409e12019-04-06 00:23:11787 update_context.config->GetUnzipperFactory()->Create(),
788 update_context.config->GetPatcherFactory()->Create(),
Joshua Pawlickif4b33f382018-08-17 17:36:51789 component.crx_component()->crx_format_requirement,
Sorin Jianua8ef73d2017-11-02 16:55:17790 base::BindOnce(&Component::StateUpdatingDiff::InstallComplete,
791 base::Unretained(this))));
sorin30474f02017-04-27 00:45:48792}
793
Minh X. Nguyena4640cb2018-05-23 21:29:10794void Component::StateUpdatingDiff::InstallComplete(ErrorCategory error_category,
sorin30474f02017-04-27 00:45:48795 int error_code,
796 int extra_code1) {
797 DCHECK(thread_checker_.CalledOnValidThread());
798
799 auto& component = Component::State::component();
800
801 component.diff_error_category_ = error_category;
802 component.diff_error_code_ = error_code;
803 component.diff_extra_code1_ = extra_code1;
804
805 if (component.diff_error_code_ != 0) {
Jinho Bangda4e4282018-01-03 13:21:23806 TransitionState(std::make_unique<StateDownloading>(&component));
sorin30474f02017-04-27 00:45:48807 return;
808 }
809
Minh X. Nguyena4640cb2018-05-23 21:29:10810 DCHECK_EQ(ErrorCategory::kNone, component.diff_error_category_);
sorin30474f02017-04-27 00:45:48811 DCHECK_EQ(0, component.diff_error_code_);
812 DCHECK_EQ(0, component.diff_extra_code1_);
813
Minh X. Nguyena4640cb2018-05-23 21:29:10814 DCHECK_EQ(ErrorCategory::kNone, component.error_category_);
sorin30474f02017-04-27 00:45:48815 DCHECK_EQ(0, component.error_code_);
816 DCHECK_EQ(0, component.extra_code1_);
817
Sorin Jianu4ab7c292017-06-15 18:40:21818 if (component.action_run_.empty())
Jinho Bangda4e4282018-01-03 13:21:23819 TransitionState(std::make_unique<StateUpdated>(&component));
Sorin Jianu4ab7c292017-06-15 18:40:21820 else
Jinho Bangda4e4282018-01-03 13:21:23821 TransitionState(std::make_unique<StateRun>(&component));
sorin30474f02017-04-27 00:45:48822}
823
824Component::StateUpdating::StateUpdating(Component* component)
sorinff403ef2017-05-16 21:48:42825 : State(component, ComponentState::kUpdating) {}
sorin30474f02017-04-27 00:45:48826
827Component::StateUpdating::~StateUpdating() {
828 DCHECK(thread_checker_.CalledOnValidThread());
829}
830
831void Component::StateUpdating::DoHandle() {
832 DCHECK(thread_checker_.CalledOnValidThread());
833
834 const auto& component = Component::State::component();
835 const auto& update_context = component.update_context_;
836
Sorin Jianu7c22795b2018-04-26 22:16:52837 DCHECK(component.crx_component());
838
sorin30474f02017-04-27 00:45:48839 component.NotifyObservers(Events::COMPONENT_UPDATE_READY);
840
Sami Kyostila14ca7642019-08-01 17:52:25841 base::CreateSequencedTaskRunner(kTaskTraits)
Sorin Jianua8ef73d2017-11-02 16:55:17842 ->PostTask(FROM_HERE,
843 base::BindOnce(
844 &update_client::StartInstallOnBlockingTaskRunner,
845 base::ThreadTaskRunnerHandle::Get(),
Sorin Jianu7c22795b2018-04-26 22:16:52846 component.crx_component()->pk_hash, component.crx_path_,
Sorin Jianu9d64af672020-02-05 19:14:34847 component.next_fp_, component.install_params(),
848 component.crx_component()->installer,
Joshua Pawlickid5409e12019-04-06 00:23:11849 update_context.config->GetUnzipperFactory()->Create(),
850 update_context.config->GetPatcherFactory()->Create(),
Joshua Pawlickif4b33f382018-08-17 17:36:51851 component.crx_component()->crx_format_requirement,
Sorin Jianua8ef73d2017-11-02 16:55:17852 base::BindOnce(&Component::StateUpdating::InstallComplete,
Sorin Jianuebd652462017-07-23 02:00:58853 base::Unretained(this))));
sorin30474f02017-04-27 00:45:48854}
855
Minh X. Nguyena4640cb2018-05-23 21:29:10856void Component::StateUpdating::InstallComplete(ErrorCategory error_category,
sorin30474f02017-04-27 00:45:48857 int error_code,
858 int extra_code1) {
859 DCHECK(thread_checker_.CalledOnValidThread());
860
861 auto& component = Component::State::component();
862
863 component.error_category_ = error_category;
864 component.error_code_ = error_code;
865 component.extra_code1_ = extra_code1;
866
867 if (component.error_code_ != 0) {
Jinho Bangda4e4282018-01-03 13:21:23868 TransitionState(std::make_unique<StateUpdateError>(&component));
sorin30474f02017-04-27 00:45:48869 return;
870 }
871
Minh X. Nguyena4640cb2018-05-23 21:29:10872 DCHECK_EQ(ErrorCategory::kNone, component.error_category_);
sorin30474f02017-04-27 00:45:48873 DCHECK_EQ(0, component.error_code_);
874 DCHECK_EQ(0, component.extra_code1_);
875
Sorin Jianu4ab7c292017-06-15 18:40:21876 if (component.action_run_.empty())
Jinho Bangda4e4282018-01-03 13:21:23877 TransitionState(std::make_unique<StateUpdated>(&component));
Sorin Jianu4ab7c292017-06-15 18:40:21878 else
Jinho Bangda4e4282018-01-03 13:21:23879 TransitionState(std::make_unique<StateRun>(&component));
sorin30474f02017-04-27 00:45:48880}
881
882Component::StateUpdated::StateUpdated(Component* component)
883 : State(component, ComponentState::kUpdated) {
884 DCHECK(thread_checker_.CalledOnValidThread());
885}
886
887Component::StateUpdated::~StateUpdated() {
888 DCHECK(thread_checker_.CalledOnValidThread());
889}
890
891void Component::StateUpdated::DoHandle() {
892 DCHECK(thread_checker_.CalledOnValidThread());
893
894 auto& component = State::component();
Sorin Jianu7c22795b2018-04-26 22:16:52895 DCHECK(component.crx_component());
896
897 component.crx_component_->version = component.next_version_;
898 component.crx_component_->fingerprint = component.next_fp_;
sorin30474f02017-04-27 00:45:48899
Sorin Jianub9258672020-02-19 16:52:17900 component.update_context_.persisted_data->SetProductVersion(
901 component.id(), component.crx_component_->version);
902 component.update_context_.persisted_data->SetFingerprint(
903 component.id(), component.crx_component_->fingerprint);
904
Sorin Jianu039032b2018-10-12 21:48:13905 component.AppendEvent(component.MakeEventUpdateComplete());
sorin117334f2017-05-19 02:36:25906
sorin30474f02017-04-27 00:45:48907 component.NotifyObservers(Events::COMPONENT_UPDATED);
Sorin Jianuee5c0db2018-04-12 23:38:47908 EndState();
sorin30474f02017-04-27 00:45:48909}
910
911Component::StateUninstalled::StateUninstalled(Component* component)
912 : State(component, ComponentState::kUninstalled) {
913 DCHECK(thread_checker_.CalledOnValidThread());
914}
915
916Component::StateUninstalled::~StateUninstalled() {
917 DCHECK(thread_checker_.CalledOnValidThread());
918}
919
920void Component::StateUninstalled::DoHandle() {
921 DCHECK(thread_checker_.CalledOnValidThread());
sorin117334f2017-05-19 02:36:25922
923 auto& component = State::component();
Sorin Jianu7c22795b2018-04-26 22:16:52924 DCHECK(component.crx_component());
925
Sorin Jianu039032b2018-10-12 21:48:13926 component.AppendEvent(component.MakeEventUninstalled());
sorin117334f2017-05-19 02:36:25927
Sorin Jianuee5c0db2018-04-12 23:38:47928 EndState();
sorin30474f02017-04-27 00:45:48929}
930
Sorin Jianu4ab7c292017-06-15 18:40:21931Component::StateRun::StateRun(Component* component)
932 : State(component, ComponentState::kRun) {}
933
934Component::StateRun::~StateRun() {
935 DCHECK(thread_checker_.CalledOnValidThread());
936}
937
938void Component::StateRun::DoHandle() {
939 DCHECK(thread_checker_.CalledOnValidThread());
940
941 const auto& component = State::component();
Sorin Jianu7c22795b2018-04-26 22:16:52942 DCHECK(component.crx_component());
943
Jinho Bangda4e4282018-01-03 13:21:23944 action_runner_ = std::make_unique<ActionRunner>(component);
Sorin Jianu4ab7c292017-06-15 18:40:21945 action_runner_->Run(
Sorin Jianua8ef73d2017-11-02 16:55:17946 base::BindOnce(&StateRun::ActionRunComplete, base::Unretained(this)));
Sorin Jianu4ab7c292017-06-15 18:40:21947}
948
949void Component::StateRun::ActionRunComplete(bool succeeded,
950 int error_code,
951 int extra_code1) {
952 DCHECK(thread_checker_.CalledOnValidThread());
953
954 auto& component = State::component();
955
956 component.AppendEvent(
Sorin Jianu039032b2018-10-12 21:48:13957 component.MakeEventActionRun(succeeded, error_code, extra_code1));
Sorin Jianu4ab7c292017-06-15 18:40:21958 switch (component.previous_state_) {
959 case ComponentState::kChecking:
Jinho Bangda4e4282018-01-03 13:21:23960 TransitionState(std::make_unique<StateUpToDate>(&component));
Sorin Jianu4ab7c292017-06-15 18:40:21961 return;
962 case ComponentState::kUpdating:
963 case ComponentState::kUpdatingDiff:
Jinho Bangda4e4282018-01-03 13:21:23964 TransitionState(std::make_unique<StateUpdated>(&component));
Sorin Jianu4ab7c292017-06-15 18:40:21965 return;
966 default:
967 break;
968 }
969 NOTREACHED();
970}
971
sorin30474f02017-04-27 00:45:48972} // namespace update_client