diff --git a/dom/geolocation/MLSFallback.cpp b/dom/geolocation/MLSFallback.cpp new file mode 100644 index 000000000000..68ac8cfffd61 --- /dev/null +++ b/dom/geolocation/MLSFallback.cpp @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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 "MLSFallback.h" +#include "nsGeoPosition.h" +#include "nsIGeolocationProvider.h" +#include "nsServiceManagerUtils.h" + +NS_IMPL_ISUPPORTS(MLSFallback, nsITimerCallback) + +MLSFallback::MLSFallback(uint32_t delay) +: mDelayMs(delay) +{ +} + +MLSFallback::~MLSFallback() +{ +} + +nsresult +MLSFallback::Startup(nsIGeolocationUpdate* aWatcher) +{ + if (mHandoffTimer || mMLSFallbackProvider) { + return NS_OK; + } + + mUpdateWatcher = aWatcher; + nsresult rv; + mHandoffTimer = do_CreateInstance("@mozilla.org/timer;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + rv = mHandoffTimer->InitWithCallback(this, mDelayMs, nsITimer::TYPE_ONE_SHOT); + return rv; +} + +nsresult +MLSFallback::Shutdown() +{ + mUpdateWatcher = nullptr; + + if (mHandoffTimer) { + mHandoffTimer->Cancel(); + mHandoffTimer = nullptr; + } + + nsresult rv = NS_OK; + if (mMLSFallbackProvider) { + rv = mMLSFallbackProvider->Shutdown(); + mMLSFallbackProvider = nullptr; + } + return rv; +} + +NS_IMETHODIMP +MLSFallback::Notify(nsITimer* aTimer) +{ + return CreateMLSFallbackProvider(); +} + +nsresult +MLSFallback::CreateMLSFallbackProvider() +{ + if (mMLSFallbackProvider || !mUpdateWatcher) { + return NS_OK; + } + + nsresult rv; + mMLSFallbackProvider = do_CreateInstance("@mozilla.org/geolocation/mls-provider;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + if (mMLSFallbackProvider) { + rv = mMLSFallbackProvider->Startup(); + if (NS_SUCCEEDED(rv)) { + mMLSFallbackProvider->Watch(mUpdateWatcher); + } + } + mUpdateWatcher = nullptr; + return rv; +} + diff --git a/dom/geolocation/MLSFallback.h b/dom/geolocation/MLSFallback.h new file mode 100644 index 000000000000..eb90fef5cb87 --- /dev/null +++ b/dom/geolocation/MLSFallback.h @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "nsCOMPtr.h" +#include "nsITimer.h" + +class nsIGeolocationUpdate; +class nsIGeolocationProvider; + +/* + This class wraps the NetworkGeolocationProvider in a delayed startup. + It is for providing a fallback to MLS when: + 1) using another provider as the primary provider, and + 2) that primary provider may fail to return a result (i.e. the error returned + is indeterminate, or no error callback occurs) + + The intent is that the primary provider is started, then MLSFallback + is started with sufficient delay that the primary provider will respond first + if successful (in the majority of cases). + + MLS has an average response of 3s, so with the 2s default delay, a response can + be expected in 5s. + + Telemetry is recommended to monitor that the primary provider is responding + first when expected to do so. +*/ +class MLSFallback : public nsITimerCallback +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSITIMERCALLBACK + + explicit MLSFallback(uint32_t delayMs = 2000); + nsresult Startup(nsIGeolocationUpdate* aWatcher); + nsresult Shutdown(); + +private: + nsresult CreateMLSFallbackProvider(); + virtual ~MLSFallback(); + nsCOMPtr mHandoffTimer; + nsCOMPtr mMLSFallbackProvider; + nsCOMPtr mUpdateWatcher; + const uint32_t mDelayMs; +}; + diff --git a/dom/geolocation/moz.build b/dom/geolocation/moz.build index ba34983a4c20..2d85b7ce63a9 100644 --- a/dom/geolocation/moz.build +++ b/dom/geolocation/moz.build @@ -15,6 +15,7 @@ SOURCES += [ ] UNIFIED_SOURCES += [ + 'MLSFallback.cpp', 'nsGeoGridFuzzer.cpp', 'nsGeolocationSettings.cpp', 'nsGeoPosition.cpp', diff --git a/dom/system/mac/CoreLocationLocationProvider.h b/dom/system/mac/CoreLocationLocationProvider.h index 33c6780c057e..534241bad727 100644 --- a/dom/system/mac/CoreLocationLocationProvider.h +++ b/dom/system/mac/CoreLocationLocationProvider.h @@ -6,6 +6,7 @@ #include "nsCOMPtr.h" #include "nsIGeolocationProvider.h" + /* * The CoreLocationObjects class contains the CoreLocation objects * we'll need. @@ -21,6 +22,7 @@ * for nsGeolocation.cpp, which is C++-only, to include this header. */ class CoreLocationObjects; +class MLSFallback; class CoreLocationLocationProvider : public nsIGeolocationProvider @@ -36,11 +38,11 @@ public: void CancelMLSFallbackProvider(); private: - virtual ~CoreLocationLocationProvider() {}; + virtual ~CoreLocationLocationProvider(); CoreLocationObjects* mCLObjects; nsCOMPtr mCallback; - nsCOMPtr mMLSFallbackProvider; + nsRefPtr mMLSFallbackProvider; class MLSUpdate : public nsIGeolocationUpdate { @@ -52,6 +54,6 @@ private: private: CoreLocationLocationProvider& mParentLocationProvider; - virtual ~MLSUpdate() {} + virtual ~MLSUpdate(); }; }; diff --git a/dom/system/mac/CoreLocationLocationProvider.mm b/dom/system/mac/CoreLocationLocationProvider.mm index 78ebea552eec..d634e1b9011a 100644 --- a/dom/system/mac/CoreLocationLocationProvider.mm +++ b/dom/system/mac/CoreLocationLocationProvider.mm @@ -13,6 +13,7 @@ #include "nsCocoaFeatures.h" #include "prtime.h" #include "mozilla/Telemetry.h" +#include "MLSFallback.h" #include #include @@ -32,7 +33,6 @@ static const CLLocationAccuracy kDEFAULT_ACCURACY = kCLLocationAccuracyNearestTe @interface LocationDelegate : NSObject { CoreLocationLocationProvider* mProvider; - NSTimer* mHandoffTimer; } - (id)init:(CoreLocationLocationProvider*)aProvider; @@ -52,23 +52,6 @@ static const CLLocationAccuracy kDEFAULT_ACCURACY = kCLLocationAccuracyNearestTe return self; } -- (void)shutdownHandoffTimer -{ - if (!mHandoffTimer) { - return; - } - - [mHandoffTimer invalidate]; - [mHandoffTimer release]; - mHandoffTimer = nil; -} - -- (void)handoffToGeoIPProvider -{ - [self shutdownHandoffTimer]; - mProvider->CreateMLSFallbackProvider(); -} - - (void)locationManager:(CLLocationManager*)aManager didFailWithError:(NSError *)aError { @@ -87,21 +70,15 @@ static const CLLocationAccuracy kDEFAULT_ACCURACY = kCLLocationAccuracyNearestTe return; } - if (!mHandoffTimer) { - // The CL provider does not fallback to GeoIP, so use NetworkGeolocationProvider for this. - // The concept here is: on error, hand off geolocation to MLS, which will then report - // back a location or error. We can't call this with no delay however, as this method - // is called with an error code of 0 in both failed geolocation cases, and also when - // geolocation is not immediately available. - // The 2 sec delay is arbitrarily large enough that CL has a reasonable head start and - // if it is likely to succeed, it should complete before the MLS provider. - // Take note that in locationManager:didUpdateLocations: the handoff to MLS is stopped. - mHandoffTimer = [[NSTimer scheduledTimerWithTimeInterval:2.0 - target:self - selector:@selector(handoffToGeoIPProvider) - userInfo:nil - repeats:NO] retain]; - } + // The CL provider does not fallback to GeoIP, so use NetworkGeolocationProvider for this. + // The concept here is: on error, hand off geolocation to MLS, which will then report + // back a location or error. We can't call this with no delay however, as this method + // is called with an error code of 0 in both failed geolocation cases, and also when + // geolocation is not immediately available. + // The 2 sec delay is arbitrarily large enough that CL has a reasonable head start and + // if it is likely to succeed, it should complete before the MLS provider. + // Take note that in locationManager:didUpdateLocations: the handoff to MLS is stopped. + mProvider->CreateMLSFallbackProvider(); } - (void)locationManager:(CLLocationManager*)aManager didUpdateLocations:(NSArray*)aLocations @@ -110,7 +87,6 @@ static const CLLocationAccuracy kDEFAULT_ACCURACY = kCLLocationAccuracyNearestTe return; } - [self shutdownHandoffTimer]; mProvider->CancelMLSFallbackProvider(); CLLocation* location = [aLocations objectAtIndex:0]; @@ -137,6 +113,10 @@ CoreLocationLocationProvider::MLSUpdate::MLSUpdate(CoreLocationLocationProvider& { } +CoreLocationLocationProvider::MLSUpdate::~MLSUpdate() +{ +} + NS_IMETHODIMP CoreLocationLocationProvider::MLSUpdate::Update(nsIDOMGeoPosition *position) { @@ -200,6 +180,10 @@ CoreLocationLocationProvider::CoreLocationLocationProvider() { } +CoreLocationLocationProvider::~CoreLocationLocationProvider() +{ +} + NS_IMETHODIMP CoreLocationLocationProvider::Startup() { @@ -234,7 +218,6 @@ CoreLocationLocationProvider::Shutdown() { NS_ENSURE_STATE(mCLObjects); - [mCLObjects->mLocationDelegate shutdownHandoffTimer]; [mCLObjects->mLocationManager stopUpdatingLocation]; delete mCLObjects; @@ -280,13 +263,8 @@ CoreLocationLocationProvider::CreateMLSFallbackProvider() return; } - mMLSFallbackProvider = do_CreateInstance("@mozilla.org/geolocation/mls-provider;1"); - if (mMLSFallbackProvider) { - nsresult rv = mMLSFallbackProvider->Startup(); - if (NS_SUCCEEDED(rv)) { - mMLSFallbackProvider->Watch(new CoreLocationLocationProvider::MLSUpdate(*this)); - } - } + mMLSFallbackProvider = new MLSFallback(); + mMLSFallbackProvider->Startup(new MLSUpdate(*this)); } void