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 |
|
---|
39 | namespace WebKit {
|
---|
40 |
|
---|
41 | static inline WebProcessProxy& connectionToWebProcessProxy(const IPC::Connection& connection)
|
---|
42 | {
|
---|
43 | return static_cast<WebProcessProxy&>(connection.client());
|
---|
44 | }
|
---|
45 |
|
---|
46 | const char* WebGeolocationManagerProxy::supplementName()
|
---|
47 | {
|
---|
48 | return "WebGeolocationManagerProxy";
|
---|
49 | }
|
---|
50 |
|
---|
51 | Ref<WebGeolocationManagerProxy> WebGeolocationManagerProxy::create(WebProcessPool* processPool)
|
---|
52 | {
|
---|
53 | return adoptRef(*new WebGeolocationManagerProxy(processPool));
|
---|
54 | }
|
---|
55 |
|
---|
56 | WebGeolocationManagerProxy::WebGeolocationManagerProxy(WebProcessPool* processPool)
|
---|
57 | : WebContextSupplement(processPool)
|
---|
58 | {
|
---|
59 | WebContextSupplement::processPool()->addMessageReceiver(Messages::WebGeolocationManagerProxy::messageReceiverName(), *this);
|
---|
60 | }
|
---|
61 |
|
---|
62 | WebGeolocationManagerProxy::~WebGeolocationManagerProxy() = default;
|
---|
63 |
|
---|
64 | void WebGeolocationManagerProxy::setProvider(std::unique_ptr<API::GeolocationProvider>&& provider)
|
---|
65 | {
|
---|
66 | m_clientProvider = WTFMove(provider);
|
---|
67 | }
|
---|
68 |
|
---|
69 | // WebContextSupplement
|
---|
70 |
|
---|
71 | void 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 |
|
---|
81 | void 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 |
|
---|
92 | void WebGeolocationManagerProxy::refWebContextSupplement()
|
---|
93 | {
|
---|
94 | API::Object::ref();
|
---|
95 | }
|
---|
96 |
|
---|
97 | void WebGeolocationManagerProxy::derefWebContextSupplement()
|
---|
98 | {
|
---|
99 | API::Object::deref();
|
---|
100 | }
|
---|
101 |
|
---|
102 | void 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 |
|
---|
111 | void 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)
|
---|
120 | void 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 |
|
---|
130 | void 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 |
|
---|
135 | void 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 |
|
---|
165 | void WebGeolocationManagerProxy::stopUpdating(IPC::Connection& connection, const WebCore::RegistrableDomain& registrableDomain)
|
---|
166 | {
|
---|
167 | stopUpdatingWithProxy(connectionToWebProcessProxy(connection), registrableDomain);
|
---|
168 | }
|
---|
169 |
|
---|
170 | void 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 |
|
---|
195 | void WebGeolocationManagerProxy::setEnableHighAccuracy(IPC::Connection& connection, const WebCore::RegistrableDomain& registrableDomain, bool enabled)
|
---|
196 | {
|
---|
197 | setEnableHighAccuracyWithProxy(connectionToWebProcessProxy(connection), registrableDomain, enabled);
|
---|
198 | }
|
---|
199 |
|
---|
200 | void 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 |
|
---|
219 | bool 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 |
|
---|
236 | bool 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 |
|
---|
252 | void 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 |
|
---|
271 | void 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 |
|
---|
287 | void 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
|
---|