Push API: register PushMessagingServiceImpl as GCMAppHandler.

Based on patch 324913004 by johnme@chromium.org who is on holiday now.

BUG=350378

Review URL: https://codereview.chromium.org/338363003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@278087 0039d316-1c4b-4281-b951-d872f2087c98
parent 8fc75ca3
......@@ -351,6 +351,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
chrome_prefs::RegisterProfilePrefs(registry);
DownloadPrefs::RegisterProfilePrefs(registry);
easy_unlock::RegisterProfilePrefs(registry);
gcm::GCMProfileService::RegisterProfilePrefs(registry);
HostContentSettingsMap::RegisterProfilePrefs(registry);
IncognitoModePrefs::RegisterProfilePrefs(registry);
InstantUI::RegisterProfilePrefs(registry);
......@@ -359,7 +360,6 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
MediaDeviceIDSalt::RegisterProfilePrefs(registry);
MediaStreamDevicesController::RegisterProfilePrefs(registry);
NetPrefObserver::RegisterProfilePrefs(registry);
password_manager::PasswordManager::RegisterProfilePrefs(registry);
PrefProxyConfigTrackerImpl::RegisterProfilePrefs(registry);
PrefsTabHelper::RegisterProfilePrefs(registry);
......@@ -372,7 +372,6 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
TemplateURLPrepopulateData::RegisterProfilePrefs(registry);
TranslatePrefs::RegisterProfilePrefs(registry);
ZeroSuggestProvider::RegisterProfilePrefs(registry);
gcm::GCMProfileService::RegisterProfilePrefs(registry);
#if defined(ENABLE_AUTOFILL_DIALOG)
autofill::AutofillDialogController::RegisterProfilePrefs(registry);
......
......@@ -68,6 +68,7 @@
#include "chrome/browser/search_engines/template_url_fetcher.h"
#include "chrome/browser/services/gcm/gcm_profile_service.h"
#include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
#include "chrome/browser/services/gcm/push_messaging_service_impl.h"
#include "chrome/browser/sessions/session_service_factory.h"
#include "chrome/browser/ui/startup/startup_browser_creator.h"
#include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
......@@ -643,6 +644,8 @@ void ProfileImpl::DoFinalInit() {
BookmarkModel* model = BookmarkModelFactory::GetForProfile(this);
model->AddObserver(new BookmarkModelLoadedObserver(this));
#endif
gcm::PushMessagingServiceImpl::InitializeForProfile(this);
}
void ProfileImpl::InitHostZoomMap() {
......
......@@ -98,12 +98,13 @@ void GCMProfileService::RegisterProfilePrefs(
prefs::kGCMChannelEnabled,
true,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
PushMessagingServiceImpl::RegisterProfilePrefs(registry);
}
#if defined(OS_ANDROID)
GCMProfileService::GCMProfileService(Profile* profile)
: profile_(profile),
push_messaging_service_(this) {
push_messaging_service_(this, profile) {
DCHECK(!profile->IsOffTheRecord());
driver_.reset(new GCMDriverAndroid);
......@@ -113,7 +114,7 @@ GCMProfileService::GCMProfileService(
Profile* profile,
scoped_ptr<GCMClientFactory> gcm_client_factory)
: profile_(profile),
push_messaging_service_(this) {
push_messaging_service_(this, profile) {
DCHECK(!profile->IsOffTheRecord());
driver_ = CreateGCMDriverDesktop(
......@@ -127,7 +128,7 @@ GCMProfileService::GCMProfileService(
GCMProfileService::GCMProfileService()
: profile_(NULL),
push_messaging_service_(this) {
push_messaging_service_(this, NULL) {
}
GCMProfileService::~GCMProfileService() {
......
......@@ -7,40 +7,170 @@
#include <vector>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/prefs/pref_service.h"
#include "base/strings/string_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/services/gcm/gcm_profile_service.h"
#include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "components/gcm_driver/gcm_driver.h"
#include "components/pref_registry/pref_registry_syncable.h"
namespace gcm {
namespace {
const char kAppIdPrefix[] = "push:";
const int kMaxRegistrations = 1000000;
} // namespace
// static
void PushMessagingServiceImpl::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterIntegerPref(
prefs::kPushMessagingRegistrationCount,
0,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
}
// static
void PushMessagingServiceImpl::InitializeForProfile(Profile* profile) {
// TODO(mvanouwerkerk): Make sure to remove this check at the same time as
// push graduates from experimental in Blink.
if (!CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableExperimentalWebPlatformFeatures)) {
return;
}
// TODO(johnme): Consider whether push should be enabled in incognito. If it
// does get enabled, then be careful that you're reading the pref from the
// right profile, as prefs defined in a regular profile are visible in the
// corresponding incognito profile unless overrriden.
if (!profile || profile->IsOffTheRecord() ||
profile->GetPrefs()->GetInteger(prefs::kPushMessagingRegistrationCount) <=
0) {
return;
}
// Create the GCMProfileService, and hence instantiate this class.
GCMProfileService* gcm_service =
gcm::GCMProfileServiceFactory::GetForProfile(profile);
PushMessagingServiceImpl* push_service =
static_cast<PushMessagingServiceImpl*>(
gcm_service->push_messaging_service());
// Register ourselves as an app handler.
gcm_service->driver()->AddAppHandler(kAppIdPrefix, push_service);
}
PushMessagingServiceImpl::PushMessagingServiceImpl(
GCMProfileService* gcm_profile_service)
GCMProfileService* gcm_profile_service,
Profile* profile)
: gcm_profile_service_(gcm_profile_service),
weak_factory_(this) {}
profile_(profile),
weak_factory_(this) {
}
PushMessagingServiceImpl::~PushMessagingServiceImpl() {
// TODO(johnme): If it's possible for this to be destroyed before GCMDriver,
// then we should call RemoveAppHandler.
}
bool PushMessagingServiceImpl::CanHandle(const std::string& app_id) const {
// TODO(mvanouwerkerk): Finalize and centralize format of Push API app_id.
return StartsWithASCII(app_id, kAppIdPrefix, true);
}
void PushMessagingServiceImpl::ShutdownHandler() {
// TODO(johnme): Do any necessary cleanup.
}
PushMessagingServiceImpl::~PushMessagingServiceImpl() {}
void PushMessagingServiceImpl::OnMessage(
const std::string& app_id,
const GCMClient::IncomingMessage& message) {
// The Push API only exposes a single string of data in the push event fired
// on the Service Worker. When developers send messages using GCM to the Push
// API, they must pass a single key-value pair, where the key is "data" and
// the value is the string they want to be passed to their Service Worker.
// For example, they could send the following JSON using the HTTPS GCM API:
// {
// "registration_ids": ["FOO", "BAR"],
// "data": {
// "data": "BAZ",
// },
// "delay_while_idle": true,
// }
// TODO(johnme): Make sure this is clearly documented for developers.
GCMClient::MessageData::const_iterator it = message.data.find("data");
if (it != message.data.end()) {
const std::string& data ALLOW_UNUSED = it->second;
// TODO(mvanouwerkerk): Fire push event with data on the Service Worker
// corresponding to app_id (and remove ALLOW_UNUSED above).
} else {
// Drop the message, as it is invalid.
// TODO(mvanouwerkerk): Show a warning in the developer console of the
// Service Worker corresponding to app_id.
// TODO(johnme): Add diagnostic observers (e.g. UMA and an internals page)
// to know when bad things happen.
}
}
void PushMessagingServiceImpl::OnMessagesDeleted(const std::string& app_id) {
// TODO(mvanouwerkerk): Fire push error event on the Service Worker
// corresponding to app_id.
}
void PushMessagingServiceImpl::OnSendError(
const std::string& app_id,
const GCMClient::SendErrorDetails& send_error_details) {
NOTREACHED() << "The Push API shouldn't have sent messages upstream";
}
void PushMessagingServiceImpl::Register(
const std::string& app_id,
const std::string& sender_id,
const content::PushMessagingService::RegisterCallback& callback) {
// The GCMDriver could be NULL if GCMProfileService has been shut down.
if (!gcm_profile_service_->driver())
if (!gcm_profile_service_->driver()) {
NOTREACHED() << "There is no GCMDriver. Has GCMProfileService shut down?";
}
if (profile_->GetPrefs()->GetInteger(
prefs::kPushMessagingRegistrationCount) >= kMaxRegistrations) {
DidRegister(app_id, callback, "", GCMClient::UNKNOWN_ERROR);
return;
}
// If this is registering for the first time then the driver does not have
// this as an app handler and registration would fail.
if (gcm_profile_service_->driver()->GetAppHandler(kAppIdPrefix) != this)
gcm_profile_service_->driver()->AddAppHandler(kAppIdPrefix, this);
std::vector<std::string> sender_ids(1, sender_id);
gcm_profile_service_->driver()->Register(
app_id,
sender_ids,
base::Bind(&PushMessagingServiceImpl::DidRegister,
weak_factory_.GetWeakPtr(),
app_id,
callback));
}
void PushMessagingServiceImpl::DidRegister(
const std::string& app_id,
const content::PushMessagingService::RegisterCallback& callback,
const std::string& registration_id,
GCMClient::Result result) {
GURL endpoint = GURL("https://android.googleapis.com/gcm/send");
callback.Run(endpoint, registration_id, result == GCMClient::SUCCESS);
bool success = (result == GCMClient::SUCCESS);
callback.Run(endpoint, registration_id, success);
if (success) {
// TODO(johnme): Make sure the pref doesn't get out of sync after crashes.
int registration_count = profile_->GetPrefs()->GetInteger(
prefs::kPushMessagingRegistrationCount);
profile_->GetPrefs()->SetInteger(prefs::kPushMessagingRegistrationCount,
registration_count + 1);
}
}
// TODO(johnme): Unregister should decrement the pref, and call
// RemoveAppHandler if the count drops to zero.
} // namespace gcm
......@@ -7,18 +7,43 @@
#include "base/compiler_specific.h"
#include "base/memory/weak_ptr.h"
#include "components/gcm_driver/gcm_app_handler.h"
#include "components/gcm_driver/gcm_client.h"
#include "content/public/browser/push_messaging_service.h"
class Profile;
namespace user_prefs {
class PrefRegistrySyncable;
}
namespace gcm {
class GCMProfileService;
class PushMessagingServiceImpl : public content::PushMessagingService {
class PushMessagingServiceImpl : public content::PushMessagingService,
public GCMAppHandler {
public:
explicit PushMessagingServiceImpl(GCMProfileService* gcm_profile_service);
// Register profile-specific prefs for GCM.
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
// If any Service Workers are using push, starts GCM and adds an app handler.
static void InitializeForProfile(Profile* profile);
PushMessagingServiceImpl(GCMProfileService* gcm_profile_service,
Profile* profile);
virtual ~PushMessagingServiceImpl();
// GCMAppHandler implementation.
virtual void ShutdownHandler() OVERRIDE;
virtual void OnMessage(const std::string& app_id,
const GCMClient::IncomingMessage& message) OVERRIDE;
virtual void OnMessagesDeleted(const std::string& app_id) OVERRIDE;
virtual void OnSendError(
const std::string& app_id,
const GCMClient::SendErrorDetails& send_error_details) OVERRIDE;
virtual bool CanHandle(const std::string& app_id) const OVERRIDE;
// content::PushMessagingService implementation:
virtual void Register(
const std::string& app_id,
......@@ -27,12 +52,15 @@ class PushMessagingServiceImpl : public content::PushMessagingService {
private:
void DidRegister(
const std::string& app_id,
const content::PushMessagingService::RegisterCallback& callback,
const std::string& registration_id,
GCMClient::Result result);
GCMProfileService* gcm_profile_service_; // It owns us.
Profile* profile_; // It owns our owner.
base::WeakPtrFactory<PushMessagingServiceImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(PushMessagingServiceImpl);
......
......@@ -1297,6 +1297,10 @@ const char kProfileResetPromptMemento[] = "profile.reset_prompt_memento";
// The GCM channel's enabled state.
const char kGCMChannelEnabled[] = "gcm.channel_enabled";
// How many Service Workers are registered with the Push API (could be zero).
const char kPushMessagingRegistrationCount[] =
"gcm.push_messaging_registration_count";
// Whether Easy Unlock is enabled.
extern const char kEasyUnlockEnabled[] = "easy_unlock.enabled";
......
......@@ -404,6 +404,7 @@ extern const char kPreferenceResetTime[];
extern const char kProfileResetPromptMemento[];
extern const char kGCMChannelEnabled[];
extern const char kPushMessagingRegistrationCount[];
extern const char kEasyUnlockEnabled[];
extern const char kEasyUnlockShowTutorial[];
......
......@@ -229,9 +229,6 @@ public class GCMDriver {
try {
final int MAX_RENDERERS = 1;
BrowserStartupController.get(context).startBrowserProcessesSync(MAX_RENDERERS);
// TODO(johnme): Explicitly call a JNI method that starts up GCMDriver,
// rather than relying on it being started automatically by
// ProfileSyncServiceFactory::BuildServiceInstanceFor.
if (sInstance != null) {
task.run();
} else {
......
......@@ -29,6 +29,10 @@ public class GCMListener extends MultiplexingGcmListener.AbstractListener {
private static final String TAG = "GCMListener";
// Used as a fallback since GCM doesn't yet give us the app ID.
// TODO(johnme): Get real app IDs from GCM, and remove this.
private static final String UNKNOWN_APP_ID = "https://example.com 0";
public GCMListener() {
super(TAG);
}
......@@ -37,8 +41,7 @@ public class GCMListener extends MultiplexingGcmListener.AbstractListener {
protected void onRegistered(final String registrationId) {
ThreadUtils.runOnUiThread(new Runnable() {
@Override public void run() {
// TODO(johnme): Get app ID.
GCMDriver.onRegisterFinished("unknown-app-id", registrationId);
GCMDriver.onRegisterFinished(UNKNOWN_APP_ID, registrationId);
}
});
}
......@@ -47,8 +50,7 @@ public class GCMListener extends MultiplexingGcmListener.AbstractListener {
protected void onUnregistered(String registrationId) {
ThreadUtils.runOnUiThread(new Runnable() {
@Override public void run() {
// TODO(johnme): Get app ID.
GCMDriver.onUnregisterFinished("unknown-app-id");
GCMDriver.onUnregisterFinished(UNKNOWN_APP_ID);
}
});
}
......@@ -57,8 +59,7 @@ public class GCMListener extends MultiplexingGcmListener.AbstractListener {
protected void onMessage(final Intent intent) {
ThreadUtils.runOnUiThread(new Runnable() {
@Override public void run() {
// TODO(johnme): Get app ID.
GCMDriver.onMessageReceived(getApplicationContext(), "unknown-app-id",
GCMDriver.onMessageReceived(getApplicationContext(), UNKNOWN_APP_ID,
intent.getExtras());
}
});
......@@ -68,8 +69,7 @@ public class GCMListener extends MultiplexingGcmListener.AbstractListener {
protected void onDeletedMessages(int total) {
ThreadUtils.runOnUiThread(new Runnable() {
@Override public void run() {
// TODO(johnme): Get app ID.
GCMDriver.onMessagesDeleted(getApplicationContext(), "unknown-app-id");
GCMDriver.onMessagesDeleted(getApplicationContext(), UNKNOWN_APP_ID);
}
});
}
......
......@@ -15,4 +15,8 @@ void GCMAppHandler::OnConnected(const net::IPEndPoint& ip_endpoint) {
void GCMAppHandler::OnDisconnected() {
}
bool GCMAppHandler::CanHandle(const std::string& app_id) const {
return false;
}
} // namespace gcm
......@@ -45,6 +45,11 @@ class GCMAppHandler {
// Called when the connection is interrupted.
// Default implementation does nothing.
virtual void OnDisconnected();
// If no app handler has been added with the exact app_id of an incoming
// event, all handlers will be asked (in arbitrary order) whether they can
// handle the app_id, and the first to return true will receive the event.
virtual bool CanHandle(const std::string& app_id) const;
};
} // namespace gcm
......
......@@ -148,7 +148,7 @@ void GCMDriver::AddAppHandler(const std::string& app_id,
GCMAppHandler* handler) {
DCHECK(!app_id.empty());
DCHECK(handler);
DCHECK(app_handlers_.find(app_id) == app_handlers_.end());
DCHECK_EQ(app_handlers_.count(app_id), 0u);
app_handlers_[app_id] = handler;
}
......@@ -158,8 +158,18 @@ void GCMDriver::RemoveAppHandler(const std::string& app_id) {
}
GCMAppHandler* GCMDriver::GetAppHandler(const std::string& app_id) {
// Look for exact match.
GCMAppHandlerMap::const_iterator iter = app_handlers_.find(app_id);
return iter == app_handlers_.end() ? &default_app_handler_ : iter->second;
if (iter != app_handlers_.end())
return iter->second;
// Ask the handlers whether they know how to handle it.
for (iter = app_handlers_.begin(); iter != app_handlers_.end(); ++iter) {
if (iter->second->CanHandle(app_id))
return iter->second;
}
return &default_app_handler_;
}
bool GCMDriver::HasRegisterCallback(const std::string& app_id) {
......
......@@ -81,6 +81,9 @@ class GCMDriver {
// Remove the handler for a given app.
virtual void RemoveAppHandler(const std::string& app_id);
// Returns the handler for the given app.
GCMAppHandler* GetAppHandler(const std::string& app_id);
// Enables/disables GCM service.
virtual void Enable() = 0;
virtual void Disable() = 0;
......@@ -141,9 +144,6 @@ class GCMDriver {
void ClearCallbacks();
// Returns the handler for the given app.
GCMAppHandler* GetAppHandler(const std::string& app_id);
private:
// Should be called when an app with |app_id| is trying to un/register.
// Checks whether another un/registration is in progress.
......
......@@ -57,8 +57,8 @@ void PushMessagingMessageFilter::DoRegister(int routing_id,
DidRegister(routing_id, callbacks_id, GURL(), "", false);
return;
}
// TODO(mvanouwerkerk): Pass in app ID based on Service Worker ID.
std::string app_id = "unknown-app-id";
// TODO(mvanouwerkerk): Pass in a real app ID based on Service Worker ID.
std::string app_id = "https://example.com 0";
service_->Register(app_id,
sender_id,
base::Bind(&PushMessagingMessageFilter::DidRegister,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment