| 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));
|
|
|
|
|