Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "google_apis/gcm/engine/checkin_request.h" | 5 #include "google_apis/gcm/engine/checkin_request.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/message_loop/message_loop.h" | 8 #include "base/message_loop/message_loop.h" |
| 9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 10 #include "google_apis/gcm/monitoring/gcm_stats_recorder.h" | |
| 10 #include "google_apis/gcm/protocol/checkin.pb.h" | 11 #include "google_apis/gcm/protocol/checkin.pb.h" |
| 11 #include "net/http/http_status_code.h" | 12 #include "net/http/http_status_code.h" |
| 12 #include "net/url_request/url_fetcher.h" | 13 #include "net/url_request/url_fetcher.h" |
| 13 #include "net/url_request/url_request_status.h" | 14 #include "net/url_request/url_request_status.h" |
| 14 #include "url/gurl.h" | 15 #include "url/gurl.h" |
| 15 | 16 |
| 16 namespace gcm { | 17 namespace gcm { |
| 17 | 18 |
| 18 namespace { | 19 namespace { |
| 19 const char kCheckinURL[] = "https://android.clients.google.com/checkin"; | 20 const char kCheckinURL[] = "https://android.clients.google.com/checkin"; |
| 20 const char kRequestContentType[] = "application/x-protobuf"; | 21 const char kRequestContentType[] = "application/x-protobuf"; |
| 21 const int kRequestVersionValue = 2; | 22 const int kRequestVersionValue = 2; |
| 22 const int kDefaultUserSerialNumber = 0; | 23 const int kDefaultUserSerialNumber = 0; |
| 23 | 24 |
| 24 // This enum is also used in an UMA histogram (GCMCheckinRequestStatus | 25 // This enum is also used in an UMA histogram (GCMCheckinRequestStatus |
| 25 // enum defined in tools/metrics/histograms/histogram.xml). Hence the entries | 26 // enum defined in tools/metrics/histograms/histogram.xml). Hence the entries |
| 26 // here shouldn't be deleted or re-ordered and new ones should be added to | 27 // here shouldn't be deleted or re-ordered and new ones should be added to |
| 27 // the end. | 28 // the end, and update the GetCheckinRequestStatusString(...) below. |
| 28 enum CheckinRequestStatus { | 29 enum CheckinRequestStatus { |
| 29 SUCCESS, // Checkin completed successfully. | 30 SUCCESS, // Checkin completed successfully. |
| 30 URL_FETCHING_FAILED, // URL fetching failed. | 31 URL_FETCHING_FAILED, // URL fetching failed. |
| 31 HTTP_BAD_REQUEST, // The request was malformed. | 32 HTTP_BAD_REQUEST, // The request was malformed. |
| 32 HTTP_UNAUTHORIZED, // The security token didn't match the android id. | 33 HTTP_UNAUTHORIZED, // The security token didn't match the android id. |
| 33 HTTP_NOT_OK, // HTTP status was not OK. | 34 HTTP_NOT_OK, // HTTP status was not OK. |
| 34 RESPONSE_PARSING_FAILED, // Check in response parsing failed. | 35 RESPONSE_PARSING_FAILED, // Check in response parsing failed. |
| 35 ZERO_ID_OR_TOKEN, // Either returned android id or security token | 36 ZERO_ID_OR_TOKEN, // Either returned android id or security token |
| 36 // was zero. | 37 // was zero. |
| 37 // NOTE: always keep this entry at the end. Add new status types only | 38 // NOTE: always keep this entry at the end. Add new status types only |
| 38 // immediately above this line. Make sure to update the corresponding | 39 // immediately above this line. Make sure to update the corresponding |
| 39 // histogram enum accordingly. | 40 // histogram enum accordingly. |
| 40 STATUS_COUNT | 41 STATUS_COUNT |
| 41 }; | 42 }; |
| 42 | 43 |
| 43 void RecordCheckinStatusToUMA(CheckinRequestStatus status) { | 44 // Returns string representation of enum CheckinRequestStatus. |
| 45 std::string GetCheckinRequestStatusString(CheckinRequestStatus status) { | |
| 46 switch (status) { | |
| 47 case SUCCESS: | |
| 48 return "SUCCESS"; | |
| 49 case URL_FETCHING_FAILED: | |
| 50 return "URL_FETCHING_FAILED"; | |
| 51 case HTTP_BAD_REQUEST: | |
| 52 return "HTTP_BAD_REQUEST"; | |
| 53 case HTTP_UNAUTHORIZED: | |
| 54 return "HTTP_UNAUTHORIZED"; | |
| 55 case HTTP_NOT_OK: | |
| 56 return "HTTP_NOT_OK"; | |
| 57 case RESPONSE_PARSING_FAILED: | |
| 58 return "RESPONSE_PARSING_FAILED"; | |
| 59 case ZERO_ID_OR_TOKEN: | |
| 60 return "ZERO_ID_OR_TOKEN"; | |
| 61 default: | |
| 62 NOTREACHED(); | |
| 63 return "UNKNOWN_STATUS"; | |
| 64 } | |
| 65 } | |
| 66 | |
| 67 // Record checkin failure status to both stats recorder and to UMA. | |
| 68 void RecordCheckinStatusAndToUMA(CheckinRequestStatus status, | |
|
jianli
2014/05/01 21:36:31
nit: RecordCheckinStatusAndReportUMA
juyik
2014/05/01 21:54:34
Done.
| |
| 69 GCMStatsRecorder* recorder, | |
| 70 bool will_retry) { | |
| 44 UMA_HISTOGRAM_ENUMERATION("GCM.CheckinRequestStatus", status, STATUS_COUNT); | 71 UMA_HISTOGRAM_ENUMERATION("GCM.CheckinRequestStatus", status, STATUS_COUNT); |
| 72 recorder->RecordCheckinFailure(GetCheckinRequestStatusString(status), | |
| 73 will_retry); | |
| 45 } | 74 } |
| 46 | 75 |
| 47 } // namespace | 76 } // namespace |
| 48 | 77 |
| 49 CheckinRequest::RequestInfo::RequestInfo( | 78 CheckinRequest::RequestInfo::RequestInfo( |
| 50 uint64 android_id, | 79 uint64 android_id, |
| 51 uint64 security_token, | 80 uint64 security_token, |
| 52 const std::string& settings_digest, | 81 const std::string& settings_digest, |
| 53 const std::vector<std::string>& account_ids, | 82 const std::vector<std::string>& account_ids, |
| 54 const checkin_proto::ChromeBuildProto& chrome_build_proto) | 83 const checkin_proto::ChromeBuildProto& chrome_build_proto) |
| 55 : android_id(android_id), | 84 : android_id(android_id), |
| 56 security_token(security_token), | 85 security_token(security_token), |
| 57 settings_digest(settings_digest), | 86 settings_digest(settings_digest), |
| 58 account_ids(account_ids), | 87 account_ids(account_ids), |
| 59 chrome_build_proto(chrome_build_proto) { | 88 chrome_build_proto(chrome_build_proto) { |
| 60 } | 89 } |
| 61 | 90 |
| 62 CheckinRequest::RequestInfo::~RequestInfo() {} | 91 CheckinRequest::RequestInfo::~RequestInfo() {} |
| 63 | 92 |
| 64 CheckinRequest::CheckinRequest( | 93 CheckinRequest::CheckinRequest( |
| 65 const RequestInfo& request_info, | 94 const RequestInfo& request_info, |
| 66 const net::BackoffEntry::Policy& backoff_policy, | 95 const net::BackoffEntry::Policy& backoff_policy, |
| 67 const CheckinRequestCallback& callback, | 96 const CheckinRequestCallback& callback, |
| 68 net::URLRequestContextGetter* request_context_getter) | 97 net::URLRequestContextGetter* request_context_getter, |
| 98 GCMStatsRecorder* recorder) | |
| 69 : request_context_getter_(request_context_getter), | 99 : request_context_getter_(request_context_getter), |
| 70 callback_(callback), | 100 callback_(callback), |
| 71 backoff_entry_(&backoff_policy), | 101 backoff_entry_(&backoff_policy), |
| 72 request_info_(request_info), | 102 request_info_(request_info), |
| 103 recorder_(recorder), | |
| 73 weak_ptr_factory_(this) { | 104 weak_ptr_factory_(this) { |
| 74 } | 105 } |
| 75 | 106 |
| 76 CheckinRequest::~CheckinRequest() {} | 107 CheckinRequest::~CheckinRequest() {} |
| 77 | 108 |
| 78 void CheckinRequest::Start() { | 109 void CheckinRequest::Start() { |
| 79 DCHECK(!url_fetcher_.get()); | 110 DCHECK(!url_fetcher_.get()); |
| 80 | 111 |
| 81 checkin_proto::AndroidCheckinRequest request; | 112 checkin_proto::AndroidCheckinRequest request; |
| 82 request.set_id(request_info_.android_id); | 113 request.set_id(request_info_.android_id); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 101 request.add_account_cookie("[" + *iter + "]"); | 132 request.add_account_cookie("[" + *iter + "]"); |
| 102 } | 133 } |
| 103 | 134 |
| 104 std::string upload_data; | 135 std::string upload_data; |
| 105 CHECK(request.SerializeToString(&upload_data)); | 136 CHECK(request.SerializeToString(&upload_data)); |
| 106 | 137 |
| 107 url_fetcher_.reset( | 138 url_fetcher_.reset( |
| 108 net::URLFetcher::Create(GURL(kCheckinURL), net::URLFetcher::POST, this)); | 139 net::URLFetcher::Create(GURL(kCheckinURL), net::URLFetcher::POST, this)); |
| 109 url_fetcher_->SetRequestContext(request_context_getter_); | 140 url_fetcher_->SetRequestContext(request_context_getter_); |
| 110 url_fetcher_->SetUploadData(kRequestContentType, upload_data); | 141 url_fetcher_->SetUploadData(kRequestContentType, upload_data); |
| 142 recorder_->RecordCheckinInitiated(request_info_.android_id); | |
| 111 url_fetcher_->Start(); | 143 url_fetcher_->Start(); |
| 112 } | 144 } |
| 113 | 145 |
| 114 void CheckinRequest::RetryWithBackoff(bool update_backoff) { | 146 void CheckinRequest::RetryWithBackoff(bool update_backoff) { |
| 115 if (update_backoff) { | 147 if (update_backoff) { |
| 116 backoff_entry_.InformOfRequest(false); | 148 backoff_entry_.InformOfRequest(false); |
| 117 url_fetcher_.reset(); | 149 url_fetcher_.reset(); |
| 118 } | 150 } |
| 119 | 151 |
| 120 if (backoff_entry_.ShouldRejectRequest()) { | 152 if (backoff_entry_.ShouldRejectRequest()) { |
| 121 DVLOG(1) << "Delay GCM checkin for: " | 153 DVLOG(1) << "Delay GCM checkin for: " |
| 122 << backoff_entry_.GetTimeUntilRelease().InMilliseconds() | 154 << backoff_entry_.GetTimeUntilRelease().InMilliseconds() |
| 123 << " milliseconds."; | 155 << " milliseconds."; |
| 156 recorder_->RecordCheckinDelayedDueToBackoff( | |
| 157 backoff_entry_.GetTimeUntilRelease().InMilliseconds()); | |
| 124 base::MessageLoop::current()->PostDelayedTask( | 158 base::MessageLoop::current()->PostDelayedTask( |
| 125 FROM_HERE, | 159 FROM_HERE, |
| 126 base::Bind(&CheckinRequest::RetryWithBackoff, | 160 base::Bind(&CheckinRequest::RetryWithBackoff, |
| 127 weak_ptr_factory_.GetWeakPtr(), | 161 weak_ptr_factory_.GetWeakPtr(), |
| 128 false), | 162 false), |
| 129 backoff_entry_.GetTimeUntilRelease()); | 163 backoff_entry_.GetTimeUntilRelease()); |
| 130 return; | 164 return; |
| 131 } | 165 } |
| 132 | 166 |
| 133 Start(); | 167 Start(); |
| 134 } | 168 } |
| 135 | 169 |
| 136 void CheckinRequest::OnURLFetchComplete(const net::URLFetcher* source) { | 170 void CheckinRequest::OnURLFetchComplete(const net::URLFetcher* source) { |
| 137 std::string response_string; | 171 std::string response_string; |
| 138 checkin_proto::AndroidCheckinResponse response_proto; | 172 checkin_proto::AndroidCheckinResponse response_proto; |
| 139 if (!source->GetStatus().is_success()) { | 173 if (!source->GetStatus().is_success()) { |
| 140 LOG(ERROR) << "Failed to get checkin response. Fetcher failed. Retrying."; | 174 LOG(ERROR) << "Failed to get checkin response. Fetcher failed. Retrying."; |
| 141 RecordCheckinStatusToUMA(URL_FETCHING_FAILED); | 175 RecordCheckinStatusAndToUMA(URL_FETCHING_FAILED, recorder_, true); |
| 142 RetryWithBackoff(true); | 176 RetryWithBackoff(true); |
| 143 return; | 177 return; |
| 144 } | 178 } |
| 145 | 179 |
| 146 net::HttpStatusCode response_status = static_cast<net::HttpStatusCode>( | 180 net::HttpStatusCode response_status = static_cast<net::HttpStatusCode>( |
| 147 source->GetResponseCode()); | 181 source->GetResponseCode()); |
| 148 if (response_status == net::HTTP_BAD_REQUEST || | 182 if (response_status == net::HTTP_BAD_REQUEST || |
| 149 response_status == net::HTTP_UNAUTHORIZED) { | 183 response_status == net::HTTP_UNAUTHORIZED) { |
| 150 // BAD_REQUEST indicates that the request was malformed. | 184 // BAD_REQUEST indicates that the request was malformed. |
| 151 // UNAUTHORIZED indicates that security token didn't match the android id. | 185 // UNAUTHORIZED indicates that security token didn't match the android id. |
| 152 LOG(ERROR) << "No point retrying the checkin with status: " | 186 LOG(ERROR) << "No point retrying the checkin with status: " |
| 153 << response_status << ". Checkin failed."; | 187 << response_status << ". Checkin failed."; |
| 154 RecordCheckinStatusToUMA(response_status == net::HTTP_BAD_REQUEST ? | 188 CheckinRequestStatus status = response_status == net::HTTP_BAD_REQUEST ? |
| 155 HTTP_BAD_REQUEST : HTTP_UNAUTHORIZED); | 189 HTTP_BAD_REQUEST : HTTP_UNAUTHORIZED; |
| 190 RecordCheckinStatusAndToUMA(status, recorder_, false); | |
| 156 callback_.Run(response_proto); | 191 callback_.Run(response_proto); |
| 157 return; | 192 return; |
| 158 } | 193 } |
| 159 | 194 |
| 160 if (response_status != net::HTTP_OK || | 195 if (response_status != net::HTTP_OK || |
| 161 !source->GetResponseAsString(&response_string) || | 196 !source->GetResponseAsString(&response_string) || |
| 162 !response_proto.ParseFromString(response_string)) { | 197 !response_proto.ParseFromString(response_string)) { |
| 163 LOG(ERROR) << "Failed to get checkin response. HTTP Status: " | 198 LOG(ERROR) << "Failed to get checkin response. HTTP Status: " |
| 164 << response_status << ". Retrying."; | 199 << response_status << ". Retrying."; |
| 165 RecordCheckinStatusToUMA(response_status != net::HTTP_OK ? | 200 CheckinRequestStatus status = response_status != net::HTTP_OK ? |
| 166 HTTP_NOT_OK : RESPONSE_PARSING_FAILED); | 201 HTTP_NOT_OK : RESPONSE_PARSING_FAILED; |
| 202 RecordCheckinStatusAndToUMA(status, recorder_, true); | |
| 167 RetryWithBackoff(true); | 203 RetryWithBackoff(true); |
| 168 return; | 204 return; |
| 169 } | 205 } |
| 170 | 206 |
| 171 if (!response_proto.has_android_id() || | 207 if (!response_proto.has_android_id() || |
| 172 !response_proto.has_security_token() || | 208 !response_proto.has_security_token() || |
| 173 response_proto.android_id() == 0 || | 209 response_proto.android_id() == 0 || |
| 174 response_proto.security_token() == 0) { | 210 response_proto.security_token() == 0) { |
| 175 LOG(ERROR) << "Android ID or security token is 0. Retrying."; | 211 LOG(ERROR) << "Android ID or security token is 0. Retrying."; |
| 176 RecordCheckinStatusToUMA(ZERO_ID_OR_TOKEN); | 212 RecordCheckinStatusAndToUMA(ZERO_ID_OR_TOKEN, recorder_, true); |
| 177 RetryWithBackoff(true); | 213 RetryWithBackoff(true); |
| 178 return; | 214 return; |
| 179 } | 215 } |
| 180 | 216 |
| 181 RecordCheckinStatusToUMA(SUCCESS); | 217 UMA_HISTOGRAM_ENUMERATION("GCM.CheckinRequestStatus", SUCCESS, STATUS_COUNT); |
| 218 recorder_->RecordCheckinSuccess(); | |
|
jianli
2014/05/01 21:36:31
nit: I think these 2 calls could also be merged in
juyik
2014/05/01 21:54:34
Done.
| |
| 182 callback_.Run(response_proto); | 219 callback_.Run(response_proto); |
| 183 } | 220 } |
| 184 | 221 |
| 185 } // namespace gcm | 222 } // namespace gcm |
| OLD | NEW |