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

Side by Side Diff: components/policy/core/common/cloud/device_management_service.cc

Issue 1928013004: Add delayed retry to DeviceManagementService requests. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Nit: punctuation Created 4 years, 7 months 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/policy/core/common/cloud/device_management_service.h" 5 #include "components/policy/core/common/cloud/device_management_service.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/compiler_specific.h" 10 #include "base/compiler_specific.h"
(...skipping 16 matching lines...) Expand all
27 namespace policy { 27 namespace policy {
28 28
29 namespace { 29 namespace {
30 30
31 const char kPostContentType[] = "application/protobuf"; 31 const char kPostContentType[] = "application/protobuf";
32 32
33 const char kServiceTokenAuthHeader[] = "Authorization: GoogleLogin auth="; 33 const char kServiceTokenAuthHeader[] = "Authorization: GoogleLogin auth=";
34 const char kDMTokenAuthHeader[] = "Authorization: GoogleDMToken token="; 34 const char kDMTokenAuthHeader[] = "Authorization: GoogleDMToken token=";
35 35
36 // Number of times to retry on ERR_NETWORK_CHANGED errors. 36 // Number of times to retry on ERR_NETWORK_CHANGED errors.
37 const int kMaxNetworkChangedRetries = 3; 37 const int kMaxRetries = 3;
38 38
39 // HTTP Error Codes of the DM Server with their concrete meanings in the context 39 // HTTP Error Codes of the DM Server with their concrete meanings in the context
40 // of the DM Server communication. 40 // of the DM Server communication.
41 const int kSuccess = 200; 41 const int kSuccess = 200;
42 const int kInvalidArgument = 400; 42 const int kInvalidArgument = 400;
43 const int kInvalidAuthCookieOrDMToken = 401; 43 const int kInvalidAuthCookieOrDMToken = 401;
44 const int kMissingLicenses = 402; 44 const int kMissingLicenses = 402;
45 const int kDeviceManagementNotAllowed = 403; 45 const int kDeviceManagementNotAllowed = 403;
46 const int kInvalidURL = 404; // This error is not coming from the GFE. 46 const int kInvalidURL = 404; // This error is not coming from the GFE.
47 const int kInvalidSerialNumber = 405; 47 const int kInvalidSerialNumber = 405;
48 const int kDomainMismatch = 406; 48 const int kDomainMismatch = 406;
49 const int kDeviceIdConflict = 409; 49 const int kDeviceIdConflict = 409;
50 const int kDeviceNotFound = 410; 50 const int kDeviceNotFound = 410;
51 const int kPendingApproval = 412; 51 const int kPendingApproval = 412;
52 const int kInternalServerError = 500; 52 const int kInternalServerError = 500;
53 const int kServiceUnavailable = 503; 53 const int kServiceUnavailable = 503;
54 const int kPolicyNotFound = 902; 54 const int kPolicyNotFound = 902;
55 const int kDeprovisioned = 903; 55 const int kDeprovisioned = 903;
56 56
57 // Delay after first unsuccessful upload attempt. After each additional failure,
58 // the delay increases exponentially. Can be changed for testing to prevent
59 // timeouts.
60 long g_retry_delay_ms = 10000;
61
57 bool IsProxyError(const net::URLRequestStatus status) { 62 bool IsProxyError(const net::URLRequestStatus status) {
58 switch (status.error()) { 63 switch (status.error()) {
59 case net::ERR_PROXY_CONNECTION_FAILED: 64 case net::ERR_PROXY_CONNECTION_FAILED:
60 case net::ERR_TUNNEL_CONNECTION_FAILED: 65 case net::ERR_TUNNEL_CONNECTION_FAILED:
61 case net::ERR_PROXY_AUTH_UNSUPPORTED: 66 case net::ERR_PROXY_AUTH_UNSUPPORTED:
62 case net::ERR_HTTPS_PROXY_TUNNEL_RESPONSE: 67 case net::ERR_HTTPS_PROXY_TUNNEL_RESPONSE:
63 case net::ERR_MANDATORY_PROXY_CONFIGURATION_FAILED: 68 case net::ERR_MANDATORY_PROXY_CONFIGURATION_FAILED:
64 case net::ERR_PROXY_CERTIFICATE_INVALID: 69 case net::ERR_PROXY_CERTIFICATE_INVALID:
65 case net::ERR_SOCKS_CONNECTION_FAILED: 70 case net::ERR_SOCKS_CONNECTION_FAILED:
66 case net::ERR_SOCKS_CONNECTION_HOST_UNREACHABLE: 71 case net::ERR_SOCKS_CONNECTION_HOST_UNREACHABLE:
67 return true; 72 return true;
68 } 73 }
69 return false; 74 return false;
70 } 75 }
71 76
77 bool IsConnectionError(const net::URLRequestStatus status) {
78 switch (status.error()) {
79 case net::ERR_NETWORK_CHANGED:
80 case net::ERR_NAME_NOT_RESOLVED:
81 case net::ERR_INTERNET_DISCONNECTED:
82 case net::ERR_ADDRESS_UNREACHABLE:
83 case net::ERR_CONNECTION_TIMED_OUT:
84 case net::ERR_NAME_RESOLUTION_FAILED:
85 return true;
86 }
87 return false;
88 }
89
72 bool IsProtobufMimeType(const net::URLFetcher* fetcher) { 90 bool IsProtobufMimeType(const net::URLFetcher* fetcher) {
73 return fetcher->GetResponseHeaders()->HasHeaderValue( 91 return fetcher->GetResponseHeaders()->HasHeaderValue(
74 "content-type", "application/x-protobuffer"); 92 "content-type", "application/x-protobuffer");
75 } 93 }
76 94
77 bool FailedWithProxy(const net::URLFetcher* fetcher) { 95 bool FailedWithProxy(const net::URLFetcher* fetcher) {
78 if ((fetcher->GetLoadFlags() & net::LOAD_BYPASS_PROXY) != 0) { 96 if ((fetcher->GetLoadFlags() & net::LOAD_BYPASS_PROXY) != 0) {
79 // The request didn't use a proxy. 97 // The request didn't use a proxy.
80 return false; 98 return false;
81 } 99 }
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 void ConfigureRequest(net::URLFetcher* fetcher); 178 void ConfigureRequest(net::URLFetcher* fetcher);
161 179
162 // Returns true if this job should be retried. |fetcher| has just completed, 180 // Returns true if this job should be retried. |fetcher| has just completed,
163 // and can be inspected to determine if the request failed and should be 181 // and can be inspected to determine if the request failed and should be
164 // retried. 182 // retried.
165 bool ShouldRetry(const net::URLFetcher* fetcher); 183 bool ShouldRetry(const net::URLFetcher* fetcher);
166 184
167 // Invoked right before retrying this job. 185 // Invoked right before retrying this job.
168 void PrepareRetry(); 186 void PrepareRetry();
169 187
188 // Number of times that this job has been retried due to connection errors.
189 int retries_count() { return retries_count_; }
190
170 protected: 191 protected:
171 // DeviceManagementRequestJob: 192 // DeviceManagementRequestJob:
172 void Run() override; 193 void Run() override;
173 194
174 private: 195 private:
175 // Invokes the callback with the given error code. 196 // Invokes the callback with the given error code.
176 void ReportError(DeviceManagementStatus code); 197 void ReportError(DeviceManagementStatus code);
177 198
178 // Pointer to the service this job is associated with. 199 // Pointer to the service this job is associated with.
179 DeviceManagementService* service_; 200 DeviceManagementService* service_;
180 201
181 // Whether the BYPASS_PROXY flag should be set by ConfigureRequest(). 202 // Whether the BYPASS_PROXY flag should be set by ConfigureRequest().
182 bool bypass_proxy_; 203 bool bypass_proxy_;
183 204
184 // Number of times that this job has been retried due to ERR_NETWORK_CHANGED. 205 // Number of times that this job has been retried due to connection errors.
185 int retries_count_; 206 int retries_count_;
186 207
187 // The request context to use for this job. 208 // The request context to use for this job.
188 scoped_refptr<net::URLRequestContextGetter> request_context_; 209 scoped_refptr<net::URLRequestContextGetter> request_context_;
189 210
190 DISALLOW_COPY_AND_ASSIGN(DeviceManagementRequestJobImpl); 211 DISALLOW_COPY_AND_ASSIGN(DeviceManagementRequestJobImpl);
191 }; 212 };
192 213
193 DeviceManagementRequestJobImpl::DeviceManagementRequestJobImpl( 214 DeviceManagementRequestJobImpl::DeviceManagementRequestJobImpl(
194 JobType type, 215 JobType type,
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
325 bool DeviceManagementRequestJobImpl::ShouldRetry( 346 bool DeviceManagementRequestJobImpl::ShouldRetry(
326 const net::URLFetcher* fetcher) { 347 const net::URLFetcher* fetcher) {
327 if (FailedWithProxy(fetcher) && !bypass_proxy_) { 348 if (FailedWithProxy(fetcher) && !bypass_proxy_) {
328 // Retry the job if it failed due to a broken proxy, by bypassing the 349 // Retry the job if it failed due to a broken proxy, by bypassing the
329 // proxy on the next try. 350 // proxy on the next try.
330 bypass_proxy_ = true; 351 bypass_proxy_ = true;
331 return true; 352 return true;
332 } 353 }
333 354
334 // Early device policy fetches on ChromeOS and Auto-Enrollment checks are 355 // Early device policy fetches on ChromeOS and Auto-Enrollment checks are
335 // often interrupted during ChromeOS startup when network change notifications 356 // often interrupted during ChromeOS startup when network is not yet ready.
336 // are sent. Allowing the fetcher to retry once after that is enough to 357 // Allowing the fetcher to retry once after that is enough to recover; allow
337 // recover; allow it to retry up to 3 times just in case. 358 // it to retry up to 3 times just in case.
338 if (fetcher->GetStatus().error() == net::ERR_NETWORK_CHANGED && 359 if (IsConnectionError(fetcher->GetStatus()) && retries_count_ < kMaxRetries) {
339 retries_count_ < kMaxNetworkChangedRetries) {
340 ++retries_count_; 360 ++retries_count_;
341 return true; 361 return true;
342 } 362 }
343 363
344 // The request didn't fail, or the limit of retry attempts has been reached; 364 // The request didn't fail, or the limit of retry attempts has been reached;
345 // forward the result to the job owner. 365 // forward the result to the job owner.
346 return false; 366 return false;
347 } 367 }
348 368
349 void DeviceManagementRequestJobImpl::PrepareRetry() { 369 void DeviceManagementRequestJobImpl::PrepareRetry() {
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
409 429
410 DeviceManagementService::~DeviceManagementService() { 430 DeviceManagementService::~DeviceManagementService() {
411 // All running jobs should have been cancelled by now. 431 // All running jobs should have been cancelled by now.
412 DCHECK(pending_jobs_.empty()); 432 DCHECK(pending_jobs_.empty());
413 DCHECK(queued_jobs_.empty()); 433 DCHECK(queued_jobs_.empty());
414 } 434 }
415 435
416 DeviceManagementRequestJob* DeviceManagementService::CreateJob( 436 DeviceManagementRequestJob* DeviceManagementService::CreateJob(
417 DeviceManagementRequestJob::JobType type, 437 DeviceManagementRequestJob::JobType type,
418 const scoped_refptr<net::URLRequestContextGetter>& request_context) { 438 const scoped_refptr<net::URLRequestContextGetter>& request_context) {
439 DCHECK(thread_checker_.CalledOnValidThread());
440
419 return new DeviceManagementRequestJobImpl( 441 return new DeviceManagementRequestJobImpl(
420 type, 442 type,
421 configuration_->GetAgentParameter(), 443 configuration_->GetAgentParameter(),
422 configuration_->GetPlatformParameter(), 444 configuration_->GetPlatformParameter(),
423 this, 445 this,
424 request_context); 446 request_context);
425 } 447 }
426 448
427 void DeviceManagementService::ScheduleInitialization( 449 void DeviceManagementService::ScheduleInitialization(
428 int64_t delay_milliseconds) { 450 int64_t delay_milliseconds) {
451 DCHECK(thread_checker_.CalledOnValidThread());
452
429 if (initialized_) 453 if (initialized_)
430 return; 454 return;
431 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( 455 task_runner_->PostDelayedTask(
432 FROM_HERE, base::Bind(&DeviceManagementService::Initialize, 456 FROM_HERE, base::Bind(&DeviceManagementService::Initialize,
433 weak_ptr_factory_.GetWeakPtr()), 457 weak_ptr_factory_.GetWeakPtr()),
434 base::TimeDelta::FromMilliseconds(delay_milliseconds)); 458 base::TimeDelta::FromMilliseconds(delay_milliseconds));
435 } 459 }
436 460
437 void DeviceManagementService::Initialize() { 461 void DeviceManagementService::Initialize() {
462 DCHECK(thread_checker_.CalledOnValidThread());
438 if (initialized_) 463 if (initialized_)
439 return; 464 return;
440 initialized_ = true; 465 initialized_ = true;
441 466
442 while (!queued_jobs_.empty()) { 467 while (!queued_jobs_.empty()) {
443 StartJob(queued_jobs_.front()); 468 StartJob(queued_jobs_.front());
444 queued_jobs_.pop_front(); 469 queued_jobs_.pop_front();
445 } 470 }
446 } 471 }
447 472
448 void DeviceManagementService::Shutdown() { 473 void DeviceManagementService::Shutdown() {
474 DCHECK(thread_checker_.CalledOnValidThread());
475 weak_ptr_factory_.InvalidateWeakPtrs();
449 for (JobFetcherMap::iterator job(pending_jobs_.begin()); 476 for (JobFetcherMap::iterator job(pending_jobs_.begin());
450 job != pending_jobs_.end(); 477 job != pending_jobs_.end();
451 ++job) { 478 ++job) {
452 delete job->first; 479 delete job->first;
453 queued_jobs_.push_back(job->second); 480 queued_jobs_.push_back(job->second);
454 } 481 }
455 pending_jobs_.clear(); 482 pending_jobs_.clear();
456 } 483 }
457 484
458 DeviceManagementService::DeviceManagementService( 485 DeviceManagementService::DeviceManagementService(
459 std::unique_ptr<Configuration> configuration) 486 std::unique_ptr<Configuration> configuration)
460 : configuration_(std::move(configuration)), 487 : configuration_(std::move(configuration)),
461 initialized_(false), 488 initialized_(false),
489 task_runner_(base::ThreadTaskRunnerHandle::Get()),
462 weak_ptr_factory_(this) { 490 weak_ptr_factory_(this) {
463 DCHECK(configuration_); 491 DCHECK(configuration_);
464 } 492 }
465 493
466 void DeviceManagementService::StartJob(DeviceManagementRequestJobImpl* job) { 494 void DeviceManagementService::StartJob(DeviceManagementRequestJobImpl* job) {
495 DCHECK(thread_checker_.CalledOnValidThread());
496
467 std::string server_url = GetServerUrl(); 497 std::string server_url = GetServerUrl();
468 net::URLFetcher* fetcher = 498 net::URLFetcher* fetcher =
469 net::URLFetcher::Create(kURLFetcherID, job->GetURL(server_url), 499 net::URLFetcher::Create(kURLFetcherID, job->GetURL(server_url),
470 net::URLFetcher::POST, this).release(); 500 net::URLFetcher::POST, this).release();
471 data_use_measurement::DataUseUserData::AttachToFetcher( 501 data_use_measurement::DataUseUserData::AttachToFetcher(
472 fetcher, data_use_measurement::DataUseUserData::POLICY); 502 fetcher, data_use_measurement::DataUseUserData::POLICY);
473 job->ConfigureRequest(fetcher); 503 job->ConfigureRequest(fetcher);
474 pending_jobs_[fetcher] = job; 504 pending_jobs_[fetcher] = job;
475 fetcher->Start(); 505 fetcher->Start();
476 } 506 }
477 507
478 std::string DeviceManagementService::GetServerUrl() { 508 std::string DeviceManagementService::GetServerUrl() {
509 DCHECK(thread_checker_.CalledOnValidThread());
479 return configuration_->GetServerUrl(); 510 return configuration_->GetServerUrl();
480 } 511 }
481 512
513 // static
514 void DeviceManagementService::SetRetryDelayForTesting(long retry_delay_ms) {
515 CHECK_GE(retry_delay_ms, 0);
516 g_retry_delay_ms = retry_delay_ms;
517 }
518
482 void DeviceManagementService::OnURLFetchComplete( 519 void DeviceManagementService::OnURLFetchComplete(
483 const net::URLFetcher* source) { 520 const net::URLFetcher* source) {
484 JobFetcherMap::iterator entry(pending_jobs_.find(source)); 521 JobFetcherMap::iterator entry(pending_jobs_.find(source));
485 if (entry == pending_jobs_.end()) { 522 if (entry == pending_jobs_.end()) {
486 NOTREACHED() << "Callback from foreign URL fetcher"; 523 NOTREACHED() << "Callback from foreign URL fetcher";
487 return; 524 return;
488 } 525 }
489 526
490 DeviceManagementRequestJobImpl* job = entry->second; 527 DeviceManagementRequestJobImpl* job = entry->second;
491 pending_jobs_.erase(entry); 528 pending_jobs_.erase(entry);
492 529
493 if (job->ShouldRetry(source)) { 530 if (job->ShouldRetry(source)) {
494 VLOG(1) << "Retrying dmserver request.";
495 job->PrepareRetry(); 531 job->PrepareRetry();
496 StartJob(job); 532 int delay = g_retry_delay_ms << (job->retries_count() - 1);
533 LOG(WARNING) << "Dmserver request failed, retrying in " << delay / 1000
534 << "s.";
535 task_runner_->PostDelayedTask(
536 FROM_HERE, base::Bind(&DeviceManagementService::StartJob,
537 weak_ptr_factory_.GetWeakPtr(), job),
538 base::TimeDelta::FromMilliseconds(delay));
497 } else { 539 } else {
498 std::string data; 540 std::string data;
499 source->GetResponseAsString(&data); 541 source->GetResponseAsString(&data);
500 job->HandleResponse(source->GetStatus(), source->GetResponseCode(), 542 job->HandleResponse(source->GetStatus(), source->GetResponseCode(),
501 source->GetCookies(), data); 543 source->GetCookies(), data);
502 } 544 }
503 delete source; 545 delete source;
504 } 546 }
505 547
506 void DeviceManagementService::AddJob(DeviceManagementRequestJobImpl* job) { 548 void DeviceManagementService::AddJob(DeviceManagementRequestJobImpl* job) {
(...skipping 14 matching lines...) Expand all
521 } 563 }
522 } 564 }
523 565
524 const JobQueue::iterator elem = 566 const JobQueue::iterator elem =
525 std::find(queued_jobs_.begin(), queued_jobs_.end(), job); 567 std::find(queued_jobs_.begin(), queued_jobs_.end(), job);
526 if (elem != queued_jobs_.end()) 568 if (elem != queued_jobs_.end())
527 queued_jobs_.erase(elem); 569 queued_jobs_.erase(elem);
528 } 570 }
529 571
530 } // namespace policy 572 } // namespace policy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698