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

Side by Side Diff: chrome/browser/services/gcm/gcm_account_tracker.cc

Issue 618003002: [GCM] Handling connection events in GCMAccountTracker (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebasing after jianli's patch made it Created 6 years, 2 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 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 "chrome/browser/services/gcm/gcm_account_tracker.h" 5 #include "chrome/browser/services/gcm/gcm_account_tracker.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/time/time.h" 10 #include "base/time/time.h"
11 #include "components/gcm_driver/gcm_driver.h"
11 #include "google_apis/gaia/google_service_auth_error.h" 12 #include "google_apis/gaia/google_service_auth_error.h"
13 #include "net/base/ip_endpoint.h"
12 14
13 namespace gcm { 15 namespace gcm {
14 16
15 namespace { 17 namespace {
16 const char kGCMGroupServerScope[] = "https://www.googleapis.com/auth/gcm"; 18 const char kGCMGroupServerScope[] = "https://www.googleapis.com/auth/gcm";
17 const char kGCMCheckinServerScope[] = 19 const char kGCMCheckinServerScope[] =
18 "https://www.googleapis.com/auth/android_checkin"; 20 "https://www.googleapis.com/auth/android_checkin";
19 const char kGCMAccountTrackerName[] = "gcm_account_tracker"; 21 const char kGCMAccountTrackerName[] = "gcm_account_tracker";
22 const int64 kMinimumTokenValidityMs = 500;
20 } // namespace 23 } // namespace
21 24
22 GCMAccountTracker::AccountInfo::AccountInfo(const std::string& email, 25 GCMAccountTracker::AccountInfo::AccountInfo(const std::string& email,
23 AccountState state) 26 AccountState state)
24 : email(email), state(state) { 27 : email(email), state(state) {
25 } 28 }
26 29
27 GCMAccountTracker::AccountInfo::~AccountInfo() { 30 GCMAccountTracker::AccountInfo::~AccountInfo() {
28 } 31 }
29 32
30 GCMAccountTracker::GCMAccountTracker( 33 GCMAccountTracker::GCMAccountTracker(
31 scoped_ptr<gaia::AccountTracker> account_tracker, 34 scoped_ptr<gaia::AccountTracker> account_tracker,
32 const UpdateAccountsCallback& callback) 35 GCMDriver* driver)
33 : OAuth2TokenService::Consumer(kGCMAccountTrackerName), 36 : OAuth2TokenService::Consumer(kGCMAccountTrackerName),
34 account_tracker_(account_tracker.release()), 37 account_tracker_(account_tracker.release()),
35 callback_(callback), 38 driver_(driver),
36 shutdown_called_(false) { 39 shutdown_called_(false) {
37 DCHECK(!callback_.is_null());
38 } 40 }
39 41
40 GCMAccountTracker::~GCMAccountTracker() { 42 GCMAccountTracker::~GCMAccountTracker() {
41 DCHECK(shutdown_called_); 43 DCHECK(shutdown_called_);
42 } 44 }
43 45
44 void GCMAccountTracker::Shutdown() { 46 void GCMAccountTracker::Shutdown() {
45 Stop();
46 shutdown_called_ = true; 47 shutdown_called_ = true;
48 driver_->RemoveConnectionObserver(this);
49 account_tracker_->RemoveObserver(this);
47 account_tracker_->Shutdown(); 50 account_tracker_->Shutdown();
48 } 51 }
49 52
50 void GCMAccountTracker::Start() { 53 void GCMAccountTracker::Start() {
51 DCHECK(!shutdown_called_); 54 DCHECK(!shutdown_called_);
52 account_tracker_->AddObserver(this); 55 account_tracker_->AddObserver(this);
56 driver_->AddConnectionObserver(this);
53 57
54 std::vector<gaia::AccountIds> accounts = account_tracker_->GetAccounts(); 58 std::vector<gaia::AccountIds> accounts = account_tracker_->GetAccounts();
55 if (accounts.empty()) { 59 if (accounts.empty()) {
56 CompleteCollectingTokens(); 60 CompleteCollectingTokens();
57 return; 61 return;
58 } 62 }
59 63
60 for (std::vector<gaia::AccountIds>::const_iterator iter = accounts.begin(); 64 for (std::vector<gaia::AccountIds>::const_iterator iter = accounts.begin();
61 iter != accounts.end(); 65 iter != accounts.end();
62 ++iter) { 66 ++iter) {
63 if (!iter->email.empty()) { 67 if (!iter->email.empty()) {
64 account_infos_.insert(std::make_pair( 68 account_infos_.insert(std::make_pair(
65 iter->account_key, AccountInfo(iter->email, TOKEN_NEEDED))); 69 iter->account_key, AccountInfo(iter->email, TOKEN_NEEDED)));
66 } 70 }
67 } 71 }
68 72
69 GetAllNeededTokens(); 73 GetAllNeededTokens();
70 } 74 }
71 75
72 void GCMAccountTracker::Stop() {
73 DCHECK(!shutdown_called_);
74 account_tracker_->RemoveObserver(this);
75 pending_token_requests_.clear();
76 }
77
78 void GCMAccountTracker::OnAccountAdded(const gaia::AccountIds& ids) { 76 void GCMAccountTracker::OnAccountAdded(const gaia::AccountIds& ids) {
79 DVLOG(1) << "Account added: " << ids.email; 77 DVLOG(1) << "Account added: " << ids.email;
80 // We listen for the account signing in, which happens after account is added. 78 // We listen for the account signing in, which happens after account is added.
81 } 79 }
82 80
83 void GCMAccountTracker::OnAccountRemoved(const gaia::AccountIds& ids) { 81 void GCMAccountTracker::OnAccountRemoved(const gaia::AccountIds& ids) {
84 DVLOG(1) << "Account removed: " << ids.email; 82 DVLOG(1) << "Account removed: " << ids.email;
85 // We listen for the account signing out, which happens before account is 83 // We listen for the account signing out, which happens before account is
86 // removed. 84 // removed.
87 } 85 }
(...skipping 17 matching lines...) Expand all
105 AccountInfos::iterator iter = account_infos_.find(request->GetAccountId()); 103 AccountInfos::iterator iter = account_infos_.find(request->GetAccountId());
106 DCHECK(iter != account_infos_.end()); 104 DCHECK(iter != account_infos_.end());
107 if (iter != account_infos_.end()) { 105 if (iter != account_infos_.end()) {
108 DCHECK(iter->second.state == GETTING_TOKEN || 106 DCHECK(iter->second.state == GETTING_TOKEN ||
109 iter->second.state == ACCOUNT_REMOVED); 107 iter->second.state == ACCOUNT_REMOVED);
110 // If OnAccountSignedOut(..) was called most recently, account is kept in 108 // If OnAccountSignedOut(..) was called most recently, account is kept in
111 // ACCOUNT_REMOVED state. 109 // ACCOUNT_REMOVED state.
112 if (iter->second.state == GETTING_TOKEN) { 110 if (iter->second.state == GETTING_TOKEN) {
113 iter->second.state = TOKEN_PRESENT; 111 iter->second.state = TOKEN_PRESENT;
114 iter->second.access_token = access_token; 112 iter->second.access_token = access_token;
113 iter->second.expiration_time = expiration_time;
115 } 114 }
116 } 115 }
117 116
118 DeleteTokenRequest(request); 117 DeleteTokenRequest(request);
119 CompleteCollectingTokens(); 118 CompleteCollectingTokens();
120 } 119 }
121 120
122 void GCMAccountTracker::OnGetTokenFailure( 121 void GCMAccountTracker::OnGetTokenFailure(
123 const OAuth2TokenService::Request* request, 122 const OAuth2TokenService::Request* request,
124 const GoogleServiceAuthError& error) { 123 const GoogleServiceAuthError& error) {
125 DCHECK(request); 124 DCHECK(request);
126 DCHECK(!request->GetAccountId().empty()); 125 DCHECK(!request->GetAccountId().empty());
127 DVLOG(1) << "Get token failure: " << request->GetAccountId(); 126 DVLOG(1) << "Get token failure: " << request->GetAccountId();
128 127
129 AccountInfos::iterator iter = account_infos_.find(request->GetAccountId()); 128 AccountInfos::iterator iter = account_infos_.find(request->GetAccountId());
130 DCHECK(iter != account_infos_.end()); 129 DCHECK(iter != account_infos_.end());
131 if (iter != account_infos_.end()) { 130 if (iter != account_infos_.end()) {
132 DCHECK(iter->second.state == GETTING_TOKEN || 131 DCHECK(iter->second.state == GETTING_TOKEN ||
133 iter->second.state == ACCOUNT_REMOVED); 132 iter->second.state == ACCOUNT_REMOVED);
134 // If OnAccountSignedOut(..) was called most recently, account is kept in 133 // If OnAccountSignedOut(..) was called most recently, account is kept in
135 // ACCOUNT_REMOVED state. 134 // ACCOUNT_REMOVED state.
136 if (iter->second.state == GETTING_TOKEN) 135 if (iter->second.state == GETTING_TOKEN)
137 iter->second.state = TOKEN_NEEDED; 136 iter->second.state = TOKEN_NEEDED;
138 } 137 }
139 138
140 DeleteTokenRequest(request); 139 DeleteTokenRequest(request);
141 CompleteCollectingTokens(); 140 CompleteCollectingTokens();
142 } 141 }
143 142
143 void GCMAccountTracker::OnConnected(const net::IPEndPoint& ip_endpoint) {
144 if (SanitizeTokens())
145 GetAllNeededTokens();
146 }
147
148 void GCMAccountTracker::OnDisconnected() {
149 // We are disconnected, so no point in trying to work with tokens.
150 }
151
144 void GCMAccountTracker::CompleteCollectingTokens() { 152 void GCMAccountTracker::CompleteCollectingTokens() {
145 DCHECK(!callback_.is_null()); 153 // Make sure all tokens are valid.
154 if (SanitizeTokens()) {
155 GetAllNeededTokens();
156 return;
157 }
158
146 // Wait for gaia::AccountTracker to be done with fetching the user info, as 159 // Wait for gaia::AccountTracker to be done with fetching the user info, as
147 // well as all of the pending token requests from GCMAccountTracker to be done 160 // well as all of the pending token requests from GCMAccountTracker to be done
148 // before you report the results. 161 // before you report the results.
149 if (!account_tracker_->IsAllUserInfoFetched() || 162 if (!account_tracker_->IsAllUserInfoFetched() ||
150 !pending_token_requests_.empty()) { 163 !pending_token_requests_.empty()) {
151 return; 164 return;
152 } 165 }
153 166
154 bool account_removed = false; 167 bool account_removed = false;
155 std::vector<GCMClient::AccountTokenInfo> account_tokens; 168 std::vector<GCMClient::AccountTokenInfo> account_tokens;
(...skipping 20 matching lines...) Expand all
176 } 189 }
177 190
178 case GETTING_TOKEN: 191 case GETTING_TOKEN:
179 // This should not happen, as we are making a check that there are no 192 // This should not happen, as we are making a check that there are no
180 // pending requests above. 193 // pending requests above.
181 NOTREACHED(); 194 NOTREACHED();
182 ++iter; 195 ++iter;
183 break; 196 break;
184 197
185 case TOKEN_NEEDED: 198 case TOKEN_NEEDED:
186 // We failed to fetch an access token for the account, but it has not 199 // This should not happen, as we are calling GetAllNeededTokens in that
187 // been signed out (perhaps there is a network issue). We don't report 200 // case and return.
188 // it, but next time there is a sign-in change we will update its state. 201 NOTREACHED();
189 ++iter; 202 ++iter;
Nicolas Zea 2014/10/08 00:36:35 nit: Why not have ++iter in the for loop itself?
fgorski 2014/10/08 18:04:27 Invalidates the iterator in 178. Since it does not
190 break; 203 break;
191 } 204 }
192 } 205 }
193 206
194 // Make sure that there is something to report, otherwise bail out. 207 // Make sure that there is something to report, otherwise bail out.
195 if (!account_tokens.empty() || account_removed) { 208 if (!account_tokens.empty() || account_removed) {
196 DVLOG(1) << "Calling callback: " << account_tokens.size(); 209 DVLOG(1) << "Reporting the tokens to driver: " << account_tokens.size();
197 callback_.Run(account_tokens); 210 driver_->SetAccountTokens(account_tokens);
198 } else { 211 } else {
199 DVLOG(1) << "No tokens and nothing removed. Skipping callback."; 212 DVLOG(1) << "No tokens and nothing removed. Skipping callback.";
200 } 213 }
201 } 214 }
202 215
216 bool GCMAccountTracker::SanitizeTokens() {
217 bool tokens_needed = false;
218 for (AccountInfos::iterator iter = account_infos_.begin();
219 iter != account_infos_.end();
220 ++iter) {
221 if (iter->second.state == TOKEN_PRESENT &&
222 iter->second.expiration_time <
223 base::Time::Now() +
224 base::TimeDelta::FromMilliseconds(kMinimumTokenValidityMs)) {
225 iter->second.access_token.clear();
226 iter->second.state = TOKEN_NEEDED;
227 iter->second.expiration_time = base::Time();
228 }
229
230 if (iter->second.state == TOKEN_NEEDED)
231 tokens_needed = true;
232 }
233
234 return tokens_needed;
235 }
236
203 void GCMAccountTracker::DeleteTokenRequest( 237 void GCMAccountTracker::DeleteTokenRequest(
204 const OAuth2TokenService::Request* request) { 238 const OAuth2TokenService::Request* request) {
205 ScopedVector<OAuth2TokenService::Request>::iterator iter = std::find( 239 ScopedVector<OAuth2TokenService::Request>::iterator iter = std::find(
206 pending_token_requests_.begin(), pending_token_requests_.end(), request); 240 pending_token_requests_.begin(), pending_token_requests_.end(), request);
207 if (iter != pending_token_requests_.end()) 241 if (iter != pending_token_requests_.end())
208 pending_token_requests_.erase(iter); 242 pending_token_requests_.erase(iter);
209 } 243 }
210 244
211 void GCMAccountTracker::GetAllNeededTokens() { 245 void GCMAccountTracker::GetAllNeededTokens() {
246 // Only start fetching tokens if driver is running, they have a limited
247 // validity time and GCM connection is a good indication of network running.
248 if (!driver_->IsConnected())
249 return;
250
212 for (AccountInfos::iterator iter = account_infos_.begin(); 251 for (AccountInfos::iterator iter = account_infos_.begin();
213 iter != account_infos_.end(); 252 iter != account_infos_.end();
214 ++iter) { 253 ++iter) {
215 if (iter->second.state == TOKEN_NEEDED) 254 if (iter->second.state == TOKEN_NEEDED)
216 GetToken(iter); 255 GetToken(iter);
217 } 256 }
218 } 257 }
219 258
220 void GCMAccountTracker::GetToken(AccountInfos::iterator& account_iter) { 259 void GCMAccountTracker::GetToken(AccountInfos::iterator& account_iter) {
221 DCHECK(GetTokenService()); 260 DCHECK(GetTokenService());
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 iter->second.state = ACCOUNT_REMOVED; 294 iter->second.state = ACCOUNT_REMOVED;
256 CompleteCollectingTokens(); 295 CompleteCollectingTokens();
257 } 296 }
258 297
259 OAuth2TokenService* GCMAccountTracker::GetTokenService() { 298 OAuth2TokenService* GCMAccountTracker::GetTokenService() {
260 DCHECK(account_tracker_->identity_provider()); 299 DCHECK(account_tracker_->identity_provider());
261 return account_tracker_->identity_provider()->GetTokenService(); 300 return account_tracker_->identity_provider()->GetTokenService();
262 } 301 }
263 302
264 } // namespace gcm 303 } // namespace gcm
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698