Chromium side of geofencing event dispatching.
BUG=383125
Review URL: https://codereview.chromium.org/629393002
Cr-Commit-Position: refs/heads/master@{#301965}
diff --git a/content/browser/DEPS b/content/browser/DEPS
index 4c48f63..a0254e3 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -41,6 +41,7 @@
"+third_party/WebKit/public/platform/WebCursorInfo.h",
"+third_party/WebKit/public/platform/WebGamepad.h",
"+third_party/WebKit/public/platform/WebGamepads.h",
+ "+third_party/WebKit/public/platform/WebGeofencingEventType.h",
"+third_party/WebKit/public/platform/WebGraphicsContext3D.h",
"+third_party/WebKit/public/platform/WebIDBDatabaseException.h",
"+third_party/WebKit/public/platform/WebIDBTypes.h",
diff --git a/content/browser/geofencing/geofencing_manager.cc b/content/browser/geofencing/geofencing_manager.cc
index 1147d7d..6899c73 100644
--- a/content/browser/geofencing/geofencing_manager.cc
+++ b/content/browser/geofencing/geofencing_manager.cc
@@ -9,8 +9,12 @@
#include "base/callback.h"
#include "content/browser/geofencing/geofencing_service.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/storage_partition.h"
#include "third_party/WebKit/public/platform/WebCircularGeofencingRegion.h"
+#include "third_party/WebKit/public/platform/WebGeofencingEventType.h"
+#include "url/gurl.h"
namespace content {
@@ -21,7 +25,6 @@
const blink::WebCircularGeofencingRegion& region,
const StatusCallback& callback,
int64 geofencing_registration_id);
-
int64 service_worker_registration_id;
GURL service_worker_origin;
std::string region_id;
@@ -47,6 +50,7 @@
const GeofencingManager::StatusCallback& callback,
int64 geofencing_registration_id)
: service_worker_registration_id(service_worker_registration_id),
+ service_worker_origin(service_worker_origin),
region_id(region_id),
region(region),
geofencing_registration_id(geofencing_registration_id),
@@ -227,6 +231,16 @@
ClearRegistration(registration);
}
+void GeofencingManager::RegionEntered(int64 geofencing_registration_id) {
+ DispatchGeofencingEvent(blink::WebGeofencingEventTypeEnter,
+ geofencing_registration_id);
+}
+
+void GeofencingManager::RegionExited(int64 geofencing_registration_id) {
+ DispatchGeofencingEvent(blink::WebGeofencingEventTypeLeave,
+ geofencing_registration_id);
+}
+
GeofencingManager::Registration* GeofencingManager::FindRegistration(
int64 service_worker_registration_id,
const std::string& region_id) {
@@ -286,4 +300,72 @@
registrations_.erase(registrations_iterator);
}
+void GeofencingManager::DispatchGeofencingEvent(
+ blink::WebGeofencingEventType event_type,
+ int64 geofencing_registration_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ Registration* registration = FindRegistrationById(geofencing_registration_id);
+ if (!registration ||
+ registration->service_worker_registration_id ==
+ kInvalidServiceWorkerRegistrationId) {
+ // TODO(mek): Log/track these failures.
+ return;
+ }
+
+ service_worker_context_->context()->storage()->FindRegistrationForId(
+ registration->service_worker_registration_id,
+ registration->service_worker_origin,
+ base::Bind(&GeofencingManager::DeliverGeofencingEvent,
+ this,
+ event_type,
+ geofencing_registration_id));
+}
+
+void GeofencingManager::DeliverGeofencingEvent(
+ blink::WebGeofencingEventType event_type,
+ int64 geofencing_registration_id,
+ ServiceWorkerStatusCode service_worker_status,
+ const scoped_refptr<ServiceWorkerRegistration>&
+ service_worker_registration) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ Registration* registration = FindRegistrationById(geofencing_registration_id);
+ if (!registration) {
+ // Geofence got unregistered in the meantime, no longer need to deliver
+ // event.
+ return;
+ }
+
+ if (service_worker_status != SERVICE_WORKER_OK) {
+ // TODO(mek): SW no longer exists, somehow handle this.
+ return;
+ }
+
+ ServiceWorkerVersion* active_version =
+ service_worker_registration->active_version();
+ if (!active_version) {
+ // TODO(mek): No active version, potentially because one is still being
+ // installed. Handle this somehow.
+ return;
+ }
+
+ // Hold on to the service worker registration in the callback to keep it alive
+ // until the callback dies. Otherwise the registration could be released when
+ // this method returns - before the event is delivered to the service worker.
+ base::Callback<void(ServiceWorkerStatusCode)> dispatch_event_callback =
+ base::Bind(&GeofencingManager::DeliverGeofencingEventEnd,
+ this,
+ service_worker_registration);
+ active_version->DispatchGeofencingEvent(dispatch_event_callback,
+ event_type,
+ registration->region_id,
+ registration->region);
+}
+
+void GeofencingManager::DeliverGeofencingEventEnd(
+ const scoped_refptr<ServiceWorkerRegistration>& service_worker_registration,
+ ServiceWorkerStatusCode service_worker_status) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ // TODO(mek): log/check result.
+}
+
} // namespace content
diff --git a/content/browser/geofencing/geofencing_manager.h b/content/browser/geofencing/geofencing_manager.h
index 7cd7b17..29c52e4 100644
--- a/content/browser/geofencing/geofencing_manager.h
+++ b/content/browser/geofencing/geofencing_manager.h
@@ -14,8 +14,10 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "content/browser/geofencing/geofencing_registration_delegate.h"
+#include "content/browser/service_worker/service_worker_storage.h"
#include "content/common/content_export.h"
#include "content/common/geofencing_status.h"
+#include "content/common/service_worker/service_worker_status_code.h"
template <typename T>
struct DefaultSingletonTraits;
@@ -29,6 +31,7 @@
class GeofencingService;
class ServiceWorkerContextWrapper;
+class ServiceWorkerRegistration;
// This is the main API to the geofencing subsystem. There is one instance of
// this class per storage partition.
@@ -38,6 +41,8 @@
// This class is created on the UI thread, but all its methods should only be
// called from the IO thread.
// TODO(mek): Implement some kind of persistence of registrations.
+// TODO(mek): Unregister a geofence when the ServiceWorkerRegistration it
+// belongs to goes away.
class CONTENT_EXPORT GeofencingManager
: NON_EXPORTED_BASE(public GeofencingRegistrationDelegate),
public base::RefCountedThreadSafe<GeofencingManager> {
@@ -102,6 +107,8 @@
// GeofencingRegistrationDelegate implementation.
void RegistrationFinished(int64 geofencing_registration_id,
GeofencingStatus status) override;
+ void RegionEntered(int64 geofencing_registration_id) override;
+ void RegionExited(int64 geofencing_registration_id) override;
// Looks up a particular geofence registration. Returns nullptr if no
// registration with the given IDs exists.
@@ -125,6 +132,29 @@
// Clears a registration.
void ClearRegistration(Registration* registration);
+ // Starts dispatching a particular geofencing |event_type| for the geofence
+ // registration with the given ID. This first looks up the Service Worker
+ // Registration the geofence is associated with, and then attempts to deliver
+ // the event to that service worker.
+ void DispatchGeofencingEvent(blink::WebGeofencingEventType event_type,
+ int64 geofencing_registration_id);
+
+ // Delivers an event to the specified service worker for the given geofence.
+ // If the geofence registration id is no longer valid, this method does
+ // nothing. This assumes the |service_worker_registration| is the service
+ // worker the geofence registration is associated with.
+ void DeliverGeofencingEvent(blink::WebGeofencingEventType event_type,
+ int64 geofencing_registration_id,
+ ServiceWorkerStatusCode service_worker_status,
+ const scoped_refptr<ServiceWorkerRegistration>&
+ service_worker_registration);
+
+ // Called when delivery of a geofence event to a service worker has finished
+ // (or failed to finish).
+ void DeliverGeofencingEventEnd(const scoped_refptr<ServiceWorkerRegistration>&
+ service_worker_registration,
+ ServiceWorkerStatusCode service_worker_status);
+
// Map of all registered regions for a particular service worker registration.
typedef std::map<std::string, Registration> RegionIdRegistrationMap;
// Map of service worker registration id to the regions registered by that
diff --git a/content/browser/geofencing/geofencing_registration_delegate.h b/content/browser/geofencing/geofencing_registration_delegate.h
index ba7836c..ead0ec8 100644
--- a/content/browser/geofencing/geofencing_registration_delegate.h
+++ b/content/browser/geofencing/geofencing_registration_delegate.h
@@ -19,6 +19,8 @@
public:
virtual void RegistrationFinished(int64 geofencing_registration_id,
GeofencingStatus status) = 0;
+ virtual void RegionEntered(int64 geofencing_registration_id) = 0;
+ virtual void RegionExited(int64 geofencing_registration_id) = 0;
protected:
virtual ~GeofencingRegistrationDelegate() {}
diff --git a/content/browser/geofencing/geofencing_service_unittest.cc b/content/browser/geofencing/geofencing_service_unittest.cc
index 25dd813..7fbe035 100644
--- a/content/browser/geofencing/geofencing_service_unittest.cc
+++ b/content/browser/geofencing/geofencing_service_unittest.cc
@@ -31,6 +31,8 @@
public:
MOCK_METHOD2(RegistrationFinished,
void(int64 geofencing_registration_id, GeofencingStatus status));
+ MOCK_METHOD1(RegionEntered, void(int64 geofencing_registration_id));
+ MOCK_METHOD1(RegionExited, void(int64 geofencing_registration_id));
};
class MockGeofencingProvider : public GeofencingProvider {
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index 62a6a60..30d9fd5 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -374,6 +374,43 @@
}
}
+void ServiceWorkerVersion::DispatchGeofencingEvent(
+ const StatusCallback& callback,
+ blink::WebGeofencingEventType event_type,
+ const std::string& region_id,
+ const blink::WebCircularGeofencingRegion& region) {
+ DCHECK_EQ(ACTIVATED, status()) << status();
+
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableExperimentalWebPlatformFeatures)) {
+ callback.Run(SERVICE_WORKER_ERROR_ABORT);
+ return;
+ }
+
+ if (running_status() != RUNNING) {
+ // Schedule calling this method after starting the worker.
+ StartWorker(base::Bind(&RunTaskAfterStartWorker,
+ weak_factory_.GetWeakPtr(),
+ callback,
+ base::Bind(&self::DispatchGeofencingEvent,
+ weak_factory_.GetWeakPtr(),
+ callback,
+ event_type,
+ region_id,
+ region)));
+ return;
+ }
+
+ int request_id = geofencing_callbacks_.Add(new StatusCallback(callback));
+ ServiceWorkerStatusCode status =
+ embedded_worker_->SendMessage(ServiceWorkerMsg_GeofencingEvent(
+ request_id, event_type, region_id, region));
+ if (status != SERVICE_WORKER_OK) {
+ geofencing_callbacks_.Remove(request_id);
+ RunSoon(base::Bind(callback, status));
+ }
+}
+
void ServiceWorkerVersion::AddControllee(
ServiceWorkerProviderHost* provider_host) {
DCHECK(!ContainsKey(controllee_map_, provider_host));
@@ -456,6 +493,9 @@
RunIDMapCallbacks(&push_callbacks_,
&StatusCallback::Run,
MakeTuple(SERVICE_WORKER_ERROR_FAILED));
+ RunIDMapCallbacks(&geofencing_callbacks_,
+ &StatusCallback::Run,
+ MakeTuple(SERVICE_WORKER_ERROR_FAILED));
FOR_EACH_OBSERVER(Listener, listeners_, OnWorkerStopped(this));
@@ -507,6 +547,8 @@
OnSyncEventFinished)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PushEventFinished,
OnPushEventFinished)
+ IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_GeofencingEventFinished,
+ OnGeofencingEventFinished)
IPC_MESSAGE_HANDLER(ServiceWorkerHostMsg_PostMessageToDocument,
OnPostMessageToDocument)
IPC_MESSAGE_UNHANDLED(handled = false)
@@ -660,6 +702,22 @@
push_callbacks_.Remove(request_id);
}
+void ServiceWorkerVersion::OnGeofencingEventFinished(int request_id) {
+ TRACE_EVENT1("ServiceWorker",
+ "ServiceWorkerVersion::OnGeofencingEventFinished",
+ "Request id",
+ request_id);
+ StatusCallback* callback = geofencing_callbacks_.Lookup(request_id);
+ if (!callback) {
+ NOTREACHED() << "Got unexpected message: " << request_id;
+ return;
+ }
+
+ scoped_refptr<ServiceWorkerVersion> protect(this);
+ callback->Run(SERVICE_WORKER_OK);
+ geofencing_callbacks_.Remove(request_id);
+}
+
void ServiceWorkerVersion::OnPostMessageToDocument(
int client_id,
const base::string16& message,
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h
index 24dd459..0dcf9a4 100644
--- a/content/browser/service_worker/service_worker_version.h
+++ b/content/browser/service_worker/service_worker_version.h
@@ -23,10 +23,15 @@
#include "content/common/content_export.h"
#include "content/common/service_worker/service_worker_status_code.h"
#include "content/common/service_worker/service_worker_types.h"
+#include "third_party/WebKit/public/platform/WebGeofencingEventType.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerEventResult.h"
class GURL;
+namespace blink {
+struct WebCircularGeofencingRegion;
+}
+
namespace content {
class EmbeddedWorkerRegistry;
@@ -151,7 +156,7 @@
void SendMessage(const IPC::Message& message, const StatusCallback& callback);
// Sends install event to the associated embedded worker and asynchronously
- // calls |callback| when it errors out or it gets response from the worker
+ // calls |callback| when it errors out or it gets a response from the worker
// to notify install completion.
// |active_version_id| must be a valid positive ID
// if there's an activated (previous) version running.
@@ -164,7 +169,7 @@
const StatusCallback& callback);
// Sends activate event to the associated embedded worker and asynchronously
- // calls |callback| when it errors out or it gets response from the worker
+ // calls |callback| when it errors out or it gets a response from the worker
// to notify activation completion.
//
// This must be called when the status() is INSTALLED. Calling this changes
@@ -183,20 +188,31 @@
const FetchCallback& fetch_callback);
// Sends sync event to the associated embedded worker and asynchronously calls
- // |callback| when it errors out or it gets response from the worker to notify
- // completion.
+ // |callback| when it errors out or it gets a response from the worker to
+ // notify completion.
//
// This must be called when the status() is ACTIVATED.
void DispatchSyncEvent(const StatusCallback& callback);
// Sends push event to the associated embedded worker and asynchronously calls
- // |callback| when it errors out or it gets response from the worker to notify
- // completion.
+ // |callback| when it errors out or it gets a response from the worker to
+ // notify completion.
//
// This must be called when the status() is ACTIVATED.
void DispatchPushEvent(const StatusCallback& callback,
const std::string& data);
+ // Sends geofencing event to the associated embedded worker and asynchronously
+ // calls |callback| when it errors out or it gets a response from the worker
+ // to notify completion.
+ //
+ // This must be called when the status() is ACTIVATED.
+ void DispatchGeofencingEvent(
+ const StatusCallback& callback,
+ blink::WebGeofencingEventType event_type,
+ const std::string& region_id,
+ const blink::WebCircularGeofencingRegion& region);
+
// Adds and removes |provider_host| as a controllee of this ServiceWorker.
// A potential controllee is a host having the version as its .installing
// or .waiting version.
@@ -262,6 +278,7 @@
const ServiceWorkerResponse& response);
void OnSyncEventFinished(int request_id);
void OnPushEventFinished(int request_id);
+ void OnGeofencingEventFinished(int request_id);
void OnPostMessageToDocument(int client_id,
const base::string16& message,
const std::vector<int>& sent_message_port_ids);
@@ -286,6 +303,7 @@
IDMap<FetchCallback, IDMapOwnPointer> fetch_callbacks_;
IDMap<StatusCallback, IDMapOwnPointer> sync_callbacks_;
IDMap<StatusCallback, IDMapOwnPointer> push_callbacks_;
+ IDMap<StatusCallback, IDMapOwnPointer> geofencing_callbacks_;
ControlleeMap controllee_map_;
ControlleeByIDMap controllee_by_id_;
diff --git a/content/common/DEPS b/content/common/DEPS
index 46118ac..ddad5b3 100644
--- a/content/common/DEPS
+++ b/content/common/DEPS
@@ -16,6 +16,7 @@
"+third_party/WebKit/public/platform/WebFloatRect.h",
"+third_party/WebKit/public/platform/WebGamepad.h",
"+third_party/WebKit/public/platform/WebGamepads.h",
+ "+third_party/WebKit/public/platform/WebGeofencingEventType.h",
"+third_party/WebKit/public/platform/WebGraphicsContext3D.h",
"+third_party/WebKit/public/platform/WebHTTPBody.h",
"+third_party/WebKit/public/platform/WebIDBCursor.h",
diff --git a/content/common/service_worker/service_worker_messages.h b/content/common/service_worker/service_worker_messages.h
index 4e85ec0f..f645c56 100644
--- a/content/common/service_worker/service_worker_messages.h
+++ b/content/common/service_worker/service_worker_messages.h
@@ -12,6 +12,8 @@
#include "content/common/service_worker/service_worker_types.h"
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_param_traits.h"
+#include "third_party/WebKit/public/platform/WebCircularGeofencingRegion.h"
+#include "third_party/WebKit/public/platform/WebGeofencingEventType.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerCacheError.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerError.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerEventResult.h"
@@ -102,6 +104,9 @@
blink::WebServiceWorkerCacheError,
blink::WebServiceWorkerCacheErrorLast)
+IPC_ENUM_TRAITS_MAX_VALUE(blink::WebGeofencingEventType,
+ blink::WebGeofencingEventTypeLast)
+
//---------------------------------------------------------------------------
// Messages sent from the child process to the browser.
@@ -178,6 +183,8 @@
int /* request_id */)
IPC_MESSAGE_ROUTED1(ServiceWorkerHostMsg_PushEventFinished,
int /* request_id */)
+IPC_MESSAGE_ROUTED1(ServiceWorkerHostMsg_GeofencingEventFinished,
+ int /* request_id */)
// Asks the browser to retrieve documents controlled by the sender
// ServiceWorker.
@@ -348,6 +355,11 @@
IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_PushEvent,
int /* request_id */,
std::string /* data */)
+IPC_MESSAGE_CONTROL4(ServiceWorkerMsg_GeofencingEvent,
+ int /* request_id */,
+ blink::WebGeofencingEventType /* event_type */,
+ std::string /* region_id */,
+ blink::WebCircularGeofencingRegion /* region */)
IPC_MESSAGE_CONTROL3(ServiceWorkerMsg_MessageToWorker,
base::string16 /* message */,
std::vector<int> /* sent_message_port_ids */,
diff --git a/content/renderer/service_worker/service_worker_script_context.cc b/content/renderer/service_worker/service_worker_script_context.cc
index f6b1168..9aa65d5 100644
--- a/content/renderer/service_worker/service_worker_script_context.cc
+++ b/content/renderer/service_worker/service_worker_script_context.cc
@@ -77,6 +77,7 @@
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_InstallEvent, OnInstallEvent)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_SyncEvent, OnSyncEvent)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_PushEvent, OnPushEvent)
+ IPC_MESSAGE_HANDLER(ServiceWorkerMsg_GeofencingEvent, OnGeofencingEvent)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_MessageToWorker, OnPostMessage)
IPC_MESSAGE_HANDLER(ServiceWorkerMsg_DidGetClientDocuments,
OnDidGetClientDocuments)
@@ -225,6 +226,19 @@
GetRoutingID(), request_id));
}
+void ServiceWorkerScriptContext::OnGeofencingEvent(
+ int request_id,
+ blink::WebGeofencingEventType event_type,
+ const std::string& region_id,
+ const blink::WebCircularGeofencingRegion& region) {
+ TRACE_EVENT0("ServiceWorker",
+ "ServiceWorkerScriptContext::OnGeofencingEvent");
+ proxy_->dispatchGeofencingEvent(
+ request_id, event_type, blink::WebString::fromUTF8(region_id), region);
+ Send(new ServiceWorkerHostMsg_GeofencingEventFinished(GetRoutingID(),
+ request_id));
+}
+
void ServiceWorkerScriptContext::OnPostMessage(
const base::string16& message,
const std::vector<int>& sent_message_port_ids,
diff --git a/content/renderer/service_worker/service_worker_script_context.h b/content/renderer/service_worker/service_worker_script_context.h
index 44e80ee..f98250d 100644
--- a/content/renderer/service_worker/service_worker_script_context.h
+++ b/content/renderer/service_worker/service_worker_script_context.h
@@ -17,11 +17,13 @@
#include "content/child/webmessageportchannel_impl.h"
#include "content/common/service_worker/service_worker_types.h"
#include "content/renderer/service_worker/service_worker_cache_storage_dispatcher.h"
+#include "third_party/WebKit/public/platform/WebGeofencingEventType.h"
#include "third_party/WebKit/public/platform/WebMessagePortChannel.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerClientsInfo.h"
#include "third_party/WebKit/public/platform/WebServiceWorkerEventResult.h"
namespace blink {
+struct WebCircularGeofencingRegion;
class WebServiceWorkerContextProxy;
}
@@ -82,6 +84,10 @@
void OnFetchEvent(int request_id, const ServiceWorkerFetchRequest& request);
void OnSyncEvent(int request_id);
void OnPushEvent(int request_id, const std::string& data);
+ void OnGeofencingEvent(int request_id,
+ blink::WebGeofencingEventType event_type,
+ const std::string& region_id,
+ const blink::WebCircularGeofencingRegion& region);
void OnPostMessage(const base::string16& message,
const std::vector<int>& sent_message_port_ids,
const std::vector<int>& new_routing_ids);