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(&times);
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