Chromium Code Reviews| Index: chrome/browser/services/gcm/gcm_profile_service.cc |
| diff --git a/chrome/browser/services/gcm/gcm_profile_service.cc b/chrome/browser/services/gcm/gcm_profile_service.cc |
| index 3f81a97eb0005fcda0f85a4e5bfa7af6f7c6d715..c215192c8df17f593250d6d4f9d6306a0d3b5f73 100644 |
| --- a/chrome/browser/services/gcm/gcm_profile_service.cc |
| +++ b/chrome/browser/services/gcm/gcm_profile_service.cc |
| @@ -236,7 +236,7 @@ class GCMProfileService::IOWorker |
| public base::RefCountedThreadSafe<GCMProfileService::IOWorker>{ |
| public: |
| // Called on UI thread. |
| - explicit IOWorker(const base::WeakPtr<GCMProfileService>& service); |
| + IOWorker(); |
| // Overridden from GCMClient::Delegate: |
| // Called on IO thread. |
| @@ -258,12 +258,13 @@ class GCMProfileService::IOWorker |
| virtual void OnGCMReady() OVERRIDE; |
| // Called on IO thread. |
| - void Initialize(GCMClientFactory* gcm_client_factory, |
| + void Initialize(scoped_ptr<GCMClientFactory> gcm_client_factory, |
| const base::FilePath& store_path, |
| const std::vector<std::string>& account_ids, |
| const scoped_refptr<net::URLRequestContextGetter>& |
| url_request_context_getter); |
| void Reset(); |
| + void Load(const base::WeakPtr<GCMProfileService>& service); |
| void CheckOut(); |
| void Register(const std::string& app_id, |
| const std::vector<std::string>& sender_ids, |
| @@ -273,18 +274,19 @@ class GCMProfileService::IOWorker |
| const std::string& receiver_id, |
| const GCMClient::OutgoingMessage& message); |
| + // For testing purpose. Can be called from UI thread. Use with care. |
| + GCMClient* gcm_client_for_testing() const { return gcm_client_.get(); } |
| + |
| private: |
| friend class base::RefCountedThreadSafe<IOWorker>; |
| virtual ~IOWorker(); |
| - const base::WeakPtr<GCMProfileService> service_; |
| + base::WeakPtr<GCMProfileService> service_; |
| scoped_ptr<GCMClient> gcm_client_; |
| }; |
| -GCMProfileService::IOWorker::IOWorker( |
| - const base::WeakPtr<GCMProfileService>& service) |
| - : service_(service) { |
| +GCMProfileService::IOWorker::IOWorker() { |
| DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| } |
| @@ -292,7 +294,7 @@ GCMProfileService::IOWorker::~IOWorker() { |
| } |
| void GCMProfileService::IOWorker::Initialize( |
| - GCMClientFactory* gcm_client_factory, |
| + scoped_ptr<GCMClientFactory> gcm_client_factory, |
| const base::FilePath& store_path, |
| const std::vector<std::string>& account_ids, |
| const scoped_refptr<net::URLRequestContextGetter>& |
| @@ -319,13 +321,6 @@ void GCMProfileService::IOWorker::Initialize( |
| blocking_task_runner, |
| url_request_context_getter, |
| this); |
| - |
| - content::BrowserThread::PostTask( |
| - content::BrowserThread::UI, |
| - FROM_HERE, |
| - base::Bind(&GCMProfileService::FinishInitializationOnUI, |
| - service_, |
| - gcm_client_->IsReady())); |
| } |
| void GCMProfileService::IOWorker::Reset() { |
| @@ -423,11 +418,21 @@ void GCMProfileService::IOWorker::OnGCMReady() { |
| service_)); |
| } |
| +void GCMProfileService::IOWorker::Load( |
| + const base::WeakPtr<GCMProfileService>& service) { |
| + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); |
| + |
| + service_ = service; |
| + gcm_client_->Load(); |
| +} |
| + |
| void GCMProfileService::IOWorker::CheckOut() { |
| DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); |
| gcm_client_->CheckOut(); |
| - gcm_client_.reset(); |
| + |
| + // Note that we still need to keep GCMClient instance alive since the profile |
| + // might be signed in again. |
| } |
| void GCMProfileService::IOWorker::Register( |
| @@ -464,18 +469,19 @@ bool GCMProfileService::RegistrationInfo::IsValid() const { |
| return !sender_ids.empty() && !registration_id.empty(); |
| } |
| -bool GCMProfileService::enable_gcm_for_testing_ = false; |
| - |
| // static |
| -bool GCMProfileService::IsGCMEnabled(Profile* profile) { |
| - // GCM is not enabled in incognito mode. |
| - if (profile->IsOffTheRecord()) |
| - return false; |
| +GCMProfileService::GCMEnabledState GCMProfileService::GetGCMEnabledState( |
| + Profile* profile) { |
| + const base::Value* gcm_enabled_value = |
| + profile->GetPrefs()->GetUserPrefValue(prefs::kGCMChannelEnabled); |
| + if (!gcm_enabled_value) |
| + return ENABLED_FOR_APPS; |
| - if (enable_gcm_for_testing_) |
| - return true; |
| + bool gcm_enabled = false; |
| + if (!gcm_enabled_value->GetAsBoolean(&gcm_enabled)) |
| + return ENABLED_FOR_APPS; |
| - return profile->GetPrefs()->GetBoolean(prefs::kGCMChannelEnabled); |
| + return gcm_enabled ? ALWAYS_ENABLED : ALWAYS_DISABLED; |
| } |
| // static |
| @@ -511,15 +517,6 @@ GCMProfileService::~GCMProfileService() { |
| void GCMProfileService::Initialize( |
| scoped_ptr<GCMClientFactory> gcm_client_factory) { |
| - gcm_client_factory_ = gcm_client_factory.Pass(); |
| - |
| - // This has to be done first since CheckIn depends on it. |
| - io_worker_ = new IOWorker(weak_ptr_factory_.GetWeakPtr()); |
| - |
| -#if !defined(OS_ANDROID) |
| - js_event_router_.reset(new extensions::GcmJsEventRouter(profile_)); |
| -#endif |
| - |
| registrar_.Add(this, |
| chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL, |
| content::Source<Profile>(profile_)); |
| @@ -534,14 +531,32 @@ void GCMProfileService::Initialize( |
| chrome:: NOTIFICATION_EXTENSION_UNINSTALLED, |
| content::Source<Profile>(profile_)); |
| - // In case that the profile has been signed in before GCMProfileService is |
| - // created. |
| - SigninManagerBase* manager = SigninManagerFactory::GetForProfile(profile_); |
| - if (manager) { |
| - std::string username = manager->GetAuthenticatedUsername(); |
| - if (!username.empty()) |
| - CheckIn(username); |
| - } |
| + // Get the list of available accounts. |
| + std::vector<std::string> account_ids; |
| +#if !defined(OS_ANDROID) |
| + account_ids = |
| + ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->GetAccounts(); |
| +#endif |
| + |
| + // Create and initialize the GCMClient. Note that this does not initiate the |
| + // GCM check-in. |
| + io_worker_ = new IOWorker(); |
| + scoped_refptr<net::URLRequestContextGetter> url_request_context_getter = |
|
SeRya
2014/03/04 08:35:26
I tried to use ProfileSyncService on startup and g
jianli
2014/03/05 01:37:34
I can't repro this. Could you please share how you
|
| + profile_->GetRequestContext(); |
| + content::BrowserThread::PostTask( |
| + content::BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind(&GCMProfileService::IOWorker::Initialize, |
| + io_worker_, |
| + base::Passed(&gcm_client_factory), |
| + profile_->GetPath().Append(chrome::kGCMStoreDirname), |
| + account_ids, |
| + url_request_context_getter)); |
| + |
| + // Load from the GCM store and initiate the GCM check-in if the rollout signal |
| + // indicates yes. |
| + if (GetGCMEnabledState(profile_) == ALWAYS_ENABLED) |
| + EnsureLoaded(); |
| } |
| void GCMProfileService::Register(const std::string& app_id, |
| @@ -551,6 +566,9 @@ void GCMProfileService::Register(const std::string& app_id, |
| DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| DCHECK(!app_id.empty() && !sender_ids.empty() && !callback.is_null()); |
| + // Ensure that check-in has been done. |
| + EnsureLoaded(); |
| + |
| // If the profile was not signed in, bail out. |
| if (username_.empty()) { |
| callback.Run(std::string(), GCMClient::NOT_SIGNED_IN); |
| @@ -636,6 +654,9 @@ void GCMProfileService::Send(const std::string& app_id, |
| DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| DCHECK(!app_id.empty() && !receiver_id.empty() && !callback.is_null()); |
| + // Ensure that check-in has been done. |
| + EnsureLoaded(); |
| + |
| // If the profile was not signed in, bail out. |
| if (username_.empty()) { |
| callback.Run(std::string(), GCMClient::NOT_SIGNED_IN); |
| @@ -680,6 +701,10 @@ void GCMProfileService::DoSend(const std::string& app_id, |
| message)); |
| } |
| +GCMClient* GCMProfileService::GetGCMClientForTesting() const { |
| + return io_worker_ ? io_worker_->gcm_client_for_testing() : NULL; |
| +} |
| + |
| void GCMProfileService::Observe(int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| @@ -687,11 +712,8 @@ void GCMProfileService::Observe(int type, |
| switch (type) { |
| case chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL: { |
| - const GoogleServiceSigninSuccessDetails* signin_details = |
| - content::Details<GoogleServiceSigninSuccessDetails>(details).ptr(); |
| - // This could be called multiple times when the password changed. |
| - if (username_ != signin_details->username) |
| - CheckIn(signin_details->username); |
| + if (GetGCMEnabledState(profile_) == ALWAYS_ENABLED) |
| + EnsureLoaded(); |
| break; |
| } |
| case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT: |
| @@ -700,54 +722,68 @@ void GCMProfileService::Observe(int type, |
| case chrome::NOTIFICATION_PROFILE_DESTROYED: |
| ResetGCMClient(); |
| break; |
| - case chrome:: NOTIFICATION_EXTENSION_UNINSTALLED: { |
| - extensions::Extension* extension = |
| - content::Details<extensions::Extension>(details).ptr(); |
| - Unregister(extension->id()); |
| + case chrome:: NOTIFICATION_EXTENSION_UNINSTALLED: |
| + if (!username_.empty()) { |
| + extensions::Extension* extension = |
| + content::Details<extensions::Extension>(details).ptr(); |
| + Unregister(extension->id()); |
| + } |
| break; |
| - } |
| default: |
| NOTREACHED(); |
| } |
| } |
| -void GCMProfileService::CheckIn(const std::string& username) { |
| - DCHECK(!username.empty() && username_.empty()); |
| +void GCMProfileService::EnsureLoaded() { |
| + SigninManagerBase* manager = SigninManagerFactory::GetForProfile(profile_); |
| + if (!manager) |
| + return; |
| + std::string username = manager->GetAuthenticatedUsername(); |
| + if (username.empty()) |
| + return; |
| + |
| + // CheckIn could be called more than once when: |
| + // 1) The password changes. |
| + // 2) Register/send function calls it to ensure CheckIn is done. |
| + if (username_ == username) |
| + return; |
| username_ = username; |
| +#if !defined(OS_ANDROID) |
| + if (!js_event_router_) |
| + js_event_router_.reset(new extensions::GcmJsEventRouter(profile_)); |
| +#endif |
| + |
| DCHECK(!delayed_task_controller_); |
| delayed_task_controller_.reset(new DelayedTaskController); |
| - // Load all register apps. |
| + // Load all the registered apps. |
| ReadRegisteredAppIDs(); |
| - // Get the list of available accounts. |
| - std::vector<std::string> account_ids; |
| -#if !defined(OS_ANDROID) |
| - account_ids = |
| - ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->GetAccounts(); |
| -#endif |
| - |
| - // Let the IO thread create and initialize GCMClient. |
| - scoped_refptr<net::URLRequestContextGetter> url_request_context_getter = |
| - profile_->GetRequestContext(); |
| + // This will load the data from the gcm store and trigger the check-in if |
| + // the persisted check-in info is not found. |
| + // Note that we need to pass weak pointer again since the existing weak |
| + // pointer in IOWorker might have been invalidated when check-out occurs. |
| content::BrowserThread::PostTask( |
| content::BrowserThread::IO, |
| FROM_HERE, |
| - base::Bind(&GCMProfileService::IOWorker::Initialize, |
| + base::Bind(&GCMProfileService::IOWorker::Load, |
| io_worker_, |
| - gcm_client_factory_.get(), |
| - profile_->GetPath().Append(chrome::kGCMStoreDirname), |
| - account_ids, |
| - url_request_context_getter)); |
| + weak_ptr_factory_.GetWeakPtr())); |
| } |
| void GCMProfileService::CheckOut() { |
| DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| - DCHECK(!username_.empty()); |
| + // We still proceed with the check-out logic even if the check-in is not |
| + // initiated in the current session. This will make sure that all the |
| + // persisted data written previously will get purged. |
| username_.clear(); |
| + // Remove all the queued tasks since they no longer make sense after |
| + // check-out. |
| + weak_ptr_factory_.InvalidateWeakPtrs(); |
| + |
| // Remove persisted data from app's state store. |
| for (RegistrationInfoMap::const_iterator iter = |
| registration_info_map_.begin(); |
| @@ -756,7 +792,6 @@ void GCMProfileService::CheckOut() { |
| } |
| // Remove persisted data from prefs store. |
| - profile_->GetPrefs()->ClearPref(prefs::kGCMChannelEnabled); |
| profile_->GetPrefs()->ClearPref(prefs::kGCMRegisteredAppIDs); |
| gcm_client_ready_ = false; |
| @@ -902,14 +937,6 @@ void GCMProfileService::MessageSendError(const std::string& app_id, |
| GetEventRouter(app_id)->OnSendError(app_id, message_id, result); |
| } |
| -void GCMProfileService::FinishInitializationOnUI(bool ready) { |
| - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| - |
| - gcm_client_ready_ = ready; |
| - if (gcm_client_ready_) |
| - delayed_task_controller_->SetGCMReady(); |
| -} |
| - |
| void GCMProfileService::GCMClientReady() { |
| DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |