summaryrefslogtreecommitdiffstats
path: root/dom/system/windows/location
diff options
context:
space:
mode:
Diffstat (limited to 'dom/system/windows/location')
-rw-r--r--dom/system/windows/location/PWindowsLocation.ipdl38
-rw-r--r--dom/system/windows/location/WindowsLocationChild.cpp257
-rw-r--r--dom/system/windows/location/WindowsLocationChild.h44
-rw-r--r--dom/system/windows/location/WindowsLocationParent.cpp36
-rw-r--r--dom/system/windows/location/WindowsLocationParent.h52
-rw-r--r--dom/system/windows/location/WindowsLocationProvider.cpp350
-rw-r--r--dom/system/windows/location/WindowsLocationProvider.h78
-rw-r--r--dom/system/windows/location/moz.build29
8 files changed, 884 insertions, 0 deletions
diff --git a/dom/system/windows/location/PWindowsLocation.ipdl b/dom/system/windows/location/PWindowsLocation.ipdl
new file mode 100644
index 0000000000..db53b5c805
--- /dev/null
+++ b/dom/system/windows/location/PWindowsLocation.ipdl
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et ft=cpp : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+include protocol PWindowsUtils;
+
+[RefCounted] using class nsIDOMGeoPosition from "nsGeoPositionIPCSerialiser.h";
+
+namespace mozilla {
+namespace dom {
+
+// Proxies geolocation functions to a utility process so that we
+// can safely handle crashes in the ILocation API. Messages to the child
+// are proxies for the ILocation COM object. Messages to the parent
+// are proxied nsIGeolocationUpdate callbacks.
+protocol PWindowsLocation {
+ manager PWindowsUtils;
+
+child:
+ async Startup();
+ async RegisterForReport();
+ async UnregisterForReport();
+ async SetHighAccuracy(bool aEnable);
+
+ async __delete__();
+
+parent:
+ // Update geolocation with new position information.
+ async Update(nullable nsIDOMGeoPosition aPosition);
+
+ // The geolocation API has reported an error.
+ async Failed(uint16_t aError);
+};
+
+} // namespace dom
+} // namespace mozilla
diff --git a/dom/system/windows/location/WindowsLocationChild.cpp b/dom/system/windows/location/WindowsLocationChild.cpp
new file mode 100644
index 0000000000..514ae4610f
--- /dev/null
+++ b/dom/system/windows/location/WindowsLocationChild.cpp
@@ -0,0 +1,257 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "WindowsLocationChild.h"
+#include "nsCOMPtr.h"
+#include "WindowsLocationProvider.h"
+#include "mozilla/dom/GeolocationPosition.h"
+#include "mozilla/dom/GeolocationPositionErrorBinding.h"
+#include "mozilla/Telemetry.h"
+#include "nsIGeolocationProvider.h"
+
+#include <locationapi.h>
+
+namespace mozilla::dom {
+
+extern LazyLogModule gWindowsLocationProviderLog;
+#define LOG(...) \
+ MOZ_LOG(gWindowsLocationProviderLog, LogLevel::Debug, (__VA_ARGS__))
+
+class LocationEvent final : public ILocationEvents {
+ public:
+ explicit LocationEvent(WindowsLocationChild* aActor)
+ : mActor(aActor), mRefCnt(0) {}
+
+ // IUnknown interface
+ STDMETHODIMP_(ULONG) AddRef() override;
+ STDMETHODIMP_(ULONG) Release() override;
+ STDMETHODIMP QueryInterface(REFIID iid, void** ppv) override;
+
+ // ILocationEvents interface
+ STDMETHODIMP OnStatusChanged(REFIID aReportType,
+ LOCATION_REPORT_STATUS aStatus) override;
+ STDMETHODIMP OnLocationChanged(REFIID aReportType,
+ ILocationReport* aReport) override;
+
+ private:
+ // Making this a WeakPtr breaks the following cycle of strong references:
+ // WindowsLocationChild -> ILocation -> ILocationEvents (this)
+ // -> WindowsLocationChild.
+ WeakPtr<WindowsLocationChild> mActor;
+
+ ULONG mRefCnt;
+};
+
+STDMETHODIMP_(ULONG)
+LocationEvent::AddRef() { return InterlockedIncrement(&mRefCnt); }
+
+STDMETHODIMP_(ULONG)
+LocationEvent::Release() {
+ ULONG count = InterlockedDecrement(&mRefCnt);
+ if (!count) {
+ delete this;
+ return 0;
+ }
+ return count;
+}
+
+STDMETHODIMP
+LocationEvent::QueryInterface(REFIID iid, void** ppv) {
+ if (!ppv) {
+ return E_INVALIDARG;
+ }
+
+ if (iid == IID_IUnknown) {
+ *ppv = static_cast<IUnknown*>(this);
+ } else if (iid == IID_ILocationEvents) {
+ *ppv = static_cast<ILocationEvents*>(this);
+ } else {
+ *ppv = nullptr;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+STDMETHODIMP
+LocationEvent::OnStatusChanged(REFIID aReportType,
+ LOCATION_REPORT_STATUS aStatus) {
+ LOG("LocationEvent::OnStatusChanged(%p, %p, %s, %04x)", this, mActor.get(),
+ aReportType == IID_ILatLongReport ? "true" : "false",
+ static_cast<uint32_t>(aStatus));
+
+ if (!mActor || aReportType != IID_ILatLongReport) {
+ return S_OK;
+ }
+
+ // When registering event, REPORT_INITIALIZING is fired at first.
+ // Then, when the location is found, REPORT_RUNNING is fired.
+ // We ignore those messages.
+ uint16_t err;
+ switch (aStatus) {
+ case REPORT_ACCESS_DENIED:
+ err = GeolocationPositionError_Binding::PERMISSION_DENIED;
+ break;
+ case REPORT_NOT_SUPPORTED:
+ case REPORT_ERROR:
+ err = GeolocationPositionError_Binding::POSITION_UNAVAILABLE;
+ break;
+ default:
+ return S_OK;
+ }
+
+ mActor->SendFailed(err);
+ return S_OK;
+}
+
+STDMETHODIMP
+LocationEvent::OnLocationChanged(REFIID aReportType, ILocationReport* aReport) {
+ LOG("LocationEvent::OnLocationChanged(%p, %p, %s)", this, mActor.get(),
+ aReportType == IID_ILatLongReport ? "true" : "false");
+
+ if (!mActor || aReportType != IID_ILatLongReport) {
+ return S_OK;
+ }
+
+ RefPtr<ILatLongReport> latLongReport;
+ if (FAILED(aReport->QueryInterface(IID_ILatLongReport,
+ getter_AddRefs(latLongReport)))) {
+ return E_FAIL;
+ }
+
+ DOUBLE latitude = 0.0;
+ latLongReport->GetLatitude(&latitude);
+
+ DOUBLE longitude = 0.0;
+ latLongReport->GetLongitude(&longitude);
+
+ DOUBLE alt = UnspecifiedNaN<double>();
+ latLongReport->GetAltitude(&alt);
+
+ DOUBLE herror = 0.0;
+ latLongReport->GetErrorRadius(&herror);
+
+ DOUBLE verror = UnspecifiedNaN<double>();
+ latLongReport->GetAltitudeError(&verror);
+
+ double heading = UnspecifiedNaN<double>();
+ double speed = UnspecifiedNaN<double>();
+
+ // nsGeoPositionCoords will convert NaNs to null for optional properties of
+ // the JavaScript Coordinates object.
+ RefPtr<nsGeoPosition> position =
+ new nsGeoPosition(latitude, longitude, alt, herror, verror, heading,
+ speed, PR_Now() / PR_USEC_PER_MSEC);
+ mActor->SendUpdate(position);
+
+ return S_OK;
+}
+
+WindowsLocationChild::WindowsLocationChild() {
+ LOG("WindowsLocationChild::WindowsLocationChild(%p)", this);
+}
+
+WindowsLocationChild::~WindowsLocationChild() {
+ LOG("WindowsLocationChild::~WindowsLocationChild(%p)", this);
+}
+
+::mozilla::ipc::IPCResult WindowsLocationChild::RecvStartup() {
+ LOG("WindowsLocationChild::RecvStartup(%p, %p)", this, mLocation.get());
+ if (mLocation) {
+ return IPC_OK();
+ }
+
+ RefPtr<ILocation> location;
+ if (FAILED(::CoCreateInstance(CLSID_Location, nullptr, CLSCTX_INPROC_SERVER,
+ IID_ILocation, getter_AddRefs(location)))) {
+ LOG("WindowsLocationChild(%p) failed to create ILocation", this);
+ // We will use MLS provider
+ SendFailed(GeolocationPositionError_Binding::POSITION_UNAVAILABLE);
+ return IPC_OK();
+ }
+
+ IID reportTypes[] = {IID_ILatLongReport};
+ if (FAILED(location->RequestPermissions(nullptr, reportTypes, 1, FALSE))) {
+ LOG("WindowsLocationChild(%p) failed to set ILocation permissions", this);
+ // We will use MLS provider
+ SendFailed(GeolocationPositionError_Binding::POSITION_UNAVAILABLE);
+ return IPC_OK();
+ }
+
+ mLocation = location;
+ return IPC_OK();
+}
+
+::mozilla::ipc::IPCResult WindowsLocationChild::RecvSetHighAccuracy(
+ bool aEnable) {
+ LOG("WindowsLocationChild::RecvSetHighAccuracy(%p, %p, %s)", this,
+ mLocation.get(), aEnable ? "true" : "false");
+
+ // We sometimes call SetHighAccuracy before Startup, so we save the
+ // request and set it later, in RegisterForReport.
+ mHighAccuracy = aEnable;
+
+ return IPC_OK();
+}
+
+::mozilla::ipc::IPCResult WindowsLocationChild::RecvRegisterForReport() {
+ LOG("WindowsLocationChild::RecvRegisterForReport(%p, %p)", this,
+ mLocation.get());
+
+ if (!mLocation) {
+ SendFailed(GeolocationPositionError_Binding::POSITION_UNAVAILABLE);
+ return IPC_OK();
+ }
+
+ LOCATION_DESIRED_ACCURACY desiredAccuracy;
+ if (mHighAccuracy) {
+ desiredAccuracy = LOCATION_DESIRED_ACCURACY_HIGH;
+ } else {
+ desiredAccuracy = LOCATION_DESIRED_ACCURACY_DEFAULT;
+ }
+
+ if (NS_WARN_IF(FAILED(mLocation->SetDesiredAccuracy(IID_ILatLongReport,
+ desiredAccuracy)))) {
+ SendFailed(GeolocationPositionError_Binding::POSITION_UNAVAILABLE);
+ return IPC_OK();
+ }
+
+ auto event = MakeRefPtr<LocationEvent>(this);
+ if (NS_WARN_IF(
+ FAILED(mLocation->RegisterForReport(event, IID_ILatLongReport, 0)))) {
+ SendFailed(GeolocationPositionError_Binding::POSITION_UNAVAILABLE);
+ }
+
+ LOG("WindowsLocationChild::RecvRegisterForReport successfully registered");
+ return IPC_OK();
+}
+
+::mozilla::ipc::IPCResult WindowsLocationChild::RecvUnregisterForReport() {
+ LOG("WindowsLocationChild::RecvUnregisterForReport(%p, %p)", this,
+ mLocation.get());
+
+ if (!mLocation) {
+ return IPC_OK();
+ }
+
+ // This will free the LocationEvent we created in RecvRegisterForReport.
+ Unused << NS_WARN_IF(
+ FAILED(mLocation->UnregisterForReport(IID_ILatLongReport)));
+
+ // The ILocation object is not reusable. Unregistering, restarting and
+ // re-registering for reports does not work; the callback is never
+ // called in that case. For that reason, we re-create the ILocation
+ // object with a call to Startup after unregistering if we need it again.
+ mLocation = nullptr;
+ return IPC_OK();
+}
+
+void WindowsLocationChild::ActorDestroy(ActorDestroyReason aWhy) {
+ LOG("WindowsLocationChild::ActorDestroy(%p, %p)", this, mLocation.get());
+ mLocation = nullptr;
+}
+
+} // namespace mozilla::dom
diff --git a/dom/system/windows/location/WindowsLocationChild.h b/dom/system/windows/location/WindowsLocationChild.h
new file mode 100644
index 0000000000..ac51cff213
--- /dev/null
+++ b/dom/system/windows/location/WindowsLocationChild.h
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_WindowsLocationChild_h__
+#define mozilla_dom_WindowsLocationChild_h__
+
+#include "mozilla/dom/PWindowsLocationChild.h"
+#include "mozilla/WeakPtr.h"
+
+class ILocation;
+
+namespace mozilla::dom {
+
+// Geolocation actor in utility process.
+class WindowsLocationChild final : public PWindowsLocationChild,
+ public SupportsWeakPtr {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WindowsLocationChild, override);
+
+ public:
+ WindowsLocationChild();
+
+ using IPCResult = ::mozilla::ipc::IPCResult;
+
+ IPCResult RecvStartup();
+ IPCResult RecvRegisterForReport();
+ IPCResult RecvUnregisterForReport();
+ IPCResult RecvSetHighAccuracy(bool aEnable);
+ void ActorDestroy(ActorDestroyReason aWhy) override;
+
+ private:
+ ~WindowsLocationChild() override;
+
+ // The COM object the actors are proxying calls for.
+ RefPtr<ILocation> mLocation;
+
+ bool mHighAccuracy = false;
+};
+
+} // namespace mozilla::dom
+
+#endif // mozilla_dom_WindowsLocationChild_h__
diff --git a/dom/system/windows/location/WindowsLocationParent.cpp b/dom/system/windows/location/WindowsLocationParent.cpp
new file mode 100644
index 0000000000..f19bcb8b0d
--- /dev/null
+++ b/dom/system/windows/location/WindowsLocationParent.cpp
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "WindowsLocationParent.h"
+#include "nsIDOMGeoPosition.h"
+#include "WindowsLocationProvider.h"
+
+namespace mozilla::dom {
+
+::mozilla::ipc::IPCResult WindowsLocationParent::RecvUpdate(
+ RefPtr<nsIDOMGeoPosition> aGeoPosition) {
+ if (mProvider) {
+ mProvider->RecvUpdate(aGeoPosition);
+ }
+ return IPC_OK();
+}
+
+// A failure occurred. This may be translated into a
+// nsIGeolocationUpdate::NotifyError or may be ignored if the MLS fallback
+// is available.
+::mozilla::ipc::IPCResult WindowsLocationParent::RecvFailed(uint16_t err) {
+ if (mProvider) {
+ mProvider->RecvFailed(err);
+ }
+ return IPC_OK();
+}
+
+void WindowsLocationParent::ActorDestroy(ActorDestroyReason aReason) {
+ if (mProvider) {
+ mProvider->ActorStopped();
+ }
+}
+
+} // namespace mozilla::dom
diff --git a/dom/system/windows/location/WindowsLocationParent.h b/dom/system/windows/location/WindowsLocationParent.h
new file mode 100644
index 0000000000..01538246ea
--- /dev/null
+++ b/dom/system/windows/location/WindowsLocationParent.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_WindowsLocationParent_h__
+#define mozilla_dom_WindowsLocationParent_h__
+
+#include "nsCOMPtr.h"
+#include "mozilla/dom/PWindowsLocationParent.h"
+
+class nsGeoPosition;
+class nsIGeolocationUpdate;
+
+namespace mozilla::dom {
+
+class WindowsLocationProvider;
+
+// Geolocation actor in main process.
+// This may receive messages asynchronously, even after it sends Unregister
+// to the child.
+class WindowsLocationParent final : public PWindowsLocationParent {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WindowsLocationParent, override);
+
+ using IPCResult = ::mozilla::ipc::IPCResult;
+
+ explicit WindowsLocationParent(WindowsLocationProvider* aProvider)
+ : mProvider(aProvider) {}
+
+ // Update geolocation with new position information.
+ IPCResult RecvUpdate(RefPtr<nsIDOMGeoPosition> aGeoPosition);
+
+ // A failure occurred. This may be translated into a
+ // nsIGeolocationUpdate::NotifyError or may be ignored if the MLS fallback
+ // is available.
+ IPCResult RecvFailed(uint16_t err);
+
+ void ActorDestroy(ActorDestroyReason aReason) override;
+
+ // After this, the actor will simply ignore any incoming messages.
+ void DetachFromLocationProvider() { mProvider = nullptr; }
+
+ private:
+ ~WindowsLocationParent() override = default;
+
+ WindowsLocationProvider* mProvider;
+};
+
+} // namespace mozilla::dom
+
+#endif // mozilla_dom_WindowsLocationParent_h__
diff --git a/dom/system/windows/location/WindowsLocationProvider.cpp b/dom/system/windows/location/WindowsLocationProvider.cpp
new file mode 100644
index 0000000000..92a6f2c9cc
--- /dev/null
+++ b/dom/system/windows/location/WindowsLocationProvider.cpp
@@ -0,0 +1,350 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WindowsLocationProvider.h"
+#include "WindowsLocationParent.h"
+#include "mozilla/dom/WindowsUtilsParent.h"
+#include "GeolocationPosition.h"
+#include "nsComponentManagerUtils.h"
+#include "mozilla/ipc/UtilityProcessManager.h"
+#include "mozilla/ipc/UtilityProcessSandboxing.h"
+#include "prtime.h"
+#include "MLSFallback.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/Logging.h"
+#include "mozilla/FloatingPoint.h"
+#include "mozilla/Telemetry.h"
+#include "mozilla/dom/GeolocationPositionErrorBinding.h"
+
+namespace mozilla::dom {
+
+LazyLogModule gWindowsLocationProviderLog("WindowsLocationProvider");
+#define LOG(...) \
+ MOZ_LOG(gWindowsLocationProviderLog, LogLevel::Debug, (__VA_ARGS__))
+
+class MLSUpdate : public nsIGeolocationUpdate {
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIGEOLOCATIONUPDATE
+ explicit MLSUpdate(nsIGeolocationUpdate* aCallback) : mCallback(aCallback) {}
+
+ private:
+ nsCOMPtr<nsIGeolocationUpdate> mCallback;
+ virtual ~MLSUpdate() {}
+};
+
+NS_IMPL_ISUPPORTS(MLSUpdate, nsIGeolocationUpdate);
+
+NS_IMETHODIMP
+MLSUpdate::Update(nsIDOMGeoPosition* aPosition) {
+ if (!mCallback) {
+ return NS_ERROR_FAILURE;
+ }
+
+ nsCOMPtr<nsIDOMGeoPositionCoords> coords;
+ aPosition->GetCoords(getter_AddRefs(coords));
+ if (!coords) {
+ return NS_ERROR_FAILURE;
+ }
+ Telemetry::Accumulate(Telemetry::GEOLOCATION_WIN8_SOURCE_IS_MLS, true);
+ return mCallback->Update(aPosition);
+}
+NS_IMETHODIMP
+MLSUpdate::NotifyError(uint16_t aError) {
+ if (!mCallback) {
+ return NS_ERROR_FAILURE;
+ }
+ nsCOMPtr<nsIGeolocationUpdate> callback(mCallback);
+ return callback->NotifyError(aError);
+}
+
+NS_IMPL_ISUPPORTS(WindowsLocationProvider, nsIGeolocationProvider)
+
+WindowsLocationProvider::WindowsLocationProvider() {
+ LOG("WindowsLocationProvider::WindowsLocationProvider(%p)", this);
+ MOZ_ASSERT(XRE_IsParentProcess());
+ MaybeCreateLocationActor();
+}
+
+WindowsLocationProvider::~WindowsLocationProvider() {
+ LOG("WindowsLocationProvider::~WindowsLocationProvider(%p,%p,%p)", this,
+ mActor.get(), mActorPromise.get());
+ Send__delete__();
+ ReleaseUtilityProcess();
+ CancelMLSProvider();
+}
+
+void WindowsLocationProvider::MaybeCreateLocationActor() {
+ LOG("WindowsLocationProvider::MaybeCreateLocationActor(%p)", this);
+ if (mActor || mActorPromise) {
+ return;
+ }
+
+ auto utilityProc = mozilla::ipc::UtilityProcessManager::GetSingleton();
+ MOZ_ASSERT(utilityProc);
+
+ // Create a PWindowsLocation actor in the Windows utility process.
+ // This will attempt to launch the process if it doesn't already exist.
+ RefPtr<WindowsLocationProvider> self = this;
+ auto wuPromise = utilityProc->GetWindowsUtilsPromise();
+ mActorPromise = wuPromise->Then(
+ GetCurrentSerialEventTarget(), __func__,
+ [self](RefPtr<WindowsUtilsParent> wup) {
+ self->mActorPromise = nullptr;
+ auto actor = MakeRefPtr<WindowsLocationParent>(self);
+ if (!wup->SendPWindowsLocationConstructor(actor)) {
+ LOG("WindowsLocationProvider(%p) SendPWindowsLocationConstructor "
+ "failed",
+ self.get());
+ actor->DetachFromLocationProvider();
+ self->mActor = nullptr;
+ return WindowsLocationPromise::CreateAndReject(false, __func__);
+ }
+ LOG("WindowsLocationProvider connected to actor (%p,%p,%p)", self.get(),
+ self->mActor.get(), self->mActorPromise.get());
+ self->mActor = actor;
+ return WindowsLocationPromise::CreateAndResolve(self->mActor, __func__);
+ },
+
+ [self](nsresult aError) {
+ LOG("WindowsLocationProvider failed to connect to actor (%p,%p,%p)",
+ self.get(), self->mActor.get(), self->mActorPromise.get());
+ self->mActorPromise = nullptr;
+ return WindowsLocationPromise::CreateAndReject(false, __func__);
+ });
+
+ if (mActor) {
+ // Utility process already existed and mActorPromise was resolved
+ // immediately.
+ mActorPromise = nullptr;
+ }
+}
+
+void WindowsLocationProvider::ReleaseUtilityProcess() {
+ LOG("WindowsLocationProvider::ReleaseUtilityProcess(%p)", this);
+ auto utilityProc = mozilla::ipc::UtilityProcessManager::GetIfExists();
+ if (utilityProc) {
+ utilityProc->ReleaseWindowsUtils();
+ }
+}
+
+template <typename Fn>
+bool WindowsLocationProvider::WhenActorIsReady(Fn&& fn) {
+ if (mActor) {
+ return fn(mActor);
+ }
+
+ if (mActorPromise) {
+ mActorPromise->Then(
+ GetCurrentSerialEventTarget(), __func__,
+ [fn](const RefPtr<WindowsLocationParent>& actor) {
+ Unused << fn(actor.get());
+ return actor;
+ },
+ [](bool) { return false; });
+ return true;
+ }
+
+ // The remote process failed to start.
+ return false;
+}
+
+bool WindowsLocationProvider::SendStartup() {
+ LOG("WindowsLocationProvider::SendStartup(%p)", this);
+ MaybeCreateLocationActor();
+ return WhenActorIsReady(
+ [](WindowsLocationParent* actor) { return actor->SendStartup(); });
+}
+
+bool WindowsLocationProvider::SendRegisterForReport(
+ nsIGeolocationUpdate* aCallback) {
+ LOG("WindowsLocationProvider::SendRegisterForReport(%p)", this);
+ RefPtr<WindowsLocationProvider> self = this;
+ RefPtr<nsIGeolocationUpdate> cb = aCallback;
+ return WhenActorIsReady([self, cb](WindowsLocationParent* actor) {
+ MOZ_ASSERT(!self->mCallback);
+ if (actor->SendRegisterForReport()) {
+ self->mCallback = cb;
+ return true;
+ }
+ return false;
+ });
+}
+
+bool WindowsLocationProvider::SendUnregisterForReport() {
+ LOG("WindowsLocationProvider::SendUnregisterForReport(%p)", this);
+ RefPtr<WindowsLocationProvider> self = this;
+ return WhenActorIsReady([self](WindowsLocationParent* actor) {
+ self->mCallback = nullptr;
+ if (actor->SendUnregisterForReport()) {
+ return true;
+ }
+ return false;
+ });
+}
+
+bool WindowsLocationProvider::SendSetHighAccuracy(bool aEnable) {
+ LOG("WindowsLocationProvider::SendSetHighAccuracy(%p)", this);
+ return WhenActorIsReady([aEnable](WindowsLocationParent* actor) {
+ return actor->SendSetHighAccuracy(aEnable);
+ });
+}
+
+bool WindowsLocationProvider::Send__delete__() {
+ LOG("WindowsLocationProvider::Send__delete__(%p)", this);
+ return WhenActorIsReady([self = RefPtr{this}](WindowsLocationParent*) {
+ if (WindowsLocationParent::Send__delete__(self->mActor)) {
+ if (self->mActor) {
+ self->mActor->DetachFromLocationProvider();
+ self->mActor = nullptr;
+ }
+ return true;
+ }
+ return false;
+ });
+}
+
+void WindowsLocationProvider::RecvUpdate(
+ RefPtr<nsIDOMGeoPosition> aGeoPosition) {
+ LOG("WindowsLocationProvider::RecvUpdate(%p)", this);
+ if (!mCallback) {
+ return;
+ }
+
+ mCallback->Update(aGeoPosition.get());
+
+ Telemetry::Accumulate(Telemetry::GEOLOCATION_WIN8_SOURCE_IS_MLS, false);
+}
+
+void WindowsLocationProvider::RecvFailed(uint16_t err) {
+ LOG("WindowsLocationProvider::RecvFailed(%p)", this);
+ // Cannot get current location at this time. We use MLS instead.
+ if (mMLSProvider || !mCallback) {
+ return;
+ }
+
+ if (NS_SUCCEEDED(CreateAndWatchMLSProvider(mCallback))) {
+ return;
+ }
+
+ // No ILocation and no MLS, so we have failed completely.
+ // We keep strong references to objects that we need to guarantee
+ // will live past the NotifyError callback.
+ RefPtr<WindowsLocationProvider> self = this;
+ nsCOMPtr<nsIGeolocationUpdate> callback = mCallback;
+ callback->NotifyError(err);
+}
+
+void WindowsLocationProvider::ActorStopped() {
+ // ActorDestroy has run. Make sure UtilityProcessHost no longer tries to use
+ // it.
+ ReleaseUtilityProcess();
+
+ if (mWatching) {
+ // Treat as remote geolocation error, which will cause it to fallback
+ // to MLS if it hasn't already.
+ mWatching = false;
+ RecvFailed(GeolocationPositionError_Binding::POSITION_UNAVAILABLE);
+ return;
+ }
+
+ MOZ_ASSERT(!mActorPromise);
+ if (mActor) {
+ mActor->DetachFromLocationProvider();
+ mActor = nullptr;
+ }
+}
+
+NS_IMETHODIMP
+WindowsLocationProvider::Startup() {
+ LOG("WindowsLocationProvider::Startup(%p, %p, %p)", this, mActor.get(),
+ mActorPromise.get());
+ // If this fails, we will use the MLS fallback.
+ SendStartup();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+WindowsLocationProvider::Watch(nsIGeolocationUpdate* aCallback) {
+ LOG("WindowsLocationProvider::Watch(%p, %p, %p, %p, %d)", this, mActor.get(),
+ mActorPromise.get(), aCallback, mWatching);
+ if (mWatching) {
+ return NS_OK;
+ }
+
+ if (SendRegisterForReport(aCallback)) {
+ mWatching = true;
+ return NS_OK;
+ }
+
+ // Couldn't send request. We will use MLS instead.
+ return CreateAndWatchMLSProvider(aCallback);
+}
+
+NS_IMETHODIMP
+WindowsLocationProvider::Shutdown() {
+ LOG("WindowsLocationProvider::Shutdown(%p, %p, %p)", this, mActor.get(),
+ mActorPromise.get());
+
+ if (mWatching) {
+ SendUnregisterForReport();
+ mWatching = false;
+ }
+
+ CancelMLSProvider();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+WindowsLocationProvider::SetHighAccuracy(bool enable) {
+ LOG("WindowsLocationProvider::SetHighAccuracy(%p, %p, %p, %s)", this,
+ mActor.get(), mActorPromise.get(), enable ? "true" : "false");
+ if (mMLSProvider) {
+ // Ignored when running MLS fallback.
+ return NS_OK;
+ }
+
+ if (!SendSetHighAccuracy(enable)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ // Since we SendSetHighAccuracy asynchronously, we cannot say for sure
+ // that it will succeed. If it does fail then we will get a
+ // RecvFailed IPC message, which will cause a fallback to MLS.
+ return NS_OK;
+}
+
+nsresult WindowsLocationProvider::CreateAndWatchMLSProvider(
+ nsIGeolocationUpdate* aCallback) {
+ LOG("WindowsLocationProvider::CreateAndWatchMLSProvider"
+ "(%p, %p, %p, %p, %p)",
+ this, mMLSProvider.get(), mActor.get(), mActorPromise.get(), aCallback);
+
+ if (mMLSProvider) {
+ return NS_OK;
+ }
+
+ mMLSProvider = new MLSFallback(0);
+ return mMLSProvider->Startup(new MLSUpdate(aCallback));
+}
+
+void WindowsLocationProvider::CancelMLSProvider() {
+ LOG("WindowsLocationProvider::CancelMLSProvider"
+ "(%p, %p, %p, %p, %p)",
+ this, mMLSProvider.get(), mActor.get(), mActorPromise.get(),
+ mCallback.get());
+
+ if (!mMLSProvider) {
+ return;
+ }
+
+ mMLSProvider->Shutdown();
+ mMLSProvider = nullptr;
+}
+
+#undef LOG
+
+} // namespace mozilla::dom
diff --git a/dom/system/windows/location/WindowsLocationProvider.h b/dom/system/windows/location/WindowsLocationProvider.h
new file mode 100644
index 0000000000..d1e4dfa936
--- /dev/null
+++ b/dom/system/windows/location/WindowsLocationProvider.h
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_WindowsLocationProvider_h__
+#define mozilla_dom_WindowsLocationProvider_h__
+
+#include "nsCOMPtr.h"
+#include "nsIGeolocationProvider.h"
+#include "mozilla/MozPromise.h"
+
+class MLSFallback;
+
+namespace mozilla::dom {
+
+class WindowsLocationParent;
+
+// Uses a PWindowsLocation actor to subscribe to geolocation updates from the
+// Windows utility process and falls back to MLS when it is not available or
+// fails.
+class WindowsLocationProvider final : public nsIGeolocationProvider {
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIGEOLOCATIONPROVIDER
+
+ WindowsLocationProvider();
+
+ private:
+ friend WindowsLocationParent;
+
+ ~WindowsLocationProvider();
+
+ nsresult CreateAndWatchMLSProvider(nsIGeolocationUpdate* aCallback);
+ void CancelMLSProvider();
+
+ void MaybeCreateLocationActor();
+ void ReleaseUtilityProcess();
+
+ // These methods either send the message on the existing actor or queue
+ // the messages to be sent (in order) once the actor exists.
+ bool SendStartup();
+ bool SendRegisterForReport(nsIGeolocationUpdate* aCallback);
+ bool SendUnregisterForReport();
+ bool SendSetHighAccuracy(bool aEnable);
+ bool Send__delete__();
+
+ void RecvUpdate(RefPtr<nsIDOMGeoPosition> aGeoPosition);
+ // See bug 1539864 for MOZ_CAN_RUN_SCRIPT_BOUNDARY justification.
+ MOZ_CAN_RUN_SCRIPT_BOUNDARY void RecvFailed(uint16_t err);
+
+ // The utility process actor has ended its connection, either successfully
+ // or with an error.
+ void ActorStopped();
+
+ // Run fn once actor is ready to send messages, which may be immediately.
+ template <typename Fn>
+ bool WhenActorIsReady(Fn&& fn);
+
+ RefPtr<MLSFallback> mMLSProvider;
+
+ nsCOMPtr<nsIGeolocationUpdate> mCallback;
+
+ using WindowsLocationPromise =
+ MozPromise<RefPtr<WindowsLocationParent>, bool, false>;
+
+ // Before the utility process exists, we have a promise that we will get our
+ // location actor. mActor and mActorPromise are never both set.
+ RefPtr<WindowsLocationPromise> mActorPromise;
+ RefPtr<WindowsLocationParent> mActor;
+
+ bool mWatching = false;
+};
+
+} // namespace mozilla::dom
+
+#endif // mozilla_dom_WindowsLocationProvider_h__
diff --git a/dom/system/windows/location/moz.build b/dom/system/windows/location/moz.build
new file mode 100644
index 0000000000..8fafb99fb1
--- /dev/null
+++ b/dom/system/windows/location/moz.build
@@ -0,0 +1,29 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+EXPORTS.mozilla.dom += [
+ "WindowsLocationChild.h",
+ "WindowsLocationParent.h",
+]
+
+UNIFIED_SOURCES += [
+ "WindowsLocationParent.cpp",
+ "WindowsLocationProvider.cpp",
+]
+
+SOURCES += [
+ "WindowsLocationChild.cpp", # includes locationapi.h
+]
+
+IPDL_SOURCES += [
+ "PWindowsLocation.ipdl",
+]
+
+LOCAL_INCLUDES += ["/dom/geolocation"]
+
+include("/ipc/chromium/chromium-config.mozbuild")
+
+FINAL_LIBRARY = "xul"