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

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: Fixing the test failing on a mac 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;
168 // Stop tracking the accounts, that were removed, as it will be reported to
169 // the driver.
170 for (AccountInfos::iterator iter = account_infos_.begin();
171 iter != account_infos_.end();) {
172 if (iter->second.state == ACCOUNT_REMOVED) {
173 account_removed = true;
174 account_infos_.erase(iter++);
175 } else {
176 ++iter;
177 }
178 }
179
155 std::vector<GCMClient::AccountTokenInfo> account_tokens; 180 std::vector<GCMClient::AccountTokenInfo> account_tokens;
156 for (AccountInfos::iterator iter = account_infos_.begin(); 181 for (AccountInfos::iterator iter = account_infos_.begin();
157 iter != account_infos_.end();) { 182 iter != account_infos_.end(); ++iter) {
158 switch (iter->second.state) { 183 if (iter->second.state == TOKEN_PRESENT) {
159 case ACCOUNT_REMOVED: 184 GCMClient::AccountTokenInfo token_info;
160 // We only mark accounts as removed when there was an account that was 185 token_info.account_id = iter->first;
161 // explicitly signed out. 186 token_info.email = iter->second.email;
162 account_removed = true; 187 token_info.access_token = iter->second.access_token;
163 // We also stop tracking the account, now that it will be reported as 188 account_tokens.push_back(token_info);
164 // removed. 189 } else {
165 account_infos_.erase(iter++); 190 // This should not happen, as we are making a check that there are no
166 break; 191 // pending requests above, stopping tracking of removed accounts, or start
167 192 // fetching tokens.
168 case TOKEN_PRESENT: { 193 NOTREACHED();
169 GCMClient::AccountTokenInfo token_info;
170 token_info.account_id = iter->first;
171 token_info.email = iter->second.email;
172 token_info.access_token = iter->second.access_token;
173 account_tokens.push_back(token_info);
174 ++iter;
175 break;
176 }
177
178 case GETTING_TOKEN:
179 // This should not happen, as we are making a check that there are no
180 // pending requests above.
181 NOTREACHED();
182 ++iter;
183 break;
184
185 case TOKEN_NEEDED:
186 // We failed to fetch an access token for the account, but it has not
187 // been signed out (perhaps there is a network issue). We don't report
188 // it, but next time there is a sign-in change we will update its state.
189 ++iter;
190 break;
191 } 194 }
192 } 195 }
193 196
194 // Make sure that there is something to report, otherwise bail out. 197 // Make sure that there is something to report, otherwise bail out.
195 if (!account_tokens.empty() || account_removed) { 198 if (!account_tokens.empty() || account_removed) {
196 DVLOG(1) << "Calling callback: " << account_tokens.size(); 199 DVLOG(1) << "Reporting the tokens to driver: " << account_tokens.size();
197 callback_.Run(account_tokens); 200 driver_->SetAccountTokens(account_tokens);
198 } else { 201 } else {
199 DVLOG(1) << "No tokens and nothing removed. Skipping callback."; 202 DVLOG(1) << "No tokens and nothing removed. Skipping callback.";
200 } 203 }
201 } 204 }
202 205
206 bool GCMAccountTracker::SanitizeTokens() {
207 bool tokens_needed = false;
208 for (AccountInfos::iterator iter = account_infos_.begin();
209 iter != account_infos_.end();
210 ++iter) {
211 if (iter->second.state == TOKEN_PRESENT &&
212 iter->second.expiration_time <
213 base::Time::Now() +
214 base::TimeDelta::FromMilliseconds(kMinimumTokenValidityMs)) {
215 iter->second.access_token.clear();
216 iter->second.state = TOKEN_NEEDED;
217 iter->second.expiration_time = base::Time();
218 }
219
220 if (iter->second.state == TOKEN_NEEDED)
221 tokens_needed = true;
222 }
223
224 return tokens_needed;
225 }
226
203 void GCMAccountTracker::DeleteTokenRequest( 227 void GCMAccountTracker::DeleteTokenRequest(
204 const OAuth2TokenService::Request* request) { 228 const OAuth2TokenService::Request* request) {
205 ScopedVector<OAuth2TokenService::Request>::iterator iter = std::find( 229 ScopedVector<OAuth2TokenService::Request>::iterator iter = std::find(
206 pending_token_requests_.begin(), pending_token_requests_.end(), request); 230 pending_token_requests_.begin(), pending_token_requests_.end(), request);
207 if (iter != pending_token_requests_.end()) 231 if (iter != pending_token_requests_.end())
208 pending_token_requests_.erase(iter); 232 pending_token_requests_.erase(iter);
209 } 233 }
210 234
211 void GCMAccountTracker::GetAllNeededTokens() { 235 void GCMAccountTracker::GetAllNeededTokens() {
236 // Only start fetching tokens if driver is running, they have a limited
237 // validity time and GCM connection is a good indication of network running.
238 if (!driver_->IsConnected())
239 return;
240
212 for (AccountInfos::iterator iter = account_infos_.begin(); 241 for (AccountInfos::iterator iter = account_infos_.begin();
213 iter != account_infos_.end(); 242 iter != account_infos_.end();
214 ++iter) { 243 ++iter) {
215 if (iter->second.state == TOKEN_NEEDED) 244 if (iter->second.state == TOKEN_NEEDED)
216 GetToken(iter); 245 GetToken(iter);
217 } 246 }
218 } 247 }
219 248
220 void GCMAccountTracker::GetToken(AccountInfos::iterator& account_iter) { 249 void GCMAccountTracker::GetToken(AccountInfos::iterator& account_iter) {
221 DCHECK(GetTokenService()); 250 DCHECK(GetTokenService());
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 iter->second.state = ACCOUNT_REMOVED; 284 iter->second.state = ACCOUNT_REMOVED;
256 CompleteCollectingTokens(); 285 CompleteCollectingTokens();
257 } 286 }
258 287
259 OAuth2TokenService* GCMAccountTracker::GetTokenService() { 288 OAuth2TokenService* GCMAccountTracker::GetTokenService() {
260 DCHECK(account_tracker_->identity_provider()); 289 DCHECK(account_tracker_->identity_provider());
261 return account_tracker_->identity_provider()->GetTokenService(); 290 return account_tracker_->identity_provider()->GetTokenService();
262 } 291 }
263 292
264 } // namespace gcm 293 } // namespace gcm
OLDNEW
« no previous file with comments | « chrome/browser/services/gcm/gcm_account_tracker.h ('k') | chrome/browser/services/gcm/gcm_account_tracker_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698