mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-05 07:18:39 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
465
dom/system/linux/GpsdLocationProvider.cpp
Normal file
465
dom/system/linux/GpsdLocationProvider.cpp
Normal file
|
|
@ -0,0 +1,465 @@
|
|||
/* -*- 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 "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,
|
||||
nsIDOMGeoPosition* aPosition)
|
||||
: mLocationProvider(aLocationProvider)
|
||||
, mPosition(aPosition)
|
||||
{
|
||||
MOZ_ASSERT(mLocationProvider);
|
||||
MOZ_ASSERT(mPosition);
|
||||
}
|
||||
|
||||
// nsIRunnable
|
||||
//
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
mLocationProvider->Update(mPosition);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsMainThreadPtrHandle<GpsdLocationProvider> mLocationProvider;
|
||||
RefPtr<nsIDOMGeoPosition> mPosition;
|
||||
};
|
||||
|
||||
//
|
||||
// NotifyErrorRunnable
|
||||
//
|
||||
|
||||
class GpsdLocationProvider::NotifyErrorRunnable final : public Runnable
|
||||
{
|
||||
public:
|
||||
NotifyErrorRunnable(
|
||||
const nsMainThreadPtrHandle<GpsdLocationProvider>& aLocationProvider,
|
||||
int aError)
|
||||
: mLocationProvider(aLocationProvider)
|
||||
, mError(aError)
|
||||
{
|
||||
MOZ_ASSERT(mLocationProvider);
|
||||
}
|
||||
|
||||
// nsIRunnable
|
||||
//
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
mLocationProvider->NotifyError(mError);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsMainThreadPtrHandle<GpsdLocationProvider> mLocationProvider;
|
||||
int mError;
|
||||
};
|
||||
|
||||
//
|
||||
// PollRunnable
|
||||
//
|
||||
|
||||
/**
|
||||
* |PollRunnable| does the main work of processing GPS data received
|
||||
* from gpsd. libgps blocks while polling, so this runnable has to be
|
||||
* executed on it's own thread. To cancel the poll runnable, invoke
|
||||
* |StopRunning| and |PollRunnable| will stop within a reasonable time
|
||||
* frame.
|
||||
*/
|
||||
class GpsdLocationProvider::PollRunnable final : public Runnable
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// nsIRunnable
|
||||
//
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
int err;
|
||||
|
||||
switch (GPSD_API_MAJOR_VERSION) {
|
||||
case 5:
|
||||
err = PollLoop5();
|
||||
break;
|
||||
default:
|
||||
err = nsIDOMGeoPositionError::POSITION_UNAVAILABLE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
NS_DispatchToMainThread(
|
||||
MakeAndAddRef<NotifyErrorRunnable>(mLocationProvider, err));
|
||||
}
|
||||
|
||||
mLocationProvider = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
int PollLoop5()
|
||||
{
|
||||
#if GPSD_API_MAJOR_VERSION == 5
|
||||
static const int GPSD_WAIT_TIMEOUT_US = 1000000; /* us to wait for GPS data */
|
||||
|
||||
struct gps_data_t gpsData;
|
||||
|
||||
auto res = gps_open(nullptr, nullptr, &gpsData);
|
||||
|
||||
if (res < 0) {
|
||||
return ErrnoToError(errno);
|
||||
}
|
||||
|
||||
gps_stream(&gpsData, WATCH_ENABLE | WATCH_JSON, NULL);
|
||||
|
||||
int err = 0;
|
||||
|
||||
double lat = -1;
|
||||
double lon = -1;
|
||||
double alt = -1;
|
||||
double hError = -1;
|
||||
double vError = -1;
|
||||
double heading = -1;
|
||||
double speed = -1;
|
||||
|
||||
while (IsRunning()) {
|
||||
|
||||
errno = 0;
|
||||
auto hasGpsData = gps_waiting(&gpsData, GPSD_WAIT_TIMEOUT_US);
|
||||
|
||||
if (errno) {
|
||||
err = ErrnoToError(errno);
|
||||
break;
|
||||
}
|
||||
if (!hasGpsData) {
|
||||
continue; /* woke up from timeout */
|
||||
}
|
||||
|
||||
res = gps_read(&gpsData);
|
||||
|
||||
if (res < 0) {
|
||||
err = ErrnoToError(errno);
|
||||
break;
|
||||
} else if (!res) {
|
||||
continue; /* no data available */
|
||||
}
|
||||
|
||||
if (gpsData.status == STATUS_NO_FIX) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (gpsData.fix.mode) {
|
||||
case MODE_3D:
|
||||
if (!IsNaN(gpsData.fix.altitude)) {
|
||||
alt = gpsData.fix.altitude;
|
||||
}
|
||||
MOZ_FALLTHROUGH;
|
||||
case MODE_2D:
|
||||
if (!IsNaN(gpsData.fix.latitude)) {
|
||||
lat = gpsData.fix.latitude;
|
||||
}
|
||||
if (!IsNaN(gpsData.fix.longitude)) {
|
||||
lon = gpsData.fix.longitude;
|
||||
}
|
||||
if (!IsNaN(gpsData.fix.epx) && !IsNaN(gpsData.fix.epy)) {
|
||||
hError = std::max(gpsData.fix.epx, gpsData.fix.epy);
|
||||
} else if (!IsNaN(gpsData.fix.epx)) {
|
||||
hError = gpsData.fix.epx;
|
||||
} else if (!IsNaN(gpsData.fix.epy)) {
|
||||
hError = gpsData.fix.epy;
|
||||
}
|
||||
if (!IsNaN(gpsData.fix.altitude)) {
|
||||
alt = gpsData.fix.altitude;
|
||||
}
|
||||
if (!IsNaN(gpsData.fix.epv)) {
|
||||
vError = gpsData.fix.epv;
|
||||
}
|
||||
if (!IsNaN(gpsData.fix.track)) {
|
||||
heading = gpsData.fix.track;
|
||||
}
|
||||
if (!IsNaN(gpsData.fix.speed)) {
|
||||
speed = gpsData.fix.speed;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
continue; // There's no useful data in this fix; continue.
|
||||
}
|
||||
|
||||
NS_DispatchToMainThread(
|
||||
MakeAndAddRef<UpdateRunnable>(mLocationProvider,
|
||||
new nsGeoPosition(lat, lon, alt,
|
||||
hError, vError,
|
||||
heading, speed,
|
||||
PR_Now() / PR_USEC_PER_MSEC)));
|
||||
}
|
||||
|
||||
gps_stream(&gpsData, WATCH_DISABLE, NULL);
|
||||
gps_close(&gpsData);
|
||||
|
||||
return err;
|
||||
#else
|
||||
return nsIDOMGeoPositionError::POSITION_UNAVAILABLE;
|
||||
#endif // GPSD_MAJOR_API_VERSION
|
||||
}
|
||||
|
||||
static int ErrnoToError(int aErrno)
|
||||
{
|
||||
switch (aErrno) {
|
||||
case EACCES:
|
||||
MOZ_FALLTHROUGH;
|
||||
case EPERM:
|
||||
MOZ_FALLTHROUGH;
|
||||
case EROFS:
|
||||
return nsIDOMGeoPositionError::PERMISSION_DENIED;
|
||||
case ETIME:
|
||||
MOZ_FALLTHROUGH;
|
||||
case ETIMEDOUT:
|
||||
return nsIDOMGeoPositionError::TIMEOUT;
|
||||
default:
|
||||
return nsIDOMGeoPositionError::POSITION_UNAVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsMainThreadPtrHandle<GpsdLocationProvider> mLocationProvider;
|
||||
Atomic<bool> mRunning;
|
||||
};
|
||||
|
||||
//
|
||||
// GpsdLocationProvider
|
||||
//
|
||||
|
||||
const uint32_t GpsdLocationProvider::GPSD_POLL_THREAD_TIMEOUT_MS = 5000;
|
||||
|
||||
GpsdLocationProvider::GpsdLocationProvider()
|
||||
{ }
|
||||
|
||||
GpsdLocationProvider::~GpsdLocationProvider()
|
||||
{ }
|
||||
|
||||
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)));
|
||||
|
||||
// Use existing poll thread...
|
||||
RefPtr<LazyIdleThread> pollThread = mPollThread;
|
||||
|
||||
// ... or create a new one.
|
||||
if (!pollThread) {
|
||||
pollThread = MakeAndAddRef<LazyIdleThread>(
|
||||
GPSD_POLL_THREAD_TIMEOUT_MS,
|
||||
NS_LITERAL_CSTRING("Gpsd poll thread"),
|
||||
LazyIdleThread::ManualShutdown);
|
||||
}
|
||||
|
||||
auto rv = pollThread->Dispatch(pollRunnable, NS_DISPATCH_NORMAL);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mPollRunnable = pollRunnable.forget();
|
||||
mPollThread = pollThread.forget();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GpsdLocationProvider::SetHighAccuracy(bool aHigh)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
Loading…
Add table
Add a link
Reference in a new issue