OLD | NEW |
| (Empty) |
1 // Copyright 2015 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/action_update.h" | |
6 | |
7 #include <vector> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/bind_helpers.h" | |
11 #include "base/callback.h" | |
12 #include "base/files/file_path.h" | |
13 #include "base/files/file_util.h" | |
14 #include "base/location.h" | |
15 #include "base/logging.h" | |
16 #include "base/threading/thread_task_runner_handle.h" | |
17 #include "base/time/time.h" | |
18 #include "base/values.h" | |
19 #include "base/version.h" | |
20 #include "components/update_client/component_unpacker.h" | |
21 #include "components/update_client/configurator.h" | |
22 #include "components/update_client/update_client_errors.h" | |
23 #include "components/update_client/utils.h" | |
24 | |
25 using std::string; | |
26 using std::vector; | |
27 | |
28 namespace update_client { | |
29 | |
30 namespace { | |
31 | |
32 void AppendDownloadMetrics( | |
33 const std::vector<CrxDownloader::DownloadMetrics>& source, | |
34 std::vector<CrxDownloader::DownloadMetrics>* destination) { | |
35 destination->insert(destination->end(), source.begin(), source.end()); | |
36 } | |
37 | |
38 } // namespace | |
39 | |
40 ActionUpdate::ActionUpdate() { | |
41 } | |
42 | |
43 ActionUpdate::~ActionUpdate() { | |
44 DCHECK(thread_checker_.CalledOnValidThread()); | |
45 } | |
46 | |
47 void ActionUpdate::Run(UpdateContext* update_context, Callback callback) { | |
48 DCHECK(thread_checker_.CalledOnValidThread()); | |
49 ActionImpl::Run(update_context, callback); | |
50 | |
51 DCHECK(!update_context_->queue.empty()); | |
52 | |
53 const std::string& id = update_context_->queue.front(); | |
54 CrxUpdateItem* item = FindUpdateItemById(id); | |
55 DCHECK(item); | |
56 | |
57 StartDownload(item); | |
58 } | |
59 | |
60 void ActionUpdate::StartDownload(CrxUpdateItem* item) { | |
61 DCHECK(thread_checker_.CalledOnValidThread()); | |
62 | |
63 crx_downloader_.reset((*update_context_->crx_downloader_factory)( | |
64 IsBackgroundDownload(item), | |
65 update_context_->config->RequestContext(), | |
66 update_context_->blocking_task_runner) | |
67 .release()); | |
68 OnDownloadStart(item); | |
69 | |
70 const std::string id = item->id; | |
71 crx_downloader_->set_progress_callback( | |
72 base::Bind(&ActionUpdate::DownloadProgress, base::Unretained(this), id)); | |
73 crx_downloader_->StartDownload( | |
74 GetUrls(item), GetHash(item), | |
75 base::Bind(&ActionUpdate::DownloadComplete, base::Unretained(this), id)); | |
76 } | |
77 | |
78 void ActionUpdate::DownloadProgress( | |
79 const std::string& id, | |
80 const CrxDownloader::Result& download_result) { | |
81 DCHECK(thread_checker_.CalledOnValidThread()); | |
82 DCHECK(id == update_context_->queue.front()); | |
83 | |
84 using Events = UpdateClient::Observer::Events; | |
85 NotifyObservers(Events::COMPONENT_UPDATE_DOWNLOADING, id); | |
86 } | |
87 | |
88 void ActionUpdate::DownloadComplete( | |
89 const std::string& id, | |
90 const CrxDownloader::Result& download_result) { | |
91 DCHECK(thread_checker_.CalledOnValidThread()); | |
92 DCHECK(id == update_context_->queue.front()); | |
93 | |
94 CrxUpdateItem* item = FindUpdateItemById(id); | |
95 DCHECK(item); | |
96 | |
97 AppendDownloadMetrics(crx_downloader_->download_metrics(), | |
98 &item->download_metrics); | |
99 | |
100 crx_downloader_.reset(); | |
101 | |
102 if (download_result.error) { | |
103 OnDownloadError(item, download_result); | |
104 } else { | |
105 OnDownloadSuccess(item, download_result); | |
106 update_context_->main_task_runner->PostTask( | |
107 FROM_HERE, | |
108 base::Bind(&ActionUpdate::StartInstall, base::Unretained(this), item, | |
109 download_result.response)); | |
110 } | |
111 } | |
112 | |
113 void ActionUpdate::StartInstall(CrxUpdateItem* item, | |
114 const base::FilePath& crx_path) { | |
115 DCHECK(thread_checker_.CalledOnValidThread()); | |
116 DCHECK(item->id == update_context_->queue.front()); | |
117 | |
118 OnInstallStart(item); | |
119 | |
120 update_context_->blocking_task_runner->PostTask( | |
121 FROM_HERE, base::Bind(&ActionUpdate::StartUnpackOnBlockingTaskRunner, | |
122 base::Unretained(this), item, crx_path)); | |
123 } | |
124 | |
125 void ActionUpdate::StartUnpackOnBlockingTaskRunner( | |
126 CrxUpdateItem* item, | |
127 const base::FilePath& crx_path) { | |
128 DCHECK(update_context_->blocking_task_runner->RunsTasksOnCurrentThread()); | |
129 unpacker_ = new ComponentUnpacker( | |
130 item->component.pk_hash, crx_path, | |
131 item->component.installer, | |
132 update_context_->config->CreateOutOfProcessPatcher(), | |
133 update_context_->blocking_task_runner); | |
134 unpacker_->Unpack( | |
135 base::Bind(&ActionUpdate::UnpackCompleteOnBlockingTaskRunner, | |
136 base::Unretained(this), item, crx_path)); | |
137 } | |
138 | |
139 void ActionUpdate::UnpackCompleteOnBlockingTaskRunner( | |
140 CrxUpdateItem* item, | |
141 const base::FilePath& crx_path, | |
142 const ComponentUnpacker::Result& result) { | |
143 DCHECK(update_context_->blocking_task_runner->RunsTasksOnCurrentThread()); | |
144 unpacker_ = nullptr; | |
145 | |
146 if (result.error == UnpackerError::kNone) { | |
147 update_context_->blocking_task_runner->PostTask( | |
148 FROM_HERE, | |
149 base::Bind(&ActionUpdate::StartInstallOnBlockingTaskRunner, | |
150 base::Unretained(this), item, crx_path, result.unpack_path)); | |
151 } else { | |
152 update_context_->blocking_task_runner->PostTask( | |
153 FROM_HERE, | |
154 base::Bind(&ActionUpdate::InstallCompleteOnBlockingTaskRunner, | |
155 base::Unretained(this), item, crx_path, | |
156 ErrorCategory::kUnpackError, static_cast<int>(result.error), | |
157 result.extended_error)); | |
158 } | |
159 } | |
160 | |
161 void ActionUpdate::StartInstallOnBlockingTaskRunner( | |
162 CrxUpdateItem* item, | |
163 const base::FilePath& crx_path, | |
164 const base::FilePath& unpack_path) { | |
165 DCHECK(update_context_->blocking_task_runner->RunsTasksOnCurrentThread()); | |
166 DCHECK(!unpack_path.empty()); | |
167 | |
168 const auto result = DoInstall(item, crx_path, unpack_path); | |
169 const ErrorCategory error_category = | |
170 result.error ? ErrorCategory::kInstallError : ErrorCategory::kErrorNone; | |
171 update_context_->blocking_task_runner->PostTask( | |
172 FROM_HERE, | |
173 base::Bind(&ActionUpdate::InstallCompleteOnBlockingTaskRunner, | |
174 base::Unretained(this), item, crx_path, error_category, | |
175 result.error, result.extended_error)); | |
176 } | |
177 | |
178 void ActionUpdate::InstallCompleteOnBlockingTaskRunner( | |
179 CrxUpdateItem* item, | |
180 const base::FilePath& crx_path, | |
181 ErrorCategory error_category, | |
182 int error, | |
183 int extended_error) { | |
184 update_client::DeleteFileAndEmptyParentDirectory(crx_path); | |
185 update_context_->main_task_runner->PostTask( | |
186 FROM_HERE, | |
187 base::Bind(&ActionUpdate::InstallComplete, base::Unretained(this), | |
188 item->id, error_category, error, extended_error)); | |
189 } | |
190 | |
191 CrxInstaller::Result ActionUpdate::DoInstall( | |
192 CrxUpdateItem* item, | |
193 const base::FilePath& crx_path, | |
194 const base::FilePath& unpack_path) { | |
195 const auto& fingerprint = item->next_fp; | |
196 if (static_cast<int>(fingerprint.size()) != | |
197 base::WriteFile( | |
198 unpack_path.Append(FILE_PATH_LITERAL("manifest.fingerprint")), | |
199 fingerprint.c_str(), base::checked_cast<int>(fingerprint.size()))) { | |
200 return CrxInstaller::Result(InstallError::FINGERPRINT_WRITE_FAILED); | |
201 } | |
202 | |
203 std::unique_ptr<base::DictionaryValue> manifest = ReadManifest(unpack_path); | |
204 if (!manifest.get()) | |
205 return CrxInstaller::Result(InstallError::BAD_MANIFEST); | |
206 | |
207 return item->component.installer->Install(*manifest, unpack_path); | |
208 } | |
209 | |
210 void ActionUpdate::InstallComplete(const std::string& id, | |
211 ErrorCategory error_category, | |
212 int error, | |
213 int extended_error) { | |
214 DCHECK(thread_checker_.CalledOnValidThread()); | |
215 DCHECK(id == update_context_->queue.front()); | |
216 | |
217 CrxUpdateItem* item = FindUpdateItemById(id); | |
218 DCHECK(item); | |
219 | |
220 if (error == 0) { | |
221 DCHECK_EQ(ErrorCategory::kErrorNone, error_category); | |
222 DCHECK_EQ(0, extended_error); | |
223 OnInstallSuccess(item); | |
224 } else { | |
225 OnInstallError(item, error_category, error, extended_error); | |
226 } | |
227 } | |
228 | |
229 ActionUpdateDiff::ActionUpdateDiff() { | |
230 } | |
231 | |
232 ActionUpdateDiff::~ActionUpdateDiff() { | |
233 DCHECK(thread_checker_.CalledOnValidThread()); | |
234 } | |
235 | |
236 std::unique_ptr<Action> ActionUpdateDiff::Create() { | |
237 return std::unique_ptr<Action>(new ActionUpdateDiff); | |
238 } | |
239 | |
240 void ActionUpdateDiff::TryUpdateFull() { | |
241 DCHECK(thread_checker_.CalledOnValidThread()); | |
242 std::unique_ptr<Action> update_action(ActionUpdateFull::Create()); | |
243 | |
244 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
245 FROM_HERE, base::Bind(&Action::Run, base::Unretained(update_action.get()), | |
246 update_context_, callback_)); | |
247 | |
248 update_context_->current_action = std::move(update_action); | |
249 } | |
250 | |
251 bool ActionUpdateDiff::IsBackgroundDownload(const CrxUpdateItem* item) { | |
252 DCHECK(thread_checker_.CalledOnValidThread()); | |
253 return false; | |
254 } | |
255 | |
256 std::vector<GURL> ActionUpdateDiff::GetUrls(const CrxUpdateItem* item) { | |
257 DCHECK(thread_checker_.CalledOnValidThread()); | |
258 return item->crx_diffurls; | |
259 } | |
260 | |
261 std::string ActionUpdateDiff::GetHash(const CrxUpdateItem* item) { | |
262 DCHECK(thread_checker_.CalledOnValidThread()); | |
263 return item->hashdiff_sha256; | |
264 } | |
265 | |
266 void ActionUpdateDiff::OnDownloadStart(CrxUpdateItem* item) { | |
267 DCHECK(thread_checker_.CalledOnValidThread()); | |
268 DCHECK(item->state == CrxUpdateItem::State::kCanUpdate); | |
269 | |
270 ChangeItemState(item, CrxUpdateItem::State::kDownloadingDiff); | |
271 } | |
272 | |
273 void ActionUpdateDiff::OnDownloadSuccess( | |
274 CrxUpdateItem* item, | |
275 const CrxDownloader::Result& download_result) { | |
276 DCHECK(thread_checker_.CalledOnValidThread()); | |
277 DCHECK(item->state == CrxUpdateItem::State::kDownloadingDiff); | |
278 | |
279 ChangeItemState(item, CrxUpdateItem::State::kDownloaded); | |
280 } | |
281 | |
282 void ActionUpdateDiff::OnDownloadError( | |
283 CrxUpdateItem* item, | |
284 const CrxDownloader::Result& download_result) { | |
285 DCHECK(thread_checker_.CalledOnValidThread()); | |
286 DCHECK(item->state == CrxUpdateItem::State::kDownloadingDiff); | |
287 | |
288 item->diff_error_category = static_cast<int>(ErrorCategory::kNetworkError); | |
289 item->diff_error_code = download_result.error; | |
290 item->diff_update_failed = true; | |
291 | |
292 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
293 FROM_HERE, | |
294 base::Bind(&ActionUpdateDiff::TryUpdateFull, base::Unretained(this))); | |
295 } | |
296 | |
297 void ActionUpdateDiff::OnInstallStart(CrxUpdateItem* item) { | |
298 DCHECK(thread_checker_.CalledOnValidThread()); | |
299 | |
300 ChangeItemState(item, CrxUpdateItem::State::kUpdatingDiff); | |
301 } | |
302 | |
303 void ActionUpdateDiff::OnInstallSuccess(CrxUpdateItem* item) { | |
304 DCHECK(thread_checker_.CalledOnValidThread()); | |
305 DCHECK(item->state == CrxUpdateItem::State::kUpdatingDiff); | |
306 | |
307 item->component.version = item->next_version; | |
308 item->component.fingerprint = item->next_fp; | |
309 ChangeItemState(item, CrxUpdateItem::State::kUpdated); | |
310 | |
311 UpdateCrxComplete(item); | |
312 } | |
313 | |
314 void ActionUpdateDiff::OnInstallError(CrxUpdateItem* item, | |
315 ErrorCategory error_category, | |
316 int error, | |
317 int extended_error) { | |
318 DCHECK(thread_checker_.CalledOnValidThread()); | |
319 | |
320 item->diff_error_category = static_cast<int>(error_category); | |
321 item->diff_error_code = error; | |
322 item->diff_extra_code1 = extended_error; | |
323 item->diff_update_failed = true; | |
324 | |
325 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
326 FROM_HERE, | |
327 base::Bind(&ActionUpdateDiff::TryUpdateFull, base::Unretained(this))); | |
328 } | |
329 | |
330 ActionUpdateFull::ActionUpdateFull() { | |
331 } | |
332 | |
333 ActionUpdateFull::~ActionUpdateFull() { | |
334 DCHECK(thread_checker_.CalledOnValidThread()); | |
335 } | |
336 | |
337 std::unique_ptr<Action> ActionUpdateFull::Create() { | |
338 return std::unique_ptr<Action>(new ActionUpdateFull); | |
339 } | |
340 | |
341 bool ActionUpdateFull::IsBackgroundDownload(const CrxUpdateItem* item) { | |
342 DCHECK(thread_checker_.CalledOnValidThread()); | |
343 | |
344 // On demand component updates are always downloaded in foreground. | |
345 return !item->on_demand && item->component.allows_background_download && | |
346 update_context_->config->EnabledBackgroundDownloader(); | |
347 } | |
348 | |
349 std::vector<GURL> ActionUpdateFull::GetUrls(const CrxUpdateItem* item) { | |
350 DCHECK(thread_checker_.CalledOnValidThread()); | |
351 return item->crx_urls; | |
352 } | |
353 | |
354 std::string ActionUpdateFull::GetHash(const CrxUpdateItem* item) { | |
355 DCHECK(thread_checker_.CalledOnValidThread()); | |
356 return item->hash_sha256; | |
357 } | |
358 | |
359 void ActionUpdateFull::OnDownloadStart(CrxUpdateItem* item) { | |
360 DCHECK(thread_checker_.CalledOnValidThread()); | |
361 DCHECK(item->state == CrxUpdateItem::State::kCanUpdate || | |
362 item->diff_update_failed); | |
363 | |
364 ChangeItemState(item, CrxUpdateItem::State::kDownloading); | |
365 } | |
366 | |
367 void ActionUpdateFull::OnDownloadSuccess( | |
368 CrxUpdateItem* item, | |
369 const CrxDownloader::Result& download_result) { | |
370 DCHECK(thread_checker_.CalledOnValidThread()); | |
371 DCHECK(item->state == CrxUpdateItem::State::kDownloading); | |
372 | |
373 ChangeItemState(item, CrxUpdateItem::State::kDownloaded); | |
374 } | |
375 | |
376 void ActionUpdateFull::OnDownloadError( | |
377 CrxUpdateItem* item, | |
378 const CrxDownloader::Result& download_result) { | |
379 DCHECK(thread_checker_.CalledOnValidThread()); | |
380 DCHECK(item->state == CrxUpdateItem::State::kDownloading); | |
381 | |
382 item->error_category = static_cast<int>(ErrorCategory::kNetworkError); | |
383 item->error_code = download_result.error; | |
384 ChangeItemState(item, CrxUpdateItem::State::kNoUpdate); | |
385 | |
386 UpdateCrxComplete(item); | |
387 } | |
388 | |
389 void ActionUpdateFull::OnInstallStart(CrxUpdateItem* item) { | |
390 DCHECK(thread_checker_.CalledOnValidThread()); | |
391 DCHECK(item->state == CrxUpdateItem::State::kDownloaded); | |
392 | |
393 ChangeItemState(item, CrxUpdateItem::State::kUpdating); | |
394 } | |
395 | |
396 void ActionUpdateFull::OnInstallSuccess(CrxUpdateItem* item) { | |
397 DCHECK(thread_checker_.CalledOnValidThread()); | |
398 DCHECK(item->state == CrxUpdateItem::State::kUpdating); | |
399 | |
400 item->component.version = item->next_version; | |
401 item->component.fingerprint = item->next_fp; | |
402 ChangeItemState(item, CrxUpdateItem::State::kUpdated); | |
403 | |
404 UpdateCrxComplete(item); | |
405 } | |
406 | |
407 void ActionUpdateFull::OnInstallError(CrxUpdateItem* item, | |
408 ErrorCategory error_category, | |
409 int error, | |
410 int extended_error) { | |
411 DCHECK(thread_checker_.CalledOnValidThread()); | |
412 DCHECK(item->state == CrxUpdateItem::State::kUpdating); | |
413 | |
414 item->error_category = static_cast<int>(error_category); | |
415 item->error_code = error; | |
416 item->extra_code1 = extended_error; | |
417 ChangeItemState(item, CrxUpdateItem::State::kNoUpdate); | |
418 | |
419 UpdateCrxComplete(item); | |
420 } | |
421 | |
422 } // namespace update_client | |
OLD | NEW |