103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 2a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// found in the LICENSE file. 4a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "components/component_updater/background_downloader_win.h" 6a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 7a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <atlbase.h> 8a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <atlcom.h> 9a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <stdint.h> 11a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <functional> 12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <iomanip> 131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <limits> 14a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <vector> 15a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/bind.h" 171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/bind_helpers.h" 181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h" 195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/message_loop/message_loop_proxy.h" 205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/single_thread_task_runner.h" 21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/strings/sys_string_conversions.h" 22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/win/scoped_co_mem.h" 2303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "components/component_updater/component_updater_utils.h" 24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/base/win/atl_module.h" 25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "url/gurl.h" 26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 27a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)using base::win::ScopedCoMem; 28a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)using base::win::ScopedComPtr; 29a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// The class BackgroundDownloader in this module is an adapter between 31a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// the CrxDownloader interface and the BITS service interfaces. 325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// The interface exposed on the CrxDownloader code runs on the main thread, 335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// while the BITS specific code runs on a separate thread passed in by the 345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// client. For every url to download, a BITS job is created, unless there is 355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// already an existing job for that url, in which case, the downloader 365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// connects to it. Once a job is associated with the url, the code looks for 375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// changes in the BITS job state. The checks are triggered by a timer. 38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// The BITS job contains just one file to download. There could only be one 39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// download in progress at a time. If Chrome closes down before the download is 40a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// complete, the BITS job remains active and finishes in the background, without 41a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// any intervention. The job can be completed next time the code runs, if the 42a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// file is still needed, otherwise it will be cleaned up on a periodic basis. 43a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// 44a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// To list the BITS jobs for a user, use the |bitsadmin| tool. The command line 45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// to do that is: "bitsadmin /list /verbose". Another useful command is 46a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// "bitsadmin /info" and provide the job id returned by the previous /list 47a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// command. 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Ignoring the suspend/resume issues since this code is not using them, the 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// job state machine implemented by BITS is something like this: 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Suspended--->Queued--->Connecting---->Transferring--->Transferred 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// | ^ | | | 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// | | V V | (complete) 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// +----------|---------+-----------------+-----+ V 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// | | | | Acknowledged 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// | V V | 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// | Transient Error------->Error | 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// | | | |(cancel) 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// | +-------+---------+--->-+ 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// | V | 625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// | (resume) | | 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// +------<----------+ +---->Cancelled 645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// 655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// The job is created in the "suspended" state. Once |Resume| is called, 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// BITS queues up the job, then tries to connect, begins transferring the 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// job bytes, and moves the job to the "transferred state, after the job files 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// have been transferred. When calling |Complete| for a job, the job files are 695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// made available to the caller, and the job is moved to the "acknowledged" 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// state. 715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// At any point, the job can be cancelled, in which case, the job is moved 725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// to the "cancelled state" and the job object is removed from the BITS queue. 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Along the way, the job can encounter recoverable and non-recoverable errors. 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// BITS moves the job to "transient error" or "error", depending on which kind 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// of error has occured. 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// If the job has reached the "transient error" state, BITS retries the 775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// job after a certain programmable delay. If the job can't be completed in a 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// certain time interval, BITS stops retrying and errors the job out. This time 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// interval is also programmable. 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// If the job is in either of the error states, the job parameters can be 815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// adjusted to handle the error, after which the job can be resumed, and the 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// whole cycle starts again. 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Jobs that are not touched in 90 days (or a value set by group policy) are 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// automatically disposed off by BITS. This concludes the brief description of 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// a job lifetime, according to BITS. 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// In addition to how BITS is managing the life time of the job, there are a 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// couple of special cases defined by the BackgroundDownloader. 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// First, if the job encounters any of the 5xx HTTP responses, the job is 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// not retried, in order to avoid DDOS-ing the servers. 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Second, there is a simple mechanism to detect stuck jobs, and allow the rest 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// of the code to move on to trying other urls or trying other components. 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Last, after completing a job, irrespective of the outcome, the jobs older 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// than a week are proactively cleaned up. 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace component_updater { 97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace { 99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// All jobs created by this module have a specific description so they can 101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// be found at run-time or by using system administration tools. 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const base::char16 kJobDescription[] = L"Chrome Component Updater"; 103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 104a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// How often the code looks for changes in the BITS job state. 105010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)const int kJobPollingIntervalSec = 4; 106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// How long BITS waits before retrying a job after the job encountered 1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// a transient error. If this value is not set, the BITS default is 10 minutes. 1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kMinimumRetryDelayMin = 1; 1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// How long to wait for stuck jobs. Stuck jobs could be queued for too long, 1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// have trouble connecting, could be suspended for any reason, or they have 1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// encountered some transient error. 1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kJobStuckTimeoutMin = 15; 1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// How long BITS waits before giving up on a job that could not be completed 1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// since the job has encountered its first transient error. If this value is 1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// not set, the BITS default is 14 days. 1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kSetNoProgressTimeoutDays = 1; 1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// How often the jobs which were started but not completed for any reason 122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// are cleaned up. Reasons for jobs to be left behind include browser restarts, 123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// system restarts, etc. Also, the check to purge stale jobs only happens 1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// at most once a day. If the job clean up code is not running, the BITS 1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// default policy is to cancel jobs after 90 days of inactivity. 126a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const int kPurgeStaleJobsAfterDays = 7; 127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const int kPurgeStaleJobsIntervalBetweenChecksDays = 1; 128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Returns the status code from a given BITS error. 130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)int GetHttpStatusFromBitsError(HRESULT error) { 131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // BITS errors are defined in bitsmsg.h. Although not documented, it is 132a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // clear that all errors corresponding to http status code have the high 133a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // word equal to 0x8019 and the low word equal to the http status code. 134010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const int kHttpStatusFirst = 100; // Continue. 135010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const int kHttpStatusLast = 505; // Version not supported. 136a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) bool is_valid = HIWORD(error) == 0x8019 && 137a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) LOWORD(error) >= kHttpStatusFirst && 138a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) LOWORD(error) <= kHttpStatusLast; 139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return is_valid ? LOWORD(error) : 0; 140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Returns the files in a BITS job. 143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)HRESULT GetFilesInJob(IBackgroundCopyJob* job, 144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::vector<ScopedComPtr<IBackgroundCopyFile> >* files) { 145a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ScopedComPtr<IEnumBackgroundCopyFiles> enum_files; 146a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) HRESULT hr = job->EnumFiles(enum_files.Receive()); 147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (FAILED(hr)) 148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return hr; 149a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 150a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ULONG num_files = 0; 151a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) hr = enum_files->GetCount(&num_files); 152a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (FAILED(hr)) 153a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return hr; 154a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 155a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) for (ULONG i = 0; i != num_files; ++i) { 156a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ScopedComPtr<IBackgroundCopyFile> file; 157010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (enum_files->Next(1, file.Receive(), NULL) == S_OK && file) 158a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) files->push_back(file); 159a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 160a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 161a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return S_OK; 162a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 163a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 164a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Returns the file name, the url, and some per-file progress information. 165a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// The function out parameters can be NULL if that data is not requested. 166a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)HRESULT GetJobFileProperties(IBackgroundCopyFile* file, 167a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16* local_name, 168a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16* remote_name, 169a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) BG_FILE_PROGRESS* progress) { 170010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (!file) 171010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return E_FAIL; 172010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 173a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) HRESULT hr = S_OK; 174a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 175a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (local_name) { 1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ScopedCoMem<base::char16> name; 177a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) hr = file->GetLocalName(&name); 178a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (FAILED(hr)) 179a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return hr; 180a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) local_name->assign(name); 181a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 182a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 183a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (remote_name) { 1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ScopedCoMem<base::char16> name; 185a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) hr = file->GetRemoteName(&name); 186a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (FAILED(hr)) 187a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return hr; 188a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) remote_name->assign(name); 189a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 190a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 191a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (progress) { 192a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) BG_FILE_PROGRESS bg_file_progress = {}; 193a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) hr = file->GetProgress(&bg_file_progress); 194a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (FAILED(hr)) 195a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return hr; 196a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) *progress = bg_file_progress; 197a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 198a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 199a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return hr; 200a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 201a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Returns the number of bytes downloaded and bytes to download for all files 2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// in the job. If the values are not known or if an error has occurred, 2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// a value of -1 is reported. 2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HRESULT GetJobByteCount(IBackgroundCopyJob* job, 2061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int64_t* downloaded_bytes, 2071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int64_t* total_bytes) { 208010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) *downloaded_bytes = -1; 209010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) *total_bytes = -1; 2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!job) 2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return E_FAIL; 2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) BG_JOB_PROGRESS job_progress = {0}; 2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HRESULT hr = job->GetProgress(&job_progress); 2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (FAILED(hr)) 2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return hr; 2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const uint64_t kMaxNumBytes = 2201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci static_cast<uint64_t>(std::numeric_limits<int64_t>::max()); 2211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (job_progress.BytesTransferred <= kMaxNumBytes) 222010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) *downloaded_bytes = job_progress.BytesTransferred; 2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (job_progress.BytesTotal <= kMaxNumBytes && 2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) job_progress.BytesTotal != BG_SIZE_UNKNOWN) 226010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) *total_bytes = job_progress.BytesTotal; 2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return S_OK; 2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 231a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)HRESULT GetJobDescription(IBackgroundCopyJob* job, const base::string16* name) { 2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ScopedCoMem<base::char16> description; 233a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return job->GetDescription(&description); 234a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 235a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Returns the job error code in |error_code| if the job is in the transient 2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// or the final error state. Otherwise, the job error is not available and 2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// the function fails. 2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HRESULT GetJobError(IBackgroundCopyJob* job, HRESULT* error_code_out) { 2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) *error_code_out = S_OK; 2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ScopedComPtr<IBackgroundCopyError> copy_error; 2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HRESULT hr = job->GetError(copy_error.Receive()); 2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (FAILED(hr)) 2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return hr; 2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) BG_ERROR_CONTEXT error_context = BG_ERROR_CONTEXT_NONE; 2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HRESULT error_code = S_OK; 2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) hr = copy_error->GetError(&error_context, &error_code); 2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (FAILED(hr)) 2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return hr; 2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) *error_code_out = FAILED(error_code) ? error_code : E_FAIL; 2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return S_OK; 2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 256a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Finds the component updater jobs matching the given predicate. 257a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Returns S_OK if the function has found at least one job, returns S_FALSE if 258a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// no job was found, and it returns an error otherwise. 259010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)template <class Predicate> 260a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)HRESULT FindBitsJobIf(Predicate pred, 261a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) IBackgroundCopyManager* bits_manager, 262a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::vector<ScopedComPtr<IBackgroundCopyJob> >* jobs) { 263a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ScopedComPtr<IEnumBackgroundCopyJobs> enum_jobs; 264a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) HRESULT hr = bits_manager->EnumJobs(0, enum_jobs.Receive()); 265a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (FAILED(hr)) 266a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return hr; 267a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 268a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ULONG job_count = 0; 269a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) hr = enum_jobs->GetCount(&job_count); 270a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (FAILED(hr)) 271a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return hr; 272a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 273a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Iterate over jobs, run the predicate, and select the job only if 274a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // the job description matches the component updater jobs. 275a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) for (ULONG i = 0; i != job_count; ++i) { 276a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ScopedComPtr<IBackgroundCopyJob> current_job; 277a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (enum_jobs->Next(1, current_job.Receive(), NULL) == S_OK && 278a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) pred(current_job)) { 279a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 job_description; 280a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) hr = GetJobDescription(current_job, &job_description); 281a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (job_description.compare(kJobDescription) == 0) 282a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) jobs->push_back(current_job); 283a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 284a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 285a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 286a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return jobs->empty() ? S_FALSE : S_OK; 287a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 288a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 289a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Compares the job creation time and returns true if the job creation time 290a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// is older than |num_days|. 291a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)struct JobCreationOlderThanDays 292a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) : public std::binary_function<IBackgroundCopyJob*, int, bool> { 293a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) bool operator()(IBackgroundCopyJob* job, int num_days) const; 294a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}; 295a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 296a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool JobCreationOlderThanDays::operator()(IBackgroundCopyJob* job, 297a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) int num_days) const { 298a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) BG_JOB_TIMES times = {0}; 299a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) HRESULT hr = job->GetTimes(×); 300a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (FAILED(hr)) 301a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return false; 302a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 303a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::TimeDelta time_delta(base::TimeDelta::FromDays(num_days)); 304a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::Time creation_time(base::Time::FromFileTime(times.CreationTime)); 305a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 306a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return creation_time + time_delta < base::Time::Now(); 307a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 308a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 309a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Compares the url of a file in a job and returns true if the remote name 310a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// of any file in a job matches the argument. 311010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)struct JobFileUrlEqual : public std::binary_function<IBackgroundCopyJob*, 312010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const base::string16&, 313010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) bool> { 314a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) bool operator()(IBackgroundCopyJob* job, 315a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16& remote_name) const; 316a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}; 317a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 318a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool JobFileUrlEqual::operator()(IBackgroundCopyJob* job, 319a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16& remote_name) const { 320a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::vector<ScopedComPtr<IBackgroundCopyFile> > files; 321a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) HRESULT hr = GetFilesInJob(job, &files); 322a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (FAILED(hr)) 323a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return false; 324a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 325a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) for (size_t i = 0; i != files.size(); ++i) { 3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ScopedCoMem<base::char16> name; 327a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (SUCCEEDED(files[i]->GetRemoteName(&name)) && 328a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) remote_name.compare(name) == 0) 329a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return true; 330a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 331a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 332a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return false; 333a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 334a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 335a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Creates an instance of the BITS manager. 336a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)HRESULT GetBitsManager(IBackgroundCopyManager** bits_manager) { 337a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ScopedComPtr<IBackgroundCopyManager> object; 338a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) HRESULT hr = object.CreateInstance(__uuidof(BackgroundCopyManager)); 339a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (FAILED(hr)) { 340a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return hr; 341a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 342a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) *bits_manager = object.Detach(); 343a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return S_OK; 344a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 345a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void CleanupJobFiles(IBackgroundCopyJob* job) { 3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::vector<ScopedComPtr<IBackgroundCopyFile> > files; 3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (FAILED(GetFilesInJob(job, &files))) 3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (size_t i = 0; i != files.size(); ++i) { 3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 local_name; 3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HRESULT hr(GetJobFileProperties(files[i], &local_name, NULL, NULL)); 3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (SUCCEEDED(hr)) 3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DeleteFileAndEmptyParentDirectory(base::FilePath(local_name)); 3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Cleans up incompleted jobs that are too old. 3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HRESULT CleanupStaleJobs( 3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::win::ScopedComPtr<IBackgroundCopyManager> bits_manager) { 3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!bits_manager) 3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return E_FAIL; 3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) static base::Time last_sweep; 3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 366010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const base::TimeDelta time_delta( 367010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) base::TimeDelta::FromDays(kPurgeStaleJobsIntervalBetweenChecksDays)); 3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::Time current_time(base::Time::Now()); 3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (last_sweep + time_delta > current_time) 3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return S_OK; 3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) last_sweep = current_time; 3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::vector<ScopedComPtr<IBackgroundCopyJob> > jobs; 3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HRESULT hr = FindBitsJobIf( 3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::bind2nd(JobCreationOlderThanDays(), kPurgeStaleJobsAfterDays), 3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bits_manager, 3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) &jobs); 3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (FAILED(hr)) 3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return hr; 3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (size_t i = 0; i != jobs.size(); ++i) { 3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) jobs[i]->Cancel(); 3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CleanupJobFiles(jobs[i]); 3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return S_OK; 3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 390a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} // namespace 391a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 392a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)BackgroundDownloader::BackgroundDownloader( 393a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) scoped_ptr<CrxDownloader> successor, 394a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) net::URLRequestContextGetter* context_getter, 3955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) scoped_refptr<base::SingleThreadTaskRunner> task_runner) 3965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu : CrxDownloader(successor.Pass()), 3975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) main_task_runner_(base::MessageLoopProxy::current()), 398a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) context_getter_(context_getter), 399a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) task_runner_(task_runner), 400a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) is_completed_(false) { 401a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 402a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 403a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)BackgroundDownloader::~BackgroundDownloader() { 4045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // The following objects have thread affinity and can't be destroyed on the 4075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // main thread. The resources managed by these objects are acquired at the 4085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // beginning of a download and released at the end of the download. Most of 4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // the time, when this destructor is called, these resources have been already 4105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // disposed by. Releasing the ownership here is a NOP. However, if the browser 4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // is shutting down while a download is in progress, the timer is active and 4125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // the interface pointers are valid. Releasing the ownership means leaking 4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // these objects and their associated resources. 4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) timer_.release(); 4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bits_manager_.Detach(); 4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) job_.Detach(); 417a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 418a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 419a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void BackgroundDownloader::DoStartDownload(const GURL& url) { 4205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 421a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 4225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) task_runner_->PostTask( 423010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) FROM_HERE, 424010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) base::Bind( 425010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) &BackgroundDownloader::BeginDownload, base::Unretained(this), url)); 426a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 427a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 428a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Called once when this class is asked to do a download. Creates or opens 429a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// an existing bits job, hooks up the notifications, and starts the timer. 430a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void BackgroundDownloader::BeginDownload(const GURL& url) { 4315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(task_runner_->RunsTasksOnCurrentThread()); 432a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 433a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DCHECK(!timer_); 434a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) is_completed_ = false; 4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) download_start_time_ = base::Time::Now(); 4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) job_stuck_begin_time_ = download_start_time_; 4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 439a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) HRESULT hr = QueueBitsJob(url); 440a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (FAILED(hr)) { 441a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EndDownload(hr); 442a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return; 443a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 444a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 445a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // A repeating timer retains the user task. This timer can be stopped and 446a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // reset multiple times. 447a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) timer_.reset(new base::RepeatingTimer<BackgroundDownloader>); 448a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) timer_->Start(FROM_HERE, 449a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::TimeDelta::FromSeconds(kJobPollingIntervalSec), 450a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) this, 451a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) &BackgroundDownloader::OnDownloading); 452a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 453a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 454a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Called any time the timer fires. 455a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void BackgroundDownloader::OnDownloading() { 4565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(task_runner_->RunsTasksOnCurrentThread()); 457a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 4585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(job_); 4595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(!is_completed_); 4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (is_completed_) 4625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 463a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 464a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) BG_JOB_STATE job_state = BG_JOB_STATE_ERROR; 465a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) HRESULT hr = job_->GetState(&job_state); 466a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (FAILED(hr)) { 467a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EndDownload(hr); 468a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return; 469a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 470a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 471a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) switch (job_state) { 472a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) case BG_JOB_STATE_TRANSFERRED: 473a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) OnStateTransferred(); 474a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return; 475a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 476a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) case BG_JOB_STATE_ERROR: 477a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) OnStateError(); 478a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return; 479a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 480a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) case BG_JOB_STATE_CANCELLED: 481a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) OnStateCancelled(); 482a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return; 483a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 484a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) case BG_JOB_STATE_ACKNOWLEDGED: 485a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) OnStateAcknowledged(); 486a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return; 487a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 488a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) case BG_JOB_STATE_QUEUED: 489010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // Fall through. 490a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) case BG_JOB_STATE_CONNECTING: 491010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // Fall through. 492a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) case BG_JOB_STATE_SUSPENDED: 4935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) OnStateQueued(); 4945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 4955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case BG_JOB_STATE_TRANSIENT_ERROR: 4975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) OnStateTransientError(); 4985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 4995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) case BG_JOB_STATE_TRANSFERRING: 5015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) OnStateTransferring(); 5025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 5035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 504a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) default: 505a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) break; 506a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 507a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 508a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 509a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Completes the BITS download, picks up the file path of the response, and 510a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// notifies the CrxDownloader. The function should be called only once. 511a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void BackgroundDownloader::EndDownload(HRESULT error) { 5125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(task_runner_->RunsTasksOnCurrentThread()); 513a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 514a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DCHECK(!is_completed_); 515a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) is_completed_ = true; 516a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 517a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) timer_.reset(); 518a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 5195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::Time download_end_time(base::Time::Now()); 5205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::TimeDelta download_time = 521010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) download_end_time >= download_start_time_ 522010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) ? download_end_time - download_start_time_ 523010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) : base::TimeDelta(); 524010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 5251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int64_t downloaded_bytes = -1; 5261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int64_t total_bytes = -1; 527010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) GetJobByteCount(job_, &downloaded_bytes, &total_bytes); 528a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 5295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (FAILED(error) && job_) { 5305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) job_->Cancel(); 5315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CleanupJobFiles(job_); 5325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 5335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) job_ = NULL; 5355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 536010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) CleanupStaleJobs(bits_manager_); 537010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) bits_manager_ = NULL; 538010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 539a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Consider the url handled if it has been successfully downloaded or a 540a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // 5xx has been received. 541010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const bool is_handled = 542010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) SUCCEEDED(error) || IsHttpServerError(GetHttpStatusFromBitsError(error)); 543a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 5445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const int error_to_report = SUCCEEDED(error) ? 0 : error; 5455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DownloadMetrics download_metrics; 5475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) download_metrics.url = url(); 5485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) download_metrics.downloader = DownloadMetrics::kBits; 5495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) download_metrics.error = error_to_report; 550010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) download_metrics.downloaded_bytes = downloaded_bytes; 551010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) download_metrics.total_bytes = total_bytes; 5525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) download_metrics.download_time_ms = download_time.InMilliseconds(); 5535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 554a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Result result; 5555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) result.error = error_to_report; 556010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) result.response = response_; 557010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) result.downloaded_bytes = downloaded_bytes; 558010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) result.total_bytes = total_bytes; 5595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) main_task_runner_->PostTask( 5605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) FROM_HERE, 5615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Bind(&BackgroundDownloader::OnDownloadComplete, 5625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Unretained(this), 5635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) is_handled, 5645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) result, 5655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) download_metrics)); 5665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 5675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Once the task is posted to the the main thread, this object may be deleted 5685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // by its owner. It is not safe to access members of this object on the 5695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // task runner from this point on. The timer is stopped and all BITS 5705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // interface pointers have been released. 571a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 572a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 573a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Called when the BITS job has been transferred successfully. Completes the 574a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// BITS job by removing it from the BITS queue and making the download 575a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// available to the caller. 576a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void BackgroundDownloader::OnStateTransferred() { 577010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) EndDownload(CompleteJob()); 578a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 579a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 580a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Called when the job has encountered an error and no further progress can 581a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// be made. Cancels this job and removes it from the BITS queue. 582a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void BackgroundDownloader::OnStateError() { 5835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HRESULT error_code = S_OK; 5845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HRESULT hr = GetJobError(job_, &error_code); 5855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (FAILED(hr)) 5865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) error_code = hr; 5875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(FAILED(error_code)); 5885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EndDownload(error_code); 5895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 5905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Called when the job has encountered a transient error, such as a 5925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// network disconnect, a server error, or some other recoverable error. 5935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void BackgroundDownloader::OnStateTransientError() { 5945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // If the job appears to be stuck, handle the transient error as if 5955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // it were a final error. This causes the job to be cancelled and a specific 5965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // error be returned, if the error was available. 5975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (IsStuck()) { 5985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) OnStateError(); 5995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 600a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 601a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 6025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Don't retry at all if the transient error was a 5xx. 6035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HRESULT error_code = S_OK; 6045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HRESULT hr = GetJobError(job_, &error_code); 6055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (SUCCEEDED(hr) && 6065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) IsHttpServerError(GetHttpStatusFromBitsError(error_code))) { 6075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) OnStateError(); 6085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 6095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 6105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 6115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 6125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void BackgroundDownloader::OnStateQueued() { 6135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (IsStuck()) 614010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) EndDownload(E_ABORT); // Return a generic error for now. 6155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 6165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 6175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void BackgroundDownloader::OnStateTransferring() { 6185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Resets the baseline for detecting a stuck job since the job is transferring 6195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // data and it is making progress. 6205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) job_stuck_begin_time_ = base::Time::Now(); 621010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 6221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int64_t downloaded_bytes = -1; 6231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int64_t total_bytes = -1; 624010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) HRESULT hr = GetJobByteCount(job_, &downloaded_bytes, &total_bytes); 625010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (FAILED(hr)) 626010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return; 627010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 628010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) Result result; 629010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) result.downloaded_bytes = downloaded_bytes; 630010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) result.total_bytes = total_bytes; 631010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 6325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) main_task_runner_->PostTask( 6335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) FROM_HERE, 6345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Bind(&BackgroundDownloader::OnDownloadProgress, 6355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) base::Unretained(this), 6365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) result)); 637a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 638a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 639a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Called when the download was cancelled. Since the observer should have 640a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// been disconnected by now, this notification must not be seen. 641a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void BackgroundDownloader::OnStateCancelled() { 642a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EndDownload(E_UNEXPECTED); 643a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 644a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 645a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Called when the download was completed. Same as above. 646a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void BackgroundDownloader::OnStateAcknowledged() { 647a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EndDownload(E_UNEXPECTED); 648a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 649a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 650a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Creates or opens a job for the given url and queues it up. Tries to 651a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// install a job observer but continues on if an observer can't be set up. 652a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)HRESULT BackgroundDownloader::QueueBitsJob(const GURL& url) { 6535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(task_runner_->RunsTasksOnCurrentThread()); 654a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 655a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) HRESULT hr = S_OK; 656a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (bits_manager_ == NULL) { 657a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) hr = GetBitsManager(bits_manager_.Receive()); 658a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (FAILED(hr)) 659a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return hr; 660a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 661a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 662a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) hr = CreateOrOpenJob(url); 663a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (FAILED(hr)) 664a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return hr; 665a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 666a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (hr == S_OK) { 667a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) hr = InitializeNewJob(url); 668a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (FAILED(hr)) 669a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return hr; 670a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 671a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 672a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return job_->Resume(); 673a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 674a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 675a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)HRESULT BackgroundDownloader::CreateOrOpenJob(const GURL& url) { 676a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::vector<ScopedComPtr<IBackgroundCopyJob> > jobs; 677a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) HRESULT hr = FindBitsJobIf( 678a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::bind2nd(JobFileUrlEqual(), base::SysUTF8ToWide(url.spec())), 679a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) bits_manager_, 680a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) &jobs); 681a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (SUCCEEDED(hr) && !jobs.empty()) { 682a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) job_ = jobs.front(); 683a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return S_FALSE; 684a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 685a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 686a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Use kJobDescription as a temporary job display name until the proper 687a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // display name is initialized later on. 688a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) GUID guid = {0}; 689a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ScopedComPtr<IBackgroundCopyJob> job; 690010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) hr = bits_manager_->CreateJob( 691010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) kJobDescription, BG_JOB_TYPE_DOWNLOAD, &guid, job.Receive()); 692a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (FAILED(hr)) 693a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return hr; 694a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 695a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) job_ = job; 696a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return S_OK; 697a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 698a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 699a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)HRESULT BackgroundDownloader::InitializeNewJob(const GURL& url) { 700a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16 filename(base::SysUTF8ToWide(url.ExtractFileName())); 701a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 702a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::FilePath tempdir; 703010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (!base::CreateNewTempDirectory(FILE_PATH_LITERAL("chrome_BITS_"), 704010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) &tempdir)) 705a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return E_FAIL; 706a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 707010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) HRESULT hr = job_->AddFile(base::SysUTF8ToWide(url.spec()).c_str(), 708010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) tempdir.Append(filename).AsUTF16Unsafe().c_str()); 709a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (FAILED(hr)) 710a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return hr; 711a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 712a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) hr = job_->SetDisplayName(filename.c_str()); 713a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (FAILED(hr)) 714a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return hr; 715a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 716a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) hr = job_->SetDescription(kJobDescription); 717a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (FAILED(hr)) 718a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return hr; 719a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 720a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) hr = job_->SetPriority(BG_JOB_PRIORITY_NORMAL); 721a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (FAILED(hr)) 722a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return hr; 723a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 7245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) hr = job_->SetMinimumRetryDelay(60 * kMinimumRetryDelayMin); 725a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (FAILED(hr)) 726a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return hr; 727a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 7285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const int kSecondsDay = 60 * 60 * 24; 7295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) hr = job_->SetNoProgressTimeout(kSecondsDay * kSetNoProgressTimeoutDays); 7305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (FAILED(hr)) 7315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return hr; 732a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 733a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return S_OK; 734a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 735a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 7365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool BackgroundDownloader::IsStuck() { 7375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::TimeDelta job_stuck_timeout( 7385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::TimeDelta::FromMinutes(kJobStuckTimeoutMin)); 7395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return job_stuck_begin_time_ + job_stuck_timeout < base::Time::Now(); 7405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 7415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 742010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)HRESULT BackgroundDownloader::CompleteJob() { 743010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) HRESULT hr = job_->Complete(); 744010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (FAILED(hr) && hr != BG_S_UNABLE_TO_DELETE_FILES) 745010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return hr; 746010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 747010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) std::vector<ScopedComPtr<IBackgroundCopyFile> > files; 748010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) hr = GetFilesInJob(job_, &files); 749010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (FAILED(hr)) 750010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return hr; 751010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 752010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (files.empty()) 753010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return E_UNEXPECTED; 754a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 755010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) base::string16 local_name; 756010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) BG_FILE_PROGRESS progress = {0}; 757010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) hr = GetJobFileProperties(files.front(), &local_name, NULL, &progress); 758010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (FAILED(hr)) 759010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return hr; 760010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 761010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // Sanity check the post-conditions of a successful download, including 762010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // the file and job invariants. The byte counts for a job and its file 763010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // must match as a job only contains one file. 764010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK(progress.Completed); 765010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) DCHECK_EQ(progress.BytesTotal, progress.BytesTransferred); 766010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 767010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) response_ = base::FilePath(local_name); 768010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 769010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return S_OK; 770010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} 771010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 772010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)} // namespace component_updater 773