summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjoth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-27 15:26:18 +0000
committerjoth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-27 15:26:18 +0000
commita2fd492a14c619f899623a0e0e05f5dd61751b6b (patch)
treea9bd46a7fe51f04ae6de7b53114ab892a064883e
parent300e4ea2cb2bfdb316cc0670cc1de8bffffe9d85 (diff)
downloadchromium_src-a2fd492a14c619f899623a0e0e05f5dd61751b6b.zip
chromium_src-a2fd492a14c619f899623a0e0e05f5dd61751b6b.tar.gz
chromium_src-a2fd492a14c619f899623a0e0e05f5dd61751b6b.tar.bz2
First cut at GPS support in chrome linux
Uses libgps / gpsd to get gps fixes. Modified the location arbitrator to use GPS instead of network location provider. Current version requires manual code edit to enable (ENABLE_LIBGPS_LOCATION_PROVIDER) See http://docs.google.com/View?id=dfbnm49n_1g8ktswhr for demo instructions (work in progress) BUG=43868 TEST=Built with ENABLE_LIBGPS_LOCATION_PROVIDER and used gpsd's gpsfake script (see linked doc above) Review URL: http://codereview.chromium.org/2032010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@48393 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/DEPS1
-rw-r--r--chrome/browser/geolocation/gps_location_provider_linux.cc122
-rw-r--r--chrome/browser/geolocation/gps_location_provider_linux.h55
-rw-r--r--chrome/browser/geolocation/libgps_2_38_wrapper_linux.cc72
-rw-r--r--chrome/browser/geolocation/libgps_2_94_wrapper_linux.cc50
-rw-r--r--chrome/browser/geolocation/libgps_wrapper_linux.cc202
-rw-r--r--chrome/browser/geolocation/libgps_wrapper_linux.h115
-rw-r--r--chrome/browser/geolocation/location_arbitrator.cc13
-rw-r--r--chrome/browser/geolocation/location_provider.cc4
-rw-r--r--chrome/chrome_browser.gypi6
10 files changed, 634 insertions, 6 deletions
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index 4035947..7120cb8 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -22,6 +22,7 @@ include_rules = [
"+media/base",
"+third_party/cros",
"+third_party/expat",
+ "+third_party/gpsd",
"+third_party/sqlite",
"+third_party/libevent", # For the remote V8 debugging server
"+third_party/cld",
diff --git a/chrome/browser/geolocation/gps_location_provider_linux.cc b/chrome/browser/geolocation/gps_location_provider_linux.cc
new file mode 100644
index 0000000..64d56e8
--- /dev/null
+++ b/chrome/browser/geolocation/gps_location_provider_linux.cc
@@ -0,0 +1,122 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/geolocation/gps_location_provider_linux.h"
+
+#include <algorithm>
+#include <cmath>
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "chrome/browser/geolocation/libgps_wrapper_linux.h"
+
+// Uncomment this to force the arbitrator to use GPS instead of network
+// location provider. Note this will break unit tests!
+// TODO(joth): remove when arbitration is implemented.
+//#define ENABLE_LIBGPS_LOCATION_PROVIDER 1
+
+namespace {
+// As per http://gpsd.berlios.de/performance.html#id374524, poll twice per sec.
+const int kPollPeriodMovingMillis = 500;
+// Poll less frequently whilst stationary.
+const int kPollPeriodStationaryMillis = kPollPeriodMovingMillis * 3;
+// GPS reading must differ by more than this amount to be considered movement.
+const int kMovementThresholdMeters = 20;
+
+// This algorithm is reused from the corresponding code in the gears project.
+// The arbitrary delta is decreased (gears used 100 meters); if we need to
+// decrease it any further we'll likely want to do some smarter filtering to
+// remove GPS location jitter noise.
+bool PositionsDifferSiginificantly(const Geoposition& position_1,
+ const Geoposition& position_2) {
+ const bool pos_1_valid = position_1.IsValidFix();
+ if (pos_1_valid != position_2.IsValidFix())
+ return true;
+ if (!pos_1_valid) {
+ DCHECK(!position_2.IsValidFix());
+ return false;
+ }
+ double delta = std::sqrt(
+ std::pow(std::fabs(position_1.latitude - position_2.latitude), 2) +
+ std::pow(std::fabs(position_1.longitude - position_2.longitude), 2));
+ // Convert to meters. 1 minute of arc of latitude (or longitude at the
+ // equator) is 1 nautical mile or 1852m.
+ delta *= 60 * 1852;
+ return delta > kMovementThresholdMeters;
+}
+} // namespace
+
+GpsLocationProviderLinux::GpsLocationProviderLinux(LibGpsFactory libgps_factory)
+ : libgps_factory_(libgps_factory),
+ ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)) {
+ DCHECK(libgps_factory_);
+}
+
+GpsLocationProviderLinux::~GpsLocationProviderLinux() {
+}
+
+bool GpsLocationProviderLinux::StartProvider() {
+ position_.error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE;
+ gps_.reset(libgps_factory_());
+ if (gps_ == NULL) {
+ LOG(WARNING) << "libgps.so could not be loaded";
+ // TODO(joth): return false once GeolocationArbitratorImpl can cope with it.
+ return true;
+ }
+ if (!gps_->Start(&error_msg_)) {
+ LOG(WARNING) << "Couldn't start GPS provider: " << error_msg_;
+ // TODO(joth): return false once GeolocationArbitratorImpl can cope with it.
+ return true;
+ }
+ ScheduleNextGpsPoll(0);
+ return true;
+}
+
+void GpsLocationProviderLinux::GetPosition(Geoposition* position) {
+ DCHECK(position);
+ *position = position_;
+ DCHECK(position->IsInitialized());
+}
+
+void GpsLocationProviderLinux::UpdatePosition() {
+ ScheduleNextGpsPoll(0);
+}
+
+void GpsLocationProviderLinux::OnPermissionGranted(
+ const GURL& requesting_frame) {
+}
+
+void GpsLocationProviderLinux::DoGpsPollTask() {
+ if (!gps_->Poll()) {
+ gps_->Stop();
+ return;
+ }
+ Geoposition new_position;
+ gps_->GetPosition(&new_position);
+ DCHECK(new_position.IsInitialized());
+ const bool differ = PositionsDifferSiginificantly(position_, new_position);
+ ScheduleNextGpsPoll(differ ? kPollPeriodMovingMillis :
+ kPollPeriodStationaryMillis);
+ if (differ || new_position.error_code != Geoposition::ERROR_CODE_NONE) {
+ // Update if the new location is interesting or we have an error to report.
+ position_ = new_position;
+ UpdateListeners();
+ }
+}
+
+void GpsLocationProviderLinux::ScheduleNextGpsPoll(int interval) {
+ task_factory_.RevokeAll();
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ task_factory_.NewRunnableMethod(&GpsLocationProviderLinux::DoGpsPollTask),
+ interval);
+}
+
+LocationProviderBase* NewGpsLocationProvider() {
+#ifdef ENABLE_LIBGPS_LOCATION_PROVIDER
+ return new GpsLocationProviderLinux(LibGps::New);
+#else
+ return NULL;
+#endif
+}
diff --git a/chrome/browser/geolocation/gps_location_provider_linux.h b/chrome/browser/geolocation/gps_location_provider_linux.h
new file mode 100644
index 0000000..816062e
--- /dev/null
+++ b/chrome/browser/geolocation/gps_location_provider_linux.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file declares GPS providers that run on linux. Currently, just uses
+// the libgps (gpsd) API. Public for testing only - for normal usage this
+// header should not be required, as location_provider.h declares the needed
+// factory function.
+
+#ifndef CHROME_BROWSER_GEOLOCATION_GPS_LOCATION_PROVIDER_LINUX_H_
+#define CHROME_BROWSER_GEOLOCATION_GPS_LOCATION_PROVIDER_LINUX_H_
+
+#include "chrome/browser/geolocation/location_provider.h"
+
+#include "base/scoped_ptr.h"
+#include "base/task.h"
+
+class LibGps;
+
+// Location provider for Linux, that uses libgps/gpsd to obtain position fixes.
+// TODO(joth): Currently this runs entirely in the client thread (i.e. Chrome's
+// IO thread). As the older libgps API is not designed to support polling,
+// there's a chance it could block, so better move this into its own worker
+// thread.
+class GpsLocationProviderLinux : public LocationProviderBase {
+ public:
+ typedef LibGps* (*LibGpsFactory)();
+ // |factory| will be used to create the gpsd client library wrapper. (Note
+ // NewGpsLocationProvider() will use the default factory).
+ GpsLocationProviderLinux(LibGpsFactory libgps_factory);
+ virtual ~GpsLocationProviderLinux();
+
+ // LocationProvider
+ virtual bool StartProvider();
+ virtual void GetPosition(Geoposition* position);
+ virtual void UpdatePosition();
+ virtual void OnPermissionGranted(const GURL& requesting_frame);
+
+ private:
+ // Task which run in the child thread.
+ void DoGpsPollTask();
+
+ // Will schedule a poll; i.e. enqueue DoGpsPollTask deferred task.
+ void ScheduleNextGpsPoll(int interval);
+
+ const LibGpsFactory libgps_factory_;
+ scoped_ptr<LibGps> gps_;
+ std::string error_msg_;
+ Geoposition position_;
+
+ // Holder for the tasks which run on the thread; takes care of cleanup.
+ ScopedRunnableMethodFactory<GpsLocationProviderLinux> task_factory_;
+};
+
+#endif // CHROME_BROWSER_GEOLOCATION_GPS_LOCATION_PROVIDER_LINUX_H_
diff --git a/chrome/browser/geolocation/libgps_2_38_wrapper_linux.cc b/chrome/browser/geolocation/libgps_2_38_wrapper_linux.cc
new file mode 100644
index 0000000..075df3e
--- /dev/null
+++ b/chrome/browser/geolocation/libgps_2_38_wrapper_linux.cc
@@ -0,0 +1,72 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Defines a variant of libgps wrapper for use with the 2.38 release of the API.
+
+#include "chrome/browser/geolocation/libgps_wrapper_linux.h"
+
+// This lot needed for Poll()
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include "base/logging.h"
+#include "chrome/common/geoposition.h"
+#include "third_party/gpsd/release-2.38/gps.h"
+
+class LibGpsV238 : public LibGps {
+ public:
+ explicit LibGpsV238(LibGpsLibraryLoader* dl_wrapper) : LibGps(dl_wrapper) {}
+
+ // LibGps
+ virtual bool StartStreaming() {
+ return library().query("w+x\n") == 0;
+ }
+ virtual bool DataWaiting(bool* ok) {
+ // Unfortunately the 2.38 API has no public method for non-blocking test
+ // for new data arrived, so we must contrive our own by doing a select() on
+ // the underlying struct's socket fd.
+ DCHECK(ok);
+ *ok = true;
+ fd_set fds;
+ struct timeval timeout = {0};
+ int fd = library().data().gps_fd;
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+
+ int ret = select(fd + 1, &fds, NULL, NULL, &timeout);
+ if (ret == -1) {
+ LOG(INFO) << "libgps socket select failed: " << ret;
+ *ok = false;
+ return false;
+ }
+ DCHECK_EQ(!!ret, !!FD_ISSET(fd, &fds));
+ return ret;
+ }
+ virtual bool GetPositionIfFixed(Geoposition* position) {
+ // This function is duplicated between the library versions, however it
+ // cannot be shared as each one must be strictly compiled against the
+ // corresponding version of gps.h.
+ DCHECK(position);
+ const gps_data_t& gps_data = library().data();
+ if (gps_data.status == STATUS_NO_FIX)
+ return false;
+ position->timestamp = base::Time::FromDoubleT(gps_data.fix.time);
+ position->latitude = gps_data.fix.latitude;
+ position->longitude = gps_data.fix.longitude;
+ position->accuracy = library().data().fix.eph;
+ position->altitude = gps_data.fix.altitude;
+ position->altitude_accuracy = gps_data.fix.epv;
+ position->heading = gps_data.fix.track;
+ position->speed = gps_data.fix.speed;
+ return true;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LibGpsV238);
+};
+
+LibGps* LibGps::NewV238(LibGpsLibraryLoader* dl_wrapper) {
+ return new LibGpsV238(dl_wrapper);
+}
diff --git a/chrome/browser/geolocation/libgps_2_94_wrapper_linux.cc b/chrome/browser/geolocation/libgps_2_94_wrapper_linux.cc
new file mode 100644
index 0000000..9c9de30
--- /dev/null
+++ b/chrome/browser/geolocation/libgps_2_94_wrapper_linux.cc
@@ -0,0 +1,50 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Defines a variant of libgps wrapper for use with the 2.94 release of the API.
+
+#include "chrome/browser/geolocation/libgps_wrapper_linux.h"
+
+#include "base/logging.h"
+#include "chrome/common/geoposition.h"
+#include "third_party/gpsd/release-2.94/gps.h"
+
+class LibGpsV294 : public LibGps {
+ public:
+ explicit LibGpsV294(LibGpsLibraryLoader* dl_wrapper) : LibGps(dl_wrapper) {}
+
+ // LibGps
+ virtual bool StartStreaming() {
+ return library().stream(WATCH_ENABLE) == 0;
+ }
+ virtual bool DataWaiting(bool* ok) {
+ *ok = true;
+ return library().waiting();
+ }
+ virtual bool GetPositionIfFixed(Geoposition* position) {
+ // This function is duplicated between the library versions, however it
+ // cannot be shared as each one must be strictly compiled against the
+ // corresponding version of gps.h.
+ DCHECK(position);
+ const gps_data_t& gps_data = library().data();
+ if (gps_data.status == STATUS_NO_FIX)
+ return false;
+ position->timestamp = base::Time::FromDoubleT(gps_data.fix.time);
+ position->latitude = gps_data.fix.latitude;
+ position->longitude = gps_data.fix.longitude;
+ position->accuracy = std::max(gps_data.fix.epx, gps_data.fix.epy);
+ position->altitude = gps_data.fix.altitude;
+ position->altitude_accuracy = gps_data.fix.epv;
+ position->heading = gps_data.fix.track;
+ position->speed = gps_data.fix.speed;
+ return true;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LibGpsV294);
+};
+
+LibGps* LibGps::NewV294(LibGpsLibraryLoader* dl_wrapper) {
+ return new LibGpsV294(dl_wrapper);
+}
diff --git a/chrome/browser/geolocation/libgps_wrapper_linux.cc b/chrome/browser/geolocation/libgps_wrapper_linux.cc
new file mode 100644
index 0000000..0dc743c
--- /dev/null
+++ b/chrome/browser/geolocation/libgps_wrapper_linux.cc
@@ -0,0 +1,202 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/geolocation/libgps_wrapper_linux.h"
+
+#include <dlfcn.h>
+
+#include "chrome/common/geoposition.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+
+namespace {
+LibGpsLibraryLoader* TryToOpen(const char* lib,
+ LibGpsLibraryLoader::InitMode mode) {
+ void* dl_handle = dlopen(lib, RTLD_LAZY);
+ if (dl_handle) {
+ LOG(INFO) << "Loaded " << lib;
+ scoped_ptr<LibGpsLibraryLoader> wrapper(new LibGpsLibraryLoader(dl_handle));
+ if (wrapper->Init(mode))
+ return wrapper.release();
+ } else {
+ DLOG(INFO) << "Could not open " << lib << ": " << dlerror();
+ }
+ return NULL;
+}
+} // namespace
+
+LibGps::LibGps(LibGpsLibraryLoader* dl_wrapper)
+ : library_(dl_wrapper) {
+ DCHECK(dl_wrapper != NULL);
+}
+
+LibGps::~LibGps() {
+}
+
+LibGps* LibGps::New() {
+ LibGpsLibraryLoader* wrapper;
+ wrapper = TryToOpen("libgps.so.19", LibGpsLibraryLoader::INITMODE_STREAM);
+ if (wrapper)
+ return NewV294(wrapper);
+ wrapper = TryToOpen("libgps.so.17", LibGpsLibraryLoader::INITMODE_QUERY);
+ if (wrapper)
+ return NewV238(wrapper);
+ wrapper = TryToOpen("libgps.so", LibGpsLibraryLoader::INITMODE_STREAM);
+ if (wrapper)
+ return NewV294(wrapper);
+ return NULL;
+}
+
+bool LibGps::Start(std::string* error_out) {
+ if (!library().open(NULL, NULL, error_out))
+ return false;
+ if (!StartStreaming()) {
+ library().close();
+ return false;
+ }
+ return true;
+}
+
+void LibGps::Stop() {
+ library().close();
+}
+
+bool LibGps::Poll() {
+ bool ret = true;
+ while (DataWaiting(&ret)) {
+ int error = library().poll();
+ if (error) {
+ last_error_ = StringPrintf("poll() returned %d", error);
+ return false;
+ }
+ }
+ if (!ret)
+ last_error_ = "DataWaiting failed";
+ return ret;
+}
+
+bool LibGps::GetPosition(Geoposition* position) {
+ DCHECK(position);
+ position->error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE;
+ if (!library().is_open()) {
+ position->error_message = L"No gpsd connection";
+ return false;
+ }
+ if (!GetPositionIfFixed(position)) {
+ position->error_message = ASCIIToWide(last_error_);
+ return false;
+ }
+ position->error_code = Geoposition::ERROR_CODE_NONE;
+ if (!position->IsValidFix()) {
+ // GetPositionIfFixed returned true, yet we've not got a valid fix.
+ // This shouldn't happen; something went wrong in the conversion.
+ NOTREACHED() << "Invalid position from GetPositionIfFixed: lat,long "
+ << position->latitude << "," << position->longitude
+ << " accuracy " << position->accuracy << " time "
+ << position->timestamp.ToDoubleT();
+ position->error_code = Geoposition::ERROR_CODE_POSITION_UNAVAILABLE;
+ position->error_message = L"Bad fix from gps";
+ return false;
+ }
+ return true;
+}
+
+LibGpsLibraryLoader::LibGpsLibraryLoader(void* dl_handle)
+ : dl_handle_(dl_handle),
+ gps_open_(NULL),
+ gps_close_(NULL),
+ gps_poll_(NULL),
+ gps_query_(NULL),
+ gps_stream_(NULL),
+ gps_waiting_(NULL),
+ gps_data_(NULL) {
+ DCHECK(dl_handle_);
+}
+
+// |mode| could be turned into a bit mask if required, but for now the
+// two options are mutually exclusive.
+bool LibGpsLibraryLoader::Init(InitMode mode) {
+ DCHECK(dl_handle_);
+ DCHECK(!gps_open_) << "Already initialized";
+ #define SET_FN_POINTER(function, required) \
+ function##_ = (function##_fn)dlsym(dl_handle_, #function); \
+ if ((required) && !function##_) { \
+ LOG(INFO) << "libgps " << #function << " error: " << dlerror(); \
+ close(); \
+ return false; \
+ }
+ SET_FN_POINTER(gps_open, true);
+ SET_FN_POINTER(gps_close, true);
+ SET_FN_POINTER(gps_poll, true);
+ SET_FN_POINTER(gps_query, mode == INITMODE_QUERY);
+ SET_FN_POINTER(gps_stream, mode == INITMODE_STREAM);
+ SET_FN_POINTER(gps_waiting, mode == INITMODE_STREAM);
+ #undef SET_FN_POINTER
+ return true;
+}
+
+LibGpsLibraryLoader::~LibGpsLibraryLoader() {
+ close();
+ if (dlclose(dl_handle_) != 0) {
+ NOTREACHED() << "Error closing dl handle";
+ }
+}
+
+bool LibGpsLibraryLoader::open(const char* host, const char* port,
+ std::string* error_out) {
+ DCHECK(!gps_data_) << "libgps handle already opened";
+ DCHECK(gps_open_) << "Must call Init() first";
+ std::string dummy;
+ if (!error_out) error_out = &dummy;
+
+ gps_data_ = gps_open_(host, port);
+ if (!gps_data_) { // GPS session was not created.
+ *error_out = "gps_open failed";
+ close();
+ }
+ return gps_data_;
+}
+
+void LibGpsLibraryLoader::close() {
+ if (gps_data_) {
+ DCHECK(gps_close_);
+ gps_close_(gps_data_);
+ gps_data_ = NULL;
+ }
+}
+
+int LibGpsLibraryLoader::poll() {
+ DCHECK(is_open());
+ DCHECK(gps_poll_);
+ return gps_poll_(gps_data_);
+}
+
+// This is intentionally ignoring the va_arg extension to query(): the caller
+// can use base::StringPrintf to achieve the same effect.
+int LibGpsLibraryLoader::query(const char* fmt) {
+ DCHECK(is_open());
+ DCHECK(gps_query_);
+ return gps_query_(gps_data_, fmt);
+}
+
+int LibGpsLibraryLoader::stream(int flags) {
+ DCHECK(is_open());
+ DCHECK(gps_stream_);
+ return gps_stream_(gps_data_, flags, NULL);
+}
+
+bool LibGpsLibraryLoader::waiting() {
+ DCHECK(is_open());
+ DCHECK(gps_waiting_);
+ return gps_waiting_(gps_data_);
+}
+
+const gps_data_t& LibGpsLibraryLoader::data() const {
+ DCHECK(is_open());
+ return *gps_data_;
+}
+
+bool LibGpsLibraryLoader::is_open() const {
+ return gps_data_ != NULL;
+}
diff --git a/chrome/browser/geolocation/libgps_wrapper_linux.h b/chrome/browser/geolocation/libgps_wrapper_linux.h
new file mode 100644
index 0000000..f49b20d
--- /dev/null
+++ b/chrome/browser/geolocation/libgps_wrapper_linux.h
@@ -0,0 +1,115 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Defines a wrapper around the C libgps API (gps.h). Similar to the libgpsmm.h
+// API provided by that package, but adds:
+// - shared object dynamic loading
+// - support for (and abstraction from) different libgps.so versions
+// - configurable for testing
+// - more convenient error handling.
+
+#ifndef CHROME_BROWSER_GEOLOCATION_LIBGPS_WRAPPER_LINUX_H_
+#define CHROME_BROWSER_GEOLOCATION_LIBGPS_WRAPPER_LINUX_H_
+
+#include <string>
+
+#include "base/scoped_ptr.h"
+#include "base/time.h"
+
+struct Geoposition;
+class LibGpsLibraryLoader;
+
+class LibGps {
+ public:
+ virtual ~LibGps();
+ // Attempts to dynamically load the libgps.so library, and creates and
+ // appropriate LibGps instance for the version loaded. Returns NULL on
+ // failure.
+ static LibGps* New();
+
+ bool Start(std::string* error_out);
+ void Stop();
+ bool Poll();
+ bool GetPosition(Geoposition* position);
+
+ protected:
+ // Takes ownership of |dl_wrapper|.
+ explicit LibGps(LibGpsLibraryLoader* dl_wrapper);
+
+ LibGpsLibraryLoader& library() {
+ return *library_;
+ }
+ // Called be start Start after successful |gps_open| to setup streaming.
+ virtual bool StartStreaming() = 0;
+ virtual bool DataWaiting(bool* ok) = 0;
+ // Returns false if there is not fix available.
+ virtual bool GetPositionIfFixed(Geoposition* position) = 0;
+
+ private:
+ // Factory functions to create instances of LibGps using the corresponding
+ // libgps API versions (v2.38 => libgps.so.17, v2.94 => libgps.so.19).
+ // See LibGps::New() for the public API to this.
+ // Takes ownership of |dl_wrapper|.
+ static LibGps* NewV238(LibGpsLibraryLoader* dl_wrapper);
+ static LibGps* NewV294(LibGpsLibraryLoader* dl_wrapper);
+
+ scoped_ptr<LibGpsLibraryLoader> library_;
+ std::string last_error_;
+
+ DISALLOW_COPY_AND_ASSIGN(LibGps);
+};
+
+struct gps_data_t;
+
+// Wraps the low-level shared object, binding C++ member functions onto the
+// underlying C functions obtained from the library.
+class LibGpsLibraryLoader {
+ public:
+ // Pass to Init() to indicate which functions should be wired up.
+ enum InitMode {
+ INITMODE_QUERY,
+ INITMODE_STREAM,
+ };
+
+ // Takes ownership of the handle passed in (will be released via dlclose).
+ explicit LibGpsLibraryLoader(void* dl_handle);
+ ~LibGpsLibraryLoader();
+ // Must be successfully called before using any of the API methods below.
+ // Returns false on error.
+ bool Init(InitMode requirement);
+
+ // Analogs of gps_xxx methods in gps.h
+ bool open(const char* host, const char* port, std::string* error_out);
+ void close();
+ int poll();
+ int query(const char* fmt);
+ int stream(int flags);
+ bool waiting();
+ const gps_data_t& data() const;
+ bool is_open() const;
+
+ private:
+ typedef gps_data_t* (*gps_open_fn)(const char*, const char*);
+ typedef int (*gps_close_fn)(gps_data_t*);
+ typedef int (*gps_poll_fn)(gps_data_t*);
+ // v2.34 only
+ typedef int (*gps_query_fn)(struct gps_data_t *gpsdata, const char* fmt, ...);
+ // v2.90+
+ typedef int (*gps_stream_fn)(gps_data_t*, unsigned int, void*);
+ typedef bool (*gps_waiting_fn)(gps_data_t*);
+
+ void* dl_handle_;
+ gps_open_fn gps_open_;
+ gps_close_fn gps_close_;
+ gps_poll_fn gps_poll_;
+ gps_query_fn gps_query_;
+ gps_stream_fn gps_stream_;
+ gps_waiting_fn gps_waiting_;
+
+ gps_data_t* gps_data_;
+
+ DISALLOW_COPY_AND_ASSIGN(LibGpsLibraryLoader);
+};
+
+#endif // CHROME_BROWSER_GEOLOCATION_LIBGPS_WRAPPER_LINUX_H_
diff --git a/chrome/browser/geolocation/location_arbitrator.cc b/chrome/browser/geolocation/location_arbitrator.cc
index e0d513a..0eb9a10 100644
--- a/chrome/browser/geolocation/location_arbitrator.cc
+++ b/chrome/browser/geolocation/location_arbitrator.cc
@@ -153,11 +153,14 @@ void GeolocationArbitratorImpl::OnAccessTokenStoresLoaded(
if (g_provider_factory_function_for_test) {
provider_.reset(g_provider_factory_function_for_test());
} else {
- // TODO(joth): When arbitration is implemented, iterate the whole
- // set rather than cherry-pick our defaul url.
- provider_.reset(NewNetworkLocationProvider(
- access_token_store_.get(), context_getter_.get(), default_url_,
- access_token_set[default_url_]));
+ provider_.reset(NewGpsLocationProvider());
+ if (provider_ == NULL) {
+ // TODO(joth): When arbitration is implemented, iterate the whole
+ // set rather than cherry-pick our default url.
+ provider_.reset(NewNetworkLocationProvider(
+ access_token_store_.get(), context_getter_.get(), default_url_,
+ access_token_set[default_url_]));
+ }
}
DCHECK(provider_ != NULL);
provider_->RegisterListener(this);
diff --git a/chrome/browser/geolocation/location_provider.cc b/chrome/browser/geolocation/location_provider.cc
index c8a9f67..858963f 100644
--- a/chrome/browser/geolocation/location_provider.cc
+++ b/chrome/browser/geolocation/location_provider.cc
@@ -65,7 +65,9 @@ void LocationProviderBase::InformListenersOfMovement() {
}
}
-// Currently no platforms have a GPS location provider.
+// Currently only Linux has a GPS provider.
+#if !defined(OS_LINUX)
LocationProviderBase* NewGpsLocationProvider() {
return NULL;
}
+#endif
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index d8acb1f..9b0a20f 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1187,6 +1187,12 @@
'browser/geolocation/geolocation_exceptions_table_model.h',
'browser/geolocation/geolocation_settings_state.cc',
'browser/geolocation/geolocation_settings_state.h',
+ 'browser/geolocation/gps_location_provider_linux.cc',
+ 'browser/geolocation/gps_location_provider_linux.h',
+ 'browser/geolocation/libgps_2_38_wrapper_linux.cc',
+ 'browser/geolocation/libgps_2_94_wrapper_linux.cc',
+ 'browser/geolocation/libgps_wrapper_linux.cc',
+ 'browser/geolocation/libgps_wrapper_linux.h',
'browser/geolocation/location_arbitrator.cc',
'browser/geolocation/location_arbitrator.h',
'browser/geolocation/location_provider.cc',