Bug 1250922: Add MLS as fallback for gpsd, r=jdm
authorThomas Zimmermann <tdz@users.sourceforge.net>
Fri, 22 Jul 2016 11:52:09 +0200
changeset 331416 457be633b6cc5b3a11ef8e5814a04024d57b59d3
parent 331415 a1a42e8d66e905fcd99042d878b2cb56f6b137ad
child 331417 30745bed2567f484ff609a6d389a0e57a1b4a8d5
push id9858
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 14:37:10 +0000
treeherdermozilla-aurora@203106ef6cb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdm
bugs1250922
milestone50.0a1
Bug 1250922: Add MLS as fallback for gpsd, r=jdm The Mozilla Location Service is the fallback for gpsd. If no location information is received from GSP within a few seconds, MLS provides a position. It will be updated once GPS is ready. If GPS fails, MLS will take over again until GPS has been restored.
dom/system/linux/GpsdLocationProvider.cpp
dom/system/linux/GpsdLocationProvider.h
--- a/dom/system/linux/GpsdLocationProvider.cpp
+++ b/dom/system/linux/GpsdLocationProvider.cpp
@@ -2,28 +2,85 @@
 /* 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 "GpsdLocationProvider.h"
 #include <errno.h>
 #include <gps.h>
+#include "MLSFallback.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/LazyIdleThread.h"
 #include "nsGeoPosition.h"
 #include "nsIDOMGeoPositionError.h"
 #include "nsProxyRelease.h"
 #include "nsThreadUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 //
+// MLSGeolocationUpdate
+//
+
+/**
+ * |MLSGeolocationUpdate| provides a fallback if gpsd is not supported.
+ */
+class GpsdLocationProvider::MLSGeolocationUpdate final
+  : public nsIGeolocationUpdate
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIGEOLOCATIONUPDATE
+
+  explicit MLSGeolocationUpdate(nsIGeolocationUpdate* aCallback);
+
+protected:
+  ~MLSGeolocationUpdate() = default;
+
+private:
+  nsCOMPtr<nsIGeolocationUpdate> mCallback;
+};
+
+GpsdLocationProvider::MLSGeolocationUpdate::MLSGeolocationUpdate(
+  nsIGeolocationUpdate* aCallback)
+  : mCallback(aCallback)
+{
+  MOZ_ASSERT(mCallback);
+}
+
+// nsISupports
+//
+
+NS_IMPL_ISUPPORTS(GpsdLocationProvider::MLSGeolocationUpdate, nsIGeolocationUpdate);
+
+// nsIGeolocationUpdate
+//
+
+NS_IMETHODIMP
+GpsdLocationProvider::MLSGeolocationUpdate::Update(nsIDOMGeoPosition* aPosition)
+{
+  nsCOMPtr<nsIDOMGeoPositionCoords> coords;
+  aPosition->GetCoords(getter_AddRefs(coords));
+  if (!coords) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return mCallback->Update(aPosition);
+}
+
+NS_IMETHODIMP
+GpsdLocationProvider::MLSGeolocationUpdate::NotifyError(uint16_t aError)
+{
+  return mCallback->NotifyError(aError);
+}
+
+//
 // UpdateRunnable
 //
 
 class GpsdLocationProvider::UpdateRunnable final : public Runnable
 {
 public:
   UpdateRunnable(
     const nsMainThreadPtrHandle<GpsdLocationProvider>& aLocationProvider,
@@ -96,16 +153,21 @@ public:
   PollRunnable(
     const nsMainThreadPtrHandle<GpsdLocationProvider>& aLocationProvider)
     : mLocationProvider(aLocationProvider)
     , mRunning(true)
   {
     MOZ_ASSERT(mLocationProvider);
   }
 
+  static bool IsSupported()
+  {
+    return GPSD_API_MAJOR_VERSION == 5;
+  }
+
   bool IsRunning() const
   {
     return mRunning;
   }
 
   void StopRunning()
   {
     mRunning = false;
@@ -283,40 +345,58 @@ GpsdLocationProvider::~GpsdLocationProvi
 
 void
 GpsdLocationProvider::Update(nsIDOMGeoPosition* aPosition)
 {
   if (!mCallback || !mPollRunnable) {
     return; // not initialized or already shut down
   }
 
+  if (mMLSProvider) {
+    /* We got a location from gpsd, so let's cancel our MLS fallback. */
+    mMLSProvider->Shutdown();
+    mMLSProvider = nullptr;
+  }
+
   mCallback->Update(aPosition);
 }
 
 void
 GpsdLocationProvider::NotifyError(int aError)
 {
   if (!mCallback) {
     return; // not initialized or already shut down
   }
 
+  if (!mMLSProvider) {
+    /* With gpsd failed, we restart MLS. It will be canceled once we
+     * get another location from gpsd.
+     */
+    mMLSProvider = MakeAndAddRef<MLSFallback>();
+    mMLSProvider->Startup(new MLSGeolocationUpdate(mCallback));
+  }
+
   mCallback->NotifyError(aError);
 }
 
 // nsISupports
 //
 
 NS_IMPL_ISUPPORTS(GpsdLocationProvider, nsIGeolocationProvider)
 
 // nsIGeolocationProvider
 //
 
 NS_IMETHODIMP
 GpsdLocationProvider::Startup()
 {
+  if (!PollRunnable::IsSupported()) {
+    return NS_OK; // We'll fall back to MLS.
+  }
+
   if (mPollRunnable) {
     return NS_OK; // already running
   }
 
   RefPtr<PollRunnable> pollRunnable =
     MakeAndAddRef<PollRunnable>(
       nsMainThreadPtrHandle<GpsdLocationProvider>(
         new nsMainThreadPtrHolder<GpsdLocationProvider>(this)));
@@ -344,22 +424,35 @@ GpsdLocationProvider::Startup()
   return NS_OK;
 }
 
 NS_IMETHODIMP
 GpsdLocationProvider::Watch(nsIGeolocationUpdate* aCallback)
 {
   mCallback = aCallback;
 
+  /* The MLS fallback will kick in after a few seconds if gpsd
+   * doesn't provide location information within time. Once we
+   * see the first message from gpsd, the fallback will be
+   * disabled in |Update|.
+   */
+  mMLSProvider = MakeAndAddRef<MLSFallback>();
+  mMLSProvider->Startup(new MLSGeolocationUpdate(aCallback));
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 GpsdLocationProvider::Shutdown()
 {
+  if (mMLSProvider) {
+    mMLSProvider->Shutdown();
+    mMLSProvider = nullptr;
+  }
+
   if (!mPollRunnable) {
     return NS_OK; // not running
   }
 
   mPollRunnable->StopRunning();
   mPollRunnable = nullptr;
 
   return NS_OK;
--- a/dom/system/linux/GpsdLocationProvider.h
+++ b/dom/system/linux/GpsdLocationProvider.h
@@ -6,24 +6,27 @@
 
 #ifndef GpsdLocationProvider_h
 #define GpsdLocationProvider_h
 
 #include "nsCOMPtr.h"
 #include "nsGeolocation.h"
 #include "nsIGeolocationProvider.h"
 
+class MLSFallback;
+
 namespace mozilla {
 
 class LazyIdleThread;
 
 namespace dom {
 
 class GpsdLocationProvider final : public nsIGeolocationProvider
 {
+  class MLSGeolocationUpdate;
   class NotifyErrorRunnable;
   class PollRunnable;
   class UpdateRunnable;
 
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIGEOLOCATIONPROVIDER
 
@@ -35,14 +38,15 @@ private:
   void Update(nsIDOMGeoPosition* aPosition);
   void NotifyError(int aError);
 
   static const uint32_t GPSD_POLL_THREAD_TIMEOUT_MS;
 
   nsCOMPtr<nsIGeolocationUpdate> mCallback;
   RefPtr<LazyIdleThread> mPollThread;
   RefPtr<PollRunnable> mPollRunnable;
+  RefPtr<MLSFallback> mMLSProvider;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* GpsLocationProvider_h */