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

Unified Diff: chrome/browser/services/gcm/gcm_profile_service.cc

Issue 165993005: [GCM] Make sure GCM checkout logic is invoked when the profile is signed out (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix test Created 6 years, 10 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 side-by-side diff with in-line comments
Download patch
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));

Powered by Google App Engine
This is Rietveld 408576698