Index: chrome/browser/services/gcm/gcm_profile_service.cc |
=================================================================== |
--- chrome/browser/services/gcm/gcm_profile_service.cc (revision 255183) |
+++ chrome/browser/services/gcm/gcm_profile_service.cc (working copy) |
@@ -232,7 +232,7 @@ |
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. |
@@ -255,11 +255,12 @@ |
// Called on IO thread. |
void Initialize( |
- GCMClientFactory* gcm_client_factory, |
+ scoped_ptr<GCMClientFactory> gcm_client_factory, |
const base::FilePath& store_path, |
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, |
@@ -269,18 +270,19 @@ |
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)); |
} |
@@ -288,7 +290,7 @@ |
} |
void GCMProfileService::IOWorker::Initialize( |
- GCMClientFactory* gcm_client_factory, |
+ scoped_ptr<GCMClientFactory> gcm_client_factory, |
const base::FilePath& store_path, |
const scoped_refptr<net::URLRequestContextGetter>& |
url_request_context_getter) { |
@@ -313,13 +315,6 @@ |
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() { |
@@ -417,11 +412,21 @@ |
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( |
@@ -458,18 +463,19 @@ |
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 |
@@ -505,15 +511,6 @@ |
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_)); |
@@ -528,14 +525,24 @@ |
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); |
- } |
+ // 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 = |
+ 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), |
+ 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, |
@@ -545,6 +552,9 @@ |
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); |
@@ -630,6 +640,9 @@ |
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); |
@@ -674,6 +687,10 @@ |
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) { |
@@ -681,11 +698,8 @@ |
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: |
@@ -694,46 +708,68 @@ |
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(); |
- // 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), |
- 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(); |
@@ -742,7 +778,6 @@ |
} |
// Remove persisted data from prefs store. |
- profile_->GetPrefs()->ClearPref(prefs::kGCMChannelEnabled); |
profile_->GetPrefs()->ClearPref(prefs::kGCMRegisteredAppIDs); |
gcm_client_ready_ = false; |
@@ -888,14 +923,6 @@ |
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)); |