Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(563)

Side by Side Diff: chrome/browser/component_updater/background_downloader_win.cc

Issue 105853002: Implement a background downloader using BITS in Windows Chrome. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: trybots and Josh's feedback. Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/component_updater/background_downloader_win.h"
6 #include <atlbase.h>
7 #include <atlcom.h>
8 #include <functional>
9 #include <iomanip>
10 #include <vector>
11 #include "base/file_util.h"
12 #include "base/strings/sys_string_conversions.h"
13 #include "base/time/time.h"
14 #include "base/win/scoped_co_mem.h"
15 #include "chrome/browser/component_updater/component_updater_utils.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "ui/base/win/atl_module.h"
18 #include "url/gurl.h"
19
20 using base::win::ScopedCoMem;
21 using base::win::ScopedComPtr;
22 using content::BrowserThread;
23
24 // The class BackgroundDownloader in this module is an adapter between
25 // the CrxDownloader interface and the BITS service interfaces.
26 // The interface exposed on the CrxDownloader code runs on the UI thread, while
27 // the BITS specific code runs in a single threaded apartment on the FILE
28 // thread.
29 // For every url to download, a BITS job is created, unless there is already
30 // an existing job for that url, in which case, the downloader connects to it.
31 // Once a job is associated with the url, the code looks for changes in the
32 // BITS job state.
cpu_(ooo_6.6-7.5) 2013/12/05 19:32:43 I haven't looked at the code yet but are we assumi
Sorin Jianu 2013/12/05 22:34:36 We do, in the sense that we expect different files
33 // The changes arrive either as COM callbacks (due to the threading model, the
34 // events always arrive on the FILE thread) or by polling, triggered by a timer,
35 // as a last resort. The BITS job contains just one file to download. There
36 // could only be one download in progress at a time. If Chrome closes down
37 // before the download is complete, the BITS job remains active and finishes in
38 // the background, without any intervention. The job can be completed next time
39 // the code runs, if the file is still needed, otherwise it will be cleaned up
40 // on a periodic basis.
41
cpu_(ooo_6.6-7.5) 2013/12/05 19:32:43 can you put here the minimalist command line to li
Sorin Jianu 2013/12/05 22:34:36 Done.
42 namespace component_updater {
43
44 namespace {
45
46 // All jobs created by this module have a specific description so they can
47 // be found at run-time or by using system administration tools.
48 const char16 kJobDescription[] = L"Chrome Component Updater";
49
50 // How often the code looks for changes in the BITS job state.
51 const int kJobPollingIntervalSec = 10;
52
53 // How often the jobs which were started but not completed for any reason
54 // are cleaned up. Reasons for jobs to be left behind include browser restarts,
55 // system restarts, etc. Also, the check to purge stale jobs only happens
56 // at most once a day.
57 const int kPurgeStaleJobsAfterDays = 7;
58 const int kPurgeStaleJobsIntervalBetweenChecksDays = 1;
cpu_(ooo_6.6-7.5) 2013/12/05 19:32:43 These two seem to be good to expose in the configu
Sorin Jianu 2013/12/05 22:34:36 will do.
59
60 // Returns the status code from a given BITS error.
61 int GetHttpStatusFromBitsError(HRESULT error) {
62 // BITS errors are defined in bitsmsg.h. Although not documented, it is
63 // clear that all errors corresponding to http status code have the high
64 // word equal to 0x8019 and the low word equal to the http status code.
65 const int kHttpStatusFirst = 100; // Continue.
66 const int kHttpStatusLast = 505; // Version not supported.
67 bool is_valid = HIWORD(error) == 0x8019 &&
68 LOWORD(error) >= kHttpStatusFirst &&
69 LOWORD(error) <= kHttpStatusLast;
70 return is_valid ? LOWORD(error) : 0;
71 }
72
73 // Returns the files in a BITS job.
74 HRESULT GetFilesInJob(IBackgroundCopyJob* job,
75 std::vector<ScopedComPtr<IBackgroundCopyFile> >* files) {
76 ScopedComPtr<IEnumBackgroundCopyFiles> enum_files;
77 HRESULT hr = job->EnumFiles(enum_files.Receive());
78 if (FAILED(hr))
79 return hr;
80
81 ULONG num_files = 0;
82 hr = enum_files->GetCount(&num_files);
83 if (FAILED(hr))
84 return hr;
85
86 for (ULONG i = 0; i != num_files; ++i) {
87 ScopedComPtr<IBackgroundCopyFile> file;
88 if (enum_files->Next(1, file.Receive(), NULL) == S_OK)
89 files->push_back(file);
90 }
91
92 return S_OK;
93 }
94
95 // Returns the file name, the url, and some per-file progress information.
96 // The function out parameters can be NULL if that data is not requested.
97 HRESULT GetJobFileProperties(IBackgroundCopyFile* file,
98 string16* local_name,
99 string16* remote_name,
100 BG_FILE_PROGRESS* progress) {
101 HRESULT hr = S_OK;
102
103 if (local_name) {
104 ScopedCoMem<char16> name;
105 hr = file->GetLocalName(&name);
106 if (FAILED(hr))
107 return hr;
108 local_name->assign(name);
109 }
110
111 if (remote_name) {
112 ScopedCoMem<char16> name;
113 hr = file->GetRemoteName(&name);
114 if (FAILED(hr))
115 return hr;
116 remote_name->assign(name);
117 }
118
119 if (progress) {
120 BG_FILE_PROGRESS bg_file_progress = {};
121 hr = file->GetProgress(&bg_file_progress);
122 if (FAILED(hr))
123 return hr;
124 *progress = bg_file_progress;
125 }
126
127 return hr;
128 }
129
130 // Finds the jobs matching the given predicate.
131 // Returns S_OK if the function has found at least one job, returns S_FALSE if
132 // no job was found, and it returns an error otherwise.
133 template<class Predicate>
134 HRESULT FindBitsJobIf(Predicate pred,
135 IBackgroundCopyManager* bits_manager,
136 std::vector<ScopedComPtr<IBackgroundCopyJob> >* jobs) {
137 ScopedComPtr<IEnumBackgroundCopyJobs> enum_jobs;
138 HRESULT hr = bits_manager->EnumJobs(0, enum_jobs.Receive());
139 if (FAILED(hr))
140 return hr;
141
142 ULONG job_count = 0;
143 hr = enum_jobs->GetCount(&job_count);
144 if (FAILED(hr))
145 return hr;
146
147 for (ULONG i = 0; i != job_count; ++i) {
148 ScopedComPtr<IBackgroundCopyJob> current_job;
149 if (enum_jobs->Next(1, current_job.Receive(), NULL) == S_OK &&
150 pred(current_job)) {
151 jobs->push_back(current_job);
152 }
cpu_(ooo_6.6-7.5) 2013/12/05 21:16:31 seems we should have here the logic of JobDescript
Sorin Jianu 2013/12/05 22:34:36 This function takes any predicate and it iterates
cpu_(ooo_6.6-7.5) 2013/12/06 00:12:51 Yes, but all the callers (predicates) filter out t
Sorin Jianu 2013/12/06 01:37:36 Done.
153 }
154
155 return jobs->empty() ? S_FALSE : S_OK;
156 }
157
158 // Compares the description of a job matches |name|.
159 struct JobDescriptionEqual
160 : public std::binary_function<IBackgroundCopyJob*, const string16&, bool> {
161 bool operator()(IBackgroundCopyJob* job, const string16& name) const;
162 };
163
164 bool JobDescriptionEqual::operator()(IBackgroundCopyJob* job,
165 const string16& name) const {
166 ScopedCoMem<char16> description;
167 HRESULT hr = job->GetDescription(&description);
168 return SUCCEEDED(hr) && name.compare(description) == 0;
169 }
170
171 // Compares the job creation time and returns true if the job creation time
172 // is older than |num_days|.
173 struct JobCreationOlderThanDays
174 : public std::binary_function<IBackgroundCopyJob*, int, bool> {
175 bool operator()(IBackgroundCopyJob* job, int num_days) const;
176 };
177
178 bool JobCreationOlderThanDays::operator()(IBackgroundCopyJob* job,
179 int num_days) const {
180 if (!JobDescriptionEqual()(job, kJobDescription))
181 return false;
182
183 BG_JOB_TIMES times = {0};
184 HRESULT hr = job->GetTimes(&times);
185 const base::TimeDelta time_delta(base::TimeDelta::FromDays(num_days));
186 const base::Time creation_time(base::Time::FromFileTime(times.CreationTime));
cpu_(ooo_6.6-7.5) 2013/12/05 21:16:31 seems incorrect to call 186 regardless of the valu
Sorin Jianu 2013/12/05 22:34:36 Done.
187 return SUCCEEDED(hr) && (creation_time + time_delta < base::Time::Now());
188 }
189
190 // Compares the url of a file in a job and returns true if the remote name
191 // of any file in a job matches |url|.
192 struct JobFileUrlEqual
193 : public std::binary_function<IBackgroundCopyJob*, const string16&, bool> {
194 bool operator()(IBackgroundCopyJob* job, const string16& url) const;
195 };
196
197 bool JobFileUrlEqual::operator()(IBackgroundCopyJob* job,
198 const string16& url) const {
cpu_(ooo_6.6-7.5) 2013/12/05 21:16:31 I think this should take a GURL& instead of a stri
Sorin Jianu 2013/12/05 22:34:36 The other predicates take string16 as well, at lea
cpu_(ooo_6.6-7.5) 2013/12/06 00:12:51 It is frowned upon to use url params not being GUR
Sorin Jianu 2013/12/06 01:37:36 Done.
199 if (!JobDescriptionEqual()(job, kJobDescription))
200 return false;
201
202 std::vector<ScopedComPtr<IBackgroundCopyFile> > files;
203 HRESULT hr = GetFilesInJob(job, &files);
204 if (FAILED(hr))
205 return false;
206
207 for (size_t i = 0; i != files.size(); ++i) {
208 ScopedCoMem<char16> name;
209 if (SUCCEEDED(files[i]->GetRemoteName(&name)) && url.compare(name) == 0)
210 return true;
211 }
212
213 return false;
214 }
215
216 // Sets the proxy authentication credentials for the job.
217 HRESULT SetProxyAuthCredentials(IBackgroundCopyJob* job) {
218 ScopedComPtr<IBackgroundCopyJob2> job2;
cpu_(ooo_6.6-7.5) 2013/12/05 21:16:31 is IBackgroundCopyJob2 Vista and above? also who
Sorin Jianu 2013/12/05 22:34:36 yes. At the moment, nobody is calling it, I will h
cpu_(ooo_6.6-7.5) 2013/12/06 00:12:51 Delete it please.
Sorin Jianu 2013/12/06 01:37:36 Done.
219 HRESULT hr = job2.QueryFrom(job);
220 if (FAILED(hr))
221 return hr;
222
223 BG_AUTH_CREDENTIALS auth_cred = {};
224 auth_cred.Target = BG_AUTH_TARGET_PROXY;
225 auth_cred.Scheme = BG_AUTH_SCHEME_NEGOTIATE;
226
cpu_(ooo_6.6-7.5) 2013/12/05 21:16:31 Is there an option for no credentials?
Sorin Jianu 2013/12/05 22:34:36 We can set proxies for a job. If we do a proxy req
cpu_(ooo_6.6-7.5) 2013/12/06 00:12:51 My only concern is leaking ntlm password hashes if
Sorin Jianu 2013/12/06 01:37:36 Understood. Let's talk about proxy authentication
227 return job2->SetCredentials(&auth_cred);
228 }
229
230 HRESULT CancelJob(IBackgroundCopyJob* job) {
231 BG_JOB_STATE job_state = BG_JOB_STATE_ERROR;
232 HRESULT hr = job->GetState(&job_state);
233 if (FAILED(hr))
234 return hr;
235
236 if (job_state != BG_JOB_STATE_CANCELLED &&
237 job_state != BG_JOB_STATE_ACKNOWLEDGED) {
238 hr = job->Cancel();
239 if (FAILED(hr))
240 return hr;
241 }
242
243 return hr;
244 }
245
246 HRESULT PauseJob(IBackgroundCopyJob* job) {
247 BG_JOB_STATE job_state = BG_JOB_STATE_ERROR;
248 HRESULT hr = job->GetState(&job_state);
249 if (FAILED(hr))
250 return hr;
cpu_(ooo_6.6-7.5) 2013/12/05 21:16:31 function also seems unused.
Sorin Jianu 2013/12/05 22:34:36 Indeed, I wrote the functions that I will need soo
cpu_(ooo_6.6-7.5) 2013/12/06 00:12:51 delete it please, chrome style is not leave unused
Sorin Jianu 2013/12/06 01:37:36 Done.
251
252 if (job_state != BG_JOB_STATE_TRANSFERRED &&
253 job_state != BG_JOB_STATE_ACKNOWLEDGED &&
254 job_state != BG_JOB_STATE_CANCELLED) {
255 hr = job->Suspend();
256 if (FAILED(hr))
257 return hr;
258 }
259
260 return hr;
261 }
262
263 HRESULT ResumeJob(IBackgroundCopyJob* job) {
cpu_(ooo_6.6-7.5) 2013/12/05 21:16:31 another unused function? unless you plan to use it
Sorin Jianu 2013/12/05 22:34:36 Done.
Sorin Jianu 2013/12/06 01:37:36 deleted.
264 BG_JOB_STATE job_state = BG_JOB_STATE_ERROR;
265 HRESULT hr = job->GetState(&job_state);
266 if (FAILED(hr))
267 return hr;
268
269 if (job_state != BG_JOB_STATE_SUSPENDED) {
270 hr = job->Resume();
271 if (FAILED(hr))
272 return hr;
273 }
274
275 return hr;
276 }
277
278 // Creates an instance of the BITS manager.
279 HRESULT GetBitsManager(IBackgroundCopyManager** bits_manager) {
280 ScopedComPtr<IBackgroundCopyManager> object;
281 HRESULT hr = object.CreateInstance(__uuidof(BackgroundCopyManager));
282 if (FAILED(hr)) {
283 VLOG(1) << "Failed to instantiate BITS." << std::hex << hr;
cpu_(ooo_6.6-7.5) 2013/12/05 21:16:31 todo: add UMA or pings here.
Sorin Jianu 2013/12/05 22:34:36 Done.
284 return hr;
285 }
286 *bits_manager = object.Detach();
287 return S_OK;
288 }
289
290 // JobObserver receives notifications when a BITS job has been completed,
291 // modified, or has encountered an error. This class lives on the FILE thread.
292 class JobObserver
293 : public CComObjectRootEx<CComSingleThreadModel>,
294 public IBackgroundCopyCallback {
295 public:
296 typedef base::Callback<void (void)> JobChangedCallback;
cpu_(ooo_6.6-7.5) 2013/12/05 21:16:31 extra space between typedef and base::
Sorin Jianu 2013/12/05 22:34:36 Done.
297
298 JobObserver() {}
299
300 virtual ~JobObserver() {}
301
302 void set_callback(const JobChangedCallback& callback) {
303 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
304 callback_ = callback;
305 }
306
307 BEGIN_COM_MAP(JobObserver)
308 COM_INTERFACE_ENTRY(IBackgroundCopyCallback)
309 END_COM_MAP()
310
311 // IBackgroundCopyCallback methods.
312 STDMETHOD(JobTransferred)(IBackgroundCopyJob* job) OVERRIDE {
313 NotifyJobChanged();
314 return S_OK;
315 }
316
317 STDMETHOD(JobError)(IBackgroundCopyJob* job,
318 IBackgroundCopyError* error) OVERRIDE {
319 NotifyJobChanged();
320 return S_OK;
321 }
322
323 STDMETHOD(JobModification)(IBackgroundCopyJob* job,
324 DWORD reserved) OVERRIDE {
cpu_(ooo_6.6-7.5) 2013/12/05 21:16:31 indent 324
Sorin Jianu 2013/12/05 22:34:36 Done.
325 NotifyJobChanged();
326 return S_OK;
327 }
328
329 private:
330 void NotifyJobChanged() {
331 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
332 if (!callback_.is_null())
333 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, callback_);
334 }
335
336 JobChangedCallback callback_;
337
338 DISALLOW_COPY_AND_ASSIGN(JobObserver);
339 };
340
341 } // namespace
342
343 BackgroundDownloader::BackgroundDownloader(
344 scoped_ptr<CrxDownloader> successor,
345 net::URLRequestContextGetter* context_getter,
346 scoped_refptr<base::SequencedTaskRunner> task_runner,
347 const DownloadCallback& download_callback)
348 : CrxDownloader(successor.Pass(), download_callback),
349 context_getter_(context_getter),
350 task_runner_(task_runner),
351 is_completed_(false) {
352 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
353 }
354
355 BackgroundDownloader::~BackgroundDownloader() {
356 }
357
358 void BackgroundDownloader::DoStartDownload(const GURL& url) {
359 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
360
361 BrowserThread::PostTask(
362 BrowserThread::FILE,
363 FROM_HERE,
364 base::Bind(&BackgroundDownloader::BeginDownload,
365 base::Unretained(this),
cpu_(ooo_6.6-7.5) 2013/12/05 21:16:31 can it really be unretained? remind me of the life
Sorin Jianu 2013/12/05 22:34:36 The caller own the head of the chain, who owns the
cpu_(ooo_6.6-7.5) 2013/12/06 00:12:51 So the top dog in the chain does not get deleted u
Sorin Jianu 2013/12/06 01:37:36 The life cycle of the downloader and its successor
366 url));
367 }
368
369 // Called once when this class is asked to do a download. Creates or opens
370 // an existing bits job, hooks up the notifications, and starts the timer.
371 void BackgroundDownloader::BeginDownload(const GURL& url) {
372 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
cpu_(ooo_6.6-7.5) 2013/12/05 21:16:31 dcheck(timer_ is null) ?
Sorin Jianu 2013/12/05 22:34:36 Done. Nothing breaks in the code if the timer is
cpu_(ooo_6.6-7.5) 2013/12/06 00:12:51 Not per se.
Sorin Jianu 2013/12/06 01:37:36 Done.
373
374 HRESULT hr = QueueBitsJob(url);
375 if (FAILED(hr)) {
376 if (job_)
377 CancelJob(job_);
378 EndDownload(hr);
379 return;
380 }
381
382 timer_.reset(new base::OneShotTimer<BackgroundDownloader>);
383 timer_->Start(FROM_HERE,
384 base::TimeDelta::FromSeconds(kJobPollingIntervalSec),
385 this,
386 &BackgroundDownloader::OnDownloading);
387 }
388
389 // Called any time there is a change in the state of the job or when
390 // the timer fires.
391 void BackgroundDownloader::OnDownloading() {
392 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
393
394 // Stop the timer in case this function has run due to a BITS event.
395 timer_->Stop();
396
397 BG_JOB_STATE job_state = BG_JOB_STATE_ERROR;
398 HRESULT hr = job_->GetState(&job_state);
399 if (FAILED(hr)) {
400 EndDownload(hr);
401 return;
402 }
403
404 switch (job_state) {
405 case BG_JOB_STATE_TRANSFERRED:
406 OnStateTransferred();
407 return;
408
409 case BG_JOB_STATE_ERROR:
410 OnStateError();
411 return;
412
413 case BG_JOB_STATE_CANCELLED:
414 OnStateCancelled();
415 return;
416
417 case BG_JOB_STATE_ACKNOWLEDGED:
418 OnStateAcknowledged();
419 return;
420
421 // TODO: handle the non-final states, so that the download does not get
422 // stuck if BITS is not able to make progress on a given url.
423 case BG_JOB_STATE_TRANSIENT_ERROR:
424 case BG_JOB_STATE_QUEUED:
425 case BG_JOB_STATE_CONNECTING:
426 case BG_JOB_STATE_TRANSFERRING:
427 case BG_JOB_STATE_SUSPENDED:
428 default:
429 break;
430 }
431
cpu_(ooo_6.6-7.5) 2013/12/05 21:16:31 can you use timer_->Reset() instead?
Sorin Jianu 2013/12/05 22:34:36 Done. Please notice I removed the Stop call at the
cpu_(ooo_6.6-7.5) 2013/12/06 00:12:51 Cursory look tells me it is ok.
Sorin Jianu 2013/12/06 01:37:36 I put the call the Stop back since I check as a po
432 timer_->Start(FROM_HERE,
433 base::TimeDelta::FromSeconds(kJobPollingIntervalSec),
434 this,
435 &BackgroundDownloader::OnDownloading);
436 }
437
438 // Completes the BITS download, picks up the file path of the response, and
439 // notifies the CrxDownloader. Usually called one time but it could be called
440 // multiple times due to the dual polling/event drive mechanism to receive
441 // job state changes.
442 void BackgroundDownloader::EndDownload(HRESULT error) {
443 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
444 DCHECK(!timer_->IsRunning());
445
446 timer_.reset();
447
448 if (is_completed_)
449 return;
450
451 base::FilePath response;
452 HRESULT hr = error;
453 if (SUCCEEDED(hr)) {
454 std::vector<ScopedComPtr<IBackgroundCopyFile> > files;
455 GetFilesInJob(job_, &files);
456 DCHECK(files.size() == 1);
457 string16 local_name;
458 BG_FILE_PROGRESS progress = {0};
459 hr = GetJobFileProperties(files[0], &local_name, NULL, &progress);
460 if (SUCCEEDED(hr)) {
461 DCHECK(progress.Completed);
462 response = base::FilePath(local_name);
463 }
464 }
465
466 // Consider the url handled if it has been successfully downloaded or a
467 // 5xx has been received.
468 const bool is_handled = SUCCEEDED(hr) ||
469 IsHttpServerError(GetHttpStatusFromBitsError(error));
470
471 Result result;
472 result.error = error;
473 result.is_background_download = true;
474 result.response = response;
475 BrowserThread::PostTask(
476 BrowserThread::UI,
477 FROM_HERE,
478 base::Bind(&BackgroundDownloader::OnDownloadComplete,
479 base::Unretained(this),
480 is_handled,
481 result));
482
483 is_completed_ = true;
484
485 CleanupStaleJobs(bits_manager_);
486 }
487
488 // Called when the BITS job has been transferred successfully. Completes the
489 // BITS job by removing it from the BITS queue and making the download
490 // available to the caller.
491 void BackgroundDownloader::OnStateTransferred() {
492 RemoveJobObserver();
493
494 HRESULT hr = job_->Complete();
495 if (SUCCEEDED(hr) || hr == BG_S_UNABLE_TO_DELETE_FILES)
496 hr = S_OK;
497 else
498 hr = job_->Cancel();
499
500 EndDownload(hr);
501 }
502
503 // Called when the job has encountered an error and no further progress can
504 // be made. Cancels this job and remove it from the BITS queue.
505 void BackgroundDownloader::OnStateError() {
506 RemoveJobObserver();
507
508 ScopedComPtr<IBackgroundCopyError> copy_error;
509 HRESULT hr = job_->GetError(copy_error.Receive());
510 if (SUCCEEDED(hr)) {
511 BG_ERROR_CONTEXT error_context = BG_ERROR_CONTEXT_NONE;
512 HRESULT error_code = E_FAIL;
513 hr = copy_error->GetError(&error_context, &error_code);
514 if (SUCCEEDED(hr)) {
515 EndDownload(error_code);
516 return;
517 }
518 }
519
520 hr = job_->Cancel();
521 EndDownload(hr);
522 }
523
524 // Called when the download was cancelled. Since the observer should have
525 // been disconnected by now, this notification must not be seen.
526 void BackgroundDownloader::OnStateCancelled() {
527 EndDownload(E_UNEXPECTED);
528 }
529
530 // Called when the download was completed. Same as above.
531 void BackgroundDownloader::OnStateAcknowledged() {
532 EndDownload(E_UNEXPECTED);
533 }
534
535 // Creates or opens a job for the given url and queues it up. Tries to
536 // install a job observer but continues on if an observer can't be set up.
537 HRESULT BackgroundDownloader::QueueBitsJob(const GURL& url) {
538 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
539
540 HRESULT hr = S_OK;
541 if (bits_manager_ == NULL) {
542 hr = GetBitsManager(bits_manager_.Receive());
543 if (FAILED(hr))
544 return hr;
545 }
546
547 hr = CreateOrOpenJob(url);
cpu_(ooo_6.6-7.5) 2013/12/05 21:16:31 I rather have CreateOrOpenJob just return the job
Sorin Jianu 2013/12/05 22:34:36 I know what you mean. I tried to do the code that
cpu_(ooo_6.6-7.5) 2013/12/06 00:12:51 I see. I think there is a happy medium point, it c
Sorin Jianu 2013/12/06 01:37:36 Thank you!
548 if (FAILED(hr))
549 return hr;
550
551 if (hr == S_OK) {
552 hr = InitializeNewJob(url);
553 if (FAILED(hr))
cpu_(ooo_6.6-7.5) 2013/12/05 21:16:31 here you need to delete the job.
Sorin Jianu 2013/12/05 22:34:36 job_ is refcounted. When the function runs again i
cpu_(ooo_6.6-7.5) 2013/12/06 00:12:51 it seems weird to have job_ point to a valid, yet
Sorin Jianu 2013/12/06 01:37:36 Done. I moved resetting the job pointer @322 where
554 return hr;
555 }
556
557 InstallJobObserver();
558
559 return job_->Resume();
560 }
561
562 HRESULT BackgroundDownloader::CreateOrOpenJob(const GURL& url) {
563 std::vector<ScopedComPtr<IBackgroundCopyJob> > jobs;
564 HRESULT hr = FindBitsJobIf(
565 std::bind2nd(JobFileUrlEqual(), base::SysUTF8ToWide(url.spec())),
566 bits_manager_,
567 &jobs);
568 if (SUCCEEDED(hr) && !jobs.empty()) {
569 job_ = jobs.front();
570 return S_FALSE;
571 }
572
573 GUID guid = {0};
574 ScopedComPtr<IBackgroundCopyJob> job;
575 hr = bits_manager_->CreateJob(L"",
cpu_(ooo_6.6-7.5) 2013/12/05 21:16:31 L"" ?
Sorin Jianu 2013/12/05 22:34:36 I need a wide string literal, is the problem with
cpu_(ooo_6.6-7.5) 2013/12/06 00:12:51 The value, should it be something that helps findi
Sorin Jianu 2013/12/06 01:37:36 Oh, that parameter is the job display name, which
576 BG_JOB_TYPE_DOWNLOAD,
577 &guid,
578 job.Receive());
579 if (FAILED(hr))
580 return hr;
581
582 job_ = job;
583 return S_OK;
584 }
585
586 HRESULT BackgroundDownloader::InitializeNewJob(const GURL& url) {
587 const string16 filename(base::SysUTF8ToWide(url.ExtractFileName()));
588
589 base::FilePath tempdir;
590 if (!file_util::CreateNewTempDirectory(
591 FILE_PATH_LITERAL("chrome_component_updates_"),
592 &tempdir))
cpu_(ooo_6.6-7.5) 2013/12/05 21:16:31 bikeshed purple: "chrome_BITS_"
Sorin Jianu 2013/12/05 22:34:36 Done.
593 return E_FAIL;
594
595 HRESULT hr = job_->AddFile(
596 base::SysUTF8ToWide(base::StringPiece(url.spec())).c_str(),
cpu_(ooo_6.6-7.5) 2013/12/05 21:16:31 you need stringpiece there?
Sorin Jianu 2013/12/05 22:34:36 I don't. Thank you for pointing it out. I notice
597 tempdir.Append(filename).AsUTF16Unsafe().c_str());
598 if (FAILED(hr))
599 return hr;
600
601 hr = job_->SetDisplayName(filename.c_str());
602 if (FAILED(hr))
603 return hr;
604
605 hr = job_->SetDescription(kJobDescription);
606 if (FAILED(hr))
607 return hr;
608
609 hr = job_->SetPriority(BG_JOB_PRIORITY_NORMAL);
610 if (FAILED(hr))
611 return hr;
612
613 return S_OK;
614 }
615
616 HRESULT BackgroundDownloader::InstallJobObserver() {
617 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
618
619 // Make sure ATL is initialized in this module.
620 ui::win::CreateATLModuleIfNeeded();
621
622 CComObject<JobObserver>* job_observer = NULL;
623 HRESULT hr(CComObject<JobObserver>::CreateInstance(&job_observer));
624 if (FAILED(hr))
625 return hr;
626
627 job_observer->set_callback(
628 base::Bind(&BackgroundDownloader::OnDownloading,
629 base::Unretained(this)));
630
631 job_observer->AddRef();
632 job_observer_.Attach(job_observer);
633
634 hr = job_->SetNotifyInterface(job_observer_);
635 if (FAILED(hr))
636 return hr;
637
638 hr = job_->SetNotifyFlags(BG_NOTIFY_FILE_TRANSFERRED |
639 BG_NOTIFY_JOB_TRANSFERRED |
640 BG_NOTIFY_JOB_ERROR);
641 if (FAILED(hr))
642 return hr;
643
644 return S_OK;
645 }
646
647 HRESULT BackgroundDownloader::RemoveJobObserver() {
648 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
649
650 if (!job_ || !job_observer_)
651 return S_OK;
652
653 HRESULT hr = job_->SetNotifyFlags(0);
654 if (FAILED(hr))
655 return hr;
656
657 hr = job_->SetNotifyInterface(NULL);
658 if (FAILED(hr))
659 return hr;
660
661 static_cast<JobObserver*>(job_observer_.get())->set_callback(
662 JobObserver::JobChangedCallback());
663 job_observer_ = NULL;
664
665 return S_OK;
666 }
667
668 // Cleans up incompleted jobs that are too old.
669 HRESULT BackgroundDownloader::CleanupStaleJobs(
670 base::win::ScopedComPtr<IBackgroundCopyManager> bits_manager) {
671 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
672
673 if (!bits_manager)
674 return E_FAIL;
675
676 static base::Time last_sweep;
677
678 const base::TimeDelta time_delta(base::TimeDelta::FromDays(
679 kPurgeStaleJobsIntervalBetweenChecksDays));
680 const base::Time current_time(base::Time::Now());
681 if (last_sweep + time_delta > current_time)
682 return S_OK;
683
684 last_sweep = current_time;
685
686 std::vector<ScopedComPtr<IBackgroundCopyJob> > jobs;
687 HRESULT hr = FindBitsJobIf(
688 std::bind2nd(JobCreationOlderThanDays(), kPurgeStaleJobsAfterDays),
689 bits_manager,
690 &jobs);
691 if (FAILED(hr))
692 return hr;
693
694 for (size_t i = 0; i != jobs.size(); ++i) {
695 CancelJob(jobs[i]);
696 }
697
698 return S_OK;
699 }
700
701 } // namespace component_updater
702
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698