cc: Make picture pile base thread safe.
[chromium-blink-merge.git] / content / browser / geofencing / geofencing_manager.cc
blob1147d7d26a5c5a22239556f4e846dee9a34cf4c2
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"
7 #include <algorithm>
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"
15 namespace content {
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),
50 region_id(region_id),
51 region(region),
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,
68 FROM_HERE,
69 base::Bind(&GeofencingManager::InitOnIO, this));
72 void GeofencingManager::Shutdown() {
73 DCHECK_CURRENTLY_ON(BrowserThread::UI);
74 BrowserThread::PostTask(BrowserThread::IO,
75 FROM_HERE,
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
105 // be set.
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);
113 return;
116 service_worker_origin = service_worker_registration->pattern().GetOrigin();
119 if (!service_->IsServiceAvailable()) {
120 callback.Run(GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE);
121 return;
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);
128 return;
131 AddRegistration(service_worker_registration_id,
132 service_worker_origin,
133 region_id,
134 region,
135 callback,
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
147 // be set.
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);
154 return;
158 if (!service_->IsServiceAvailable()) {
159 callback.Run(GEOFENCING_STATUS_OPERATION_FAILED_SERVICE_NOT_AVAILABLE);
160 return;
163 Registration* registration =
164 FindRegistration(service_worker_registration_id, region_id);
165 if (!registration) {
166 // Not registered, return an error.
167 callback.Run(GEOFENCING_STATUS_UNREGISTRATION_FAILED_NOT_REGISTERED);
168 return;
171 if (!registration->is_active()) {
172 // Started registration, but not completed yet, error.
173 callback.Run(GEOFENCING_STATUS_UNREGISTRATION_FAILED_NOT_REGISTERED);
174 return;
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);
186 CHECK(result);
188 // Look up service worker. In unit tests |service_worker_context_| might not
189 // be set.
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.
204 result->clear();
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())
237 return nullptr;
238 RegionIdRegistrationMap::iterator registration =
239 registrations_iterator->second.find(region_id);
240 if (registration == registrations_iterator->second.end())
241 return nullptr;
242 return &registration->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())
251 return nullptr;
252 return &registration_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,
269 region_id,
270 region,
271 callback,
272 geofencing_registration_id)))
273 .first;
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