summaryrefslogtreecommitdiffstats
path: root/dom/system/windows/location/WindowsLocationProvider.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/system/windows/location/WindowsLocationProvider.cpp')
-rw-r--r--dom/system/windows/location/WindowsLocationProvider.cpp350
1 files changed, 350 insertions, 0 deletions
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