GNSS HAL & VTS for Duty Cycling & Low Power APIs.
Defintions for 2 GNSS Android P features:
- The Duty Cycling OFF API to enable high accuracy applications development
- The Low Power Mode GNSS API to save power when indoor
VTS tests for both features.
Bug: 64009176
Test: hidl-gen/compile/build checks, no functional tests yet
Change-Id: I4a41757e4ad6747f22a7e9ae1e0024f083c5fbfb
diff --git a/gnss/1.1/Android.bp b/gnss/1.1/Android.bp
index 09f65a4..6909807 100644
--- a/gnss/1.1/Android.bp
+++ b/gnss/1.1/Android.bp
@@ -9,6 +9,7 @@
srcs: [
"IGnss.hal",
"IGnssCallback.hal",
+ "IGnssMeasurement.hal",
],
interfaces: [
"android.hardware.gnss@1.0",
diff --git a/gnss/1.1/IGnss.hal b/gnss/1.1/IGnss.hal
index f26d47c..d5e0c3e 100644
--- a/gnss/1.1/IGnss.hal
+++ b/gnss/1.1/IGnss.hal
@@ -18,17 +18,56 @@
import @1.0::IGnss;
+import IGnssMeasurement;
import IGnssCallback;
/** Represents the standard GNSS (Global Navigation Satellite System) interface. */
interface IGnss extends @1.0::IGnss {
/**
- * Opens the interface and provides the callback routines
- * to the implementation of this interface.
+ * Opens the interface and provides the callback routines to the implementation of this
+ * interface.
*
* @param callback Callback interface for IGnss.
*
* @return success Returns true on success.
*/
setCallback_1_1(IGnssCallback callback) generates (bool success);
+
+ /**
+ * Sets the GnssPositionMode parameter, its associated recurrence value,
+ * the time between fixes, requested fix accuracy, time to first fix.
+ *
+ * @param mode Parameter must be one of MS_BASED or STANDALONE. It is allowed by the platform
+ * (and it is recommended) to fallback to MS_BASED if MS_ASSISTED is passed in, and MS_BASED
+ * is supported.
+ * @param recurrence GNSS postion recurrence value, either periodic or single.
+ * @param minIntervalMs Represents the time between fixes in milliseconds.
+ * @param preferredAccuracyMeters Represents the requested fix accuracy in meters.
+ * @param preferredTimeMs Represents the requested time to first fix in milliseconds.
+ * @param lowPowerMode When true, HAL must make strong tradeoffs to substantially restrict power
+ * use. Specifically, in the case of a several second long minIntervalMs, the GNSS chipset
+ * must not, on average, run power hungry operations like RF and signal searches for more
+ * than one second per interval, and must make exactly one call to gnssSvStatusCb(), and
+ * either zero or one call to GnssLocationCb() at each interval. When false, HAL must
+ * operate in the nominal mode (similar to V1.0 where this flag wasn't present) and is
+ * expected to make power and performance tradoffs such as duty-cycling when signal
+ * conditions are good and more active searches to reacquire GNSS signals when no signals
+ * are present.
+ *
+ * @return success Returns true if successful.
+ */
+ setPositionMode_1_1(GnssPositionMode mode,
+ GnssPositionRecurrence recurrence,
+ uint32_t minIntervalMs,
+ uint32_t preferredAccuracyMeters,
+ uint32_t preferredTimeMs,
+ bool lowPowerMode)
+ generates (bool success);
+
+ /**
+ * This method returns the IGnssMeasurement interface.
+ *
+ * @return gnssMeasurementIface Handle to the IGnssMeasurement interface.
+ */
+ getExtensionGnssMeasurement_1_1() generates (IGnssMeasurement gnssMeasurementIface);
};
\ No newline at end of file
diff --git a/gnss/1.1/IGnssMeasurement.hal b/gnss/1.1/IGnssMeasurement.hal
new file mode 100644
index 0000000..75df5a8
--- /dev/null
+++ b/gnss/1.1/IGnssMeasurement.hal
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.hardware.gnss@1.1;
+
+import @1.0::IGnssMeasurement;
+import @1.0::IGnssMeasurementCallback;
+
+/**
+ * Extended interface for GNSS Measurements support.
+ */
+interface IGnssMeasurement extends @1.0::IGnssMeasurement {
+
+ /**
+ * Initializes the interface and registers the callback routines with the HAL. After a
+ * successful call to 'setCallback_1_1' the HAL must begin to provide updates at an average
+ * output rate of 1Hz (occasional intra-measurement time offsets in the range from 0-2000msec
+ * can be tolerated.)
+ *
+ * @param callback Handle to GnssMeasurement callback interface.
+ * @param enableFullTracking If true, GNSS chipset must switch off duty cycling. In such mode
+ * no clock discontinuities are expected and, when supported, carrier phase should be
+ * continuous in good signal conditions. All constellations and frequency bands that the
+ * chipset supports must be reported in this mode. The GNSS chipset is allowed to consume
+ * more power in this mode. If false, API must behave as in HAL V1_0, optimizing power via
+ * duty cycling, constellations and frequency limits, etc.
+ *
+ * @return initRet Returns SUCCESS if successful. Returns ERROR_ALREADY_INIT if a callback has
+ * already been registered without a corresponding call to 'close'. Returns ERROR_GENERIC
+ * for any other error. The HAL must not generate any other updates upon returning this
+ * error code.
+ */
+ setCallback_1_1(IGnssMeasurementCallback callback, bool enableFullTracking)
+ generates (GnssMeasurementStatus initRet);
+
+};
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.cpp b/gnss/1.1/vts/functional/gnss_hal_test.cpp
index 40fd71b..2f4dd93 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test.cpp
@@ -22,7 +22,12 @@
#include <chrono>
// Implementations for the main test class for GNSS HAL
-GnssHalTest::GnssHalTest() : info_called_count_(0), name_called_count_(0), notify_count_(0) {}
+GnssHalTest::GnssHalTest()
+ : info_called_count_(0),
+ capabilities_called_count_(0),
+ location_called_count_(0),
+ name_called_count_(0),
+ notify_count_(0) {}
void GnssHalTest::SetUp() {
gnss_hal_ = ::testing::VtsHalHidlTargetTestBase::getService<IGnss>();
@@ -56,7 +61,6 @@
return status;
}
-// Actual (test) callback handlers
Return<void> GnssHalTest::GnssCallback::gnssSetSystemInfoCb(
const IGnssCallback::GnssSystemInfo& info) {
ALOGI("Info received, year %d", info.yearOfHw);
@@ -66,11 +70,26 @@
return Void();
}
-// Actual (test) callback handlers
+Return<void> GnssHalTest::GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) {
+ ALOGI("Capabilities received %d", capabilities);
+ parent_.capabilities_called_count_++;
+ parent_.last_capabilities_ = capabilities;
+ parent_.notify();
+ return Void();
+}
+
Return<void> GnssHalTest::GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) {
ALOGI("Name received: %s", name.c_str());
parent_.name_called_count_++;
parent_.last_name_ = name;
parent_.notify();
return Void();
-}
\ No newline at end of file
+}
+
+Return<void> GnssHalTest::GnssCallback::gnssLocationCb(const GnssLocation& location) {
+ ALOGI("Location received");
+ parent_.location_called_count_++;
+ parent_.last_location_ = location;
+ parent_.notify();
+ return Void();
+}
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.h b/gnss/1.1/vts/functional/gnss_hal_test.h
index 05cb4ab..bbc8d9f 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.h
+++ b/gnss/1.1/vts/functional/gnss_hal_test.h
@@ -31,8 +31,9 @@
using android::hardware::gnss::V1_1::IGnss;
using android::hardware::gnss::V1_1::IGnssCallback;
-
+using android::hardware::gnss::V1_0::GnssLocationFlags;
using android::sp;
+#define TIMEOUT_SEC 2 // for basic commands/responses
// The main test class for GNSS HAL.
class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase {
@@ -72,13 +73,134 @@
Return<void> gnssAcquireWakelockCb() override { return Void(); }
Return<void> gnssReleaseWakelockCb() override { return Void(); }
Return<void> gnssRequestTimeCb() override { return Void(); }
- Return<void> gnssLocationCb(const GnssLocation& /* location */) override { return Void(); }
- Return<void> gnssSetCapabilitesCb(uint32_t /* capabilities */) override { return Void(); }
// Actual (test) callback handlers
+ Return<void> gnssLocationCb(const GnssLocation& location) override;
+ Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
Return<void> gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) override;
Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
};
+ /*
+ * StartAndGetSingleLocation:
+ * Helper function to get one Location and check fields
+ *
+ * returns true if a location was successfully generated
+ */
+ bool StartAndGetSingleLocation(bool checkAccuracies) {
+ auto result = gnss_hal_->start();
+
+ EXPECT_TRUE(result.isOk());
+ EXPECT_TRUE(result);
+
+ /*
+ * GPS signals initially optional for this test, so don't expect fast fix,
+ * or no timeout, unless signal is present
+ */
+ int firstGnssLocationTimeoutSeconds = 15;
+
+ wait(firstGnssLocationTimeoutSeconds);
+ EXPECT_EQ(location_called_count_, 1);
+
+ if (location_called_count_ > 0) {
+ // don't require speed on first fix
+ CheckLocation(last_location_, checkAccuracies, false);
+ return true;
+ }
+ return false;
+ }
+
+ /*
+ * CheckLocation:
+ * Helper function to vet Location fields when calling setPositionMode_1_1()
+ */
+ void CheckLocation(GnssLocation& location, bool checkAccuracies, bool checkSpeed) {
+ EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_LAT_LONG);
+ EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_ALTITUDE);
+ if (checkSpeed) {
+ EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED);
+ }
+ EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_HORIZONTAL_ACCURACY);
+ // New uncertainties available in O must be provided,
+ // at least when paired with modern hardware (2017+)
+ if (checkAccuracies) {
+ EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY);
+ if (checkSpeed) {
+ EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY);
+ if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) {
+ EXPECT_TRUE(location.gnssLocationFlags &
+ GnssLocationFlags::HAS_BEARING_ACCURACY);
+ }
+ }
+ }
+ EXPECT_GE(location.latitudeDegrees, -90.0);
+ EXPECT_LE(location.latitudeDegrees, 90.0);
+ EXPECT_GE(location.longitudeDegrees, -180.0);
+ EXPECT_LE(location.longitudeDegrees, 180.0);
+ EXPECT_GE(location.altitudeMeters, -1000.0);
+ EXPECT_LE(location.altitudeMeters, 30000.0);
+ if (checkSpeed) {
+ EXPECT_GE(location.speedMetersPerSec, 0.0);
+ EXPECT_LE(location.speedMetersPerSec, 5.0); // VTS tests are stationary.
+
+ // Non-zero speeds must be reported with an associated bearing
+ if (location.speedMetersPerSec > 0.0) {
+ EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING);
+ }
+ }
+
+ /*
+ * Tolerating some especially high values for accuracy estimate, in case of
+ * first fix with especially poor geometry (happens occasionally)
+ */
+ EXPECT_GT(location.horizontalAccuracyMeters, 0.0);
+ EXPECT_LE(location.horizontalAccuracyMeters, 250.0);
+
+ /*
+ * Some devices may define bearing as -180 to +180, others as 0 to 360.
+ * Both are okay & understandable.
+ */
+ if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) {
+ EXPECT_GE(location.bearingDegrees, -180.0);
+ EXPECT_LE(location.bearingDegrees, 360.0);
+ }
+ if (location.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY) {
+ EXPECT_GT(location.verticalAccuracyMeters, 0.0);
+ EXPECT_LE(location.verticalAccuracyMeters, 500.0);
+ }
+ if (location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY) {
+ EXPECT_GT(location.speedAccuracyMetersPerSecond, 0.0);
+ EXPECT_LE(location.speedAccuracyMetersPerSecond, 50.0);
+ }
+ if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING_ACCURACY) {
+ EXPECT_GT(location.bearingAccuracyDegrees, 0.0);
+ EXPECT_LE(location.bearingAccuracyDegrees, 360.0);
+ }
+
+ // Check timestamp > 1.48e12 (47 years in msec - 1970->2017+)
+ EXPECT_GT(location.timestamp, 1.48e12);
+ }
+
+ /*
+ * StopAndClearLocations:
+ * Helper function to stop locations
+ *
+ * returns true if a location was successfully generated
+ */
+ void StopAndClearLocations() {
+ auto result = gnss_hal_->stop();
+
+ EXPECT_TRUE(result.isOk());
+ EXPECT_TRUE(result);
+
+ /*
+ * Clear notify/waiting counter, allowing up till the timeout after
+ * the last reply for final startup messages to arrive (esp. system
+ * info.)
+ */
+ while (wait(TIMEOUT_SEC) == std::cv_status::no_timeout) {
+ }
+ }
+
sp<IGnss> gnss_hal_; // GNSS HAL to call into
sp<IGnssCallback> gnss_cb_; // Primary callback interface
@@ -87,6 +209,10 @@
*/
int info_called_count_;
IGnssCallback::GnssSystemInfo last_info_;
+ uint32_t last_capabilities_;
+ int capabilities_called_count_;
+ int location_called_count_;
+ GnssLocation last_location_;
int name_called_count_;
android::hardware::hidl_string last_name_;
diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
index 075940c..47bad34 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
@@ -18,7 +18,7 @@
#include <VtsHalHidlTargetTestBase.h>
-#define TIMEOUT_SEC 2 // for basic commands/responses
+using android::hardware::gnss::V1_1::IGnssMeasurement;
/*
* SetupTeardownCreateCleanup:
@@ -30,7 +30,7 @@
/*
* SetCallbackResponses:
- * Sets up the callback, awaits the info & name
+ * Sets up the callback, awaits the capability, info & name
*/
TEST_F(GnssHalTest, SetCallbackResponses) {
gnss_cb_ = new GnssCallback(*this);
@@ -45,11 +45,68 @@
ASSERT_TRUE(result);
/*
- * Both name and systemInfo callbacks should trigger
+ * All capabilities, name and systemInfo callbacks should trigger
*/
EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
+ EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
+ EXPECT_EQ(capabilities_called_count_, 1);
EXPECT_EQ(info_called_count_, 1);
EXPECT_EQ(name_called_count_, 1);
+}
+
+/*
+ * TestGnssMeasurementCallback:
+ * Gets the GnssMeasurementExtension and verify that it returns an actual extension.
+ */
+TEST_F(GnssHalTest, TestGnssMeasurementCallback) {
+ auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_1_1();
+ ASSERT_TRUE(gnssMeasurement.isOk());
+ if (last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS) {
+ sp<IGnssMeasurement> iGnssMeas = gnssMeasurement;
+ EXPECT_NE(iGnssMeas, nullptr);
+ }
+}
+
+/*
+ * GetLocation:
+ * Turns on location, waits for at least 5 locations allowing max of LOCATION_TIMEOUT_SUBSEQUENT_SEC
+ * between one location and the next. Also ensure that MIN_INTERVAL_MSEC is respected by waiting
+ * NO_LOCATION_PERIOD_SEC and verfiy that no location is received. Also perform validity checks on
+ * each received location.
+ */
+TEST_F(GnssHalTest, GetLocationLowPower) {
+#define MIN_INTERVAL_MSEC 5000
+#define PREFERRED_ACCURACY 0 // Ideally perfect (matches GnssLocationProvider)
+#define PREFERRED_TIME_MSEC 0 // Ideally immediate
+
+#define LOCATION_TIMEOUT_SUBSEQUENT_SEC (MIN_INTERVAL_MSEC + 1000) / 1000
+#define NO_LOCATION_PERIOD_SEC 2
+#define LOCATIONS_TO_CHECK 5
+#define LOW_POWER_MODE true
+
+ bool checkMoreAccuracies = (info_called_count_ > 0 && last_info_.yearOfHw >= 2017);
+
+ auto result = gnss_hal_->setPositionMode_1_1(
+ IGnss::GnssPositionMode::MS_BASED, IGnss::GnssPositionRecurrence::RECURRENCE_PERIODIC,
+ MIN_INTERVAL_MSEC, PREFERRED_ACCURACY, PREFERRED_TIME_MSEC, LOW_POWER_MODE);
+
+ ASSERT_TRUE(result.isOk());
+ EXPECT_TRUE(result);
+
+ EXPECT_TRUE(StartAndGetSingleLocation(checkMoreAccuracies));
+
+ for (int i = 1; i < LOCATIONS_TO_CHECK; i++) {
+ // Verify that MIN_INTERVAL_MSEC is respected by waiting NO_LOCATION_PERIOD_SEC and
+ // ensure that no location is received yet
+ wait(NO_LOCATION_PERIOD_SEC);
+ EXPECT_EQ(location_called_count_, i);
+ EXPECT_EQ(std::cv_status::no_timeout,
+ wait(LOCATION_TIMEOUT_SUBSEQUENT_SEC - NO_LOCATION_PERIOD_SEC));
+ EXPECT_EQ(location_called_count_, i + 1);
+ CheckLocation(last_location_, checkMoreAccuracies, true);
+ }
+
+ StopAndClearLocations();
}
\ No newline at end of file