1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/geofencing/geofencing_manager.h"
9 #include "base/callback.h"
10 #include "content/browser/geofencing/geofencing_service.h"
11 #include "content/browser/service_worker/service_worker_context_wrapper.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "third_party/WebKit/public/platform/WebCircularGeofencingRegion.h"
17 struct GeofencingManager::Registration
{
18 Registration(int64 service_worker_registration_id
,
19 const GURL
& service_worker_origin
,
20 const std::string
& region_id
,
21 const blink::WebCircularGeofencingRegion
& region
,
22 const StatusCallback
& callback
,
23 int64 geofencing_registration_id
);
25 int64 service_worker_registration_id
;
26 GURL service_worker_origin
;
27 std::string region_id
;
28 blink::WebCircularGeofencingRegion region
;
30 // Registration ID as returned by the |GeofencingService|.
31 int64 geofencing_registration_id
;
33 // Callback to call when registration is completed. This field is reset when
34 // registration is complete.
35 StatusCallback registration_callback
;
37 // Returns true if registration has been completed, and thus should be
38 // included in calls to GetRegisteredRegions.
39 bool is_active() const { return registration_callback
.is_null(); }
42 GeofencingManager::Registration::Registration(
43 int64 service_worker_registration_id
,
44 const GURL
& service_worker_origin
,
45 const std::string
& region_id
,
46 const blink::WebCircularGeofencingRegion
& region
,
47 const GeofencingManager::StatusCallback
& callback
,
48 int64 geofencing_registration_id
)
49 : service_worker_registration_id(service_worker_registration_id
),
52 geofencing_registration_id(geofencing_registration_id
),
53 registration_callback(callback
) {
56 GeofencingManager::GeofencingManager(
57 const scoped_refptr
<ServiceWorkerContextWrapper
>& service_worker_context
)
58 : service_(nullptr), service_worker_context_(service_worker_context
) {
59 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
62 GeofencingManager::~GeofencingManager() {
65 void GeofencingManager::Init() {
66 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
67 BrowserThread::PostTask(BrowserThread::IO
,
69 base::Bind(&GeofencingManager::InitOnIO
, this));
72 void GeofencingManager::Shutdown() {
73 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
74 BrowserThread::PostTask(BrowserThread::IO
,
76 base::Bind(&GeofencingManager::ShutdownOnIO
, this));
79 void GeofencingManager::InitOnIO() {
80 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
81 service_
= GeofencingServiceImpl::GetInstance();
84 void GeofencingManager::ShutdownOnIO() {
85 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
86 // Clean up all registrations with the |GeofencingService|.
87 // TODO(mek): This will need to change to support geofence registrations that
88 // outlive the browser, although removing the references to this
89 // |GeofencingManager| from the |GeofencingService| will still be needed.
90 for (const auto& registration
: registrations_by_id_
) {
91 service_
->UnregisterRegion(registration
.first
);
95 void GeofencingManager::RegisterRegion(
96 int64 service_worker_registration_id
,
97 const std::string
& region_id
,
98 const blink::WebCircularGeofencingRegion
& region
,
99 const StatusCallback
& callback
) {
100 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
102 // TODO(mek): Validate region_id and region.
104 // Look up service worker. In unit tests |service_worker_context_| might not
106 GURL service_worker_origin
;
107 if (service_worker_context_
.get()) {
108 ServiceWorkerRegistration
* service_worker_registration
=
109 service_worker_context_
->context()->GetLiveRegistration(
110 service_worker_registration_id
);
111 if (!service_worker_registration
) {
112 callback
.Run(GEOFENCING_STATUS_OPERATION_FAILED_NO_SERVICE_WORKER
);
116 service_worker_origin
= service_worker_registration
->pattern().GetOrigin();
119 if (!service_
->IsServiceAvailable()) {
120 callback
.Run(GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE
);
124 if (FindRegistration(service_worker_registration_id
, region_id
)) {
125 // Already registered, return an error.
126 // TODO(mek): Use a more specific error code.
127 callback
.Run(GEOFENCING_STATUS_ERROR
);
131 AddRegistration(service_worker_registration_id
,
132 service_worker_origin
,
136 service_
->RegisterRegion(region
, this));
139 void GeofencingManager::UnregisterRegion(int64 service_worker_registration_id
,
140 const std::string
& region_id
,
141 const StatusCallback
& callback
) {
142 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
144 // TODO(mek): Validate region_id.
146 // Look up service worker. In unit tests |service_worker_context_| might not
148 if (service_worker_context_
.get()) {
149 ServiceWorkerRegistration
* service_worker_registration
=
150 service_worker_context_
->context()->GetLiveRegistration(
151 service_worker_registration_id
);
152 if (!service_worker_registration
) {
153 callback
.Run(GEOFENCING_STATUS_OPERATION_FAILED_NO_SERVICE_WORKER
);
158 if (!service_
->IsServiceAvailable()) {
159 callback
.Run(GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE
);
163 Registration
* registration
=
164 FindRegistration(service_worker_registration_id
, region_id
);
166 // Not registered, return an error.
167 callback
.Run(GEOFENCING_STATUS_UNREGISTRATION_FAILED_NOT_REGISTERED
);
171 if (!registration
->is_active()) {
172 // Started registration, but not completed yet, error.
173 callback
.Run(GEOFENCING_STATUS_UNREGISTRATION_FAILED_NOT_REGISTERED
);
177 service_
->UnregisterRegion(registration
->geofencing_registration_id
);
178 ClearRegistration(registration
);
179 callback
.Run(GEOFENCING_STATUS_OK
);
182 GeofencingStatus
GeofencingManager::GetRegisteredRegions(
183 int64 service_worker_registration_id
,
184 std::map
<std::string
, blink::WebCircularGeofencingRegion
>* result
) {
185 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
188 // Look up service worker. In unit tests |service_worker_context_| might not
190 if (service_worker_context_
.get()) {
191 ServiceWorkerRegistration
* service_worker_registration
=
192 service_worker_context_
->context()->GetLiveRegistration(
193 service_worker_registration_id
);
194 if (!service_worker_registration
) {
195 return GEOFENCING_STATUS_OPERATION_FAILED_NO_SERVICE_WORKER
;
199 if (!service_
->IsServiceAvailable()) {
200 return GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE
;
203 // Populate result, filtering out inactive registrations.
205 ServiceWorkerRegistrationsMap::iterator registrations
=
206 registrations_
.find(service_worker_registration_id
);
207 if (registrations
== registrations_
.end())
208 return GEOFENCING_STATUS_OK
;
209 for (const auto& registration
: registrations
->second
) {
210 if (registration
.second
.is_active())
211 (*result
)[registration
.first
] = registration
.second
.region
;
213 return GEOFENCING_STATUS_OK
;
216 void GeofencingManager::RegistrationFinished(int64 geofencing_registration_id
,
217 GeofencingStatus status
) {
218 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
219 Registration
* registration
= FindRegistrationById(geofencing_registration_id
);
220 DCHECK(registration
);
221 DCHECK(!registration
->is_active());
222 registration
->registration_callback
.Run(status
);
223 registration
->registration_callback
.Reset();
225 // If the registration wasn't succesful, remove it from our storage.
226 if (status
!= GEOFENCING_STATUS_OK
)
227 ClearRegistration(registration
);
230 GeofencingManager::Registration
* GeofencingManager::FindRegistration(
231 int64 service_worker_registration_id
,
232 const std::string
& region_id
) {
233 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
234 ServiceWorkerRegistrationsMap::iterator registrations_iterator
=
235 registrations_
.find(service_worker_registration_id
);
236 if (registrations_iterator
== registrations_
.end())
238 RegionIdRegistrationMap::iterator registration
=
239 registrations_iterator
->second
.find(region_id
);
240 if (registration
== registrations_iterator
->second
.end())
242 return ®istration
->second
;
245 GeofencingManager::Registration
* GeofencingManager::FindRegistrationById(
246 int64 geofencing_registration_id
) {
247 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
248 RegistrationIdRegistrationMap::iterator registration_iterator
=
249 registrations_by_id_
.find(geofencing_registration_id
);
250 if (registration_iterator
== registrations_by_id_
.end())
252 return ®istration_iterator
->second
->second
;
255 GeofencingManager::Registration
& GeofencingManager::AddRegistration(
256 int64 service_worker_registration_id
,
257 const GURL
& service_worker_origin
,
258 const std::string
& region_id
,
259 const blink::WebCircularGeofencingRegion
& region
,
260 const StatusCallback
& callback
,
261 int64 geofencing_registration_id
) {
262 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
263 DCHECK(!FindRegistration(service_worker_registration_id
, region_id
));
264 RegionIdRegistrationMap::iterator registration
=
265 registrations_
[service_worker_registration_id
]
266 .insert(std::make_pair(region_id
,
267 Registration(service_worker_registration_id
,
268 service_worker_origin
,
272 geofencing_registration_id
)))
274 registrations_by_id_
[geofencing_registration_id
] = registration
;
275 return registration
->second
;
278 void GeofencingManager::ClearRegistration(Registration
* registration
) {
279 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
280 registrations_by_id_
.erase(registration
->geofencing_registration_id
);
281 ServiceWorkerRegistrationsMap::iterator registrations_iterator
=
282 registrations_
.find(registration
->service_worker_registration_id
);
283 DCHECK(registrations_iterator
!= registrations_
.end());
284 registrations_iterator
->second
.erase(registration
->region_id
);
285 if (registrations_iterator
->second
.empty())
286 registrations_
.erase(registrations_iterator
);
289 } // namespace content