15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/gcm/engine/checkin_request.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/bind.h"
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/message_loop/message_loop.h"
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/metrics/histogram.h"
10010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "google_apis/gcm/monitoring/gcm_stats_recorder.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/gcm/protocol/checkin.pb.h"
12116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "net/base/load_flags.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/http/http_status_code.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/url_request/url_fetcher.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/url_request/url_request_status.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace gcm {
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kRequestContentType[] = "application/x-protobuf";
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const int kRequestVersionValue = 3;
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const int kDefaultUserSerialNumber = 0;
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// This enum is also used in an UMA histogram (GCMCheckinRequestStatus
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// enum defined in tools/metrics/histograms/histogram.xml). Hence the entries
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// here shouldn't be deleted or re-ordered and new ones should be added to
27010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// the end, and update the GetCheckinRequestStatusString(...) below.
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)enum CheckinRequestStatus {
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SUCCESS,                    // Checkin completed successfully.
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  URL_FETCHING_FAILED,        // URL fetching failed.
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HTTP_BAD_REQUEST,           // The request was malformed.
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HTTP_UNAUTHORIZED,          // The security token didn't match the android id.
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HTTP_NOT_OK,                // HTTP status was not OK.
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RESPONSE_PARSING_FAILED,    // Check in response parsing failed.
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ZERO_ID_OR_TOKEN,           // Either returned android id or security token
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              // was zero.
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // NOTE: always keep this entry at the end. Add new status types only
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // immediately above this line. Make sure to update the corresponding
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // histogram enum accordingly.
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  STATUS_COUNT
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
43010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Returns string representation of enum CheckinRequestStatus.
44010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)std::string GetCheckinRequestStatusString(CheckinRequestStatus status) {
45010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  switch (status) {
46010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    case SUCCESS:
47010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      return "SUCCESS";
48010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    case URL_FETCHING_FAILED:
49010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      return "URL_FETCHING_FAILED";
50010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    case HTTP_BAD_REQUEST:
51010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      return "HTTP_BAD_REQUEST";
52010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    case HTTP_UNAUTHORIZED:
53010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      return "HTTP_UNAUTHORIZED";
54010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    case HTTP_NOT_OK:
55010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      return "HTTP_NOT_OK";
56010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    case RESPONSE_PARSING_FAILED:
57010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      return "RESPONSE_PARSING_FAILED";
58010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    case ZERO_ID_OR_TOKEN:
59010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      return "ZERO_ID_OR_TOKEN";
60010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    default:
61010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      NOTREACHED();
62010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      return "UNKNOWN_STATUS";
63010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
64010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
65010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
66010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Records checkin status to both stats recorder and reports to UMA.
67010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void RecordCheckinStatusAndReportUMA(CheckinRequestStatus status,
68010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                     GCMStatsRecorder* recorder,
69010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                     bool will_retry) {
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("GCM.CheckinRequestStatus", status, STATUS_COUNT);
71010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (status == SUCCESS)
72010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    recorder->RecordCheckinSuccess();
73010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  else {
74010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    recorder->RecordCheckinFailure(GetCheckinRequestStatusString(status),
75010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                   will_retry);
76010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
81a02191e04bc25c4935f804f2c080ae28663d096dBen MurdochCheckinRequest::RequestInfo::RequestInfo(
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint64 android_id,
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint64 security_token,
84116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const std::map<std::string, std::string>& account_tokens,
85a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const std::string& settings_digest,
86a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const checkin_proto::ChromeBuildProto& chrome_build_proto)
87a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    : android_id(android_id),
88a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      security_token(security_token),
89116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      account_tokens(account_tokens),
90a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      settings_digest(settings_digest),
91a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      chrome_build_proto(chrome_build_proto) {
92a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
93a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
94a02191e04bc25c4935f804f2c080ae28663d096dBen MurdochCheckinRequest::RequestInfo::~RequestInfo() {}
95a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
96a02191e04bc25c4935f804f2c080ae28663d096dBen MurdochCheckinRequest::CheckinRequest(
97010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const GURL& checkin_url,
98a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const RequestInfo& request_info,
99a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const net::BackoffEntry::Policy& backoff_policy,
100a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const CheckinRequestCallback& callback,
101010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    net::URLRequestContextGetter* request_context_getter,
102010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    GCMStatsRecorder* recorder)
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : request_context_getter_(request_context_getter),
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      callback_(callback),
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      backoff_entry_(&backoff_policy),
106010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      checkin_url_(checkin_url),
107a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      request_info_(request_info),
108010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      recorder_(recorder),
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      weak_ptr_factory_(this) {
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)CheckinRequest::~CheckinRequest() {}
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void CheckinRequest::Start() {
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!url_fetcher_.get());
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  checkin_proto::AndroidCheckinRequest request;
118a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  request.set_id(request_info_.android_id);
119a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  request.set_security_token(request_info_.security_token);
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  request.set_user_serial_number(kDefaultUserSerialNumber);
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  request.set_version(kRequestVersionValue);
122a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (!request_info_.settings_digest.empty())
123a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    request.set_digest(request_info_.settings_digest);
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  checkin_proto::AndroidCheckinProto* checkin = request.mutable_checkin();
126a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  checkin->mutable_chrome_build()->CopyFrom(request_info_.chrome_build_proto);
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(CHROME_OS)
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  checkin->set_type(checkin_proto::DEVICE_CHROME_OS);
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#else
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  checkin->set_type(checkin_proto::DEVICE_CHROME_BROWSER);
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
133116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Pack a map of email -> token mappings into a repeated field, where odd
134116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // entries are email addresses, while even ones are respective OAuth2 tokens.
135116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (std::map<std::string, std::string>::const_iterator iter =
136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch           request_info_.account_tokens.begin();
137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       iter != request_info_.account_tokens.end();
138116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       ++iter) {
139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    request.add_account_cookie(iter->first);
140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    request.add_account_cookie(iter->second);
141116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
142116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string upload_data;
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CHECK(request.SerializeToString(&upload_data));
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  url_fetcher_.reset(
147010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      net::URLFetcher::Create(checkin_url_, net::URLFetcher::POST, this));
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  url_fetcher_->SetRequestContext(request_context_getter_);
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  url_fetcher_->SetUploadData(kRequestContentType, upload_data);
150116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
151116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                             net::LOAD_DO_NOT_SAVE_COOKIES);
152010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  recorder_->RecordCheckinInitiated(request_info_.android_id);
1530de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  request_start_time_ = base::TimeTicks::Now();
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  url_fetcher_->Start();
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void CheckinRequest::RetryWithBackoff(bool update_backoff) {
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (update_backoff) {
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    backoff_entry_.InformOfRequest(false);
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    url_fetcher_.reset();
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (backoff_entry_.ShouldRejectRequest()) {
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DVLOG(1) << "Delay GCM checkin for: "
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             << backoff_entry_.GetTimeUntilRelease().InMilliseconds()
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             << " milliseconds.";
167010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    recorder_->RecordCheckinDelayedDueToBackoff(
168010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        backoff_entry_.GetTimeUntilRelease().InMilliseconds());
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::MessageLoop::current()->PostDelayedTask(
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        FROM_HERE,
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::Bind(&CheckinRequest::RetryWithBackoff,
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   weak_ptr_factory_.GetWeakPtr(),
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   false),
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        backoff_entry_.GetTimeUntilRelease());
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Start();
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void CheckinRequest::OnURLFetchComplete(const net::URLFetcher* source) {
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string response_string;
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  checkin_proto::AndroidCheckinResponse response_proto;
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!source->GetStatus().is_success()) {
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Failed to get checkin response. Fetcher failed. Retrying.";
186010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    RecordCheckinStatusAndReportUMA(URL_FETCHING_FAILED, recorder_, true);
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RetryWithBackoff(true);
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  net::HttpStatusCode response_status = static_cast<net::HttpStatusCode>(
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      source->GetResponseCode());
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (response_status == net::HTTP_BAD_REQUEST ||
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      response_status == net::HTTP_UNAUTHORIZED) {
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // BAD_REQUEST indicates that the request was malformed.
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // UNAUTHORIZED indicates that security token didn't match the android id.
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "No point retrying the checkin with status: "
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               << response_status << ". Checkin failed.";
199010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    CheckinRequestStatus status = response_status == net::HTTP_BAD_REQUEST ?
200010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        HTTP_BAD_REQUEST : HTTP_UNAUTHORIZED;
201010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    RecordCheckinStatusAndReportUMA(status, recorder_, false);
202a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    callback_.Run(response_proto);
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (response_status != net::HTTP_OK ||
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      !source->GetResponseAsString(&response_string) ||
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      !response_proto.ParseFromString(response_string)) {
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Failed to get checkin response. HTTP Status: "
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               << response_status << ". Retrying.";
211010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    CheckinRequestStatus status = response_status != net::HTTP_OK ?
212010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        HTTP_NOT_OK : RESPONSE_PARSING_FAILED;
213010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    RecordCheckinStatusAndReportUMA(status, recorder_, true);
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RetryWithBackoff(true);
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!response_proto.has_android_id() ||
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      !response_proto.has_security_token() ||
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      response_proto.android_id() == 0 ||
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      response_proto.security_token() == 0) {
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Android ID or security token is 0. Retrying.";
223010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    RecordCheckinStatusAndReportUMA(ZERO_ID_OR_TOKEN, recorder_, true);
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RetryWithBackoff(true);
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
228010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  RecordCheckinStatusAndReportUMA(SUCCESS, recorder_, false);
2290de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  UMA_HISTOGRAM_COUNTS("GCM.CheckinRetryCount",
2300de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                       backoff_entry_.failure_count());
2310de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)  UMA_HISTOGRAM_TIMES("GCM.CheckinCompleteTime",
2320de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)                      base::TimeTicks::Now() - request_start_time_);
233a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  callback_.Run(response_proto);
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace gcm
237