Upgrade gnss to @2.0
Bug: 152575718
Test: atest VtsHalGnssV2_0TargetTest
Signed-off-by: Roman Kiryanov <rkir@google.com>
Change-Id: I6ea8562da77a6b12d53e5d92ceed9456a71ad699
diff --git a/gnss/Android.bp b/gnss/Android.bp
new file mode 100644
index 0000000..dbee0de
--- /dev/null
+++ b/gnss/Android.bp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_binary {
+ name: "android.hardware.gnss@2.0-service.ranchu",
+ vendor: true,
+ relative_install_path: "hw",
+ init_rc: ["android.hardware.gnss@2.0-service.ranchu.rc"],
+ vintf_fragments: ["android.hardware.gnss@2.0-service.ranchu.xml"],
+ defaults: ["hidl_defaults"],
+ srcs: [
+ "agnss.cpp",
+ "gnss_configuration.cpp",
+ "gnss_measurement.cpp",
+ "gnss_hw_conn.cpp",
+ "gnss_hw_listener.cpp",
+ "data_sink.cpp",
+ "gnss.cpp",
+ "main.cpp",
+ "util.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ "android.hardware.gnss@2.0",
+ "android.hardware.gnss@1.1",
+ "android.hardware.gnss@1.0",
+ "android.hardware.gnss.measurement_corrections@1.0",
+ "android.hardware.gnss.visibility_control@1.0",
+ ],
+ cflags: [
+ "-DLOG_TAG=\"android.hardware.gnss@2.0-service.ranchu\"",
+ "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION",
+ ],
+}
diff --git a/gnss/agnss.cpp b/gnss/agnss.cpp
new file mode 100644
index 0000000..ae7a0aa
--- /dev/null
+++ b/gnss/agnss.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "agnss.h"
+
+namespace goldfish {
+
+Return<void> AGnss20::setCallback(const sp<ahg20::IAGnssCallback>& callback) {
+ (void)callback;
+ return {};
+}
+
+Return<bool> AGnss20::dataConnClosed() {
+ return false;
+}
+
+Return<bool> AGnss20::dataConnFailed() {
+ return false;
+}
+
+Return<bool> AGnss20::setServer(ahg20::IAGnssCallback::AGnssType type,
+ const hidl_string& hostname,
+ int32_t port) {
+ (void)type;
+ (void)hostname;
+ (void)port;
+ return true;
+}
+
+Return<bool> AGnss20::dataConnOpen(uint64_t networkHandle,
+ const hidl_string& apn,
+ ahg20::IAGnss::ApnIpType apnIpType) {
+ (void)networkHandle;
+ (void)apn;
+ (void)apnIpType;
+ return false;
+}
+
+} // namespace goldfish
diff --git a/gnss/agnss.h b/gnss/agnss.h
new file mode 100644
index 0000000..e9df28b
--- /dev/null
+++ b/gnss/agnss.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <android/hardware/gnss/1.0/IAGnss.h>
+#include <android/hardware/gnss/2.0/IAGnss.h>
+
+namespace goldfish {
+namespace ahg = ::android::hardware::gnss;
+namespace ahg10 = ahg::V1_0;
+namespace ahg20 = ahg::V2_0;
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::Return;
+
+struct AGnss20 : public ahg20::IAGnss {
+ Return<void> setCallback(const sp<ahg20::IAGnssCallback>& callback) override;
+ Return<bool> dataConnClosed() override;
+ Return<bool> dataConnFailed() override;
+ Return<bool> setServer(ahg20::IAGnssCallback::AGnssType type,
+ const hidl_string& hostname,
+ int32_t port) override;
+ Return<bool> dataConnOpen(uint64_t networkHandle, const hidl_string& apn,
+ ahg20::IAGnss::ApnIpType apnIpType) override;
+};
+
+} // namespace goldfish
diff --git a/gnss/android.hardware.gnss@2.0-service.ranchu.rc b/gnss/android.hardware.gnss@2.0-service.ranchu.rc
new file mode 100644
index 0000000..77dca15
--- /dev/null
+++ b/gnss/android.hardware.gnss@2.0-service.ranchu.rc
@@ -0,0 +1,9 @@
+service vendor.gnss-2-0 /vendor/bin/hw/android.hardware.gnss@2.0-service.ranchu
+ interface android.hardware.gnss@2.0::IGnss default
+ interface android.hardware.gnss@1.1::IGnss default
+ interface android.hardware.gnss@1.0::IGnss default
+ class hal
+ user gps
+ group system gps radio
+ oneshot
+ disabled
diff --git a/manifest.gnss.xml b/gnss/android.hardware.gnss@2.0-service.ranchu.xml
similarity index 69%
rename from manifest.gnss.xml
rename to gnss/android.hardware.gnss@2.0-service.ranchu.xml
index 69a178f..5b417f6 100644
--- a/manifest.gnss.xml
+++ b/gnss/android.hardware.gnss@2.0-service.ranchu.xml
@@ -1,8 +1,9 @@
-<manifest version="1.0" type="device" target-level="3">
+<manifest version="1.0" type="device">
<hal format="hidl">
<name>android.hardware.gnss</name>
<transport>hwbinder</transport>
- <version>1.0</version>
+ <version>2.0</version>
+ <version>1.1</version>
<interface>
<name>IGnss</name>
<instance>default</instance>
diff --git a/gnss/data_sink.cpp b/gnss/data_sink.cpp
new file mode 100644
index 0000000..4b0c52c
--- /dev/null
+++ b/gnss/data_sink.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <log/log.h>
+#include "data_sink.h"
+
+namespace goldfish {
+
+void DataSink::gnssLocation(const ahg20::GnssLocation& loc) const {
+ std::unique_lock<std::mutex> lock(mtx);
+ if (cb20) {
+ cb20->gnssLocationCb_2_0(loc);
+ }
+}
+
+void DataSink::gnssSvStatus(const hidl_vec<ahg20::IGnssCallback::GnssSvInfo>& svInfoList20) const {
+ std::unique_lock<std::mutex> lock(mtx);
+ if (cb20) {
+ cb20->gnssSvStatusCb_2_0(svInfoList20);
+ }
+}
+
+void DataSink::gnssStatus(const ahg10::IGnssCallback::GnssStatusValue status) const {
+ std::unique_lock<std::mutex> lock(mtx);
+ if (cb20) {
+ cb20->gnssStatusCb(status);
+ }
+}
+
+void DataSink::gnssNmea(const ahg10::GnssUtcTime t,
+ const hidl_string& nmea) const {
+ std::unique_lock<std::mutex> lock(mtx);
+ if (cb20) {
+ cb20->gnssNmeaCb(t, nmea);
+ }
+}
+
+void DataSink::setCallback20(sp<ahg20::IGnssCallback> cb) {
+ std::unique_lock<std::mutex> lock(mtx);
+ cb20 = std::move(cb);
+}
+
+void DataSink::cleanup() {
+ std::unique_lock<std::mutex> lock(mtx);
+ cb20 = nullptr;
+}
+
+} // namespace goldfish
diff --git a/gnss/data_sink.h b/gnss/data_sink.h
new file mode 100644
index 0000000..d182f2d
--- /dev/null
+++ b/gnss/data_sink.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <android/hardware/gnss/2.0/IGnss.h>
+#include <mutex>
+
+namespace goldfish {
+namespace ahg = ::android::hardware::gnss;
+namespace ahg20 = ahg::V2_0;
+namespace ahg10 = ahg::V1_0;
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+
+class DataSink {
+public:
+ void gnssLocation(const ahg20::GnssLocation&) const;
+ void gnssSvStatus(const hidl_vec<ahg20::IGnssCallback::GnssSvInfo>&) const;
+ void gnssStatus(const ahg10::IGnssCallback::GnssStatusValue) const;
+ void gnssNmea(const ahg10::GnssUtcTime, const hidl_string&) const;
+
+ void setCallback20(sp<ahg20::IGnssCallback>);
+ void cleanup();
+
+private:
+ sp<ahg20::IGnssCallback> cb20;
+ mutable std::mutex mtx;
+};
+
+} // namespace goldfish
diff --git a/gnss/gnss.cpp b/gnss/gnss.cpp
new file mode 100644
index 0000000..8fa81fc
--- /dev/null
+++ b/gnss/gnss.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <log/log.h>
+
+#include "gnss.h"
+#include "gnss_configuration.h"
+#include "gnss_measurement.h"
+#include "agnss.h"
+
+namespace {
+constexpr char kGnssDeviceName[] = "Android Studio Emulator GPS";
+};
+
+namespace goldfish {
+
+Return<sp<ahg20::IGnssConfiguration>> Gnss20::getExtensionGnssConfiguration_2_0() {
+ return new GnssConfiguration20();
+}
+
+Return<sp<ahg20::IGnssDebug>> Gnss20::getExtensionGnssDebug_2_0() {
+ return nullptr;
+}
+
+Return<sp<ahg20::IAGnss>> Gnss20::getExtensionAGnss_2_0() {
+ return new AGnss20();
+}
+
+Return<sp<ahg20::IAGnssRil>> Gnss20::getExtensionAGnssRil_2_0() {
+ return nullptr;
+}
+
+Return<sp<ahg20::IGnssMeasurement>> Gnss20::getExtensionGnssMeasurement_2_0() {
+ return new GnssMeasurement20();
+}
+
+Return<bool> Gnss20::setCallback_2_0(const sp<ahg20::IGnssCallback>& callback) {
+ if (callback == nullptr) {
+ return false;
+ } else if (open()) {
+ using Caps = ahg20::IGnssCallback::Capabilities;
+ callback->gnssSetCapabilitiesCb_2_0(Caps::MEASUREMENTS | 0);
+ callback->gnssNameCb(kGnssDeviceName);
+ callback->gnssSetSystemInfoCb({.yearOfHw = 2020});
+
+ m_dataSink.setCallback20(callback);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+Return<sp<ahgmc10::IMeasurementCorrections>> Gnss20::getExtensionMeasurementCorrections() {
+ return nullptr;
+}
+
+Return<sp<ahgvc10::IGnssVisibilityControl>> Gnss20::getExtensionVisibilityControl() {
+ return nullptr;
+}
+
+Return<sp<ahg20::IGnssBatching>> Gnss20::getExtensionGnssBatching_2_0() {
+ return nullptr;
+}
+
+Return<bool> Gnss20::injectBestLocation_2_0(const ahg20::GnssLocation& location) {
+ (void)location;
+ return true;
+}
+
+Return<bool> Gnss20::setPositionMode_1_1(ahg10::IGnss::GnssPositionMode mode,
+ ahg10::IGnss::GnssPositionRecurrence recurrence,
+ uint32_t minIntervalMs, uint32_t preferredAccuracyMeters,
+ uint32_t preferredTimeMs, bool lowPowerMode) {
+ (void)mode;
+ (void)recurrence;
+ (void)minIntervalMs;
+ (void)preferredAccuracyMeters;
+ (void)preferredTimeMs;
+ (void)lowPowerMode;
+ return true;
+}
+
+Return<bool> Gnss20::start() {
+ std::unique_lock<std::mutex> lock(m_gnssHwConnMtx);
+ if (m_gnssHwConn) {
+ return m_gnssHwConn->start();
+ } else {
+ return false;
+ }
+}
+
+Return<bool> Gnss20::stop() {
+ std::unique_lock<std::mutex> lock(m_gnssHwConnMtx);
+ if (m_gnssHwConn) {
+ return m_gnssHwConn->stop();
+ } else {
+ return false;
+ }
+}
+
+Return<void> Gnss20::cleanup() {
+ {
+ std::unique_lock<std::mutex> lock(m_gnssHwConnMtx);
+ m_gnssHwConn.reset();
+ }
+
+ m_dataSink.cleanup();
+
+ return {};
+}
+
+Return<bool> Gnss20::injectTime(int64_t timeMs, int64_t timeReferenceMs,
+ int32_t uncertaintyMs) {
+ (void)timeMs;
+ (void)timeReferenceMs;
+ (void)uncertaintyMs;
+ return true;
+}
+
+Return<bool> Gnss20::injectLocation(double latitudeDegrees, double longitudeDegrees,
+ float accuracyMeters) {
+ (void)latitudeDegrees;
+ (void)longitudeDegrees;
+ (void)accuracyMeters;
+ return false;
+}
+
+Return<void> Gnss20::deleteAidingData(ahg10::IGnss::GnssAidingData aidingDataFlags) {
+ (void)aidingDataFlags;
+ return {};
+}
+
+Return<sp<ahg10::IGnssGeofencing>> Gnss20::getExtensionGnssGeofencing() {
+ return nullptr;
+}
+
+Return<sp<ahg10::IGnssNavigationMessage>> Gnss20::getExtensionGnssNavigationMessage() {
+ return nullptr;
+}
+
+Return<sp<ahg10::IGnssXtra>> Gnss20::getExtensionXtra() {
+ return nullptr;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool Gnss20::open() {
+ std::unique_lock<std::mutex> lock(m_gnssHwConnMtx);
+ if (m_gnssHwConn) {
+ return true;
+ } else {
+ auto conn = std::make_unique<GnssHwConn>(&m_dataSink);
+ if (conn->ok()) {
+ m_gnssHwConn = std::move(conn);
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
+
+//// deprecated and old versions ///////////////////////////////////////////////
+Return<bool> Gnss20::setCallback_1_1(const sp<ahg11::IGnssCallback>&) {
+ return false;
+}
+
+Return<sp<ahg11::IGnssMeasurement>> Gnss20::getExtensionGnssMeasurement_1_1() {
+ return nullptr;
+}
+
+Return<sp<ahg11::IGnssConfiguration>> Gnss20::getExtensionGnssConfiguration_1_1() {
+ return nullptr;
+}
+
+Return<bool> Gnss20::setCallback(const sp<ahg10::IGnssCallback>&) {
+ return false;
+}
+
+Return<sp<ahg10::IGnssMeasurement>> Gnss20::getExtensionGnssMeasurement() {
+ return nullptr;
+}
+
+Return<sp<ahg10::IAGnss>> Gnss20::getExtensionAGnss() {
+ return nullptr;
+}
+
+Return<sp<ahg10::IGnssNi>> Gnss20::getExtensionGnssNi() {
+ return nullptr;
+}
+
+Return<sp<ahg10::IGnssDebug>> Gnss20::getExtensionGnssDebug() {
+ return nullptr;
+}
+
+Return<sp<ahg10::IGnssBatching>> Gnss20::getExtensionGnssBatching() {
+ return nullptr;
+}
+
+Return<bool> Gnss20::injectBestLocation(const ahg10::GnssLocation&) {
+ return false;
+}
+
+Return<bool> Gnss20::setPositionMode(ahg10::IGnss::GnssPositionMode,
+ ahg10::IGnss::GnssPositionRecurrence,
+ uint32_t, uint32_t, uint32_t) {
+ return false;
+}
+
+Return<sp<ahg10::IGnssConfiguration>> Gnss20::getExtensionGnssConfiguration() {
+ return nullptr;
+}
+
+Return<sp<ahg10::IAGnssRil>> Gnss20::getExtensionAGnssRil() {
+ return nullptr;
+}
+
+} // namespace goldfish
diff --git a/gnss/gnss.h b/gnss/gnss.h
new file mode 100644
index 0000000..bc8ccfc
--- /dev/null
+++ b/gnss/gnss.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <android/hardware/gnss/2.0/IGnss.h>
+#include <mutex>
+#include <memory>
+#include "data_sink.h"
+#include "gnss_hw_conn.h"
+
+namespace goldfish {
+namespace ahg = ::android::hardware::gnss;
+namespace ahg20 = ahg::V2_0;
+namespace ahg11 = ahg::V1_1;
+namespace ahg10 = ahg::V1_0;
+namespace ahgmc10 = ahg::measurement_corrections::V1_0;
+namespace ahgvc10 = ahg::visibility_control::V1_0;
+
+using ::android::sp;
+using ::android::hardware::Return;
+
+struct Gnss20 : public ahg20::IGnss {
+ // Methods from V2_0::IGnss follow.
+ Return<sp<ahg20::IGnssConfiguration>> getExtensionGnssConfiguration_2_0() override;
+ Return<sp<ahg20::IGnssDebug>> getExtensionGnssDebug_2_0() override;
+ Return<sp<ahg20::IAGnss>> getExtensionAGnss_2_0() override;
+ Return<sp<ahg20::IAGnssRil>> getExtensionAGnssRil_2_0() override;
+ Return<sp<ahg20::IGnssMeasurement>> getExtensionGnssMeasurement_2_0() override;
+ Return<bool> setCallback_2_0(const sp<ahg20::IGnssCallback>& callback) override;
+ Return<sp<ahgmc10::IMeasurementCorrections>>
+ getExtensionMeasurementCorrections() override;
+ Return<sp<ahgvc10::IGnssVisibilityControl>> getExtensionVisibilityControl() override;
+ Return<sp<ahg20::IGnssBatching>> getExtensionGnssBatching_2_0() override;
+ Return<bool> injectBestLocation_2_0(const ahg20::GnssLocation& location) override;
+
+ // Methods from V1_1::IGnss follow.
+ Return<bool> setCallback_1_1(const sp<ahg11::IGnssCallback>& callback) override;
+ Return<bool> setPositionMode_1_1(ahg10::IGnss::GnssPositionMode mode,
+ ahg10::IGnss::GnssPositionRecurrence recurrence,
+ uint32_t minIntervalMs, uint32_t preferredAccuracyMeters,
+ uint32_t preferredTimeMs, bool lowPowerMode) override;
+ Return<sp<ahg11::IGnssConfiguration>> getExtensionGnssConfiguration_1_1() override;
+ Return<sp<ahg11::IGnssMeasurement>> getExtensionGnssMeasurement_1_1() override;
+ Return<bool> injectBestLocation(const ahg10::GnssLocation& location) override;
+
+ // Methods from V1_0::IGnss follow.
+ Return<bool> setCallback(const sp<ahg10::IGnssCallback>& callback) override;
+ Return<bool> start() override;
+ Return<bool> stop() override;
+ Return<void> cleanup() override;
+ Return<bool> injectTime(int64_t timeMs, int64_t timeReferenceMs,
+ int32_t uncertaintyMs) override;
+ Return<bool> injectLocation(double latitudeDegrees, double longitudeDegrees,
+ float accuracyMeters) override;
+ Return<void> deleteAidingData(ahg10::IGnss::GnssAidingData aidingDataFlags) override;
+ Return<bool> setPositionMode(ahg10::IGnss::GnssPositionMode mode,
+ ahg10::IGnss::GnssPositionRecurrence recurrence,
+ uint32_t minIntervalMs, uint32_t preferredAccuracyMeters,
+ uint32_t preferredTimeMs) override;
+ Return<sp<ahg10::IAGnssRil>> getExtensionAGnssRil() override;
+ Return<sp<ahg10::IGnssGeofencing>> getExtensionGnssGeofencing() override;
+ Return<sp<ahg10::IAGnss>> getExtensionAGnss() override;
+ Return<sp<ahg10::IGnssNi>> getExtensionGnssNi() override;
+ Return<sp<ahg10::IGnssMeasurement>> getExtensionGnssMeasurement() override;
+ Return<sp<ahg10::IGnssNavigationMessage>> getExtensionGnssNavigationMessage() override;
+ Return<sp<ahg10::IGnssXtra>> getExtensionXtra() override;
+ Return<sp<ahg10::IGnssConfiguration>> getExtensionGnssConfiguration() override;
+ Return<sp<ahg10::IGnssDebug>> getExtensionGnssDebug() override;
+ Return<sp<ahg10::IGnssBatching>> getExtensionGnssBatching() override;
+
+private:
+ bool open();
+ void cleanupImpl();
+ bool injectBestLocationImpl(const ahg10::GnssLocation&,
+ const ahg20::ElapsedRealtime);
+
+
+ DataSink m_dataSink; // all updates go here
+
+ std::unique_ptr<GnssHwConn> m_gnssHwConn;
+ mutable std::mutex m_gnssHwConnMtx;
+};
+
+} // namespace goldfish
diff --git a/gnss/gnss_configuration.cpp b/gnss/gnss_configuration.cpp
new file mode 100644
index 0000000..49ef6e1
--- /dev/null
+++ b/gnss/gnss_configuration.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gnss_configuration.h"
+
+namespace goldfish {
+
+Return<bool> GnssConfiguration20::setEsExtensionSec(uint32_t emergencyExtensionSeconds) {
+ (void)emergencyExtensionSeconds;
+ return false;
+}
+
+Return<bool> GnssConfiguration20::setBlacklist(const hidl_vec<ahg11::IGnssConfiguration::BlacklistedSource>& blacklist) {
+ (void)blacklist;
+ return false;
+}
+
+Return<bool> GnssConfiguration20::setSuplVersion(uint32_t version) {
+ (void)version;
+ return true;
+}
+
+Return<bool> GnssConfiguration20::setSuplMode(hidl_bitfield<SuplMode> mode) {
+ (void)mode;
+ return true;
+}
+
+Return<bool> GnssConfiguration20::setGpsLock(hidl_bitfield<GpsLock> lock) {
+ (void)lock;
+ return false;
+}
+
+Return<bool> GnssConfiguration20::setLppProfile(hidl_bitfield<LppProfile> lppProfile) {
+ (void)lppProfile;
+ return true;
+}
+
+Return<bool> GnssConfiguration20::setGlonassPositioningProtocol(hidl_bitfield<GlonassPosProtocol> protocol) {
+ (void)protocol;
+ return true;
+}
+
+Return<bool> GnssConfiguration20::setEmergencySuplPdn(bool enable) {
+ (void)enable;
+ return true;
+}
+
+/// old and deprecated /////////////////////////////////////////////////////////
+Return<bool> GnssConfiguration20::setSuplEs(bool enable) {
+ (void)enable;
+ return false;
+}
+
+} // namespace goldfish
diff --git a/gnss/gnss_configuration.h b/gnss/gnss_configuration.h
new file mode 100644
index 0000000..36e71ca
--- /dev/null
+++ b/gnss/gnss_configuration.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <android/hardware/gnss/2.0/IGnssConfiguration.h>
+
+namespace goldfish {
+namespace ahg = ::android::hardware::gnss;
+namespace ahg20 = ahg::V2_0;
+namespace ahg11 = ahg::V1_1;
+namespace ahg10 = ahg::V1_0;
+
+using ::android::sp;
+using ::android::hardware::hidl_bitfield;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+
+struct Gnss20;
+
+struct GnssConfiguration20 : public ahg20::IGnssConfiguration {
+ // Methods from ::android::hardware::gnss::V2_0::IGnssConfiguration follow.
+ Return<bool> setEsExtensionSec(uint32_t emergencyExtensionSeconds) override;
+
+ // Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow.
+ Return<bool> setBlacklist(const hidl_vec<ahg11::IGnssConfiguration::BlacklistedSource>& blacklist) override;
+
+ // Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow.
+ Return<bool> setSuplEs(bool enabled) override;
+ Return<bool> setSuplVersion(uint32_t version) override;
+ Return<bool> setSuplMode(hidl_bitfield<SuplMode> mode) override;
+ Return<bool> setGpsLock(hidl_bitfield<GpsLock> lock) override;
+ Return<bool> setLppProfile(hidl_bitfield<LppProfile> lppProfile) override;
+ Return<bool> setGlonassPositioningProtocol(hidl_bitfield<GlonassPosProtocol> protocol) override;
+ Return<bool> setEmergencySuplPdn(bool enable) override;
+};
+
+} // namespace goldfish
diff --git a/gnss/gnss_hw_conn.cpp b/gnss/gnss_hw_conn.cpp
new file mode 100644
index 0000000..371e4db
--- /dev/null
+++ b/gnss/gnss_hw_conn.cpp
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <log/log.h>
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include "gnss_hw_conn.h"
+#include "gnss_hw_listener.h"
+
+namespace {
+constexpr char kCMD_QUIT = 'q';
+constexpr char kCMD_START = 'a';
+constexpr char kCMD_STOP = 'o';
+
+ssize_t qemu_pipe_write_fully(int pipe, const void* buffer, ssize_t len) {
+ const char* p = (const char*)buffer;
+
+ while (len > 0) {
+ ssize_t n = TEMP_FAILURE_RETRY(write(pipe, p, len));
+ if (n < 0) return n;
+
+ p += n;
+ len -= n;
+ }
+
+ return 0;
+}
+
+int qemu_pipe_open_ns(const char* ns, const char* pipeName, const int flags) {
+ int fd = TEMP_FAILURE_RETRY(open("/dev/goldfish_pipe", flags));
+ if (fd < 0) {
+ return -1;
+ }
+
+ char buff[64];
+ int len = snprintf(buff, sizeof(buff), "pipe:%s:%s", ns, pipeName);
+ if (qemu_pipe_write_fully(fd, buff, len + 1)) {
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+int epollCtlAdd(int epollFd, int fd) {
+ int ret;
+
+ /* make the fd non-blocking */
+ ret = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL));
+ if (ret < 0) {
+ return ret;
+ }
+ ret = TEMP_FAILURE_RETRY(fcntl(fd, F_SETFL, ret | O_NONBLOCK));
+ if (ret < 0) {
+ return ret;
+ }
+
+ struct epoll_event ev;
+ ev.events = EPOLLIN;
+ ev.data.fd = fd;
+
+ return TEMP_FAILURE_RETRY(epoll_ctl(epollFd, EPOLL_CTL_ADD, fd, &ev));
+}
+} // namespace
+
+namespace goldfish {
+
+GnssHwConn::GnssHwConn(const DataSink* sink) {
+ m_devFd.reset(qemu_pipe_open_ns("qemud", "gps", O_RDWR));
+ if (!m_devFd.ok()) {
+ ALOGE("%s:%d: qemu_pipe_open_ns failed", __PRETTY_FUNCTION__, __LINE__);
+ return;
+ }
+
+ if (!::android::base::Socketpair(AF_LOCAL, SOCK_STREAM, 0,
+ &m_callersFd, &m_threadsFd)) {
+ ALOGE("%s:%d: Socketpair failed", __PRETTY_FUNCTION__, __LINE__);
+ m_devFd.reset();
+ return;
+ }
+
+ m_thread = std::thread([this, sink]() {
+ sink->gnssStatus(ahg10::IGnssCallback::GnssStatusValue::ENGINE_ON);
+ workerThread(m_devFd.get(), m_threadsFd.get(), sink);
+ sink->gnssStatus(ahg10::IGnssCallback::GnssStatusValue::ENGINE_OFF);
+ });
+}
+
+GnssHwConn::~GnssHwConn() {
+ if (m_thread.joinable()) {
+ sendWorkerThreadCommand(kCMD_QUIT);
+ m_thread.join();
+ }
+}
+
+bool GnssHwConn::ok() const {
+ return m_thread.joinable();
+}
+
+bool GnssHwConn::start() {
+ return ok() && sendWorkerThreadCommand(kCMD_START);
+}
+
+bool GnssHwConn::stop() {
+ return ok() && sendWorkerThreadCommand(kCMD_STOP);
+}
+
+void GnssHwConn::workerThread(int devFd, int threadsFd, const DataSink* sink) {
+ const unique_fd epollFd(epoll_create1(0));
+ if (!epollFd.ok()) {
+ ALOGE("%s:%d: epoll_create1 failed", __PRETTY_FUNCTION__, __LINE__);
+ ::abort();
+ }
+
+ epollCtlAdd(epollFd.get(), devFd);
+ epollCtlAdd(epollFd.get(), threadsFd);
+
+ GnssHwListener listener(sink);
+ bool running = false;
+
+ while (true) {
+ struct epoll_event events[2];
+ const int kTimeoutMs = 60000;
+ const int n = TEMP_FAILURE_RETRY(epoll_wait(epollFd.get(),
+ events, 2,
+ kTimeoutMs));
+ if (n < 0) {
+ ALOGE("%s:%d: epoll_wait failed with '%s'",
+ __PRETTY_FUNCTION__, __LINE__, strerror(errno));
+ continue;
+ }
+
+ for (int i = 0; i < n; ++i) {
+ const struct epoll_event* ev = &events[i];
+ const int fd = ev->data.fd;
+ const int ev_events = ev->events;
+
+ if (fd == devFd) {
+ if (ev_events & (EPOLLERR | EPOLLHUP)) {
+ ALOGE("%s:%d: epoll_wait: devFd has an error, ev_events=%x",
+ __PRETTY_FUNCTION__, __LINE__, ev_events);
+ ::abort();
+ } else if (ev_events & EPOLLIN) {
+ char buf[64];
+ while (true) {
+ int n = TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf)));
+ if (n > 0) {
+ if (running) {
+ for (int i = 0; i < n; ++i) {
+ listener.consume(buf[i]);
+ }
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ } else if (fd == threadsFd) {
+ if (ev_events & (EPOLLERR | EPOLLHUP)) {
+ ALOGE("%s:%d: epoll_wait: threadsFd has an error, ev_events=%x",
+ __PRETTY_FUNCTION__, __LINE__, ev_events);
+ ::abort();
+ } else if (ev_events & EPOLLIN) {
+ const int cmd = workerThreadRcvCommand(fd);
+ switch (cmd) {
+ case kCMD_QUIT:
+ return;
+
+ case kCMD_START:
+ if (!running) {
+ listener.reset();
+ sink->gnssStatus(ahg10::IGnssCallback::GnssStatusValue::SESSION_BEGIN);
+ running = true;
+ }
+ break;
+
+ case kCMD_STOP:
+ if (running) {
+ running = false;
+ sink->gnssStatus(ahg10::IGnssCallback::GnssStatusValue::SESSION_END);
+ }
+ break;
+
+ default:
+ ALOGE("%s:%d: workerThreadRcvCommand returned unexpected command, cmd=%d",
+ __PRETTY_FUNCTION__, __LINE__, cmd);
+ ::abort();
+ break;
+ }
+ }
+ } else {
+ ALOGE("%s:%d: epoll_wait() returned unexpected fd",
+ __PRETTY_FUNCTION__, __LINE__);
+ }
+ }
+ }
+}
+
+int GnssHwConn::workerThreadRcvCommand(const int fd) {
+ char buf;
+ if (TEMP_FAILURE_RETRY(read(fd, &buf, 1)) == 1) {
+ return buf;
+ } else {
+ return -1;
+ }
+}
+
+bool GnssHwConn::sendWorkerThreadCommand(char cmd) const {
+ return TEMP_FAILURE_RETRY(write(m_callersFd.get(), &cmd, 1)) == 1;
+}
+
+} // namespace goldfish
diff --git a/gnss/gnss_hw_conn.h b/gnss/gnss_hw_conn.h
new file mode 100644
index 0000000..06bc530
--- /dev/null
+++ b/gnss/gnss_hw_conn.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <android-base/unique_fd.h>
+#include <mutex>
+#include <thread>
+#include "data_sink.h"
+
+namespace goldfish {
+using ::android::base::unique_fd;
+
+class GnssHwConn {
+public:
+ explicit GnssHwConn(const DataSink* sink);
+ ~GnssHwConn();
+
+ bool ok() const;
+ bool start();
+ bool stop();
+
+private:
+ static void workerThread(int devFd, int threadsFd, const DataSink* sink);
+ static int workerThreadRcvCommand(int fd);
+ bool sendWorkerThreadCommand(char cmd) const;
+
+ unique_fd m_devFd; // Goldfish GPS QEMU device
+ // a pair of connected sockets to talk to the worker thread
+ unique_fd m_callersFd; // a caller writes here
+ unique_fd m_threadsFd; // the worker thread listens from here
+ std::thread m_thread;
+};
+
+} // namespace goldfish
diff --git a/gnss/gnss_hw_listener.cpp b/gnss/gnss_hw_listener.cpp
new file mode 100644
index 0000000..cde8c57
--- /dev/null
+++ b/gnss/gnss_hw_listener.cpp
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <chrono>
+#include <log/log.h>
+#include <utils/SystemClock.h>
+#include "gnss_hw_listener.h"
+#include "util.h"
+
+namespace goldfish {
+namespace {
+const char* testNmeaField(const char* i, const char* end,
+ const char* v,
+ const char sep) {
+ while (i < end) {
+ if (*v == 0) {
+ return (*i == sep) ? (i + 1) : nullptr;
+ } else if (*v == *i) {
+ ++v;
+ ++i;
+ } else {
+ return nullptr;
+ }
+ }
+
+ return nullptr;
+}
+
+const char* skipAfter(const char* i, const char* end, const char c) {
+ for (; i < end; ++i) {
+ if (*i == c) {
+ return i + 1;
+ }
+ }
+ return nullptr;
+}
+
+double convertDMMF(const int dmm, const int f, int p10) {
+ const int d = dmm / 100;
+ const int m = dmm % 100;
+ int base10 = 1;
+ for (; p10 > 0; --p10) { base10 *= 10; }
+
+ return double(d) + (m + (f / double(base10))) / 60.0;
+}
+
+double sign(char m, char positive) { return (m == positive) ? 1.0 : -1; }
+
+} // namespace
+
+GnssHwListener::GnssHwListener(const DataSink* sink): m_sink(sink) {
+ m_buffer.reserve(256);
+}
+
+void GnssHwListener::reset() {
+ m_buffer.clear();
+}
+
+void GnssHwListener::consume(char c) {
+ if (c == '$' || !m_buffer.empty()) {
+ m_buffer.push_back(c);
+ }
+ if (c == '\n') {
+ const ahg20::ElapsedRealtime ts = util::makeElapsedRealtime(util::nowNanos());
+
+ if (parse(m_buffer.data() + 1, m_buffer.data() + m_buffer.size() - 2, ts)) {
+ m_sink->gnssNmea(ts.timestampNs / 1000000,
+ hidl_string(m_buffer.data(), m_buffer.size()));
+ } else {
+ m_buffer.back() = 0;
+ ALOGW("%s:%d: failed to parse an NMEA message, '%s'",
+ __PRETTY_FUNCTION__, __LINE__, m_buffer.data());
+ }
+ m_buffer.clear();
+ } else if (m_buffer.size() >= 1024) {
+ ALOGW("%s:%d buffer was too long, dropped", __PRETTY_FUNCTION__, __LINE__);
+ m_buffer.clear();
+ }
+}
+
+bool GnssHwListener::parse(const char* begin, const char* end,
+ const ahg20::ElapsedRealtime& ts) {
+ if (const char* fields = testNmeaField(begin, end, "GPRMC", ',')) {
+ return parseGPRMC(fields, end, ts);
+ } else if (const char* fields = testNmeaField(begin, end, "GPGGA", ',')) {
+ return parseGPGGA(fields, end, ts);
+ } else {
+ return false;
+ }
+}
+
+// begin end
+// $GPRMC,195206,A,1000.0000,N,10000.0000,E,173.8,231.8,010420,004.2,W*47
+// 1 2 3 4 5 6 7 8 9 10 11 12
+// 1 195206 Time Stamp
+// 2 A validity - A-ok, V-invalid
+// 3 1000.0000 current Latitude
+// 4 N North/South
+// 5 10000.0000 current Longitude
+// 6 E East/West
+// 7 173.8 Speed in knots
+// 8 231.8 True course
+// 9 010420 Date Stamp (13 June 1994)
+// 10 004.2 Variation
+// 11 W East/West
+// 12 *70 checksum
+bool GnssHwListener::parseGPRMC(const char* begin, const char*,
+ const ahg20::ElapsedRealtime& ts) {
+ double speedKnots = 0;
+ double course = 0;
+ double variation = 0;
+ int latdmm = 0;
+ int londmm = 0;
+ int latf = 0;
+ int lonf = 0;
+ int latdmmConsumed = 0;
+ int latfConsumed = 0;
+ int londmmConsumed = 0;
+ int lonfConsumed = 0;
+ int hhmmss = -1;
+ int ddmoyy = 0;
+ char validity = 0;
+ char ns = 0; // north/south
+ char ew = 0; // east/west
+ char var_ew = 0;
+
+ if (sscanf(begin, "%06d,%c,%d.%n%d%n,%c,%d.%n%d%n,%c,%lf,%lf,%d,%lf,%c*",
+ &hhmmss, &validity,
+ &latdmm, &latdmmConsumed, &latf, &latfConsumed, &ns,
+ &londmm, &londmmConsumed, &lonf, &lonfConsumed, &ew,
+ &speedKnots, &course,
+ &ddmoyy,
+ &variation, &var_ew) != 13) {
+ return false;
+ }
+ if (validity != 'A') {
+ return false;
+ }
+
+ const double lat = convertDMMF(latdmm, latf, latfConsumed - latdmmConsumed) * sign(ns, 'N');
+ const double lon = convertDMMF(londmm, lonf, lonfConsumed - londmmConsumed) * sign(ew, 'E');
+ const double speed = speedKnots * 0.514444;
+
+ ahg20::GnssLocation loc20;
+ loc20.elapsedRealtime = ts;
+
+ auto& loc10 = loc20.v1_0;
+
+ loc10.latitudeDegrees = lat;
+ loc10.longitudeDegrees = lon;
+ loc10.speedMetersPerSec = speed;
+ loc10.bearingDegrees = course;
+ loc10.horizontalAccuracyMeters = 5;
+ loc10.speedAccuracyMetersPerSecond = .5;
+ loc10.bearingAccuracyDegrees = 30;
+ loc10.timestamp = ts.timestampNs / 1000000;
+
+ using ahg10::GnssLocationFlags;
+ loc10.gnssLocationFlags =
+ GnssLocationFlags::HAS_LAT_LONG |
+ GnssLocationFlags::HAS_SPEED |
+ GnssLocationFlags::HAS_BEARING |
+ GnssLocationFlags::HAS_HORIZONTAL_ACCURACY |
+ GnssLocationFlags::HAS_SPEED_ACCURACY |
+ GnssLocationFlags::HAS_BEARING_ACCURACY;
+
+ if (m_flags & GnssLocationFlags::HAS_ALTITUDE) {
+ loc10.altitudeMeters = m_altitude;
+ loc10.verticalAccuracyMeters = .5;
+ loc10.gnssLocationFlags |= GnssLocationFlags::HAS_ALTITUDE |
+ GnssLocationFlags::HAS_VERTICAL_ACCURACY;
+
+ }
+
+ m_sink->gnssLocation(loc20);
+ return true;
+}
+
+// $GPGGA,123519,4807.0382,N,12204.9799,W,1,6,,4.2,M,0.,M,,,*47
+// time of fix 123519 12:35:19 UTC
+// latitude 4807.0382 48 degrees, 07.0382 minutes
+// north/south N or S
+// longitude 12204.9799 122 degrees, 04.9799 minutes
+// east/west E or W
+// fix quality 1 standard GPS fix
+// satellites 1 to 12 number of satellites being tracked
+// HDOP <dontcare> horizontal dilution
+// altitude 4.2 altitude above sea-level
+// altitude units M to indicate meters
+// diff <dontcare> height of sea-level above ellipsoid
+// diff units M to indicate meters (should be <dontcare>)
+// dgps age <dontcare> time in seconds since last DGPS fix
+// dgps sid <dontcare> DGPS station id
+bool GnssHwListener::parseGPGGA(const char* begin, const char* end,
+ const ahg20::ElapsedRealtime&) {
+ double altitude = 0;
+ int latdmm = 0;
+ int londmm = 0;
+ int latf = 0;
+ int lonf = 0;
+ int latdmmConsumed = 0;
+ int latfConsumed = 0;
+ int londmmConsumed = 0;
+ int lonfConsumed = 0;
+ int hhmmss = 0;
+ int fixQuality = 0;
+ int nSatellites = 0;
+ int consumed = 0;
+ char ns = 0;
+ char ew = 0;
+ char altitudeUnit = 0;
+
+ if (sscanf(begin, "%06d,%d.%n%d%n,%c,%d.%n%d%n,%c,%d,%d,%n",
+ &hhmmss,
+ &latdmm, &latdmmConsumed, &latf, &latfConsumed, &ns,
+ &londmm, &londmmConsumed, &lonf, &lonfConsumed, &ew,
+ &fixQuality,
+ &nSatellites,
+ &consumed) != 9) {
+ return false;
+ }
+
+ begin = skipAfter(begin + consumed, end, ','); // skip HDOP
+ if (!begin) {
+ return false;
+ }
+ if (sscanf(begin, "%lf,%c,", &altitude, &altitudeUnit) != 2) {
+ return false;
+ }
+ if (altitudeUnit != 'M') {
+ return false;
+ }
+
+ m_altitude = altitude;
+ m_flags |= ahg10::GnssLocationFlags::HAS_ALTITUDE;
+
+ hidl_vec<ahg20::IGnssCallback::GnssSvInfo> svInfo(nSatellites);
+ for (int i = 0; i < nSatellites; ++i) {
+ auto* info20 = &svInfo[i];
+ auto* info10 = &info20->v1_0;
+
+ info20->constellation = ahg20::GnssConstellationType::GPS;
+ info10->svid = i + 3;
+ info10->constellation = ahg10::GnssConstellationType::GPS;
+ info10->cN0Dbhz = 30;
+ info10->elevationDegrees = 0;
+ info10->azimuthDegrees = 0;
+ info10->carrierFrequencyHz = 1.59975e+09;
+ info10->svFlag = ahg10::IGnssCallback::GnssSvFlags::HAS_CARRIER_FREQUENCY | 0;
+ }
+
+ m_sink->gnssSvStatus(svInfo);
+
+ return true;
+}
+
+} // namespace goldfish
diff --git a/gnss/gnss_hw_listener.h b/gnss/gnss_hw_listener.h
new file mode 100644
index 0000000..234908b
--- /dev/null
+++ b/gnss/gnss_hw_listener.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <vector>
+#include "data_sink.h"
+
+namespace goldfish {
+using ::android::hardware::hidl_bitfield;
+
+class GnssHwListener {
+public:
+ explicit GnssHwListener(const DataSink* sink);
+ void reset();
+ void consume(char);
+
+private:
+ bool parse(const char* begin, const char* end, const ahg20::ElapsedRealtime&);
+ bool parseGPRMC(const char* begin, const char* end, const ahg20::ElapsedRealtime&);
+ bool parseGPGGA(const char* begin, const char* end, const ahg20::ElapsedRealtime&);
+
+ const DataSink* m_sink;
+ std::vector<char> m_buffer;
+
+ double m_altitude = 0;
+
+ hidl_bitfield<ahg10::GnssLocationFlags> m_flags;
+};
+
+} // namespace goldfish
diff --git a/gnss/gnss_measurement.cpp b/gnss/gnss_measurement.cpp
new file mode 100644
index 0000000..746167d
--- /dev/null
+++ b/gnss/gnss_measurement.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <chrono>
+#include "gnss_measurement.h"
+#include "util.h"
+
+namespace goldfish {
+using ::android::hardware::hidl_vec;
+
+GnssMeasurement20::~GnssMeasurement20() {
+ if (m_isRunning) {
+ stopLocked();
+ }
+}
+
+Return<GnssMeasurementStatus10>
+GnssMeasurement20::setCallback_2_0(const sp<ahg20::IGnssMeasurementCallback>& callback,
+ bool enableFullTracking) {
+ (void)enableFullTracking;
+ if (callback == nullptr) {
+ return GnssMeasurementStatus10::ERROR_GENERIC;
+ }
+
+ std::unique_lock<std::mutex> lock(m_mtx);
+ if (m_isRunning) {
+ stopLocked();
+ }
+
+ m_callback = callback;
+ startLocked();
+
+ return GnssMeasurementStatus10::SUCCESS;
+}
+
+Return<void> GnssMeasurement20::close() {
+ std::unique_lock<std::mutex> lock(m_mtx);
+ if (m_isRunning) {
+ stopLocked();
+ }
+
+ m_callback = nullptr;
+ return {};
+}
+
+void GnssMeasurement20::startLocked() {
+ m_thread = std::thread([this](){
+ while (m_isRunning) {
+ update();
+ std::this_thread::sleep_for(std::chrono::milliseconds(1000));
+ }
+ });
+ m_isRunning = true;
+}
+
+void GnssMeasurement20::stopLocked() {
+ m_isRunning = false;
+ m_thread.join();
+}
+
+void GnssMeasurement20::update() {
+ using GnssMeasurement20 = ahg20::IGnssMeasurementCallback::GnssMeasurement;
+ using GnssAccumulatedDeltaRangeState10 = ahg10::IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState;
+ using GnssMeasurementFlags10 = ahg10::IGnssMeasurementCallback::GnssMeasurementFlags;
+ using GnssMultipathIndicator10 = ahg10::IGnssMeasurementCallback::GnssMultipathIndicator;
+ using GnssMeasurementState20 = ahg20::IGnssMeasurementCallback::GnssMeasurementState;
+ using GnssData = ahg20::IGnssMeasurementCallback::GnssData;
+
+ ahg10::IGnssMeasurementCallback::GnssMeasurement measurement10 = {
+ .flags = GnssMeasurementFlags10::HAS_CARRIER_FREQUENCY | 0,
+ .svid = 6,
+ .constellation = ahg10::GnssConstellationType::GPS,
+ .timeOffsetNs = 0.0,
+ .receivedSvTimeInNs = 8195997131077,
+ .receivedSvTimeUncertaintyInNs = 15,
+ .cN0DbHz = 30.0,
+ .pseudorangeRateMps = -484.13739013671875,
+ .pseudorangeRateUncertaintyMps = 1.0379999876022339,
+ .accumulatedDeltaRangeState = GnssAccumulatedDeltaRangeState10::ADR_STATE_UNKNOWN | 0,
+ .accumulatedDeltaRangeM = 0.0,
+ .accumulatedDeltaRangeUncertaintyM = 0.0,
+ .carrierFrequencyHz = 1.59975e+09,
+ .multipathIndicator = GnssMultipathIndicator10::INDICATOR_UNKNOWN
+ };
+ ahg11::IGnssMeasurementCallback::GnssMeasurement measurement11 = {
+ .v1_0 = measurement10,
+ .accumulatedDeltaRangeState = 0
+ };
+
+ ahg20::IGnssMeasurementCallback::GnssMeasurement measurement20 = {
+ .v1_1 = measurement11,
+ .codeType = "C",
+ .state = GnssMeasurementState20::STATE_CODE_LOCK |
+ GnssMeasurementState20::STATE_BIT_SYNC |
+ GnssMeasurementState20::STATE_SUBFRAME_SYNC |
+ GnssMeasurementState20::STATE_TOW_DECODED |
+ GnssMeasurementState20::STATE_GLO_STRING_SYNC |
+ GnssMeasurementState20::STATE_GLO_TOD_DECODED,
+ .constellation = ahg20::GnssConstellationType::GPS,
+ };
+
+ hidl_vec<GnssMeasurement20> measurements(1);
+ measurements[0] = measurement20;
+
+ const int64_t nowNs = util::nowNanos();
+ const int64_t fullBiasNs = (nowNs % 15331) * ((nowNs & 1) ? -1 : 1);
+ const int64_t hwTimeNs = nowNs + fullBiasNs; // local hardware clock
+
+ ahg10::IGnssMeasurementCallback::GnssClock clock10 = {
+ .gnssClockFlags = 0,
+ .leapSecond = 0,
+ .timeNs = hwTimeNs,
+ .timeUncertaintyNs = 4.5,
+ .fullBiasNs = fullBiasNs,
+ .biasNs = 1.5,
+ .biasUncertaintyNs = .7,
+ .driftNsps = -51.757811607455452,
+ .driftUncertaintyNsps = 310.64968328491528,
+ .hwClockDiscontinuityCount = 1
+ };
+
+ GnssData gnssData = {
+ .measurements = measurements,
+ .clock = clock10,
+ .elapsedRealtime = util::makeElapsedRealtime(util::nowNanos())
+ };
+
+ std::unique_lock<std::mutex> lock(m_mtx);
+ m_callback->gnssMeasurementCb_2_0(gnssData);
+}
+
+/// old and deprecated /////////////////////////////////////////////////////////
+Return<GnssMeasurementStatus10> GnssMeasurement20::setCallback_1_1(const sp<ahg11::IGnssMeasurementCallback>&, bool) {
+ return GnssMeasurementStatus10::ERROR_GENERIC;
+}
+
+Return<GnssMeasurementStatus10> GnssMeasurement20::setCallback(const sp<ahg10::IGnssMeasurementCallback>&) {
+ return GnssMeasurementStatus10::ERROR_GENERIC;
+}
+
+
+} // namespace goldfish
diff --git a/gnss/gnss_measurement.h b/gnss/gnss_measurement.h
new file mode 100644
index 0000000..8da3b4c
--- /dev/null
+++ b/gnss/gnss_measurement.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <atomic>
+#include <mutex>
+#include <thread>
+#include <android/hardware/gnss/2.0/IGnssMeasurement.h>
+
+namespace goldfish {
+namespace ahg = ::android::hardware::gnss;
+namespace ahg20 = ahg::V2_0;
+namespace ahg11 = ahg::V1_1;
+namespace ahg10 = ahg::V1_0;
+using GnssMeasurementStatus10 = ahg10::IGnssMeasurement::GnssMeasurementStatus;
+
+using ::android::sp;
+using ::android::hardware::Return;
+
+struct GnssMeasurement20 : public ahg20::IGnssMeasurement {
+ ~GnssMeasurement20();
+
+ // Methods from V2_0::IGnssMeasurement follow.
+ Return<GnssMeasurementStatus10> setCallback_2_0(const sp<ahg20::IGnssMeasurementCallback>& callback, bool enableFullTracking) override;
+
+ // Methods from V1_1::IGnssMeasurement follow.
+ Return<GnssMeasurementStatus10> setCallback_1_1(const sp<ahg11::IGnssMeasurementCallback>& callback, bool enableFullTracking) override;
+
+ // Methods from V1_0::IGnssMeasurement follow.
+ Return<GnssMeasurementStatus10> setCallback(const sp<ahg10::IGnssMeasurementCallback>& callback) override;
+ Return<void> close() override;
+
+private:
+ void startLocked();
+ void stopLocked();
+ void update();
+
+ sp<ahg20::IGnssMeasurementCallback> m_callback;
+ std::thread m_thread;
+ std::atomic<bool> m_isRunning;
+ mutable std::mutex m_mtx;
+};
+
+} // namespace goldfish
diff --git a/gnss/main.cpp b/gnss/main.cpp
new file mode 100644
index 0000000..ede611b
--- /dev/null
+++ b/gnss/main.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <hidl/HidlLazyUtils.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "gnss.h"
+
+int main(int /* argc */, char* /* argv */ []) {
+ ::android::sp<goldfish::Gnss20> gnss(new goldfish::Gnss20);
+
+ ::android::hardware::configureRpcThreadpool(1, true);
+
+ auto serviceRegistrar = ::android::hardware::LazyServiceRegistrar::getInstance();
+ CHECK_EQ(serviceRegistrar.registerService(gnss), ::android::OK)
+ << "Failed to register Gnss HAL";
+
+ ::android::hardware::joinRpcThreadpool();
+}
diff --git a/gnss/util.cpp b/gnss/util.cpp
new file mode 100644
index 0000000..d0be41b
--- /dev/null
+++ b/gnss/util.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <chrono>
+#include "util.h"
+
+namespace goldfish {
+namespace util {
+
+int64_t nowNanos() {
+ using namespace std::chrono;
+ return time_point_cast<nanoseconds>(system_clock::now()).time_since_epoch().count();
+}
+
+ahg20::ElapsedRealtime makeElapsedRealtime(long long timestampNs) {
+ ahg20::ElapsedRealtime ts = {
+ .flags = ahg20::ElapsedRealtimeFlags::HAS_TIMESTAMP_NS |
+ ahg20::ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS,
+ .timestampNs = static_cast<uint64_t>(timestampNs),
+ .timeUncertaintyNs = 1000000
+ };
+
+ return ts;
+}
+
+} // namespace util
+} // namespace goldfish
diff --git a/gnss/util.h b/gnss/util.h
new file mode 100644
index 0000000..ba1b5a4
--- /dev/null
+++ b/gnss/util.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/2.0/types.h>
+
+namespace goldfish {
+namespace ahg20 = ::android::hardware::gnss::V2_0;
+
+namespace util {
+
+int64_t nowNanos();
+
+ahg20::ElapsedRealtime makeElapsedRealtime(long long timestampNs);
+
+} // namespace util
+} // namespace goldfish
diff --git a/gps/Android.mk b/gps/Android.mk
deleted file mode 100644
index 7196f5f..0000000
--- a/gps/Android.mk
+++ /dev/null
@@ -1,55 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-# We're moving the emulator-specific platform libs to
-# development.git/tools/emulator/. The following test is to ensure
-# smooth builds even if the tree contains both versions.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-# HAL module implemenation stored in
-# hw/<GPS_HARDWARE_MODULE_ID>.<ro.hardware>.so
-include $(CLEAR_VARS)
-
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_CFLAGS += -DQEMU_HARDWARE
-LOCAL_SHARED_LIBRARIES := liblog libcutils libhardware
-LOCAL_C_INCLUDES += \
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../../goldfish-opengl/shared/OpenglCodecCommon
-LOCAL_SRC_FILES := gps_qemu.c
-ifeq ($(TARGET_PRODUCT),vbox_x86)
-LOCAL_MODULE := gps.vbox_x86
-else
-LOCAL_MODULE := gps.goldfish
-endif
-include $(BUILD_SHARED_LIBRARY)
-
-
-include $(CLEAR_VARS)
-
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_CFLAGS += -DQEMU_HARDWARE
-LOCAL_SHARED_LIBRARIES := liblog libcutils libhardware
-LOCAL_C_INCLUDES += \
- $(LOCAL_PATH)/../include \
- $(LOCAL_PATH)/../../goldfish-opengl/shared/OpenglCodecCommon
-LOCAL_SRC_FILES := gps_qemu.c
-LOCAL_MODULE := gps.ranchu
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/gps/gps_qemu.c b/gps/gps_qemu.c
deleted file mode 100644
index cfb8e36..0000000
--- a/gps/gps_qemu.c
+++ /dev/null
@@ -1,1150 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* this implements a GPS hardware library for the Android emulator.
- * the following code should be built as a shared library that will be
- * placed into /system/lib/hw/gps.goldfish.so
- *
- * it will be loaded by the code in hardware/libhardware/hardware.c
- * which is itself called from android_location_GpsLocationProvider.cpp
- */
-
-
-#include <errno.h>
-#include <pthread.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <sys/epoll.h>
-#include <math.h>
-#include <time.h>
-
-#define LOG_TAG "gps_qemu"
-#include <log/log.h>
-#include <cutils/sockets.h>
-#include <cutils/properties.h>
-#include <hardware/gps.h>
-#include "qemud.h"
-
-/* the name of the qemu-controlled pipe */
-#define QEMUD_CHANNEL_NAME "gps"
-
-#define GPS_DEBUG 0
-
-#undef D
-#if GPS_DEBUG
-# define D(...) ALOGD(__VA_ARGS__)
-#else
-# define D(...) ((void)0)
-#endif
-
-/*****************************************************************/
-/*****************************************************************/
-/***** *****/
-/***** N M E A T O K E N I Z E R *****/
-/***** *****/
-/*****************************************************************/
-/*****************************************************************/
-
-typedef struct {
- const char* p;
- const char* end;
-} Token;
-
-#define MAX_NMEA_TOKENS 64
-
-typedef struct {
- int count;
- Token tokens[ MAX_NMEA_TOKENS ];
-} NmeaTokenizer;
-
-/* this is the state of our connection to the qemu_gpsd daemon */
-typedef struct {
- int init;
- int fd;
- GpsCallbacks callbacks;
- pthread_t thread;
- int control[2];
- pthread_mutex_t lock;
- GpsMeasurementCallbacks* measurement_callbacks; /* protected by lock:
- accessed by main and child threads */
- bool gnss_enabled; /* set by ro.kernel.qemu.gps.gnss_enabled=1 */
- bool fix_provided_by_gnss; /* set by ro.kernel.qemu.gps.fix_by_gnss=1 */
-} GpsState;
-
-static GpsState _gps_state[1];
-
-static int
-nmea_tokenizer_init( NmeaTokenizer* t, const char* p, const char* end )
-{
- int count = 0;
-
- // the initial '$' is optional
- if (p < end && p[0] == '$')
- p += 1;
-
- // remove trailing newline
- if (end > p && end[-1] == '\n') {
- end -= 1;
- if (end > p && end[-1] == '\r')
- end -= 1;
- }
-
- // get rid of checksum at the end of the sentecne
- if (end >= p+3 && end[-3] == '*') {
- end -= 3;
- }
-
- while (p < end) {
- const char* q = p;
-
- q = memchr(p, ',', end-p);
- if (q == NULL)
- q = end;
-
- if (count < MAX_NMEA_TOKENS) {
- t->tokens[count].p = p;
- t->tokens[count].end = q;
- count += 1;
- }
- if (q < end)
- q += 1;
-
- p = q;
- }
-
- t->count = count;
- return count;
-}
-
-static Token
-nmea_tokenizer_get( NmeaTokenizer* t, int index )
-{
- Token tok;
- static const char* dummy = "";
-
- if (index < 0 || index >= t->count) {
- tok.p = tok.end = dummy;
- } else
- tok = t->tokens[index];
-
- return tok;
-}
-
-
-static int64_t
-str2int64( const char* p, const char* end )
-{
- int64_t result = 0;
-
-#if GPS_DEBUG
- char temp[1024];
- snprintf(temp, sizeof(temp), "'%.*s'", end-p, p);
-#endif
-
- bool is_negative = false;
- if (end > p && *p == '-') {
- is_negative = true;
- ++p;
- }
-
- int len = end - p;
-
- for ( ; len > 0; len--, p++ )
- {
- int c;
-
- if (p >= end) {
- ALOGE("parse error at func %s line %d", __func__, __LINE__);
- goto Fail;
- }
-
- c = *p - '0';
- if ((unsigned)c >= 10) {
- ALOGE("parse error at func %s line %d on %c", __func__, __LINE__, c);
- goto Fail;
- }
-
- result = result*10 + c;
- }
- if (is_negative) {
- result = - result;
- }
-#if GPS_DEBUG
- ALOGD("%s ==> %" PRId64, temp, result);
-#endif
- return result;
-
-Fail:
- return -1;
-}
-
-static int
-str2int( const char* p, const char* end )
-{
- /* danger: downward convert to 32bit */
- return str2int64(p, end);
-}
-
-static double
-str2float( const char* p, const char* end )
-{
- int len = end - p;
- char temp[64];
-
- if (len >= (int)sizeof(temp)) {
- ALOGE("%s %d input is too long: '%.*s'", __func__, __LINE__, end-p, p);
- return 0.;
- }
-
- memcpy( temp, p, len );
- temp[len] = 0;
- return strtod( temp, NULL );
-}
-
-/*****************************************************************/
-/*****************************************************************/
-/***** *****/
-/***** N M E A P A R S E R *****/
-/***** *****/
-/*****************************************************************/
-/*****************************************************************/
-
-#define NMEA_MAX_SIZE 1024
-
-typedef struct {
- int pos;
- int overflow;
- int utc_year;
- int utc_mon;
- int utc_day;
- GpsLocation fix;
- gps_location_callback callback;
- GnssData gnss_data;
- int gnss_count;
-
- char in[ NMEA_MAX_SIZE+1 ];
- bool gnss_enabled; /* passed in from _gps_state */
- bool fix_provided_by_gnss; /* passed in from _gps_state */
-} NmeaReader;
-
-static void
-nmea_reader_init( NmeaReader* r )
-{
- memset( r, 0, sizeof(*r) );
-
- r->pos = 0;
- r->overflow = 0;
- r->utc_year = -1;
- r->utc_mon = -1;
- r->utc_day = -1;
- r->callback = NULL;
- r->fix.size = sizeof(r->fix);
-
- GpsState* s = _gps_state;
- r->gnss_enabled = s->gnss_enabled;
- r->fix_provided_by_gnss = s->fix_provided_by_gnss;
-
-}
-
-
-static int
-nmea_reader_update_time( NmeaReader* r, Token tok )
-{
- int hour, minute;
- double seconds;
- struct tm tm;
- time_t fix_time;
-
- if (tok.p + 6 > tok.end)
- return -1;
-
- if (r->utc_year < 0) {
- // no date yet, get current one
- time_t now = time(NULL);
- gmtime_r( &now, &tm );
- r->utc_year = tm.tm_year + 1900;
- r->utc_mon = tm.tm_mon + 1;
- r->utc_day = tm.tm_mday;
- }
-
- hour = str2int(tok.p, tok.p+2);
- minute = str2int(tok.p+2, tok.p+4);
- seconds = str2float(tok.p+4, tok.end);
-
- tm.tm_hour = hour;
- tm.tm_min = minute;
- tm.tm_sec = (int) seconds;
- tm.tm_year = r->utc_year - 1900;
- tm.tm_mon = r->utc_mon - 1;
- tm.tm_mday = r->utc_day;
- tm.tm_isdst = -1;
-
- fix_time = timegm( &tm );
- r->fix.timestamp = (long long)fix_time * 1000;
- return 0;
-}
-
-static int
-nmea_reader_update_date( NmeaReader* r, Token date, Token time )
-{
- Token tok = date;
- int day, mon, year;
-
- if (tok.p + 6 != tok.end) {
- D("date not properly formatted: '%.*s'", tok.end-tok.p, tok.p);
- return -1;
- }
- day = str2int(tok.p, tok.p+2);
- mon = str2int(tok.p+2, tok.p+4);
- year = str2int(tok.p+4, tok.p+6) + 2000;
-
- if ((day|mon|year) < 0) {
- D("date not properly formatted: '%.*s'", tok.end-tok.p, tok.p);
- return -1;
- }
-
- r->utc_year = year;
- r->utc_mon = mon;
- r->utc_day = day;
-
- return nmea_reader_update_time( r, time );
-}
-
-
-static double
-convert_from_hhmm( Token tok )
-{
- double val = str2float(tok.p, tok.end);
- int degrees = (int)(floor(val) / 100);
- double minutes = val - degrees*100.;
- double dcoord = degrees + minutes / 60.0;
- return dcoord;
-}
-
-
-static int
-nmea_reader_update_latlong( NmeaReader* r,
- Token latitude,
- char latitudeHemi,
- Token longitude,
- char longitudeHemi )
-{
- double lat, lon;
- Token tok;
-
- r->fix.flags &= ~GPS_LOCATION_HAS_LAT_LONG;
-
- tok = latitude;
- if (tok.p + 6 > tok.end) {
- D("latitude is too short: '%.*s'", tok.end-tok.p, tok.p);
- return -1;
- }
- lat = convert_from_hhmm(tok);
- if (latitudeHemi == 'S')
- lat = -lat;
-
- tok = longitude;
- if (tok.p + 6 > tok.end) {
- D("longitude is too short: '%.*s'", tok.end-tok.p, tok.p);
- return -1;
- }
- lon = convert_from_hhmm(tok);
- if (longitudeHemi == 'W')
- lon = -lon;
-
- r->fix.flags |= GPS_LOCATION_HAS_LAT_LONG;
- r->fix.latitude = lat;
- r->fix.longitude = lon;
- return 0;
-}
-
-
-static int
-nmea_reader_update_altitude( NmeaReader* r,
- Token altitude,
- Token __unused units )
-{
- Token tok = altitude;
-
- r->fix.flags &= ~GPS_LOCATION_HAS_ALTITUDE;
-
- if (tok.p >= tok.end)
- return -1;
-
- r->fix.flags |= GPS_LOCATION_HAS_ALTITUDE;
- r->fix.altitude = str2float(tok.p, tok.end);
- return 0;
-}
-
-
-static int
-nmea_reader_update_bearing( NmeaReader* r,
- Token bearing )
-{
- Token tok = bearing;
-
- r->fix.flags &= ~GPS_LOCATION_HAS_BEARING;
-
- if (tok.p >= tok.end)
- return -1;
-
- r->fix.flags |= GPS_LOCATION_HAS_BEARING;
- r->fix.bearing = str2float(tok.p, tok.end);
- return 0;
-}
-
-
-static int
-nmea_reader_update_speed( NmeaReader* r,
- Token speed )
-{
- Token tok = speed;
-
- r->fix.flags &= ~GPS_LOCATION_HAS_SPEED;
-
- if (tok.p >= tok.end)
- return -1;
-
- r->fix.flags |= GPS_LOCATION_HAS_SPEED;
- r->fix.speed = str2float(tok.p, tok.end);
- return 0;
-}
-
-static int
-nmea_reader_update_accuracy( NmeaReader* r )
-{
- // Always return 20m accuracy.
- // Possibly parse it from the NMEA sentence in the future.
- r->fix.flags |= GPS_LOCATION_HAS_ACCURACY;
- r->fix.accuracy = 20;
- return 0;
-}
-
-static int64_t get_int64(Token tok) {
- return str2int64(tok.p, tok.end);
-}
-
-static int get_int(Token tok) {
- return str2int(tok.p, tok.end);
-}
-
-static double get_double(Token tok) {
- return str2float(tok.p, tok.end);
-}
-
-static bool has_all_required_flags(GpsLocationFlags flags) {
- return ( flags & GPS_LOCATION_HAS_LAT_LONG
- && flags & GPS_LOCATION_HAS_ALTITUDE
- );
-}
-
-static bool is_ready_to_send(NmeaReader* r) {
- if (has_all_required_flags(r->fix.flags)) {
- if (r->gnss_enabled && r->fix_provided_by_gnss) {
- return (r->gnss_count > 2); /* required by CTS */
- }
- return true;
- }
- return false;
-}
-
-static void
-nmea_reader_set_callback( NmeaReader* r, gps_location_callback cb )
-{
- r->callback = cb;
- if (cb != NULL && is_ready_to_send(r)) {
- D("%s: sending latest fix to new callback", __FUNCTION__);
- r->callback( &r->fix );
- }
-}
-
-static void
-nmea_reader_parse( NmeaReader* r )
-{
- /* we received a complete sentence, now parse it to generate
- * a new GPS fix...
- */
- NmeaTokenizer tzer[1];
- Token tok;
-
- D("Received: '%.*s'", r->pos, r->in);
- if (r->pos < 9) {
- D("Too short. discarded.");
- return;
- }
-
- nmea_tokenizer_init(tzer, r->in, r->in + r->pos);
-#if GPS_DEBUG
- {
- int n;
- D("Found %d tokens", tzer->count);
- for (n = 0; n < tzer->count; n++) {
- Token tok = nmea_tokenizer_get(tzer,n);
- D("%2d: '%.*s'", n, tok.end-tok.p, tok.p);
- }
- }
-#endif
-
- tok = nmea_tokenizer_get(tzer, 0);
- if (tok.p + 5 > tok.end) {
- D("sentence id '%.*s' too short, ignored.", tok.end-tok.p, tok.p);
- return;
- }
-
- // ignore first two characters.
- tok.p += 2;
- if ( !memcmp(tok.p, "GGA", 3) ) {
- // GPS fix
- Token tok_time = nmea_tokenizer_get(tzer,1);
- Token tok_latitude = nmea_tokenizer_get(tzer,2);
- Token tok_latitudeHemi = nmea_tokenizer_get(tzer,3);
- Token tok_longitude = nmea_tokenizer_get(tzer,4);
- Token tok_longitudeHemi = nmea_tokenizer_get(tzer,5);
- Token tok_altitude = nmea_tokenizer_get(tzer,9);
- Token tok_altitudeUnits = nmea_tokenizer_get(tzer,10);
-
- nmea_reader_update_time(r, tok_time);
- nmea_reader_update_latlong(r, tok_latitude,
- tok_latitudeHemi.p[0],
- tok_longitude,
- tok_longitudeHemi.p[0]);
- nmea_reader_update_altitude(r, tok_altitude, tok_altitudeUnits);
-
- } else if ( !memcmp(tok.p, "GNSSv1", 6) ) {
- r->gnss_data.clock.time_ns = get_int64(nmea_tokenizer_get(tzer,1));
- r->gnss_data.clock.full_bias_ns = get_int64(nmea_tokenizer_get(tzer,2));
- r->gnss_data.clock.bias_ns = get_double(nmea_tokenizer_get(tzer,3));
- r->gnss_data.clock.bias_uncertainty_ns = get_double(nmea_tokenizer_get(tzer,4));
- r->gnss_data.clock.drift_nsps = get_double(nmea_tokenizer_get(tzer,5));
- r->gnss_data.clock.drift_uncertainty_nsps = get_double(nmea_tokenizer_get(tzer,6));
- r->gnss_data.clock.hw_clock_discontinuity_count = get_int(nmea_tokenizer_get(tzer,7));
- r->gnss_data.clock.flags = get_int(nmea_tokenizer_get(tzer,8));
-
- r->gnss_data.measurement_count = get_int(nmea_tokenizer_get(tzer,9));
-
- for (int i = 0; i < r->gnss_data.measurement_count; ++i) {
- r->gnss_data.measurements[i].svid = get_int(nmea_tokenizer_get(tzer,10 + i*9 + 0));
- r->gnss_data.measurements[i].constellation = get_int(nmea_tokenizer_get(tzer,10 + i*9 + 1));
- r->gnss_data.measurements[i].state = get_int(nmea_tokenizer_get(tzer,10 + i*9 + 2));
- r->gnss_data.measurements[i].received_sv_time_in_ns = get_int64(nmea_tokenizer_get(tzer,10 + i*9 + 3));
- r->gnss_data.measurements[i].received_sv_time_uncertainty_in_ns = get_int64(nmea_tokenizer_get(tzer,10 + i*9 + 4));
- r->gnss_data.measurements[i].c_n0_dbhz = get_double(nmea_tokenizer_get(tzer,10 + i*9 + 5));
- r->gnss_data.measurements[i].pseudorange_rate_mps = get_double(nmea_tokenizer_get(tzer,10 + i*9 + 6));
- r->gnss_data.measurements[i].pseudorange_rate_uncertainty_mps = get_double(nmea_tokenizer_get(tzer,10 + i*9 + 7));
- r->gnss_data.measurements[i].carrier_frequency_hz = get_double(nmea_tokenizer_get(tzer,10 + i*9 + 8));
- r->gnss_data.measurements[i].flags = GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY;
- }
- } else if ( !memcmp(tok.p, "GSA", 3) ) {
- // do something ?
- } else if ( !memcmp(tok.p, "RMC", 3) ) {
- Token tok_time = nmea_tokenizer_get(tzer,1);
- Token tok_fixStatus = nmea_tokenizer_get(tzer,2);
- Token tok_latitude = nmea_tokenizer_get(tzer,3);
- Token tok_latitudeHemi = nmea_tokenizer_get(tzer,4);
- Token tok_longitude = nmea_tokenizer_get(tzer,5);
- Token tok_longitudeHemi = nmea_tokenizer_get(tzer,6);
- Token tok_speed = nmea_tokenizer_get(tzer,7);
- Token tok_bearing = nmea_tokenizer_get(tzer,8);
- Token tok_date = nmea_tokenizer_get(tzer,9);
-
- D("in RMC, fixStatus=%c", tok_fixStatus.p[0]);
- if (tok_fixStatus.p[0] == 'A')
- {
- nmea_reader_update_date( r, tok_date, tok_time );
-
- nmea_reader_update_latlong( r, tok_latitude,
- tok_latitudeHemi.p[0],
- tok_longitude,
- tok_longitudeHemi.p[0] );
-
- nmea_reader_update_bearing( r, tok_bearing );
- nmea_reader_update_speed ( r, tok_speed );
- }
- } else {
- tok.p -= 2;
- D("unknown sentence '%.*s", tok.end-tok.p, tok.p);
- }
-
- // Always update accuracy
- nmea_reader_update_accuracy( r );
-
- if (is_ready_to_send(r)) {
-#if GPS_DEBUG
- char temp[256];
- char* p = temp;
- char* end = p + sizeof(temp);
- struct tm utc;
-
- p += snprintf( p, end-p, "sending fix" );
- if (r->fix.flags & GPS_LOCATION_HAS_LAT_LONG) {
- p += snprintf(p, end-p, " lat=%g lon=%g", r->fix.latitude, r->fix.longitude);
- }
- if (r->fix.flags & GPS_LOCATION_HAS_ALTITUDE) {
- p += snprintf(p, end-p, " altitude=%g", r->fix.altitude);
- }
- if (r->fix.flags & GPS_LOCATION_HAS_SPEED) {
- p += snprintf(p, end-p, " speed=%g", r->fix.speed);
- }
- if (r->fix.flags & GPS_LOCATION_HAS_BEARING) {
- p += snprintf(p, end-p, " bearing=%g", r->fix.bearing);
- }
- if (r->fix.flags & GPS_LOCATION_HAS_ACCURACY) {
- p += snprintf(p,end-p, " accuracy=%g", r->fix.accuracy);
- }
- //The unit of r->fix.timestamp is millisecond.
- time_t timestamp = r->fix.timestamp / 1000;
- gmtime_r( (time_t*) ×tamp, &utc );
- p += snprintf(p, end-p, " time=%s", asctime( &utc ) );
-#endif
- if (r->callback) {
- D("%s", temp);
- r->callback( &r->fix );
- /* we have sent a complete fix, now prepare for next complete fix */
- r->fix.flags = 0;
- }
- else {
- D("no callback, keeping data until needed !");
- }
- }
-
- if (r->gnss_data.measurement_count > 0) {
- /* this runs in child thread */
- GpsState* s = _gps_state;
- pthread_mutex_lock(&s->lock);
- if (s->measurement_callbacks && s->measurement_callbacks->gnss_measurement_callback) {
- D("sending gnss measurement data");
- s->measurement_callbacks->gnss_measurement_callback(&r->gnss_data);
- r->gnss_data.measurement_count = 0;
- r->gnss_count ++;
- } else {
- D("no gnss measurement_callbacks, keeping data until needed !");
- }
- pthread_mutex_unlock(&s->lock);
- }
-}
-
-
-static void
-nmea_reader_addc( NmeaReader* r, int c )
-{
- if (r->overflow) {
- r->overflow = (c != '\n');
- return;
- }
-
- if (r->pos >= (int) sizeof(r->in)-1 ) {
- r->overflow = 1;
- r->pos = 0;
- return;
- }
-
- r->in[r->pos] = (char)c;
- r->pos += 1;
-
- if (c == '\n') {
- nmea_reader_parse( r );
- r->pos = 0;
- }
-}
-
-
-/*****************************************************************/
-/*****************************************************************/
-/***** *****/
-/***** C O N N E C T I O N S T A T E *****/
-/***** *****/
-/*****************************************************************/
-/*****************************************************************/
-
-/* commands sent to the gps thread */
-enum {
- CMD_QUIT = 0,
- CMD_START = 1,
- CMD_STOP = 2
-};
-
-
-
-static void
-gps_state_done( GpsState* s )
-{
- // tell the thread to quit, and wait for it
- char cmd = CMD_QUIT;
- void* dummy;
- write( s->control[0], &cmd, 1 );
- pthread_join(s->thread, &dummy);
-
- pthread_mutex_destroy(&s->lock);
-
- // close the control socket pair
- close( s->control[0] ); s->control[0] = -1;
- close( s->control[1] ); s->control[1] = -1;
-
- // close connection to the QEMU GPS daemon
- close( s->fd ); s->fd = -1;
- s->init = 0;
-}
-
-
-static void
-gps_state_start( GpsState* s )
-{
- char cmd = CMD_START;
- int ret;
-
- do { ret=write( s->control[0], &cmd, 1 ); }
- while (ret < 0 && errno == EINTR);
-
- if (ret != 1)
- D("%s: could not send CMD_START command: ret=%d: %s",
- __FUNCTION__, ret, strerror(errno));
-}
-
-
-static void
-gps_state_stop( GpsState* s )
-{
- char cmd = CMD_STOP;
- int ret;
-
- do { ret=write( s->control[0], &cmd, 1 ); }
- while (ret < 0 && errno == EINTR);
-
- if (ret != 1)
- D("%s: could not send CMD_STOP command: ret=%d: %s",
- __FUNCTION__, ret, strerror(errno));
-}
-
-
-static int
-epoll_register( int epoll_fd, int fd )
-{
- struct epoll_event ev;
- int ret, flags;
-
- /* important: make the fd non-blocking */
- flags = fcntl(fd, F_GETFL);
- fcntl(fd, F_SETFL, flags | O_NONBLOCK);
-
- ev.events = EPOLLIN;
- ev.data.fd = fd;
- do {
- ret = epoll_ctl( epoll_fd, EPOLL_CTL_ADD, fd, &ev );
- } while (ret < 0 && errno == EINTR);
- return ret;
-}
-
-
-// static int
-// epoll_deregister( int epoll_fd, int fd )
-// {
-// int ret;
-// do {
-// ret = epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd, NULL );
-// } while (ret < 0 && errno == EINTR);
-// return ret;
-// }
-
-/* this is the main thread, it waits for commands from gps_state_start/stop and,
- * when started, messages from the QEMU GPS daemon. these are simple NMEA sentences
- * that must be parsed to be converted into GPS fixes sent to the framework
- */
-static void
-gps_state_thread( void* arg )
-{
- GpsState* state = (GpsState*) arg;
- NmeaReader reader[1];
- int epoll_fd = epoll_create(2);
- int started = 0;
- int gps_fd = state->fd;
- int control_fd = state->control[1];
- GpsStatus gps_status;
- gps_status.size = sizeof(gps_status);
-
- GnssSvStatus gnss_sv_status;
- memset(&gnss_sv_status, 0, sizeof(gnss_sv_status));
- gnss_sv_status.size = sizeof(gnss_sv_status);
- gnss_sv_status.num_svs = 1;
- gnss_sv_status.gnss_sv_list[0].size = sizeof(gnss_sv_status.gnss_sv_list[0]);
- gnss_sv_status.gnss_sv_list[0].svid = 17;
- gnss_sv_status.gnss_sv_list[0].constellation = GNSS_CONSTELLATION_GPS;
- gnss_sv_status.gnss_sv_list[0].c_n0_dbhz = 60.0;
- gnss_sv_status.gnss_sv_list[0].elevation = 30.0;
- gnss_sv_status.gnss_sv_list[0].azimuth = 30.0;
- gnss_sv_status.gnss_sv_list[0].flags = GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY;
-
- nmea_reader_init( reader );
-
- // register control file descriptors for polling
- epoll_register( epoll_fd, control_fd );
- epoll_register( epoll_fd, gps_fd );
-
- D("gps thread running");
-
- // now loop
- for (;;) {
- struct epoll_event events[2];
- int ne, nevents;
-
- int timeout = -1;
- if (gps_status.status == GPS_STATUS_SESSION_BEGIN) {
- timeout = 10 * 1000; // 10 seconds
- }
- nevents = epoll_wait( epoll_fd, events, 2, timeout );
- if (state->callbacks.gnss_sv_status_cb) {
- state->callbacks.gnss_sv_status_cb(&gnss_sv_status);
- }
- // update satilite info
- if (nevents < 0) {
- if (errno != EINTR)
- ALOGE("epoll_wait() unexpected error: %s", strerror(errno));
- continue;
- }
- D("gps thread received %d events", nevents);
- for (ne = 0; ne < nevents; ne++) {
- if ((events[ne].events & (EPOLLERR|EPOLLHUP)) != 0) {
- ALOGE("EPOLLERR or EPOLLHUP after epoll_wait() !?");
- return;
- }
- if ((events[ne].events & EPOLLIN) != 0) {
- int fd = events[ne].data.fd;
-
- if (fd == control_fd)
- {
- char cmd = 0xFF;
- int ret;
- D("gps control fd event");
- do {
- ret = read( fd, &cmd, 1 );
- } while (ret < 0 && errno == EINTR);
-
- if (cmd == CMD_QUIT) {
- D("gps thread quitting on demand");
- return;
- }
- else if (cmd == CMD_START) {
- if (!started) {
- D("gps thread starting location_cb=%p", state->callbacks.location_cb);
- started = 1;
- reader->gnss_count = 0;
- nmea_reader_set_callback( reader, state->callbacks.location_cb );
- gps_status.status = GPS_STATUS_SESSION_BEGIN;
- if (state->callbacks.status_cb) {
- state->callbacks.status_cb(&gps_status);
- }
- }
- }
- else if (cmd == CMD_STOP) {
- if (started) {
- D("gps thread stopping");
- started = 0;
- nmea_reader_set_callback( reader, NULL );
- gps_status.status = GPS_STATUS_SESSION_END;
- if (state->callbacks.status_cb) {
- state->callbacks.status_cb(&gps_status);
- }
- }
- }
- }
- else if (fd == gps_fd)
- {
- char buff[32];
- D("gps fd event");
- for (;;) {
- int nn, ret;
-
- ret = read( fd, buff, sizeof(buff) );
- if (ret < 0) {
- if (errno == EINTR)
- continue;
- if (errno != EWOULDBLOCK)
- ALOGE("error while reading from gps daemon socket: %s:", strerror(errno));
- break;
- }
- D("received %d bytes: %.*s", ret, ret, buff);
- for (nn = 0; nn < ret; nn++)
- nmea_reader_addc( reader, buff[nn] );
- }
- D("gps fd event end");
- }
- else
- {
- ALOGE("epoll_wait() returned unkown fd %d ?", fd);
- }
- }
- }
- }
-}
-
-#define BUFF_SIZE (PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX + 2)
-static bool is_gnss_measurement_enabled() {
- char temp[BUFF_SIZE];
- property_get("ro.kernel.qemu.gps.gnss_enabled", temp, "");
- return (strncmp(temp, "1", 1) == 0);
-}
-
-static bool is_fix_provided_by_gnss_measurement() {
- char temp[BUFF_SIZE];
- property_get("ro.kernel.qemu.gps.fix_by_gnss", temp, "");
- return (strncmp(temp, "1", 1) == 0);
-}
-
-static void
-gps_state_init( GpsState* state, GpsCallbacks* callbacks )
-{
- state->init = 1;
- state->control[0] = -1;
- state->control[1] = -1;
- state->fd = -1;
-
- state->fd = qemud_channel_open(QEMUD_CHANNEL_NAME);
-
- if (state->fd < 0) {
- D("no gps emulation detected");
- return;
- }
-
- D("gps emulation will read from '%s' qemud channel", QEMUD_CHANNEL_NAME );
-
- if ( socketpair( AF_LOCAL, SOCK_STREAM, 0, state->control ) < 0 ) {
- ALOGE("could not create thread control socket pair: %s", strerror(errno));
- goto Fail;
- }
-
- state->gnss_enabled = is_gnss_measurement_enabled();
- D("gnss_enabled:%s", state->gnss_enabled ? "yes":"no");
- state->fix_provided_by_gnss = is_fix_provided_by_gnss_measurement();
-
- pthread_mutex_init (&state->lock, (const pthread_mutexattr_t *) NULL);
-
- state->thread = callbacks->create_thread_cb( "gps_state_thread", gps_state_thread, state );
-
- if ( !state->thread ) {
- ALOGE("could not create gps thread: %s", strerror(errno));
- goto Fail;
- }
-
- state->callbacks = *callbacks;
-
- // Explicitly initialize capabilities
- state->callbacks.set_capabilities_cb(0);
-
-
-
-
- // Setup system info, we are pre 2016 hardware.
- GnssSystemInfo sysinfo;
- sysinfo.size = sizeof(GnssSystemInfo);
- sysinfo.year_of_hw = 2015;
- state->callbacks.set_system_info_cb(&sysinfo);
- if (state->gnss_enabled) {
- D("enabling GPS_CAPABILITY_MEASUREMENTS");
- state->callbacks.set_capabilities_cb(GPS_CAPABILITY_MEASUREMENTS);
- }
-
- D("gps state initialized");
- return;
-
-Fail:
- gps_state_done( state );
-}
-
-
-/*****************************************************************/
-/*****************************************************************/
-/***** *****/
-/***** I N T E R F A C E *****/
-/***** *****/
-/*****************************************************************/
-/*****************************************************************/
-
-
-static int
-qemu_gps_init(GpsCallbacks* callbacks)
-{
- GpsState* s = _gps_state;
-
- if (!s->init)
- gps_state_init(s, callbacks);
-
- if (s->fd < 0)
- return -1;
-
- return 0;
-}
-
-static void
-qemu_gps_cleanup(void)
-{
- GpsState* s = _gps_state;
-
- if (s->init)
- gps_state_done(s);
-}
-
-
-static int
-qemu_gps_start()
-{
- GpsState* s = _gps_state;
-
- if (!s->init) {
- D("%s: called with uninitialized state !!", __FUNCTION__);
- return -1;
- }
-
- D("%s: called", __FUNCTION__);
- gps_state_start(s);
- return 0;
-}
-
-
-static int
-qemu_gps_stop()
-{
- GpsState* s = _gps_state;
-
- if (!s->init) {
- D("%s: called with uninitialized state !!", __FUNCTION__);
- return -1;
- }
-
- D("%s: called", __FUNCTION__);
- gps_state_stop(s);
- return 0;
-}
-
-
-static int
-qemu_gps_inject_time(GpsUtcTime __unused time,
- int64_t __unused timeReference,
- int __unused uncertainty)
-{
- return 0;
-}
-
-static int
-qemu_gps_inject_location(double __unused latitude,
- double __unused longitude,
- float __unused accuracy)
-{
- return 0;
-}
-
-static void
-qemu_gps_delete_aiding_data(GpsAidingData __unused flags)
-{
-}
-
-static int qemu_gps_set_position_mode(GpsPositionMode __unused mode,
- GpsPositionRecurrence __unused recurrence,
- uint32_t __unused min_interval,
- uint32_t __unused preferred_accuracy,
- uint32_t __unused preferred_time)
-{
- // FIXME - support fix_frequency
- return 0;
-}
-
-static int qemu_gps_measurement_init(GpsMeasurementCallbacks* callbacks) {
- /* this runs in main thread */
- D("calling %s with input %p", __func__, callbacks);
- GpsState* s = _gps_state;
- pthread_mutex_lock(&s->lock);
- s->measurement_callbacks = callbacks;
- pthread_mutex_unlock(&s->lock);
-
- return 0;
-}
-
-static void qemu_gps_measurement_close() {
- /* this runs in main thread */
- D("calling %s", __func__);
- GpsState* s = _gps_state;
- pthread_mutex_lock(&s->lock);
- s->measurement_callbacks = NULL;
- pthread_mutex_unlock(&s->lock);
-}
-
-static const GpsMeasurementInterface qemuGpsMeasurementInterface = {
- sizeof(GpsMeasurementInterface),
- qemu_gps_measurement_init,
- qemu_gps_measurement_close,
-};
-
-static const void*
-qemu_gps_get_extension(const char* name)
-{
- if(name && strcmp(name, GPS_MEASUREMENT_INTERFACE) == 0) {
- /* when this is called, _gps_state is not initialized yet */
- bool gnss_enabled = is_gnss_measurement_enabled();
- if (gnss_enabled) {
- D("calling %s with GPS_MEASUREMENT_INTERFACE enabled", __func__);
- return &qemuGpsMeasurementInterface;
- }
- }
- return NULL;
-}
-
-static const GpsInterface qemuGpsInterface = {
- sizeof(GpsInterface),
- qemu_gps_init,
- qemu_gps_start,
- qemu_gps_stop,
- qemu_gps_cleanup,
- qemu_gps_inject_time,
- qemu_gps_inject_location,
- qemu_gps_delete_aiding_data,
- qemu_gps_set_position_mode,
- qemu_gps_get_extension,
-};
-
-const GpsInterface* gps__get_gps_interface(struct gps_device_t* __unused dev)
-{
- return &qemuGpsInterface;
-}
-
-static int open_gps(const struct hw_module_t* module,
- char const* __unused name,
- struct hw_device_t** device)
-{
- struct gps_device_t *dev = malloc(sizeof(struct gps_device_t));
- memset(dev, 0, sizeof(*dev));
-
- dev->common.tag = HARDWARE_DEVICE_TAG;
- dev->common.version = 0;
- dev->common.module = (struct hw_module_t*)module;
-// dev->common.close = (int (*)(struct hw_device_t*))close_lights;
- dev->get_gps_interface = gps__get_gps_interface;
-
- *device = (struct hw_device_t*)dev;
- return 0;
-}
-
-
-static struct hw_module_methods_t gps_module_methods = {
- .open = open_gps
-};
-
-struct hw_module_t HAL_MODULE_INFO_SYM = {
- .tag = HARDWARE_MODULE_TAG,
- .version_major = 1,
- .version_minor = 0,
- .id = GPS_HARDWARE_MODULE_ID,
- .name = "Goldfish GPS Module",
- .author = "The Android Open Source Project",
- .methods = &gps_module_methods,
-};
diff --git a/sepolicy/common/file_contexts b/sepolicy/common/file_contexts
index e6afeb3..a1be172 100644
--- a/sepolicy/common/file_contexts
+++ b/sepolicy/common/file_contexts
@@ -41,6 +41,7 @@
/vendor/bin/hw/android\.hardware\.authsecret@1\.0-service u:object_r:hal_authsecret_default_exec:s0
/vendor/bin/hw/android\.hardware\.input\.classifier@1\.0-service.default u:object_r:hal_input_classifier_default_exec:s0
/vendor/bin/hw/android\.hardware\.power\.stats@1\.0-service\.mock u:object_r:hal_power_stats_default_exec:s0
+/vendor/bin/hw/android\.hardware\.gnss@2\.0-service\.ranchu u:object_r:hal_gnss_default_exec:s0
/vendor/lib(64)?/hw/vulkan\.ranchu\.so u:object_r:same_process_hal_file:s0
/vendor/lib(64)?/hw/gralloc\.ranchu\.so u:object_r:same_process_hal_file:s0
diff --git a/vendor.mk b/vendor.mk
index ffc0a1c..c8e758d 100644
--- a/vendor.mk
+++ b/vendor.mk
@@ -54,8 +54,6 @@
libOpenglSystemCommon \
libgoldfish-ril \
qemu-props \
- gps.goldfish \
- gps.ranchu \
fingerprint.goldfish \
audio.primary.goldfish \
audio.primary.goldfish_legacy \
@@ -110,10 +108,7 @@
NavigationBarMode2ButtonOverlay \
ifneq ($(EMULATOR_VENDOR_NO_GNSS),true)
-PRODUCT_PACKAGES += \
- android.hardware.gnss@1.0-service \
- android.hardware.gnss@1.0-impl
-DEVICE_MANIFEST_FILE += device/generic/goldfish/manifest.gnss.xml
+PRODUCT_PACKAGES += android.hardware.gnss@2.0-service.ranchu
endif
ifneq ($(EMULATOR_VENDOR_NO_SENSORS),true)