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 |
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 | |
43 void RecordCheckinStatusToUMA(CheckinRequestStatus status) { | 67 void RecordCheckinStatusToUMA(CheckinRequestStatus status) { |
44 UMA_HISTOGRAM_ENUMERATION("GCM.CheckinRequestStatus", status, STATUS_COUNT); | 68 UMA_HISTOGRAM_ENUMERATION("GCM.CheckinRequestStatus", status, STATUS_COUNT); |
45 } | 69 } |
46 | 70 |
47 } // namespace | 71 } // namespace |
48 | 72 |
49 CheckinRequest::RequestInfo::RequestInfo( | 73 CheckinRequest::RequestInfo::RequestInfo( |
50 uint64 android_id, | 74 uint64 android_id, |
51 uint64 security_token, | 75 uint64 security_token, |
52 const std::string& settings_digest, | 76 const std::string& settings_digest, |
53 const std::vector<std::string>& account_ids, | 77 const std::vector<std::string>& account_ids, |
54 const checkin_proto::ChromeBuildProto& chrome_build_proto) | 78 const checkin_proto::ChromeBuildProto& chrome_build_proto) |
55 : android_id(android_id), | 79 : android_id(android_id), |
56 security_token(security_token), | 80 security_token(security_token), |
57 settings_digest(settings_digest), | 81 settings_digest(settings_digest), |
58 account_ids(account_ids), | 82 account_ids(account_ids), |
59 chrome_build_proto(chrome_build_proto) { | 83 chrome_build_proto(chrome_build_proto) { |
60 } | 84 } |
61 | 85 |
62 CheckinRequest::RequestInfo::~RequestInfo() {} | 86 CheckinRequest::RequestInfo::~RequestInfo() {} |
63 | 87 |
64 CheckinRequest::CheckinRequest( | 88 CheckinRequest::CheckinRequest( |
65 const RequestInfo& request_info, | 89 const RequestInfo& request_info, |
66 const net::BackoffEntry::Policy& backoff_policy, | 90 const net::BackoffEntry::Policy& backoff_policy, |
67 const CheckinRequestCallback& callback, | 91 const CheckinRequestCallback& callback, |
68 net::URLRequestContextGetter* request_context_getter) | 92 net::URLRequestContextGetter* request_context_getter, |
93 GCMStatsRecorder* recorder) | |
69 : request_context_getter_(request_context_getter), | 94 : request_context_getter_(request_context_getter), |
70 callback_(callback), | 95 callback_(callback), |
71 backoff_entry_(&backoff_policy), | 96 backoff_entry_(&backoff_policy), |
72 request_info_(request_info), | 97 request_info_(request_info), |
98 recorder_(recorder), | |
73 weak_ptr_factory_(this) { | 99 weak_ptr_factory_(this) { |
74 } | 100 } |
75 | 101 |
76 CheckinRequest::~CheckinRequest() {} | 102 CheckinRequest::~CheckinRequest() {} |
77 | 103 |
78 void CheckinRequest::Start() { | 104 void CheckinRequest::Start() { |
79 DCHECK(!url_fetcher_.get()); | 105 DCHECK(!url_fetcher_.get()); |
80 | 106 |
81 checkin_proto::AndroidCheckinRequest request; | 107 checkin_proto::AndroidCheckinRequest request; |
82 request.set_id(request_info_.android_id); | 108 request.set_id(request_info_.android_id); |
(...skipping 18 matching lines...) Expand all Loading... | |
101 request.add_account_cookie("[" + *iter + "]"); | 127 request.add_account_cookie("[" + *iter + "]"); |
102 } | 128 } |
103 | 129 |
104 std::string upload_data; | 130 std::string upload_data; |
105 CHECK(request.SerializeToString(&upload_data)); | 131 CHECK(request.SerializeToString(&upload_data)); |
106 | 132 |
107 url_fetcher_.reset( | 133 url_fetcher_.reset( |
108 net::URLFetcher::Create(GURL(kCheckinURL), net::URLFetcher::POST, this)); | 134 net::URLFetcher::Create(GURL(kCheckinURL), net::URLFetcher::POST, this)); |
109 url_fetcher_->SetRequestContext(request_context_getter_); | 135 url_fetcher_->SetRequestContext(request_context_getter_); |
110 url_fetcher_->SetUploadData(kRequestContentType, upload_data); | 136 url_fetcher_->SetUploadData(kRequestContentType, upload_data); |
137 recorder_->RecordCheckinInitiated(request_info_.android_id); | |
111 url_fetcher_->Start(); | 138 url_fetcher_->Start(); |
112 } | 139 } |
113 | 140 |
114 void CheckinRequest::RetryWithBackoff(bool update_backoff) { | 141 void CheckinRequest::RetryWithBackoff(bool update_backoff) { |
115 if (update_backoff) { | 142 if (update_backoff) { |
116 backoff_entry_.InformOfRequest(false); | 143 backoff_entry_.InformOfRequest(false); |
117 url_fetcher_.reset(); | 144 url_fetcher_.reset(); |
118 } | 145 } |
119 | 146 |
120 if (backoff_entry_.ShouldRejectRequest()) { | 147 if (backoff_entry_.ShouldRejectRequest()) { |
121 DVLOG(1) << "Delay GCM checkin for: " | 148 DVLOG(1) << "Delay GCM checkin for: " |
122 << backoff_entry_.GetTimeUntilRelease().InMilliseconds() | 149 << backoff_entry_.GetTimeUntilRelease().InMilliseconds() |
123 << " milliseconds."; | 150 << " milliseconds."; |
151 recorder_->RecordCheckinDelayedDueToBackoff( | |
152 backoff_entry_.GetTimeUntilRelease().InMilliseconds()); | |
124 base::MessageLoop::current()->PostDelayedTask( | 153 base::MessageLoop::current()->PostDelayedTask( |
125 FROM_HERE, | 154 FROM_HERE, |
126 base::Bind(&CheckinRequest::RetryWithBackoff, | 155 base::Bind(&CheckinRequest::RetryWithBackoff, |
127 weak_ptr_factory_.GetWeakPtr(), | 156 weak_ptr_factory_.GetWeakPtr(), |
128 false), | 157 false), |
129 backoff_entry_.GetTimeUntilRelease()); | 158 backoff_entry_.GetTimeUntilRelease()); |
130 return; | 159 return; |
131 } | 160 } |
132 | 161 |
133 Start(); | 162 Start(); |
134 } | 163 } |
135 | 164 |
136 void CheckinRequest::OnURLFetchComplete(const net::URLFetcher* source) { | 165 void CheckinRequest::OnURLFetchComplete(const net::URLFetcher* source) { |
137 std::string response_string; | 166 std::string response_string; |
138 checkin_proto::AndroidCheckinResponse response_proto; | 167 checkin_proto::AndroidCheckinResponse response_proto; |
139 if (!source->GetStatus().is_success()) { | 168 if (!source->GetStatus().is_success()) { |
140 LOG(ERROR) << "Failed to get checkin response. Fetcher failed. Retrying."; | 169 LOG(ERROR) << "Failed to get checkin response. Fetcher failed. Retrying."; |
141 RecordCheckinStatusToUMA(URL_FETCHING_FAILED); | 170 RecordCheckinStatusToUMA(URL_FETCHING_FAILED); |
171 recorder_->RecordCheckinFailure( | |
jianli
2014/05/01 00:22:35
Can this be merged with RecordCheckinStatusToUMA?
juyik
2014/05/01 01:03:35
Done.
| |
172 GetCheckinRequestStatusString(URL_FETCHING_FAILED), true); | |
142 RetryWithBackoff(true); | 173 RetryWithBackoff(true); |
143 return; | 174 return; |
144 } | 175 } |
145 | 176 |
146 net::HttpStatusCode response_status = static_cast<net::HttpStatusCode>( | 177 net::HttpStatusCode response_status = static_cast<net::HttpStatusCode>( |
147 source->GetResponseCode()); | 178 source->GetResponseCode()); |
148 if (response_status == net::HTTP_BAD_REQUEST || | 179 if (response_status == net::HTTP_BAD_REQUEST || |
149 response_status == net::HTTP_UNAUTHORIZED) { | 180 response_status == net::HTTP_UNAUTHORIZED) { |
150 // BAD_REQUEST indicates that the request was malformed. | 181 // BAD_REQUEST indicates that the request was malformed. |
151 // UNAUTHORIZED indicates that security token didn't match the android id. | 182 // UNAUTHORIZED indicates that security token didn't match the android id. |
152 LOG(ERROR) << "No point retrying the checkin with status: " | 183 LOG(ERROR) << "No point retrying the checkin with status: " |
153 << response_status << ". Checkin failed."; | 184 << response_status << ". Checkin failed."; |
154 RecordCheckinStatusToUMA(response_status == net::HTTP_BAD_REQUEST ? | 185 CheckinRequestStatus status = response_status == net::HTTP_BAD_REQUEST ? |
155 HTTP_BAD_REQUEST : HTTP_UNAUTHORIZED); | 186 HTTP_BAD_REQUEST : HTTP_UNAUTHORIZED; |
187 RecordCheckinStatusToUMA(status); | |
188 recorder_->RecordCheckinFailure( | |
189 GetCheckinRequestStatusString(status), false); | |
156 callback_.Run(response_proto); | 190 callback_.Run(response_proto); |
157 return; | 191 return; |
158 } | 192 } |
159 | 193 |
160 if (response_status != net::HTTP_OK || | 194 if (response_status != net::HTTP_OK || |
161 !source->GetResponseAsString(&response_string) || | 195 !source->GetResponseAsString(&response_string) || |
162 !response_proto.ParseFromString(response_string)) { | 196 !response_proto.ParseFromString(response_string)) { |
163 LOG(ERROR) << "Failed to get checkin response. HTTP Status: " | 197 LOG(ERROR) << "Failed to get checkin response. HTTP Status: " |
164 << response_status << ". Retrying."; | 198 << response_status << ". Retrying."; |
165 RecordCheckinStatusToUMA(response_status != net::HTTP_OK ? | 199 CheckinRequestStatus status = response_status != net::HTTP_OK ? |
166 HTTP_NOT_OK : RESPONSE_PARSING_FAILED); | 200 HTTP_NOT_OK : RESPONSE_PARSING_FAILED; |
201 RecordCheckinStatusToUMA(status); | |
202 recorder_->RecordCheckinFailure( | |
203 GetCheckinRequestStatusString(status), true); | |
167 RetryWithBackoff(true); | 204 RetryWithBackoff(true); |
168 return; | 205 return; |
169 } | 206 } |
170 | 207 |
171 if (!response_proto.has_android_id() || | 208 if (!response_proto.has_android_id() || |
172 !response_proto.has_security_token() || | 209 !response_proto.has_security_token() || |
173 response_proto.android_id() == 0 || | 210 response_proto.android_id() == 0 || |
174 response_proto.security_token() == 0) { | 211 response_proto.security_token() == 0) { |
175 LOG(ERROR) << "Android ID or security token is 0. Retrying."; | 212 LOG(ERROR) << "Android ID or security token is 0. Retrying."; |
176 RecordCheckinStatusToUMA(ZERO_ID_OR_TOKEN); | 213 RecordCheckinStatusToUMA(ZERO_ID_OR_TOKEN); |
214 recorder_->RecordCheckinFailure( | |
215 GetCheckinRequestStatusString(ZERO_ID_OR_TOKEN), true); | |
177 RetryWithBackoff(true); | 216 RetryWithBackoff(true); |
178 return; | 217 return; |
179 } | 218 } |
180 | 219 |
181 RecordCheckinStatusToUMA(SUCCESS); | 220 RecordCheckinStatusToUMA(SUCCESS); |
221 recorder_->RecordCheckinSuccess(); | |
182 callback_.Run(response_proto); | 222 callback_.Run(response_proto); |
183 } | 223 } |
184 | 224 |
185 } // namespace gcm | 225 } // namespace gcm |
OLD | NEW |