#include "chrome/browser/services/gcm/gcm_profile_service.h"
#include "base/base64.h"
+#include "base/files/file_path.h"
#include "base/logging.h"
+#include "base/path_service.h"
#include "base/prefs/pref_service.h"
#include "base/strings/string_number_conversions.h"
+#include "base/threading/sequenced_worker_pool.h"
#include "chrome/browser/chrome_notification_types.h"
+#if !defined(OS_ANDROID)
+#include "chrome/browser/extensions/api/gcm/gcm_api.h"
+#endif
#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/state_store.h"
#include "chrome/browser/services/gcm/gcm_client_factory.h"
#include "chrome/browser/services/gcm/gcm_event_router.h"
#include "chrome/browser/signin/signin_manager.h"
#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/pref_names.h"
#include "components/user_prefs/pref_registry_syncable.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
+#include "extensions/browser/extension_system.h"
#include "extensions/common/extension.h"
+#include "google_apis/gcm/protocol/android_checkin.pb.h"
+#include "net/url_request/url_request_context_getter.h"
using extensions::Extension;
namespace gcm {
+namespace {
+
const char kRegistrationKey[] = "gcm.registration";
const char kSendersKey[] = "senders";
const char kRegistrationIDKey[] = "reg_id";
+checkin_proto::ChromeBuildProto_Platform GetPlatform() {
+#if defined(OS_WIN)
+ return checkin_proto::ChromeBuildProto_Platform_PLATFORM_WIN;
+#elif defined(OS_MACOSX)
+ return checkin_proto::ChromeBuildProto_Platform_PLATFORM_MAC;
+#elif defined(OS_CHROMEOS)
+ return checkin_proto::ChromeBuildProto_Platform_PLATFORM_CROS;
+#elif defined(OS_LINUX)
+ return checkin_proto::ChromeBuildProto_Platform_PLATFORM_LINUX;
+#else
+ // For all other platforms, return as LINUX.
+ return checkin_proto::ChromeBuildProto_Platform_PLATFORM_LINUX;
+#endif
+}
+
+std::string GetVersion() {
+ chrome::VersionInfo version_info;
+ return version_info.Version();
+}
+
+checkin_proto::ChromeBuildProto_Channel GetChannel() {
+ chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
+ switch (channel) {
+ case chrome::VersionInfo::CHANNEL_UNKNOWN:
+ return checkin_proto::ChromeBuildProto_Channel_CHANNEL_UNKNOWN;
+ case chrome::VersionInfo::CHANNEL_CANARY:
+ return checkin_proto::ChromeBuildProto_Channel_CHANNEL_CANARY;
+ case chrome::VersionInfo::CHANNEL_DEV:
+ return checkin_proto::ChromeBuildProto_Channel_CHANNEL_DEV;
+ case chrome::VersionInfo::CHANNEL_BETA:
+ return checkin_proto::ChromeBuildProto_Channel_CHANNEL_BETA;
+ case chrome::VersionInfo::CHANNEL_STABLE:
+ return checkin_proto::ChromeBuildProto_Channel_CHANNEL_STABLE;
+ default:
+ NOTREACHED();
+ return checkin_proto::ChromeBuildProto_Channel_CHANNEL_UNKNOWN;
+ };
+}
+
+} // namespace
+
// Helper class to save tasks to run until we're ready to execute them.
class GCMProfileService::DelayedTaskController {
public:
// Adds a task that will be invoked once we're ready.
void AddTask(const std::string& app_id, base::Closure task);
- // Marks that GCMClient is ready.
- void SetGCMClientReady();
+ // Sets GCM ready status. GCM is ready only when check-in is completed and
+ // the GCMClient is fully initialized. If it is set to ready for the first
+ // time, all the pending tasks for any ready apps will be run.
+ void SetGCMReady();
- // Marks that the app is ready to have operations performed.
+ // Sets ready status for the app. If GCM is already ready, all the pending
+ // tasks for this app will be run.
void SetAppReady(const std::string& app_id);
// Returns true if it is ready to perform operations for an app.
AppTaskQueue();
~AppTaskQueue();
- // The flag that indicates if GCMProfileService completes loading the
- // persistent data for the app.
+ // The flag that indicates if GCMClient is ready.
bool ready;
// Tasks to be invoked upon ready.
void RunTasks(AppTaskQueue* task_queue);
- // Flag that indicates that GCMClient is ready.
- bool gcm_client_ready_;
+ // Flag that indicates that GCM is done.
+ bool gcm_ready_;
- // Map from app_id to callbacks.
+ // Map from app_id to AppTaskQueue storing the tasks that will be invoked
+ // when both GCM and the app get ready.
typedef std::map<std::string, AppTaskQueue*> DelayedTaskMap;
DelayedTaskMap delayed_task_map_;
};
}
GCMProfileService::DelayedTaskController::DelayedTaskController()
- : gcm_client_ready_(false) {
+ : gcm_ready_(false) {
}
GCMProfileService::DelayedTaskController::~DelayedTaskController() {
void GCMProfileService::DelayedTaskController::RemoveApp(
const std::string& app_id) {
- delayed_task_map_.erase(app_id);
+ DelayedTaskMap::iterator iter = delayed_task_map_.find(app_id);
+ if (iter == delayed_task_map_.end())
+ return;
+ delete iter->second;
+ delayed_task_map_.erase(iter);
}
void GCMProfileService::DelayedTaskController::AddTask(
iter->second->tasks.push_back(task);
}
-void GCMProfileService::DelayedTaskController::SetGCMClientReady() {
- gcm_client_ready_ = true;
+void GCMProfileService::DelayedTaskController::SetGCMReady() {
+ gcm_ready_ = true;
for (DelayedTaskMap::iterator iter = delayed_task_map_.begin();
- iter != delayed_task_map_.end();) {
- if (iter->second->ready) {
- AppTaskQueue* task_queue = iter->second;
- RunTasks(task_queue);
- delete task_queue;
- delayed_task_map_.erase(iter++);
- } else {
- ++iter;
- }
+ iter != delayed_task_map_.end(); ++iter) {
+ if (iter->second->ready)
+ RunTasks(iter->second);
}
}
DCHECK(task_queue);
task_queue->ready = true;
- if (gcm_client_ready_) {
+ if (gcm_ready_)
RunTasks(task_queue);
- delete task_queue;
- delayed_task_map_.erase(iter);
- }
}
bool GCMProfileService::DelayedTaskController::CanRunTaskWithoutDelay(
const std::string& app_id) const {
- if (!gcm_client_ready_)
+ if (!gcm_ready_)
return false;
DelayedTaskMap::const_iterator iter = delayed_task_map_.find(app_id);
if (iter == delayed_task_map_.end())
void GCMProfileService::DelayedTaskController::RunTasks(
AppTaskQueue* task_queue) {
- DCHECK(gcm_client_ready_ && task_queue->ready);
+ DCHECK(gcm_ready_ && task_queue->ready);
for (size_t i = 0; i < task_queue->tasks.size(); ++i)
task_queue->tasks[i].Run();
// Overridden from GCMClient::Delegate:
// Called on IO thread.
- virtual void OnCheckInFinished(const GCMClient::CheckinInfo& checkin_info,
- GCMClient::Result result) OVERRIDE;
virtual void OnRegisterFinished(const std::string& app_id,
const std::string& registration_id,
GCMClient::Result result) OVERRIDE;
+ virtual void OnUnregisterFinished(const std::string& app_id,
+ bool success) OVERRIDE;
virtual void OnSendFinished(const std::string& app_id,
const std::string& message_id,
GCMClient::Result result) OVERRIDE;
virtual void OnMessageSendError(const std::string& app_id,
const std::string& message_id,
GCMClient::Result result) OVERRIDE;
- virtual GCMClient::CheckinInfo GetCheckinInfo() const OVERRIDE;
- virtual void OnLoadingCompleted() OVERRIDE;
+ virtual void OnGCMReady() OVERRIDE;
// Called on IO thread.
- void Initialize();
- void SetUser(const std::string& username);
- void RemoveUser();
- void CheckIn();
- void SetCheckinInfo(const GCMClient::CheckinInfo& checkin_info);
+ void Initialize(
+ GCMClientFactory* gcm_client_factory,
+ const base::FilePath& store_path,
+ const scoped_refptr<net::URLRequestContextGetter>&
+ url_request_context_getter);
+ void Reset();
void CheckOut();
void Register(const std::string& app_id,
const std::vector<std::string>& sender_ids,
const base::WeakPtr<GCMProfileService> service_;
- // Not owned.
- GCMClient* gcm_client_;
-
- // The username (email address) of the signed-in user.
- std::string username_;
-
- // The checkin info obtained from the server for the signed in user associated
- // with the profile.
- GCMClient::CheckinInfo checkin_info_;
+ scoped_ptr<GCMClient> gcm_client_;
};
GCMProfileService::IOWorker::IOWorker(
const base::WeakPtr<GCMProfileService>& service)
- : service_(service),
- gcm_client_(NULL) {
+ : service_(service) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
}
GCMProfileService::IOWorker::~IOWorker() {
}
-void GCMProfileService::IOWorker::Initialize() {
+void GCMProfileService::IOWorker::Initialize(
+ GCMClientFactory* gcm_client_factory,
+ const base::FilePath& store_path,
+ const scoped_refptr<net::URLRequestContextGetter>&
+ url_request_context_getter) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
- gcm_client_ = GCMClientFactory::GetClient();
+ gcm_client_ = gcm_client_factory->BuildInstance().Pass();
+
+ checkin_proto::ChromeBuildProto chrome_build_proto;
+ chrome_build_proto.set_platform(GetPlatform());
+ chrome_build_proto.set_chrome_version(GetVersion());
+ chrome_build_proto.set_channel(GetChannel());
+
+ scoped_refptr<base::SequencedWorkerPool> worker_pool(
+ content::BrowserThread::GetBlockingPool());
+ scoped_refptr<base::SequencedTaskRunner> blocking_task_runner(
+ worker_pool->GetSequencedTaskRunnerWithShutdownBehavior(
+ worker_pool->GetSequenceToken(),
+ base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
+
+ gcm_client_->Initialize(chrome_build_proto,
+ store_path,
+ blocking_task_runner,
+ url_request_context_getter,
+ this);
content::BrowserThread::PostTask(
content::BrowserThread::UI,
FROM_HERE,
- base::Bind(&GCMProfileService::CheckGCMClientLoadingFinished,
+ base::Bind(&GCMProfileService::FinishInitializationOnUI,
service_,
- gcm_client_->IsLoading()));
+ gcm_client_->IsReady()));
}
-void GCMProfileService::IOWorker::OnCheckInFinished(
- const GCMClient::CheckinInfo& checkin_info,
- GCMClient::Result result) {
+void GCMProfileService::IOWorker::Reset() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
- checkin_info_ = checkin_info;
-
- content::BrowserThread::PostTask(
- content::BrowserThread::UI,
- FROM_HERE,
- base::Bind(&GCMProfileService::CheckInFinished,
- service_,
- checkin_info_,
- result));
+ // GCMClient instance must be destroyed from the same thread where it was
+ // created.
+ gcm_client_.reset();
}
void GCMProfileService::IOWorker::OnRegisterFinished(
result));
}
+void GCMProfileService::IOWorker::OnUnregisterFinished(
+ const std::string& app_id,
+ bool success) {
+ // Nothing to do here.
+}
+
void GCMProfileService::IOWorker::OnSendFinished(
const std::string& app_id,
const std::string& message_id,
result));
}
-GCMClient::CheckinInfo GCMProfileService::IOWorker::GetCheckinInfo() const {
- return checkin_info_;
-}
-
-void GCMProfileService::IOWorker::OnLoadingCompleted() {
+void GCMProfileService::IOWorker::OnGCMReady() {
content::BrowserThread::PostTask(
content::BrowserThread::UI,
FROM_HERE,
- base::Bind(&GCMProfileService::GCMClientLoadingFinished,
+ base::Bind(&GCMProfileService::GCMClientReady,
service_));
}
-void GCMProfileService::IOWorker::SetUser(const std::string& username) {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
- DCHECK(username_.empty() && !username.empty());
-
- username_ = username;
- gcm_client_->SetUserDelegate(username_, this);
-}
-
-void GCMProfileService::IOWorker::RemoveUser() {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
-
- if (username_.empty())
- return;
- gcm_client_->SetUserDelegate(username_, NULL);
- username_.clear();
-}
-
-void GCMProfileService::IOWorker::CheckIn() {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
-
- gcm_client_->CheckIn(username_);
-}
-
-void GCMProfileService::IOWorker::SetCheckinInfo(
- const GCMClient::CheckinInfo& checkin_info) {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
-
- checkin_info_ = checkin_info;
-}
-
void GCMProfileService::IOWorker::CheckOut() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
- checkin_info_.Reset();
- RemoveUser();
+ gcm_client_->CheckOut();
+ gcm_client_.reset();
}
void GCMProfileService::IOWorker::Register(
const std::vector<std::string>& sender_ids,
const std::string& cert) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
- DCHECK(!username_.empty() && checkin_info_.IsValid());
- gcm_client_->Register(username_, app_id, cert, sender_ids);
+ gcm_client_->Register(app_id, cert, sender_ids);
}
void GCMProfileService::IOWorker::Unregister(const std::string& app_id) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
- DCHECK(!username_.empty() && checkin_info_.IsValid());
- gcm_client_->Unregister(username_, app_id);
+ gcm_client_->Unregister(app_id);
}
void GCMProfileService::IOWorker::Send(
const std::string& receiver_id,
const GCMClient::OutgoingMessage& message) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
- DCHECK(!username_.empty() && checkin_info_.IsValid());
- gcm_client_->Send(username_, app_id, receiver_id, message);
+ gcm_client_->Send(app_id, receiver_id, message);
}
GCMProfileService::RegistrationInfo::RegistrationInfo() {
if (enable_gcm_for_testing_)
return true;
- // GCM support is only enabled for Canary/Dev builds.
- chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
- return channel == chrome::VersionInfo::CHANNEL_UNKNOWN ||
- channel == chrome::VersionInfo::CHANNEL_CANARY ||
- channel == chrome::VersionInfo::CHANNEL_DEV;
+ return profile->GetPrefs()->GetBoolean(prefs::kGCMChannelEnabled);
}
// static
void GCMProfileService::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
- registry->RegisterUint64Pref(
- prefs::kGCMUserAccountID,
- 0,
+ // GCM support is only enabled by default for Canary/Dev/Custom builds.
+ chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
+ bool on_by_default = false;
+ if (channel == chrome::VersionInfo::CHANNEL_UNKNOWN ||
+ channel == chrome::VersionInfo::CHANNEL_CANARY ||
+ channel == chrome::VersionInfo::CHANNEL_DEV) {
+ on_by_default = true;
+ }
+ registry->RegisterBooleanPref(
+ prefs::kGCMChannelEnabled,
+ on_by_default,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
- registry->RegisterStringPref(
- prefs::kGCMUserToken,
- "",
+ registry->RegisterListPref(
+ prefs::kGCMRegisteredAppIDs,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
}
GCMProfileService::GCMProfileService(Profile* profile)
: profile_(profile),
+ gcm_client_ready_(false),
testing_delegate_(NULL),
weak_ptr_factory_(this) {
DCHECK(!profile->IsOffTheRecord());
}
GCMProfileService::~GCMProfileService() {
- if (username_.empty())
- return;
- content::BrowserThread::PostTask(
- content::BrowserThread::IO,
- FROM_HERE,
- base::Bind(&GCMProfileService::IOWorker::RemoveUser,
- io_worker_));
}
-void GCMProfileService::Initialize() {
- delayed_task_controller_.reset(new DelayedTaskController);
+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());
- // This initializes GCMClient and also does the check to find out if GCMClient
- // has finished the loading.
- content::BrowserThread::PostTask(
- content::BrowserThread::IO,
- FROM_HERE,
- base::Bind(&GCMProfileService::IOWorker::Initialize, io_worker_));
-
- // In case that the profile has been signed in before GCMProfileService is
- // created.
- SigninManagerBase* manager = SigninManagerFactory::GetForProfile(profile_);
- if (manager)
- AddUser(manager->GetAuthenticatedUsername());
+#if !defined(OS_ANDROID)
+ js_event_router_.reset(new extensions::GcmJsEventRouter(profile_));
+#endif
registrar_.Add(this,
chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL,
registrar_.Add(this,
chrome::NOTIFICATION_GOOGLE_SIGNED_OUT,
content::Source<Profile>(profile_));
- // TODO(jianli): move extension specific logic out of GCMProfileService.
registrar_.Add(this,
- chrome::NOTIFICATION_EXTENSION_LOADED,
+ chrome::NOTIFICATION_PROFILE_DESTROYED,
content::Source<Profile>(profile_));
+ // TODO(jianli): move extension specific logic out of GCMProfileService.
registrar_.Add(this,
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);
+ }
}
void GCMProfileService::Register(const std::string& app_id,
return;
}
- // Delay the register operation until the loading is done.
+ register_callbacks_[app_id] = callback;
+
+ EnsureAppReady(app_id);
+
+ // Delay the register operation until GCMClient is ready.
if (!delayed_task_controller_->CanRunTaskWithoutDelay(app_id)) {
delayed_task_controller_->AddTask(
app_id,
weak_ptr_factory_.GetWeakPtr(),
app_id,
sender_ids,
- cert,
- callback));
+ cert));
return;
}
- DoRegister(app_id, sender_ids, cert, callback);
+ DoRegister(app_id, sender_ids, cert);
}
void GCMProfileService::DoRegister(const std::string& app_id,
const std::vector<std::string>& sender_ids,
- const std::string& cert,
- RegisterCallback callback) {
+ const std::string& cert) {
+ std::map<std::string, RegisterCallback>::iterator callback_iter =
+ register_callbacks_.find(app_id);
+ if (callback_iter == register_callbacks_.end()) {
+ // The callback could have been removed when the app is uninstalled.
+ return;
+ }
+
// Normalize the sender IDs by making them sorted.
std::vector<std::string> normalized_sender_ids = sender_ids;
std::sort(normalized_sender_ids.begin(), normalized_sender_ids.end());
registration_info_map_.find(app_id);
if (registration_info_iter != registration_info_map_.end() &&
registration_info_iter->second.sender_ids == normalized_sender_ids) {
+ RegisterCallback callback = callback_iter->second;
+ register_callbacks_.erase(callback_iter);
callback.Run(registration_info_iter->second.registration_id,
GCMClient::SUCCESS);
return;
registration_info.sender_ids = normalized_sender_ids;
registration_info_map_[app_id] = registration_info;
- register_callbacks_[app_id] = callback;
+ // Save the IDs of all registered apps such that we know what to remove from
+ // the the app's state store when the profile is signed out.
+ WriteRegisteredAppIDs();
content::BrowserThread::PostTask(
content::BrowserThread::IO,
}
send_callbacks_[key] = callback;
- // Delay the send operation until all the loadings are done.
+ EnsureAppReady(app_id);
+
+ // Delay the send operation until all GCMClient is ready.
if (!delayed_task_controller_->CanRunTaskWithoutDelay(app_id)) {
delayed_task_controller_->AddTask(
app_id,
case chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL: {
const GoogleServiceSigninSuccessDetails* signin_details =
content::Details<GoogleServiceSigninSuccessDetails>(details).ptr();
- AddUser(signin_details->username);
+ // This could be called multiple times when the password changed.
+ if (username_ != signin_details->username)
+ CheckIn(signin_details->username);
break;
}
case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT:
- username_.clear();
- RemoveUser();
+ CheckOut();
break;
- case chrome::NOTIFICATION_EXTENSION_LOADED: {
- extensions::Extension* extension =
- content::Details<extensions::Extension>(details).ptr();
- // No need to load the persisted registration info if the extension does
- // not have the GCM permission.
- if (extension->HasAPIPermission(extensions::APIPermission::kGcm))
- ReadRegistrationInfo(extension->id());
+ case chrome::NOTIFICATION_PROFILE_DESTROYED:
+ ResetGCMClient();
break;
- }
case chrome:: NOTIFICATION_EXTENSION_UNINSTALLED: {
extensions::Extension* extension =
content::Details<extensions::Extension>(details).ptr();
}
}
-void GCMProfileService::AddUser(const std::string& username) {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-
- // If re-signin occurs due to password change, there is no need to do
- // check-in again.
- if (username_ == username || username.empty())
- return;
+void GCMProfileService::CheckIn(const std::string& username) {
+ DCHECK(!username.empty() && username_.empty());
username_ = username;
+ DCHECK(!delayed_task_controller_);
+ delayed_task_controller_.reset(new DelayedTaskController);
+
+ // Load all register apps.
+ ReadRegisteredAppIDs();
+
+ // Let the IO thread create and initialize GCMClient.
+ scoped_refptr<net::URLRequestContextGetter> url_request_context_getter =
+ profile_->GetRequestContext();
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
- base::Bind(&GCMProfileService::IOWorker::SetUser,
+ base::Bind(&GCMProfileService::IOWorker::Initialize,
io_worker_,
- username_));
-
- // Try to read persisted check-in info from the profile's prefs store.
- PrefService* pref_service = profile_->GetPrefs();
- uint64 android_id = pref_service->GetUint64(prefs::kGCMUserAccountID);
- std::string base64_token = pref_service->GetString(prefs::kGCMUserToken);
- std::string encrypted_secret;
- base::Base64Decode(base::StringPiece(base64_token), &encrypted_secret);
- if (android_id && !encrypted_secret.empty()) {
- std::string decrypted_secret;
- Encryptor::DecryptString(encrypted_secret, &decrypted_secret);
- uint64 secret = 0;
- if (base::StringToUint64(decrypted_secret, &secret) && secret) {
- GCMClient::CheckinInfo checkin_info;
- checkin_info.android_id = android_id;
- checkin_info.secret = secret;
- content::BrowserThread::PostTask(
- content::BrowserThread::IO,
- FROM_HERE,
- base::Bind(&GCMProfileService::IOWorker::SetCheckinInfo,
- io_worker_,
- checkin_info));
-
- if (testing_delegate_)
- testing_delegate_->CheckInFinished(checkin_info, GCMClient::SUCCESS);
-
- return;
- }
+ gcm_client_factory_.get(),
+ profile_->GetPath().Append(chrome::kGCMStoreDirname),
+ url_request_context_getter));
+}
+
+void GCMProfileService::CheckOut() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+ DCHECK(!username_.empty());
+ username_.clear();
+
+ // Remove persisted data from app's state store.
+ for (RegistrationInfoMap::const_iterator iter =
+ registration_info_map_.begin();
+ iter != registration_info_map_.end(); ++iter) {
+ DeleteRegistrationInfo(iter->first);
}
+ // Remove persisted data from prefs store.
+ profile_->GetPrefs()->ClearPref(prefs::kGCMChannelEnabled);
+ profile_->GetPrefs()->ClearPref(prefs::kGCMRegisteredAppIDs);
+
+ gcm_client_ready_ = false;
+ delayed_task_controller_.reset();
+ register_callbacks_.clear();
+ send_callbacks_.clear();
+ registration_info_map_.clear();
+
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
- base::Bind(&GCMProfileService::IOWorker::CheckIn, io_worker_));
+ base::Bind(&GCMProfileService::IOWorker::CheckOut, io_worker_));
}
-void GCMProfileService::RemoveUser() {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-
- PrefService* pref_service = profile_->GetPrefs();
- pref_service->ClearPref(prefs::kGCMUserAccountID);
- pref_service->ClearPref(prefs::kGCMUserToken);
-
+void GCMProfileService::ResetGCMClient() {
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
- base::Bind(&GCMProfileService::IOWorker::CheckOut, io_worker_));
+ base::Bind(&GCMProfileService::IOWorker::Reset, io_worker_));
+}
+
+void GCMProfileService::EnsureAppReady(const std::string& app_id) {
+ if (delayed_task_controller_->IsAppTracked(app_id))
+ return;
+
+ ReadRegistrationInfo(app_id);
}
void GCMProfileService::Unregister(const std::string& app_id) {
return;
registration_info_map_.erase(registration_info_iter);
+ // Update the persisted IDs of registered apps.
+ WriteRegisteredAppIDs();
+
// Remove the persisted registration info.
DeleteRegistrationInfo(app_id);
app_id));
}
-void GCMProfileService::CheckInFinished(
- const GCMClient::CheckinInfo& checkin_info, GCMClient::Result result) {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-
- // Save the check-in info into the profile's prefs store.
- PrefService* pref_service = profile_->GetPrefs();
- pref_service->SetUint64(prefs::kGCMUserAccountID, checkin_info.android_id);
-
- // Encrypt the secret for persisting purpose.
- std::string encrypted_secret;
- Encryptor::EncryptString(base::Uint64ToString(checkin_info.secret),
- &encrypted_secret);
-
- // |encrypted_secret| might contain binary data and our prefs store only
- // works for the text.
- std::string base64_token;
- base::Base64Encode(encrypted_secret, &base64_token);
- pref_service->SetString(prefs::kGCMUserToken, base64_token);
-
- if (testing_delegate_)
- testing_delegate_->CheckInFinished(checkin_info, result);
-}
-
void GCMProfileService::RegisterFinished(const std::string& app_id,
const std::string& registration_id,
GCMClient::Result result) {
GetEventRouter(app_id)->OnSendError(app_id, message_id, result);
}
-void GCMProfileService::CheckGCMClientLoadingFinished(bool is_loading) {
+void GCMProfileService::FinishInitializationOnUI(bool ready) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- if (!is_loading)
- delayed_task_controller_->SetGCMClientReady();
+ gcm_client_ready_ = ready;
+ if (gcm_client_ready_)
+ delayed_task_controller_->SetGCMReady();
}
-void GCMProfileService::GCMClientLoadingFinished() {
+void GCMProfileService::GCMClientReady() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- delayed_task_controller_->SetGCMClientReady();
+ if (gcm_client_ready_)
+ return;
+ gcm_client_ready_ = true;
+
+ delayed_task_controller_->SetGCMReady();
}
-GCMEventRouter* GCMProfileService::GetEventRouter(const std::string& app_id) {
+GCMEventRouter* GCMProfileService::GetEventRouter(const std::string& app_id)
+ const {
if (testing_delegate_ && testing_delegate_->GetEventRouter())
return testing_delegate_->GetEventRouter();
- // TODO(fgorski): check and create the event router for JS routing.
+#if defined(OS_ANDROID)
+ return NULL;
+#else
return js_event_router_.get();
+#endif
+}
+
+void GCMProfileService::ReadRegisteredAppIDs() {
+ const base::ListValue* app_id_list =
+ profile_->GetPrefs()->GetList(prefs::kGCMRegisteredAppIDs);
+ for (size_t i = 0; i < app_id_list->GetSize(); ++i) {
+ std::string app_id;
+ if (!app_id_list->GetString(i, &app_id))
+ continue;
+ ReadRegistrationInfo(app_id);
+ }
+}
+
+void GCMProfileService::WriteRegisteredAppIDs() {
+ base::ListValue apps;
+ for (RegistrationInfoMap::const_iterator iter =
+ registration_info_map_.begin();
+ iter != registration_info_map_.end(); ++iter) {
+ apps.Append(new base::StringValue(iter->first));
+ }
+ profile_->GetPrefs()->Set(prefs::kGCMRegisteredAppIDs, apps);
}
void GCMProfileService::DeleteRegistrationInfo(const std::string& app_id) {
}
void GCMProfileService::ReadRegistrationInfo(const std::string& app_id) {
- // This function can be called more than once when the app is allowed in
- // incognito and the extension service reloads the app.
- if (delayed_task_controller_->IsAppTracked(app_id))
- return;
-
delayed_task_controller_->AddApp(app_id);
extensions::StateStore* storage =