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 "components/gcm_driver/gcm_client_impl.h" | 5 #include "components/gcm_driver/gcm_client_impl.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/files/file_path.h" | 8 #include "base/files/file_path.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
240 net::NetLog* net_log, | 240 net::NetLog* net_log, |
241 GCMStatsRecorder* recorder) { | 241 GCMStatsRecorder* recorder) { |
242 return make_scoped_ptr<ConnectionFactory>( | 242 return make_scoped_ptr<ConnectionFactory>( |
243 new ConnectionFactoryImpl(endpoints, | 243 new ConnectionFactoryImpl(endpoints, |
244 backoff_policy, | 244 backoff_policy, |
245 network_session, | 245 network_session, |
246 net_log, | 246 net_log, |
247 recorder)); | 247 recorder)); |
248 } | 248 } |
249 | 249 |
| 250 GCMClientImpl::CheckinInfo::CheckinInfo() |
| 251 : android_id(0), secret(0), accounts_set(false) { |
| 252 } |
| 253 |
| 254 GCMClientImpl::CheckinInfo::~CheckinInfo() { |
| 255 } |
| 256 |
| 257 void GCMClientImpl::CheckinInfo::SnapshotCheckinAccounts() { |
| 258 last_checkin_accounts.clear(); |
| 259 for (std::map<std::string, std::string>::iterator iter = |
| 260 account_tokens.begin(); |
| 261 iter != account_tokens.end(); |
| 262 ++iter) { |
| 263 last_checkin_accounts.insert(iter->first); |
| 264 } |
| 265 } |
| 266 |
| 267 void GCMClientImpl::CheckinInfo::Reset() { |
| 268 android_id = 0; |
| 269 secret = 0; |
| 270 accounts_set = false; |
| 271 account_tokens.clear(); |
| 272 last_checkin_accounts.clear(); |
| 273 } |
| 274 |
250 GCMClientImpl::GCMClientImpl(scoped_ptr<GCMInternalsBuilder> internals_builder) | 275 GCMClientImpl::GCMClientImpl(scoped_ptr<GCMInternalsBuilder> internals_builder) |
251 : internals_builder_(internals_builder.Pass()), | 276 : internals_builder_(internals_builder.Pass()), |
252 state_(UNINITIALIZED), | 277 state_(UNINITIALIZED), |
253 delegate_(NULL), | 278 delegate_(NULL), |
254 clock_(internals_builder_->BuildClock()), | 279 clock_(internals_builder_->BuildClock()), |
255 url_request_context_getter_(NULL), | 280 url_request_context_getter_(NULL), |
256 pending_registration_requests_deleter_(&pending_registration_requests_), | 281 pending_registration_requests_deleter_(&pending_registration_requests_), |
257 pending_unregistration_requests_deleter_( | 282 pending_unregistration_requests_deleter_( |
258 &pending_unregistration_requests_), | 283 &pending_unregistration_requests_), |
259 periodic_checkin_ptr_factory_(this), | 284 periodic_checkin_ptr_factory_(this), |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
307 DCHECK_EQ(LOADING, state_); | 332 DCHECK_EQ(LOADING, state_); |
308 | 333 |
309 if (!result->success) { | 334 if (!result->success) { |
310 ResetState(); | 335 ResetState(); |
311 return; | 336 return; |
312 } | 337 } |
313 | 338 |
314 registrations_ = result->registrations; | 339 registrations_ = result->registrations; |
315 device_checkin_info_.android_id = result->device_android_id; | 340 device_checkin_info_.android_id = result->device_android_id; |
316 device_checkin_info_.secret = result->device_security_token; | 341 device_checkin_info_.secret = result->device_security_token; |
| 342 device_checkin_info_.last_checkin_accounts = result->last_checkin_accounts; |
| 343 // A case where there were previously no accounts reported with checkin is |
| 344 // considered to be the same as when the list of accounts is empty. It enables |
| 345 // scheduling a periodic checkin for devices with no signed in users |
| 346 // immediately after restart, while keeping |accounts_set == false| delays the |
| 347 // checkin until the list of accounts is set explicitly. |
| 348 if (result->last_checkin_accounts.size() == 0) |
| 349 device_checkin_info_.accounts_set = true; |
317 last_checkin_time_ = result->last_checkin_time; | 350 last_checkin_time_ = result->last_checkin_time; |
318 gservices_settings_.UpdateFromLoadResult(*result); | 351 gservices_settings_.UpdateFromLoadResult(*result); |
319 InitializeMCSClient(result.Pass()); | 352 InitializeMCSClient(result.Pass()); |
320 | 353 |
321 if (device_checkin_info_.IsValid()) { | 354 if (device_checkin_info_.IsValid()) { |
322 SchedulePeriodicCheckin(); | 355 SchedulePeriodicCheckin(); |
323 OnReady(); | 356 OnReady(); |
324 return; | 357 return; |
325 } | 358 } |
326 | 359 |
(...skipping 29 matching lines...) Expand all Loading... |
356 weak_ptr_factory_.GetWeakPtr()), | 389 weak_ptr_factory_.GetWeakPtr()), |
357 result.Pass()); | 390 result.Pass()); |
358 } | 391 } |
359 | 392 |
360 void GCMClientImpl::OnFirstTimeDeviceCheckinCompleted( | 393 void GCMClientImpl::OnFirstTimeDeviceCheckinCompleted( |
361 const CheckinInfo& checkin_info) { | 394 const CheckinInfo& checkin_info) { |
362 DCHECK(!device_checkin_info_.IsValid()); | 395 DCHECK(!device_checkin_info_.IsValid()); |
363 | 396 |
364 device_checkin_info_.android_id = checkin_info.android_id; | 397 device_checkin_info_.android_id = checkin_info.android_id; |
365 device_checkin_info_.secret = checkin_info.secret; | 398 device_checkin_info_.secret = checkin_info.secret; |
| 399 // If accounts were not set by now, we can consider them set (to empty list) |
| 400 // to make sure periodic checkins get scheduled after initial checkin. |
| 401 device_checkin_info_.accounts_set = true; |
366 gcm_store_->SetDeviceCredentials( | 402 gcm_store_->SetDeviceCredentials( |
367 checkin_info.android_id, checkin_info.secret, | 403 checkin_info.android_id, checkin_info.secret, |
368 base::Bind(&GCMClientImpl::SetDeviceCredentialsCallback, | 404 base::Bind(&GCMClientImpl::SetDeviceCredentialsCallback, |
369 weak_ptr_factory_.GetWeakPtr())); | 405 weak_ptr_factory_.GetWeakPtr())); |
370 | 406 |
371 OnReady(); | 407 OnReady(); |
372 } | 408 } |
373 | 409 |
374 void GCMClientImpl::OnReady() { | 410 void GCMClientImpl::OnReady() { |
375 state_ = READY; | 411 state_ = READY; |
376 StartMCSLogin(); | 412 StartMCSLogin(); |
377 | 413 |
378 delegate_->OnGCMReady(); | 414 delegate_->OnGCMReady(); |
379 } | 415 } |
380 | 416 |
381 void GCMClientImpl::StartMCSLogin() { | 417 void GCMClientImpl::StartMCSLogin() { |
382 DCHECK_EQ(READY, state_); | 418 DCHECK_EQ(READY, state_); |
383 DCHECK(device_checkin_info_.IsValid()); | 419 DCHECK(device_checkin_info_.IsValid()); |
384 mcs_client_->Login(device_checkin_info_.android_id, | 420 mcs_client_->Login(device_checkin_info_.android_id, |
385 device_checkin_info_.secret); | 421 device_checkin_info_.secret); |
386 } | 422 } |
387 | 423 |
388 void GCMClientImpl::ResetState() { | 424 void GCMClientImpl::ResetState() { |
389 state_ = UNINITIALIZED; | 425 state_ = UNINITIALIZED; |
390 // TODO(fgorski): reset all of the necessart objects and start over. | 426 // TODO(fgorski): reset all of the necessart objects and start over. |
391 } | 427 } |
392 | 428 |
| 429 void GCMClientImpl::SetAccountsForCheckin( |
| 430 const std::map<std::string, std::string>& account_tokens) { |
| 431 bool accounts_set_before = device_checkin_info_.accounts_set; |
| 432 device_checkin_info_.account_tokens = account_tokens; |
| 433 device_checkin_info_.accounts_set = true; |
| 434 |
| 435 DVLOG(1) << "Set account called with: " << account_tokens.size() |
| 436 << " accounts."; |
| 437 |
| 438 if (state_ != READY && state_ != INITIAL_DEVICE_CHECKIN) |
| 439 return; |
| 440 |
| 441 bool account_removed = false; |
| 442 for (std::set<std::string>::iterator iter = |
| 443 device_checkin_info_.last_checkin_accounts.begin(); |
| 444 iter != device_checkin_info_.last_checkin_accounts.end(); |
| 445 ++iter) { |
| 446 if (account_tokens.find(*iter) == account_tokens.end()) |
| 447 account_removed = true; |
| 448 } |
| 449 |
| 450 // Checkin will be forced when any of the accounts was removed during the |
| 451 // current Chrome session or if there has been an account removed between the |
| 452 // restarts of Chrome. If there is a checkin in progress, it will be canceled. |
| 453 // We only force checkin when user signs out. When there is a new account |
| 454 // signed in, the periodic checkin will take care of adding the association in |
| 455 // reasonable time. |
| 456 if (account_removed) { |
| 457 DVLOG(1) << "Detected that account has been removed. Forcing checkin."; |
| 458 checkin_request_.reset(); |
| 459 StartCheckin(); |
| 460 } else if (!accounts_set_before) { |
| 461 SchedulePeriodicCheckin(); |
| 462 DVLOG(1) << "Accounts set for the first time. Scheduled periodic checkin."; |
| 463 } |
| 464 } |
| 465 |
393 void GCMClientImpl::StartCheckin() { | 466 void GCMClientImpl::StartCheckin() { |
394 // Make sure no checkin is in progress. | 467 // Make sure no checkin is in progress. |
395 if (checkin_request_.get()) | 468 if (checkin_request_.get()) |
396 return; | 469 return; |
397 | 470 |
398 checkin_proto::ChromeBuildProto chrome_build_proto; | 471 checkin_proto::ChromeBuildProto chrome_build_proto; |
399 ToCheckinProtoVersion(chrome_build_info_, &chrome_build_proto); | 472 ToCheckinProtoVersion(chrome_build_info_, &chrome_build_proto); |
400 CheckinRequest::RequestInfo request_info(device_checkin_info_.android_id, | 473 CheckinRequest::RequestInfo request_info(device_checkin_info_.android_id, |
401 device_checkin_info_.secret, | 474 device_checkin_info_.secret, |
| 475 device_checkin_info_.account_tokens, |
402 gservices_settings_.digest(), | 476 gservices_settings_.digest(), |
403 chrome_build_proto); | 477 chrome_build_proto); |
404 checkin_request_.reset( | 478 checkin_request_.reset( |
405 new CheckinRequest(gservices_settings_.GetCheckinURL(), | 479 new CheckinRequest(gservices_settings_.GetCheckinURL(), |
406 request_info, | 480 request_info, |
407 kDefaultBackoffPolicy, | 481 kDefaultBackoffPolicy, |
408 base::Bind(&GCMClientImpl::OnCheckinCompleted, | 482 base::Bind(&GCMClientImpl::OnCheckinCompleted, |
409 weak_ptr_factory_.GetWeakPtr()), | 483 weak_ptr_factory_.GetWeakPtr()), |
410 url_request_context_getter_, | 484 url_request_context_getter_, |
411 &recorder_)); | 485 &recorder_)); |
| 486 // Taking a snapshot of the accounts count here, as there might be an asynch |
| 487 // update of the account tokens while checkin is in progress. |
| 488 device_checkin_info_.SnapshotCheckinAccounts(); |
412 checkin_request_->Start(); | 489 checkin_request_->Start(); |
413 } | 490 } |
414 | 491 |
415 void GCMClientImpl::OnCheckinCompleted( | 492 void GCMClientImpl::OnCheckinCompleted( |
416 const checkin_proto::AndroidCheckinResponse& checkin_response) { | 493 const checkin_proto::AndroidCheckinResponse& checkin_response) { |
417 checkin_request_.reset(); | 494 checkin_request_.reset(); |
418 | 495 |
419 if (!checkin_response.has_android_id() || | 496 if (!checkin_response.has_android_id() || |
420 !checkin_response.has_security_token()) { | 497 !checkin_response.has_security_token()) { |
421 // TODO(fgorski): I don't think a retry here will help, we should probably | 498 // TODO(fgorski): I don't think a retry here will help, we should probably |
(...skipping 19 matching lines...) Expand all Loading... |
441 // First update G-services settings, as something might have changed. | 518 // First update G-services settings, as something might have changed. |
442 if (gservices_settings_.UpdateFromCheckinResponse(checkin_response)) { | 519 if (gservices_settings_.UpdateFromCheckinResponse(checkin_response)) { |
443 gcm_store_->SetGServicesSettings( | 520 gcm_store_->SetGServicesSettings( |
444 gservices_settings_.settings_map(), | 521 gservices_settings_.settings_map(), |
445 gservices_settings_.digest(), | 522 gservices_settings_.digest(), |
446 base::Bind(&GCMClientImpl::SetGServicesSettingsCallback, | 523 base::Bind(&GCMClientImpl::SetGServicesSettingsCallback, |
447 weak_ptr_factory_.GetWeakPtr())); | 524 weak_ptr_factory_.GetWeakPtr())); |
448 } | 525 } |
449 | 526 |
450 last_checkin_time_ = clock_->Now(); | 527 last_checkin_time_ = clock_->Now(); |
451 gcm_store_->SetLastCheckinTime( | 528 gcm_store_->SetLastCheckinInfo( |
452 last_checkin_time_, | 529 last_checkin_time_, |
453 base::Bind(&GCMClientImpl::SetLastCheckinTimeCallback, | 530 device_checkin_info_.last_checkin_accounts, |
| 531 base::Bind(&GCMClientImpl::SetLastCheckinInfoCallback, |
454 weak_ptr_factory_.GetWeakPtr())); | 532 weak_ptr_factory_.GetWeakPtr())); |
455 SchedulePeriodicCheckin(); | 533 SchedulePeriodicCheckin(); |
456 } | 534 } |
457 } | 535 } |
458 | 536 |
459 void GCMClientImpl::SetGServicesSettingsCallback(bool success) { | 537 void GCMClientImpl::SetGServicesSettingsCallback(bool success) { |
460 DCHECK(success); | 538 DCHECK(success); |
461 } | 539 } |
462 | 540 |
463 void GCMClientImpl::SchedulePeriodicCheckin() { | 541 void GCMClientImpl::SchedulePeriodicCheckin() { |
464 // Make sure no checkin is in progress. | 542 // Make sure no checkin is in progress. |
465 if (checkin_request_.get()) | 543 if (checkin_request_.get() || !device_checkin_info_.accounts_set) |
466 return; | 544 return; |
467 | 545 |
468 // There should be only one periodic checkin pending at a time. Removing | 546 // There should be only one periodic checkin pending at a time. Removing |
469 // pending periodic checkin to schedule a new one. | 547 // pending periodic checkin to schedule a new one. |
470 periodic_checkin_ptr_factory_.InvalidateWeakPtrs(); | 548 periodic_checkin_ptr_factory_.InvalidateWeakPtrs(); |
471 | 549 |
472 base::TimeDelta time_to_next_checkin = GetTimeToNextCheckin(); | 550 base::TimeDelta time_to_next_checkin = GetTimeToNextCheckin(); |
473 if (time_to_next_checkin < base::TimeDelta()) | 551 if (time_to_next_checkin < base::TimeDelta()) |
474 time_to_next_checkin = base::TimeDelta(); | 552 time_to_next_checkin = base::TimeDelta(); |
475 | 553 |
476 base::MessageLoop::current()->PostDelayedTask( | 554 base::MessageLoop::current()->PostDelayedTask( |
477 FROM_HERE, | 555 FROM_HERE, |
478 base::Bind(&GCMClientImpl::StartCheckin, | 556 base::Bind(&GCMClientImpl::StartCheckin, |
479 periodic_checkin_ptr_factory_.GetWeakPtr()), | 557 periodic_checkin_ptr_factory_.GetWeakPtr()), |
480 time_to_next_checkin); | 558 time_to_next_checkin); |
481 } | 559 } |
482 | 560 |
483 base::TimeDelta GCMClientImpl::GetTimeToNextCheckin() const { | 561 base::TimeDelta GCMClientImpl::GetTimeToNextCheckin() const { |
484 return last_checkin_time_ + gservices_settings_.GetCheckinInterval() - | 562 return last_checkin_time_ + gservices_settings_.GetCheckinInterval() - |
485 clock_->Now(); | 563 clock_->Now(); |
486 } | 564 } |
487 | 565 |
488 void GCMClientImpl::SetLastCheckinTimeCallback(bool success) { | 566 void GCMClientImpl::SetLastCheckinInfoCallback(bool success) { |
489 // TODO(fgorski): This is one of the signals that store needs a rebuild. | 567 // TODO(fgorski): This is one of the signals that store needs a rebuild. |
490 DCHECK(success); | 568 DCHECK(success); |
491 } | 569 } |
492 | 570 |
493 void GCMClientImpl::SetDeviceCredentialsCallback(bool success) { | 571 void GCMClientImpl::SetDeviceCredentialsCallback(bool success) { |
494 // TODO(fgorski): This is one of the signals that store needs a rebuild. | 572 // TODO(fgorski): This is one of the signals that store needs a rebuild. |
495 DCHECK(success); | 573 DCHECK(success); |
496 } | 574 } |
497 | 575 |
498 void GCMClientImpl::UpdateRegistrationCallback(bool success) { | 576 void GCMClientImpl::UpdateRegistrationCallback(bool success) { |
(...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
882 | 960 |
883 recorder_.RecordIncomingSendError( | 961 recorder_.RecordIncomingSendError( |
884 data_message_stanza.category(), | 962 data_message_stanza.category(), |
885 data_message_stanza.to(), | 963 data_message_stanza.to(), |
886 data_message_stanza.id()); | 964 data_message_stanza.id()); |
887 delegate_->OnMessageSendError(data_message_stanza.category(), | 965 delegate_->OnMessageSendError(data_message_stanza.category(), |
888 send_error_details); | 966 send_error_details); |
889 } | 967 } |
890 | 968 |
891 } // namespace gcm | 969 } // namespace gcm |
OLD | NEW |