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

Side by Side Diff: chrome/browser/chrome_to_mobile_service.cc

Issue 10914155: Revert 155364 - Revert 155317 - Adjust ChromeToMobile error logging and mitigation. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 3 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 | Annotate | Revision Log
« no previous file with comments | « chrome/browser/chrome_to_mobile_service.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "chrome/browser/chrome_to_mobile_service.h" 5 #include "chrome/browser/chrome_to_mobile_service.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/file_util.h" 9 #include "base/file_util.h"
10 #include "base/guid.h" 10 #include "base/guid.h"
(...skipping 25 matching lines...) Expand all
36 #include "content/public/browser/notification_details.h" 36 #include "content/public/browser/notification_details.h"
37 #include "content/public/browser/notification_source.h" 37 #include "content/public/browser/notification_source.h"
38 #include "content/public/browser/web_contents.h" 38 #include "content/public/browser/web_contents.h"
39 #include "google/cacheinvalidation/include/types.h" 39 #include "google/cacheinvalidation/include/types.h"
40 #include "google/cacheinvalidation/types.pb.h" 40 #include "google/cacheinvalidation/types.pb.h"
41 #include "google_apis/gaia/gaia_constants.h" 41 #include "google_apis/gaia/gaia_constants.h"
42 #include "google_apis/gaia/gaia_urls.h" 42 #include "google_apis/gaia/gaia_urls.h"
43 #include "google_apis/gaia/oauth2_access_token_fetcher.h" 43 #include "google_apis/gaia/oauth2_access_token_fetcher.h"
44 #include "net/base/escape.h" 44 #include "net/base/escape.h"
45 #include "net/base/load_flags.h" 45 #include "net/base/load_flags.h"
46 #include "net/http/http_status_code.h"
46 #include "net/url_request/url_fetcher.h" 47 #include "net/url_request/url_fetcher.h"
47 #include "net/url_request/url_request_context_getter.h" 48 #include "net/url_request/url_request_context_getter.h"
48 #include "sync/notifier/invalidation_util.h" 49 #include "sync/notifier/invalidation_util.h"
49 50
50 namespace { 51 namespace {
51 52
52 // The maximum number of retries for the URLFetcher requests. 53 // The maximum number of retries for the URLFetcher requests.
53 const size_t kMaxRetries = 1; 54 const size_t kMaxRetries = 5;
54 55
55 // The number of hours to delay before retrying authentication on failure. 56 // The number of hours to delay before retrying certain failed operations.
56 const size_t kAuthRetryDelayHours = 6; 57 const size_t kDelayHours = 1;
57
58 // The number of hours before subsequent search requests are allowed.
59 // This value is used to throttle expensive cloud print search requests.
60 // Note that this limitation does not hold across application restarts.
61 const int kSearchRequestDelayHours = 24;
62 58
63 // The sync invalidation object ID for Chrome to Mobile's mobile device list. 59 // The sync invalidation object ID for Chrome to Mobile's mobile device list.
64 // This corresponds with cloud print's server-side invalidation object ID. 60 // This corresponds with cloud print's server-side invalidation object ID.
65 // Meaning: "U" == "User", "CM" == "Chrome to Mobile", "MLST" == "Mobile LiST". 61 // Meaning: "U" == "User", "CM" == "Chrome to Mobile", "MLST" == "Mobile LiST".
66 const char kSyncInvalidationObjectIdChromeToMobileDeviceList[] = "UCMMLST"; 62 const char kSyncInvalidationObjectIdChromeToMobileDeviceList[] = "UCMMLST";
67 63
68 // The cloud print OAuth2 scope and 'printer' type of compatible mobile devices. 64 // The cloud print OAuth2 scope and 'printer' type of compatible mobile devices.
69 const char kCloudPrintAuth[] = "https://www.googleapis.com/auth/cloudprint"; 65 const char kCloudPrintAuth[] = "https://www.googleapis.com/auth/cloudprint";
70 const char kTypeAndroid[] = "ANDROID_CHROME_SNAPSHOT"; 66 const char kTypeAndroid[] = "ANDROID_CHROME_SNAPSHOT";
71 const char kTypeIOS[] = "IOS_CHROME_SNAPSHOT"; 67 const char kTypeIOS[] = "IOS_CHROME_SNAPSHOT";
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after
326 } 322 }
327 323
328 void ChromeToMobileService::Observe( 324 void ChromeToMobileService::Observe(
329 int type, 325 int type,
330 const content::NotificationSource& source, 326 const content::NotificationSource& source,
331 const content::NotificationDetails& details) { 327 const content::NotificationDetails& details) {
332 DCHECK_EQ(type, chrome::NOTIFICATION_TOKEN_AVAILABLE); 328 DCHECK_EQ(type, chrome::NOTIFICATION_TOKEN_AVAILABLE);
333 TokenService::TokenAvailableDetails* token_details = 329 TokenService::TokenAvailableDetails* token_details =
334 content::Details<TokenService::TokenAvailableDetails>(details).ptr(); 330 content::Details<TokenService::TokenAvailableDetails>(details).ptr();
335 // Invalidate the cloud print access token on Gaia login token updates. 331 // Invalidate the cloud print access token on Gaia login token updates.
336 if (token_details->service() == GaiaConstants::kGaiaOAuth2LoginRefreshToken) 332 if (token_details->service() == GaiaConstants::kGaiaOAuth2LoginRefreshToken ||
333 token_details->service() == GaiaConstants::kGaiaOAuth2LoginAccessToken)
337 access_token_.clear(); 334 access_token_.clear();
338 } 335 }
339 336
340 void ChromeToMobileService::OnGetTokenSuccess( 337 void ChromeToMobileService::OnGetTokenSuccess(
341 const std::string& access_token, 338 const std::string& access_token,
342 const base::Time& expiration_time) { 339 const base::Time& expiration_time) {
343 DCHECK(!access_token.empty()); 340 DCHECK(!access_token.empty());
344 access_token_fetcher_.reset(); 341 access_token_fetcher_.reset();
345 auth_retry_timer_.Stop(); 342 auth_retry_timer_.Stop();
346 access_token_ = access_token; 343 access_token_ = access_token;
347 344
348 while (!task_queue_.empty()) { 345 while (!task_queue_.empty()) {
349 // Post all tasks that were queued and waiting on a valid access token. 346 // Post all tasks that were queued and waiting on a valid access token.
350 if (!content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 347 if (!content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
351 task_queue_.front())) { 348 task_queue_.front())) {
352 NOTREACHED(); 349 NOTREACHED();
353 } 350 }
354 task_queue_.pop(); 351 task_queue_.pop();
355 } 352 }
356 } 353 }
357 354
358 void ChromeToMobileService::OnGetTokenFailure( 355 void ChromeToMobileService::OnGetTokenFailure(
359 const GoogleServiceAuthError& error) { 356 const GoogleServiceAuthError& error) {
357 LogMetric(BAD_TOKEN);
358 access_token_.clear();
360 access_token_fetcher_.reset(); 359 access_token_fetcher_.reset();
361 auth_retry_timer_.Stop(); 360 auth_retry_timer_.Stop();
362 361
363 auth_retry_timer_.Start( 362 base::TimeDelta delay = std::max(base::TimeDelta::FromHours(kDelayHours),
364 FROM_HERE, base::TimeDelta::FromHours(kAuthRetryDelayHours), 363 auth_retry_timer_.GetCurrentDelay() * 2);
365 this, &ChromeToMobileService::RequestAccessToken); 364 auth_retry_timer_.Start(FROM_HERE, delay, this,
365 &ChromeToMobileService::RequestAccessToken);
366
367 // Clear the mobile list, which may be (or become) out of date.
368 ListValue empty;
369 profile_->GetPrefs()->Set(prefs::kChromeToMobileDeviceList, empty);
370 UpdateCommandState();
366 } 371 }
367 372
368 void ChromeToMobileService::OnInvalidatorStateChange( 373 void ChromeToMobileService::OnInvalidatorStateChange(
369 syncer::InvalidatorState state) { 374 syncer::InvalidatorState state) {
370 sync_invalidation_enabled_ = (state == syncer::INVALIDATIONS_ENABLED); 375 sync_invalidation_enabled_ = (state == syncer::INVALIDATIONS_ENABLED);
371 UpdateCommandState(); 376 UpdateCommandState();
372 } 377 }
373 378
374 void ChromeToMobileService::OnIncomingInvalidation( 379 void ChromeToMobileService::OnIncomingInvalidation(
375 const syncer::ObjectIdStateMap& id_state_map, 380 const syncer::ObjectIdStateMap& id_state_map,
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
484 request->Start(); 489 request->Start();
485 } 490 }
486 491
487 void ChromeToMobileService::RequestAccessToken() { 492 void ChromeToMobileService::RequestAccessToken() {
488 // Register to observe Gaia login refresh token updates. 493 // Register to observe Gaia login refresh token updates.
489 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); 494 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
490 if (registrar_.IsEmpty()) 495 if (registrar_.IsEmpty())
491 registrar_.Add(this, chrome::NOTIFICATION_TOKEN_AVAILABLE, 496 registrar_.Add(this, chrome::NOTIFICATION_TOKEN_AVAILABLE,
492 content::Source<TokenService>(token_service)); 497 content::Source<TokenService>(token_service));
493 498
494 // Deny concurrent requests and bail without a valid Gaia login refresh token. 499 // Deny concurrent requests.
495 if (access_token_fetcher_.get() || !token_service->HasOAuthLoginToken()) 500 if (access_token_fetcher_.get())
496 return; 501 return;
497 502
503 // Handle invalid login refresh tokens as a failure.
504 if (!token_service->HasOAuthLoginToken()) {
505 OnGetTokenFailure(GoogleServiceAuthError(GoogleServiceAuthError::NONE));
506 return;
507 }
508
498 auth_retry_timer_.Stop(); 509 auth_retry_timer_.Stop();
499 access_token_fetcher_.reset( 510 access_token_fetcher_.reset(
500 new OAuth2AccessTokenFetcher(this, profile_->GetRequestContext())); 511 new OAuth2AccessTokenFetcher(this, profile_->GetRequestContext()));
501 GaiaUrls* gaia_urls = GaiaUrls::GetInstance(); 512 GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
502 access_token_fetcher_->Start(gaia_urls->oauth2_chrome_client_id(), 513 access_token_fetcher_->Start(gaia_urls->oauth2_chrome_client_id(),
503 gaia_urls->oauth2_chrome_client_secret(), 514 gaia_urls->oauth2_chrome_client_secret(),
504 token_service->GetOAuth2LoginRefreshToken(), 515 token_service->GetOAuth2LoginRefreshToken(),
505 std::vector<std::string>(1, kCloudPrintAuth)); 516 std::vector<std::string>(1, kCloudPrintAuth));
506 } 517 }
507 518
508 void ChromeToMobileService::RequestDeviceSearch() { 519 void ChromeToMobileService::RequestDeviceSearch() {
520 search_retry_timer_.Stop();
509 if (access_token_.empty()) { 521 if (access_token_.empty()) {
510 // Enqueue this task to perform after obtaining an access token. 522 // Enqueue this task to perform after obtaining an access token.
511 task_queue_.push(base::Bind(&ChromeToMobileService::RequestDeviceSearch, 523 task_queue_.push(base::Bind(&ChromeToMobileService::RequestDeviceSearch,
512 weak_ptr_factory_.GetWeakPtr())); 524 weak_ptr_factory_.GetWeakPtr()));
513 RequestAccessToken(); 525 RequestAccessToken();
514 return; 526 return;
515 } 527 }
516 528
517 LogMetric(DEVICES_REQUESTED); 529 LogMetric(DEVICES_REQUESTED);
518 530
519 net::URLFetcher* search_request = net::URLFetcher::Create( 531 net::URLFetcher* search_request = net::URLFetcher::Create(
520 GetSearchURL(cloud_print_url_), net::URLFetcher::GET, this); 532 GetSearchURL(cloud_print_url_), net::URLFetcher::GET, this);
521 url_fetchers_.push_back(search_request); 533 url_fetchers_.push_back(search_request);
522 InitRequest(search_request); 534 InitRequest(search_request);
523 search_request->Start(); 535 search_request->Start();
524 } 536 }
525 537
526 void ChromeToMobileService::HandleSearchResponse( 538 void ChromeToMobileService::HandleSearchResponse(
527 const net::URLFetcher* source) { 539 const net::URLFetcher* source) {
528 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 540 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
529 DCHECK_EQ(source->GetURL(), GetSearchURL(cloud_print_url_)); 541 DCHECK_EQ(source->GetURL(), GetSearchURL(cloud_print_url_));
530 542
543 ListValue mobiles;
531 std::string data; 544 std::string data;
532 ListValue* list = NULL; 545 ListValue* list = NULL;
533 DictionaryValue* dictionary = NULL; 546 DictionaryValue* dictionary = NULL;
534 source->GetResponseAsString(&data); 547 source->GetResponseAsString(&data);
535 scoped_ptr<Value> json(base::JSONReader::Read(data)); 548 scoped_ptr<Value> json(base::JSONReader::Read(data));
536 if (json.get() && json->GetAsDictionary(&dictionary) && dictionary && 549 if (json.get() && json->GetAsDictionary(&dictionary) && dictionary &&
537 dictionary->GetList(cloud_print::kPrinterListValue, &list)) { 550 dictionary->GetList(cloud_print::kPrinterListValue, &list)) {
538 ListValue mobiles;
539 std::string type, name, id; 551 std::string type, name, id;
540 DictionaryValue* printer = NULL; 552 DictionaryValue* printer = NULL;
541 DictionaryValue* mobile = NULL; 553 DictionaryValue* mobile = NULL;
542 for (size_t index = 0; index < list->GetSize(); ++index) { 554 for (size_t index = 0; index < list->GetSize(); ++index) {
543 if (list->GetDictionary(index, &printer) && 555 if (list->GetDictionary(index, &printer) &&
544 printer->GetString("type", &type) && 556 printer->GetString("type", &type) &&
545 (type.compare(kTypeAndroid) == 0 || type.compare(kTypeIOS) == 0)) { 557 (type.compare(kTypeAndroid) == 0 || type.compare(kTypeIOS) == 0)) {
546 // Copy just the requisite values from the full |printer| definition. 558 // Copy just the requisite values from the full |printer| definition.
547 if (printer->GetString("displayName", &name) && 559 if (printer->GetString("displayName", &name) &&
548 printer->GetString("id", &id)) { 560 printer->GetString("id", &id)) {
549 mobile = new DictionaryValue(); 561 mobile = new DictionaryValue();
550 mobile->SetString("type", type); 562 mobile->SetString("type", type);
551 mobile->SetString("name", name); 563 mobile->SetString("name", name);
552 mobile->SetString("id", id); 564 mobile->SetString("id", id);
553 mobiles.Append(mobile); 565 mobiles.Append(mobile);
554 } else { 566 } else {
555 NOTREACHED(); 567 NOTREACHED();
556 } 568 }
557 } 569 }
558 } 570 }
571 } else if (source->GetResponseCode() == net::HTTP_FORBIDDEN) {
572 LogMetric(BAD_SEARCH_AUTH);
573 // Invalidate the access token and retry a delayed search on access errors.
574 access_token_.clear();
575 search_retry_timer_.Stop();
576 base::TimeDelta delay = std::max(base::TimeDelta::FromHours(kDelayHours),
577 search_retry_timer_.GetCurrentDelay() * 2);
578 search_retry_timer_.Start(FROM_HERE, delay, this,
579 &ChromeToMobileService::RequestDeviceSearch);
580 } else {
581 LogMetric(BAD_SEARCH_OTHER);
582 }
559 583
560 // Update the cached mobile device list in profile prefs. 584 // Update the cached mobile device list in profile prefs.
561 profile_->GetPrefs()->Set(prefs::kChromeToMobileDeviceList, mobiles); 585 profile_->GetPrefs()->Set(prefs::kChromeToMobileDeviceList, mobiles);
562 586 if (HasMobiles())
563 if (HasMobiles()) 587 LogMetric(DEVICES_AVAILABLE);
564 LogMetric(DEVICES_AVAILABLE); 588 UpdateCommandState();
565 UpdateCommandState();
566 }
567 } 589 }
568 590
569 void ChromeToMobileService::HandleSubmitResponse( 591 void ChromeToMobileService::HandleSubmitResponse(
570 const net::URLFetcher* source) { 592 const net::URLFetcher* source) {
571 // Get the success value from the cloud print server response data. 593 // Get the success value from the cloud print server response data.
572 std::string data; 594 std::string data;
595 bool success = false;
573 source->GetResponseAsString(&data); 596 source->GetResponseAsString(&data);
574 bool success = false;
575 DictionaryValue* dictionary = NULL; 597 DictionaryValue* dictionary = NULL;
576 scoped_ptr<Value> json(base::JSONReader::Read(data)); 598 scoped_ptr<Value> json(base::JSONReader::Read(data));
577 if (json.get() && json->GetAsDictionary(&dictionary) && dictionary) 599 if (json.get() && json->GetAsDictionary(&dictionary) && dictionary) {
578 dictionary->GetBoolean("success", &success); 600 dictionary->GetBoolean("success", &success);
601 int error_code = -1;
602 if (dictionary->GetInteger("errorCode", &error_code))
603 LogMetric(error_code == 407 ? BAD_SEND_407 : BAD_SEND_ERROR);
604 } else if (source->GetResponseCode() == net::HTTP_FORBIDDEN) {
605 LogMetric(BAD_SEND_AUTH);
606 } else {
607 LogMetric(BAD_SEND_OTHER);
608 }
579 609
580 // Log each URL and [DELAYED_]SNAPSHOT job submission response. 610 // Log each URL and [DELAYED_]SNAPSHOT job submission response.
581 LogMetric(success ? SEND_SUCCESS : SEND_ERROR); 611 LogMetric(success ? SEND_SUCCESS : SEND_ERROR);
612 LOG_IF(INFO, !success) << "ChromeToMobile send failed (" <<
613 source->GetResponseCode() << "): " << data;
582 614
583 // Get the observer for this job submission response. 615 // Get the observer for this job submission response.
584 base::WeakPtr<Observer> observer; 616 base::WeakPtr<Observer> observer;
585 RequestObserverMap::iterator i = request_observer_map_.find(source); 617 RequestObserverMap::iterator i = request_observer_map_.find(source);
586 if (i != request_observer_map_.end()) { 618 if (i != request_observer_map_.end()) {
587 observer = i->second; 619 observer = i->second;
588 request_observer_map_.erase(i); 620 request_observer_map_.erase(i);
589 } 621 }
590 622
591 // Check if the observer is waiting on a second response (url or snapshot). 623 // Check if the observer is waiting on a second response (url or snapshot).
592 for (RequestObserverMap::iterator other = request_observer_map_.begin(); 624 for (RequestObserverMap::iterator other = request_observer_map_.begin();
593 observer.get() && (other != request_observer_map_.end()); ++other) { 625 observer.get() && (other != request_observer_map_.end()); ++other) {
594 if (other->second == observer) { 626 if (other->second == observer) {
595 // Delay reporting success until the second response is received. 627 // Delay reporting success until the second response is received.
596 if (success) 628 if (success)
597 return; 629 return;
598 630
599 // Report failure below and ignore the second response. 631 // Report failure below and ignore the second response.
600 request_observer_map_.erase(other); 632 request_observer_map_.erase(other);
601 break; 633 break;
602 } 634 }
603 } 635 }
604 636
605 if (observer.get()) 637 if (observer.get())
606 observer->OnSendComplete(success); 638 observer->OnSendComplete(success);
607 } 639 }
OLDNEW
« no previous file with comments | « chrome/browser/chrome_to_mobile_service.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698