source: webkit/trunk/Source/WebKit/UIProcess/WebGeolocationManagerProxy.cpp

Last change on this file was 291496, checked in by Chris Dumez, 3 years ago

Avoid calls to [CLLocationManager authorizationStatus] & [CLLocationManager locationServicesEnabled]
https://bugs.webkit.org/show_bug.cgi?id=237933
<rdar://89931043>

Reviewed by Geoffrey Garen.

Source/WebCore:

Avoid calls to [CLLocationManager authorizationStatus] & [CLLocationManager locationServicesEnabled]
for performance reasons since those are synchronous, potentially slow and called on the UIProcess
main thread.

Instead, rely on the fact that the locationManagerDidChangeAuthorization always gets called
asynchronously right after constructing the CLLocationManager with the actual authorization.
This simplifies our logic a bit too.

We now only call [CLLocationManager requestWhenInUseAuthorization] when locationManagerDidChangeAuthorization
gets called with kCLAuthorizationStatusNotDetermined asynchronously after construction.
If locationManagerDidChangeAuthorization gets called with an authorized enum value, we
call [CLLocationManager startUpdatingLocation] then (if the client is interested in locations, and not
merely in the authorization).

  • platform/cocoa/CoreLocationGeolocationProvider.h:
  • platform/cocoa/CoreLocationGeolocationProvider.mm:

(-[WebCLLocationManager initWithWebsiteIdentifier:client:mode:]):
(-[WebCLLocationManager locationManagerDidChangeAuthorization:]):
(WebCore::CoreLocationGeolocationProvider::CoreLocationGeolocationProvider):
(isAuthorizationGranted): Deleted.
(-[WebCLLocationManager initWithWebsiteIdentifier:client:]): Deleted.
(-[WebCLLocationManager start]): Deleted.
(-[WebCLLocationManager requestGeolocationAuthorization]): Deleted.
(WebCore::CoreLocationGeolocationProvider::start): Deleted.
(WebCore::CoreLocationGeolocationProvider::stop): Deleted.

Source/WebKit:

Minor changes to reflect API changes for our CoreLocation location manager.

  • UIProcess/WebGeolocationManagerProxy.cpp:

(WebKit::WebGeolocationManagerProxy::providerStartUpdating):
(WebKit::WebGeolocationManagerProxy::providerStopUpdating):

  • Property svn:eol-style set to native
File size: 10.7 KB
Line 
1/*
2 * Copyright (C) 2011-2022 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "WebGeolocationManagerProxy.h"
28
29#include "APIGeolocationProvider.h"
30#include "Logging.h"
31#include "WebGeolocationManagerMessages.h"
32#include "WebGeolocationManagerProxyMessages.h"
33#include "WebGeolocationPosition.h"
34#include "WebPageProxy.h"
35#include "WebProcessPool.h"
36
37#define MESSAGE_CHECK(connection, assertion) MESSAGE_CHECK_BASE(assertion, (connection))
38
39namespace WebKit {
40
41static inline WebProcessProxy& connectionToWebProcessProxy(const IPC::Connection& connection)
42{
43 return static_cast<WebProcessProxy&>(connection.client());
44}
45
46const char* WebGeolocationManagerProxy::supplementName()
47{
48 return "WebGeolocationManagerProxy";
49}
50
51Ref<WebGeolocationManagerProxy> WebGeolocationManagerProxy::create(WebProcessPool* processPool)
52{
53 return adoptRef(*new WebGeolocationManagerProxy(processPool));
54}
55
56WebGeolocationManagerProxy::WebGeolocationManagerProxy(WebProcessPool* processPool)
57 : WebContextSupplement(processPool)
58{
59 WebContextSupplement::processPool()->addMessageReceiver(Messages::WebGeolocationManagerProxy::messageReceiverName(), *this);
60}
61
62WebGeolocationManagerProxy::~WebGeolocationManagerProxy() = default;
63
64void WebGeolocationManagerProxy::setProvider(std::unique_ptr<API::GeolocationProvider>&& provider)
65{
66 m_clientProvider = WTFMove(provider);
67}
68
69// WebContextSupplement
70
71void WebGeolocationManagerProxy::processPoolDestroyed()
72{
73 if (m_perDomainData.isEmpty())
74 return;
75
76 m_perDomainData.clear();
77 if (m_clientProvider)
78 m_clientProvider->stopUpdating(*this);
79}
80
81void WebGeolocationManagerProxy::webProcessIsGoingAway(WebProcessProxy& proxy)
82{
83 Vector<WebCore::RegistrableDomain> affectedDomains;
84 for (auto& [registrableDomain, perDomainData] : m_perDomainData) {
85 if (perDomainData->watchers.contains(proxy))
86 affectedDomains.append(registrableDomain);
87 }
88 for (auto& registrableDomain : affectedDomains)
89 stopUpdatingWithProxy(proxy, registrableDomain);
90}
91
92void WebGeolocationManagerProxy::refWebContextSupplement()
93{
94 API::Object::ref();
95}
96
97void WebGeolocationManagerProxy::derefWebContextSupplement()
98{
99 API::Object::deref();
100}
101
102void WebGeolocationManagerProxy::providerDidChangePosition(WebGeolocationPosition* position)
103{
104 for (auto& [registrableDomain, perDomainData] : m_perDomainData) {
105 perDomainData->lastPosition = position->corePosition();
106 for (auto& process : perDomainData->watchers)
107 process.send(Messages::WebGeolocationManager::DidChangePosition(registrableDomain, perDomainData->lastPosition.value()), 0);
108 }
109}
110
111void WebGeolocationManagerProxy::providerDidFailToDeterminePosition(const String& errorMessage)
112{
113 for (auto& [registrableDomain, perDomainData] : m_perDomainData) {
114 for (auto& proxy : perDomainData->watchers)
115 proxy.send(Messages::WebGeolocationManager::DidFailToDeterminePosition(registrableDomain, errorMessage), 0);
116 }
117}
118
119#if PLATFORM(IOS_FAMILY)
120void WebGeolocationManagerProxy::resetPermissions()
121{
122 ASSERT(m_clientProvider);
123 for (auto& [registrableDomain, perDomainData] : m_perDomainData) {
124 for (auto& proxy : perDomainData->watchers)
125 proxy.send(Messages::WebGeolocationManager::ResetPermissions(registrableDomain), 0);
126 }
127}
128#endif
129
130void WebGeolocationManagerProxy::startUpdating(IPC::Connection& connection, const WebCore::RegistrableDomain& registrableDomain, WebPageProxyIdentifier pageProxyID, const String& authorizationToken, bool enableHighAccuracy)
131{
132 startUpdatingWithProxy(connectionToWebProcessProxy(connection), registrableDomain, pageProxyID, authorizationToken, enableHighAccuracy);
133}
134
135void WebGeolocationManagerProxy::startUpdatingWithProxy(WebProcessProxy& proxy, const WebCore::RegistrableDomain& registrableDomain, WebPageProxyIdentifier pageProxyID, const String& authorizationToken, bool enableHighAccuracy)
136{
137 auto* page = WebProcessProxy::webPage(pageProxyID);
138 MESSAGE_CHECK(proxy.connection(), page);
139
140 auto isValidAuthorizationToken = page->geolocationPermissionRequestManager().isValidAuthorizationToken(authorizationToken);
141 MESSAGE_CHECK(proxy.connection(), isValidAuthorizationToken);
142
143 auto& perDomainData = *m_perDomainData.ensure(registrableDomain, [] {
144 return makeUnique<PerDomainData>();
145 }).iterator->value;
146
147 bool wasUpdating = isUpdating(perDomainData);
148 bool highAccuracyWasEnabled = isHighAccuracyEnabled(perDomainData);
149
150 perDomainData.watchers.add(proxy);
151 if (enableHighAccuracy)
152 perDomainData.watchersNeedingHighAccuracy.add(proxy);
153
154 if (!wasUpdating) {
155 providerStartUpdating(perDomainData, registrableDomain);
156 return;
157 }
158 if (!highAccuracyWasEnabled && enableHighAccuracy)
159 providerSetEnabledHighAccuracy(perDomainData, enableHighAccuracy);
160
161 if (perDomainData.lastPosition)
162 proxy.send(Messages::WebGeolocationManager::DidChangePosition(registrableDomain, perDomainData.lastPosition.value()), 0);
163}
164
165void WebGeolocationManagerProxy::stopUpdating(IPC::Connection& connection, const WebCore::RegistrableDomain& registrableDomain)
166{
167 stopUpdatingWithProxy(connectionToWebProcessProxy(connection), registrableDomain);
168}
169
170void WebGeolocationManagerProxy::stopUpdatingWithProxy(WebProcessProxy& proxy, const WebCore::RegistrableDomain& registrableDomain)
171{
172 auto it = m_perDomainData.find(registrableDomain);
173 if (it == m_perDomainData.end())
174 return;
175
176 auto& perDomainData = *it->value;
177 bool wasUpdating = isUpdating(perDomainData);
178 bool highAccuracyWasEnabled = isHighAccuracyEnabled(perDomainData);
179
180 perDomainData.watchers.remove(proxy);
181 perDomainData.watchersNeedingHighAccuracy.remove(proxy);
182
183 if (wasUpdating && !isUpdating(perDomainData))
184 providerStopUpdating(perDomainData);
185 else {
186 bool highAccuracyShouldBeEnabled = isHighAccuracyEnabled(perDomainData);
187 if (highAccuracyShouldBeEnabled != highAccuracyWasEnabled)
188 providerSetEnabledHighAccuracy(perDomainData, highAccuracyShouldBeEnabled);
189 }
190
191 if (perDomainData.watchers.computesEmpty() && perDomainData.watchersNeedingHighAccuracy.computesEmpty())
192 m_perDomainData.remove(it);
193}
194
195void WebGeolocationManagerProxy::setEnableHighAccuracy(IPC::Connection& connection, const WebCore::RegistrableDomain& registrableDomain, bool enabled)
196{
197 setEnableHighAccuracyWithProxy(connectionToWebProcessProxy(connection), registrableDomain, enabled);
198}
199
200void WebGeolocationManagerProxy::setEnableHighAccuracyWithProxy(WebProcessProxy& proxy, const WebCore::RegistrableDomain& registrableDomain, bool enabled)
201{
202 auto it = m_perDomainData.find(registrableDomain);
203 ASSERT(it != m_perDomainData.end());
204 if (it == m_perDomainData.end())
205 return;
206
207 auto& perDomainData = *it->value;
208 bool highAccuracyWasEnabled = isHighAccuracyEnabled(perDomainData);
209
210 if (enabled)
211 perDomainData.watchersNeedingHighAccuracy.add(proxy);
212 else
213 perDomainData.watchersNeedingHighAccuracy.remove(proxy);
214
215 if (isUpdating(perDomainData) && highAccuracyWasEnabled != enabled)
216 providerSetEnabledHighAccuracy(perDomainData, enabled);
217}
218
219bool WebGeolocationManagerProxy::isUpdating(const PerDomainData& perDomainData) const
220{
221#if PLATFORM(IOS_FAMILY)
222 if (!m_clientProvider)
223 return !perDomainData.watchers.computesEmpty();
224#else
225 UNUSED_PARAM(perDomainData);
226#endif
227
228 for (auto& perDomainData : m_perDomainData.values()) {
229 if (!perDomainData->watchers.computesEmpty())
230 return true;
231 }
232 return false;
233}
234
235
236bool WebGeolocationManagerProxy::isHighAccuracyEnabled(const PerDomainData& perDomainData) const
237{
238#if PLATFORM(IOS_FAMILY)
239 if (!m_clientProvider)
240 return !perDomainData.watchersNeedingHighAccuracy.computesEmpty();
241#else
242 UNUSED_PARAM(perDomainData);
243#endif
244
245 for (auto& data : m_perDomainData.values()) {
246 if (!data->watchersNeedingHighAccuracy.computesEmpty())
247 return true;
248 }
249 return false;
250}
251
252void WebGeolocationManagerProxy::providerStartUpdating(PerDomainData& perDomainData, const WebCore::RegistrableDomain& registrableDomain)
253{
254#if PLATFORM(IOS_FAMILY)
255 if (!m_clientProvider) {
256 ASSERT(!perDomainData.provider);
257 perDomainData.provider = makeUnique<WebCore::CoreLocationGeolocationProvider>(registrableDomain, *this);
258 perDomainData.provider->setEnableHighAccuracy(!perDomainData.watchersNeedingHighAccuracy.computesEmpty());
259 return;
260 }
261#else
262 UNUSED_PARAM(registrableDomain);
263 if (!m_clientProvider)
264 return;
265#endif
266
267 m_clientProvider->setEnableHighAccuracy(*this, isHighAccuracyEnabled(perDomainData));
268 m_clientProvider->startUpdating(*this);
269}
270
271void WebGeolocationManagerProxy::providerStopUpdating(PerDomainData& perDomainData)
272{
273#if PLATFORM(IOS_FAMILY)
274 if (!m_clientProvider) {
275 perDomainData.provider = nullptr;
276 return;
277 }
278#else
279 UNUSED_PARAM(perDomainData);
280 if (!m_clientProvider)
281 return;
282#endif
283
284 m_clientProvider->stopUpdating(*this);
285}
286
287void WebGeolocationManagerProxy::providerSetEnabledHighAccuracy(PerDomainData& perDomainData, bool enabled)
288{
289#if PLATFORM(IOS_FAMILY)
290 if (!m_clientProvider) {
291 perDomainData.provider->setEnableHighAccuracy(enabled);
292 return;
293 }
294#else
295 UNUSED_PARAM(perDomainData);
296 if (!m_clientProvider)
297 return;
298#endif
299
300 m_clientProvider->setEnableHighAccuracy(*this, enabled);
301}
302
303} // namespace WebKit
304
305#undef MESSAGE_CHECK
Note: See TracBrowser for help on using the repository browser.