diff --git a/current.txt b/current.txt index 024cf1c0f1..c716c5431b 100644 --- a/current.txt +++ b/current.txt @@ -619,8 +619,9 @@ f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardwar 4d85e814f94949dae4dc6cb82bbd7d6bb24ffafda6ddb2eac928d2a4fc2e21ce android.hardware.cas@1.2::types 66931c2506fbb5af61f20138cb05e0a09e7bf67d6964c231d27c648933bb33ec android.hardware.drm@1.3::ICryptoFactory 994d08ab27d613022c258a9ec48cece7adf2a305e92df5d76ef923e2c6665f64 android.hardware.drm@1.3::IDrmFactory -1bd8028b974bf1d65cfa102196a2b008afc5d42fe73fed2cb94fa7533d07f581 android.hardware.gnss@2.1::IGnss +3dacec7801968e1e4479724dc0180442d9e915466bff051f80996266b1a51c2c android.hardware.gnss@2.1::IGnss ba62e1e8993bfb9f27fa04816fa0f2241ae2d01edfa3d0c04182e2e5de80045c android.hardware.gnss@2.1::IGnssCallback +ccdf3c0fb2c02a6d4dc57afb276c3497ae8172b80b00ebc0bf8a0238dd38b01d android.hardware.gnss@2.1::IGnssConfiguration 5a125c49ca83629e22afc8c39e865509343bfa2c38f0baea9a186bbac103492d android.hardware.gnss@2.1::IGnssMeasurement 0bfb291708dd4a7c6ec6b9883e2b8592357edde8d7e962ef83918e4a2154ce69 android.hardware.gnss@2.1::IGnssMeasurementCallback ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth diff --git a/gnss/2.1/Android.bp b/gnss/2.1/Android.bp index 5d3d62df80..8b0c374469 100644 --- a/gnss/2.1/Android.bp +++ b/gnss/2.1/Android.bp @@ -11,6 +11,7 @@ hidl_interface { "IGnssCallback.hal", "IGnssMeasurement.hal", "IGnssMeasurementCallback.hal", + "IGnssConfiguration.hal", ], interfaces: [ "android.hardware.gnss.measurement_corrections@1.0", diff --git a/gnss/2.1/IGnss.hal b/gnss/2.1/IGnss.hal index 812f9cc370..2d633928dd 100644 --- a/gnss/2.1/IGnss.hal +++ b/gnss/2.1/IGnss.hal @@ -20,6 +20,7 @@ import @2.0::IGnss; import IGnssCallback; import IGnssMeasurement; +import IGnssConfiguration; /** * Represents the standard GNSS (Global Navigation Satellite System) interface. @@ -50,4 +51,15 @@ interface IGnss extends @2.0::IGnss { * @return gnssMeasurementIface Handle to the IGnssMeasurement interface. */ getExtensionGnssMeasurement_2_1() generates (IGnssMeasurement gnssMeasurementIface); + + /** + * This method returns the IGnssConfiguration interface. + * + * At least one of getExtensionGnssConfiguration(), getExtensionGnssConfiguration_1_1(), + * getExtensionGnssConfiguration_2_0(), and getExtensionGnssConfiguration_2_1() methods must + * return a non-null handle, and the other methods must return nullptr. + * + * @return gnssConfigurationIface Handle to the IGnssConfiguration interface. + */ + getExtensionGnssConfiguration_2_1() generates (IGnssConfiguration gnssConfigurationIface); }; \ No newline at end of file diff --git a/gnss/2.1/IGnssConfiguration.hal b/gnss/2.1/IGnssConfiguration.hal new file mode 100644 index 0000000000..8360ba9953 --- /dev/null +++ b/gnss/2.1/IGnssConfiguration.hal @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2019 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@2.1; + +import @2.0::IGnssConfiguration; +import @2.0::GnssConstellationType; + +/** + * Extended interface for GNSS Configuration support. + */ +interface IGnssConfiguration extends @2.0::IGnssConfiguration { + /** + * Represents a blacklisted source, updating the GnssConstellationType to 2.0, which supports + * IRNSS. + */ + struct BlacklistedSource { + /** + * Defines the constellation of the given satellite(s). + */ + GnssConstellationType constellation; + + /** + * Satellite (space vehicle) ID number, as defined in GnssSvInfo::svid + * + * Or 0 to blacklist all svid's for the specified constellation + */ + int16_t svid; + }; + + /** + * Injects a vector of BlacklistedSource(s) which the HAL must not use to calculate the + * GNSS location output. + * + * The superset of all satellite sources provided, including wildcards, in the latest call + * to this method, is the set of satellites sources that must not be used in calculating + * location. + * + * All measurements from the specified satellites, across frequency bands, are blacklisted + * together. + * + * If this method is never called after the IGnssConfiguration.hal connection is made on boot, + * or is called with an empty vector, then no satellites are to be blacklisted as a result of + * this API. + * + * This blacklist must be considered as an additional source of which satellites + * should not be trusted for location on top of existing sources of similar information + * such as satellite broadcast health being unhealthy and measurement outlier removal. + * + * @param blacklist The BlacklistedSource(s) of satellites the HAL must not use. + * + * @return success Whether the HAL accepts and abides by the provided blacklist. + */ + setBlacklist_2_1(vec blacklist) generates (bool success); +}; \ No newline at end of file diff --git a/gnss/2.1/default/Android.bp b/gnss/2.1/default/Android.bp index a7cf63da5a..57233aa6cb 100644 --- a/gnss/2.1/default/Android.bp +++ b/gnss/2.1/default/Android.bp @@ -23,6 +23,7 @@ cc_binary { srcs: [ "Gnss.cpp", "GnssMeasurement.cpp", + "GnssConfiguration.cpp", "service.cpp" ], shared_libs: [ diff --git a/gnss/2.1/default/Gnss.cpp b/gnss/2.1/default/Gnss.cpp index 2771f27b79..384fd49cf6 100644 --- a/gnss/2.1/default/Gnss.cpp +++ b/gnss/2.1/default/Gnss.cpp @@ -32,7 +32,7 @@ namespace implementation { sp Gnss::sGnssCallback_2_1 = nullptr; -Gnss::Gnss() : mMinIntervalMs(1000) {} +Gnss::Gnss() : mMinIntervalMs(1000), mGnssConfiguration{new GnssConfiguration()} {} Gnss::~Gnss() { stop(); @@ -48,7 +48,7 @@ Return Gnss::start() { mIsActive = true; mThread = std::thread([this]() { while (mIsActive == true) { - auto svStatus = Utils::getMockSvInfoListV2_1(); + auto svStatus = filterBlacklistedSatellitesV2_1(Utils::getMockSvInfoListV2_1()); this->reportSvStatus(svStatus); const auto location = Utils::getMockLocationV2_0(); @@ -60,6 +60,16 @@ Return Gnss::start() { return true; } +hidl_vec Gnss::filterBlacklistedSatellitesV2_1(hidl_vec gnssSvInfoList) { + for (uint32_t i = 0; i < gnssSvInfoList.size(); i++) { + if (mGnssConfiguration->isBlacklistedV2_1(gnssSvInfoList[i])) { + gnssSvInfoList[i].v2_0.v1_0.svFlag &= + ~static_cast(V1_0::IGnssCallback::GnssSvFlags::USED_IN_FIX); + } + } + return gnssSvInfoList; +} + Return Gnss::stop() { ALOGD("stop"); mIsActive = false; @@ -270,6 +280,10 @@ Return> Gnss::getExtensionGnssMeasurement_2_1() { return new GnssMeasurement(); } +Return> Gnss::getExtensionGnssConfiguration_2_1() { + return mGnssConfiguration; +} + void Gnss::reportSvStatus(const hidl_vec& svInfoList) const { std::unique_lock lock(mMutex); if (sGnssCallback_2_1 == nullptr) { diff --git a/gnss/2.1/default/Gnss.h b/gnss/2.1/default/Gnss.h index a61f71cf75..674b070d99 100644 --- a/gnss/2.1/default/Gnss.h +++ b/gnss/2.1/default/Gnss.h @@ -22,6 +22,7 @@ #include #include #include +#include "GnssConfiguration.h" namespace android { namespace hardware { @@ -87,6 +88,7 @@ struct Gnss : public IGnss { // Methods from V2_1::IGnss follow. Return setCallback_2_1(const sp& callback) override; Return> getExtensionGnssMeasurement_2_1() override; + Return> getExtensionGnssConfiguration_2_1() override; private: void reportLocation(const V2_0::GnssLocation&) const; @@ -94,9 +96,11 @@ struct Gnss : public IGnss { static sp sGnssCallback_2_1; std::atomic mMinIntervalMs; + sp mGnssConfiguration; std::atomic mIsActive; std::thread mThread; mutable std::mutex mMutex; + hidl_vec filterBlacklistedSatellitesV2_1(hidl_vec gnssSvInfoList); }; } // namespace implementation diff --git a/gnss/2.1/default/GnssConfiguration.cpp b/gnss/2.1/default/GnssConfiguration.cpp new file mode 100644 index 0000000000..cd8f07fcc4 --- /dev/null +++ b/gnss/2.1/default/GnssConfiguration.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2019 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. + */ + +#define LOG_TAG "GnssConfiguration" + +#include "GnssConfiguration.h" +#include + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_1 { +namespace implementation { + +// Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow. +Return GnssConfiguration::setSuplEs(bool enable) { + ALOGD("setSuplEs enable: %d", enable); + // Method deprecated in 2.0 and not expected to be called by the framework. + return false; +} + +Return GnssConfiguration::setSuplVersion(uint32_t) { + return true; +} + +Return GnssConfiguration::setSuplMode(hidl_bitfield) { + return true; +} + +Return GnssConfiguration::setGpsLock(hidl_bitfield gpsLock) { + ALOGD("setGpsLock gpsLock: %hhu", static_cast(gpsLock)); + // Method deprecated in 2.0 and not expected to be called by the framework. + return false; +} + +Return GnssConfiguration::setLppProfile(hidl_bitfield) { + return true; +} + +Return GnssConfiguration::setGlonassPositioningProtocol(hidl_bitfield) { + return true; +} + +Return GnssConfiguration::setEmergencySuplPdn(bool) { + return true; +} + +// Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow. +Return GnssConfiguration::setBlacklist( + const hidl_vec&) { + // TODO (b/122463906): Reuse 1.1 implementation. + return bool{}; +} + +// Methods from ::android::hardware::gnss::V2_0::IGnssConfiguration follow. +Return GnssConfiguration::setEsExtensionSec(uint32_t emergencyExtensionSeconds) { + ALOGD("setEsExtensionSec emergencyExtensionSeconds: %d", emergencyExtensionSeconds); + return true; +} + +// Methods from ::android::hardware::gnss::V2_1::IGnssConfiguration follow. +Return GnssConfiguration::setBlacklist_2_1( + const hidl_vec& sourceList) { + std::unique_lock lock(mMutex); + mBlacklistedConstellationSet.clear(); + mBlacklistedSourceSet.clear(); + for (auto source : sourceList) { + if (source.svid == 0) { + // Wildcard blacklist, i.e., blacklist entire constellation. + mBlacklistedConstellationSet.insert(source.constellation); + } else { + mBlacklistedSourceSet.insert(source); + } + } + return true; +} + +Return GnssConfiguration::isBlacklistedV2_1(const GnssSvInfoV2_1& gnssSvInfo) const { + std::unique_lock lock(mMutex); + if (mBlacklistedConstellationSet.find(gnssSvInfo.v2_0.constellation) != + mBlacklistedConstellationSet.end()) { + return true; + } + BlacklistedSourceV2_1 source = {.constellation = gnssSvInfo.v2_0.constellation, + .svid = gnssSvInfo.v2_0.v1_0.svid}; + return (mBlacklistedSourceSet.find(source) != mBlacklistedSourceSet.end()); +} + +} // namespace implementation +} // namespace V2_1 +} // namespace gnss +} // namespace hardware +} // namespace android \ No newline at end of file diff --git a/gnss/2.1/default/GnssConfiguration.h b/gnss/2.1/default/GnssConfiguration.h new file mode 100644 index 0000000000..662d61d038 --- /dev/null +++ b/gnss/2.1/default/GnssConfiguration.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H +#define ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H + +#include +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace gnss { +namespace V2_1 { +namespace implementation { + +using ::android::sp; +using ::android::hardware::hidl_array; +using ::android::hardware::hidl_memory; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; +using ::android::hardware::Void; + +using BlacklistedSourceV2_1 = + ::android::hardware::gnss::V2_1::IGnssConfiguration::BlacklistedSource; +using GnssConstellationTypeV2_0 = V2_0::GnssConstellationType; +using GnssSvInfoV2_1 = V2_1::IGnssCallback::GnssSvInfo; + +struct BlacklistedSourceHashV2_1 { + inline int operator()(const BlacklistedSourceV2_1& source) const { + return int(source.constellation) * 1000 + int(source.svid); + } +}; + +struct BlacklistedSourceEqualV2_1 { + inline bool operator()(const BlacklistedSourceV2_1& s1, const BlacklistedSourceV2_1& s2) const { + return (s1.constellation == s2.constellation) && (s1.svid == s2.svid); + } +}; + +using BlacklistedSourceSetV2_1 = + std::unordered_set; +using BlacklistedConstellationSetV2_1 = std::unordered_set; + +struct GnssConfiguration : public IGnssConfiguration { + // Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow. + Return setSuplEs(bool enabled) override; + Return setSuplVersion(uint32_t version) override; + Return setSuplMode(hidl_bitfield mode) override; + Return setGpsLock(hidl_bitfield lock) override; + Return setLppProfile(hidl_bitfield lppProfile) override; + Return setGlonassPositioningProtocol(hidl_bitfield protocol) override; + Return setEmergencySuplPdn(bool enable) override; + + // Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow. + Return setBlacklist( + const hidl_vec& blacklist) override; + + std::recursive_mutex& getMutex() const; + + // Methods from ::android::hardware::gnss::V2_0::IGnssConfiguration follow. + Return setEsExtensionSec(uint32_t emergencyExtensionSeconds) override; + + // Methods from ::android::hardware::gnss::V2_1::IGnssConfiguration follow. + Return setBlacklist_2_1( + const hidl_vec& blacklist) override; + + Return isBlacklistedV2_1(const GnssSvInfoV2_1& gnssSvInfo) const; + + private: + mutable std::recursive_mutex mMutex; + + BlacklistedSourceSetV2_1 mBlacklistedSourceSet; + BlacklistedConstellationSetV2_1 mBlacklistedConstellationSet; +}; + +} // namespace implementation +} // namespace V2_1 +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H \ No newline at end of file diff --git a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp index ef8249b4d0..45a3d2ae4d 100644 --- a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp +++ b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp @@ -30,6 +30,13 @@ using IGnssMeasurement_2_1 = android::hardware::gnss::V2_1::IGnssMeasurement; using IGnssMeasurement_2_0 = android::hardware::gnss::V2_0::IGnssMeasurement; using IGnssMeasurement_1_1 = android::hardware::gnss::V1_1::IGnssMeasurement; using IGnssMeasurement_1_0 = android::hardware::gnss::V1_0::IGnssMeasurement; +using IGnssConfiguration_2_1 = android::hardware::gnss::V2_1::IGnssConfiguration; +using IGnssConfiguration_2_0 = android::hardware::gnss::V2_0::IGnssConfiguration; +using IGnssConfiguration_1_1 = android::hardware::gnss::V1_1::IGnssConfiguration; +using IGnssConfiguration_1_0 = android::hardware::gnss::V1_0::IGnssConfiguration; + +using android::hardware::gnss::V2_0::GnssConstellationType; +using android::hardware::gnss::V2_1::IGnssConfiguration; /* * SetupTeardownCreateCleanup: @@ -60,6 +67,27 @@ TEST_P(GnssHalTest, TestGnssMeasurementExtension) { ASSERT_TRUE(numNonNull >= 1); } +/* + * TestGnssConfigurationExtension: + * Gets the GnssConfigurationExtension and verifies that it returns an actual extension. + */ +TEST_P(GnssHalTest, TestGnssConfigurationExtension) { + auto gnssConfiguration_2_1 = gnss_hal_->getExtensionGnssConfiguration_2_1(); + auto gnssConfiguration_2_0 = gnss_hal_->getExtensionGnssConfiguration_2_0(); + auto gnssConfiguration_1_1 = gnss_hal_->getExtensionGnssConfiguration_1_1(); + auto gnssConfiguration_1_0 = gnss_hal_->getExtensionGnssConfiguration(); + ASSERT_TRUE(gnssConfiguration_2_1.isOk() && gnssConfiguration_2_0.isOk() && + gnssConfiguration_1_1.isOk() && gnssConfiguration_1_0.isOk()); + sp iGnssConfig_2_1 = gnssConfiguration_2_1; + sp iGnssConfig_2_0 = gnssConfiguration_2_0; + sp iGnssConfig_1_1 = gnssConfiguration_1_1; + sp iGnssConfig_1_0 = gnssConfiguration_1_0; + // At least one interface is non-null. + int numNonNull = (int)(iGnssConfig_2_1 != nullptr) + (int)(iGnssConfig_2_0 != nullptr) + + (int)(iGnssConfig_1_1 != nullptr) + (int)(iGnssConfig_1_0 != nullptr); + ASSERT_TRUE(numNonNull >= 1); +} + /* * TestGnssMeasurementFields: * Sets a GnssMeasurementCallback, waits for a measurement, and verifies @@ -126,3 +154,338 @@ TEST_P(GnssHalTest, TestGnssSvInfoFields) { ASSERT_TRUE(nonZeroCn0Found); StopAndClearLocations(); } + +/* + * FindStrongFrequentNonGpsSource: + * + * Search through a GnssSvStatus list for the strongest non-GPS satellite observed enough times + * + * returns the strongest source, + * or a source with constellation == UNKNOWN if none are found sufficient times + * TODO(skz): create a template for this to reduce code duplication of v2.1 and v2.0 since both + * are using vectors. + */ +IGnssConfiguration::BlacklistedSource FindStrongFrequentNonGpsSource( + const std::list> sv_info_list, + const int min_observations) { + struct ComparableBlacklistedSource { + IGnssConfiguration::BlacklistedSource id; + + ComparableBlacklistedSource() { + id.constellation = GnssConstellationType::UNKNOWN; + id.svid = 0; + } + + bool operator<(const ComparableBlacklistedSource& compare) const { + return ((id.svid < compare.id.svid) || ((id.svid == compare.id.svid) && + (id.constellation < compare.id.constellation))); + } + }; + + struct SignalCounts { + int observations; + float max_cn0_dbhz; + }; + + std::map mapSignals; + + for (const auto& sv_info_vec : sv_info_list) { + for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) { + const auto& gnss_sv = sv_info_vec[iSv]; + if ((gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX) && + (gnss_sv.v2_0.constellation != GnssConstellationType::GPS)) { + ComparableBlacklistedSource source; + source.id.svid = gnss_sv.v2_0.v1_0.svid; + source.id.constellation = gnss_sv.v2_0.constellation; + + const auto& itSignal = mapSignals.find(source); + if (itSignal == mapSignals.end()) { + SignalCounts counts; + counts.observations = 1; + counts.max_cn0_dbhz = gnss_sv.v2_0.v1_0.cN0Dbhz; + mapSignals.insert( + std::pair(source, counts)); + } else { + itSignal->second.observations++; + if (itSignal->second.max_cn0_dbhz < gnss_sv.v2_0.v1_0.cN0Dbhz) { + itSignal->second.max_cn0_dbhz = gnss_sv.v2_0.v1_0.cN0Dbhz; + } + } + } + } + } + + float max_cn0_dbhz_with_sufficient_count = 0.; + int total_observation_count = 0; + int blacklisted_source_count_observation = 0; + + ComparableBlacklistedSource source_to_blacklist; // initializes to zero = UNKNOWN constellation + for (auto const& pairSignal : mapSignals) { + total_observation_count += pairSignal.second.observations; + if ((pairSignal.second.observations >= min_observations) && + (pairSignal.second.max_cn0_dbhz > max_cn0_dbhz_with_sufficient_count)) { + source_to_blacklist = pairSignal.first; + blacklisted_source_count_observation = pairSignal.second.observations; + max_cn0_dbhz_with_sufficient_count = pairSignal.second.max_cn0_dbhz; + } + } + ALOGD("Among %d observations, chose svid %d, constellation %d, " + "with %d observations at %.1f max CNo", + total_observation_count, source_to_blacklist.id.svid, + (int)source_to_blacklist.id.constellation, blacklisted_source_count_observation, + max_cn0_dbhz_with_sufficient_count); + + return source_to_blacklist.id; +} + +/* + * BlacklistIndividualSatellites: + * + * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding + * GnssStatus for common satellites (strongest and one other.) + * 2a & b) Turns off location, and blacklists common satellites. + * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding + * GnssStatus does not use those satellites. + * 4a & b) Turns off location, and send in empty blacklist. + * 5a) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding + * GnssStatus does re-use at least the previously strongest satellite + * 5b) Retry a few times, in case GNSS search strategy takes a while to reacquire even the + * formerly strongest satellite + */ +TEST_P(GnssHalTest, BlacklistIndividualSatellites) { + const int kLocationsToAwait = 3; + const int kRetriesToUnBlacklist = 10; + + gnss_cb_->location_cbq_.reset(); + StartAndCheckLocations(kLocationsToAwait); + int location_called_count = gnss_cb_->location_cbq_.calledCount(); + + // Tolerate 1 less sv status to handle edge cases in reporting. + int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size(); + EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait); + ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)", + sv_info_list_cbq_size, kLocationsToAwait, location_called_count); + + /* + * Identify strongest SV seen at least kLocationsToAwait -1 times + * Why -1? To avoid test flakiness in case of (plausible) slight flakiness in strongest signal + * observability (one epoch RF null) + */ + + const int kGnssSvInfoListTimeout = 2; + std::list> sv_info_vec_list; + int count = gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec_list, sv_info_list_cbq_size, + kGnssSvInfoListTimeout); + + ASSERT_EQ(count, sv_info_list_cbq_size); + + IGnssConfiguration::BlacklistedSource source_to_blacklist = + FindStrongFrequentNonGpsSource(sv_info_vec_list, kLocationsToAwait - 1); + + if (source_to_blacklist.constellation == GnssConstellationType::UNKNOWN) { + // Cannot find a non-GPS satellite. Let the test pass. + ALOGD("Cannot find a non-GPS satellite. Letting the test pass."); + return; + } + + // Stop locations, blacklist the common SV + StopAndClearLocations(); + + auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_2_1(); + ASSERT_TRUE(gnss_configuration_hal_return.isOk()); + sp gnss_configuration_hal = gnss_configuration_hal_return; + ASSERT_NE(gnss_configuration_hal, nullptr); + + hidl_vec sources; + sources.resize(1); + sources[0] = source_to_blacklist; + + auto result = gnss_configuration_hal->setBlacklist_2_1(sources); + ASSERT_TRUE(result.isOk()); + EXPECT_TRUE(result); + + // retry and ensure satellite not used + gnss_cb_->sv_info_list_cbq_.reset(); + + gnss_cb_->location_cbq_.reset(); + StartAndCheckLocations(kLocationsToAwait); + + // early exit if test is being run with insufficient signal + location_called_count = gnss_cb_->location_cbq_.calledCount(); + if (location_called_count == 0) { + ALOGE("0 Gnss locations received - ensure sufficient signal and retry"); + } + ASSERT_TRUE(location_called_count > 0); + + // Tolerate 1 less sv status to handle edge cases in reporting. + sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size(); + EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait); + ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)", + sv_info_list_cbq_size, kLocationsToAwait, location_called_count); + for (int i = 0; i < sv_info_list_cbq_size; ++i) { + hidl_vec sv_info_vec; + gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout); + for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) { + const auto& gnss_sv = sv_info_vec[iSv]; + EXPECT_FALSE((gnss_sv.v2_0.v1_0.svid == source_to_blacklist.svid) && + (gnss_sv.v2_0.constellation == source_to_blacklist.constellation) && + (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX)); + } + } + + // clear blacklist and restart - this time updating the blacklist while location is still on + sources.resize(0); + + result = gnss_configuration_hal->setBlacklist_2_1(sources); + ASSERT_TRUE(result.isOk()); + EXPECT_TRUE(result); + + bool strongest_sv_is_reobserved = false; + // do several loops awaiting a few locations, allowing non-immediate reacquisition strategies + int unblacklist_loops_remaining = kRetriesToUnBlacklist; + while (!strongest_sv_is_reobserved && (unblacklist_loops_remaining-- > 0)) { + StopAndClearLocations(); + gnss_cb_->sv_info_list_cbq_.reset(); + + gnss_cb_->location_cbq_.reset(); + StartAndCheckLocations(kLocationsToAwait); + + // early exit loop if test is being run with insufficient signal + location_called_count = gnss_cb_->location_cbq_.calledCount(); + if (location_called_count == 0) { + ALOGE("0 Gnss locations received - ensure sufficient signal and retry"); + } + ASSERT_TRUE(location_called_count > 0); + + // Tolerate 1 less sv status to handle edge cases in reporting. + sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size(); + EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait); + ALOGD("Clear blacklist, observed %d GnssSvInfo, while awaiting %d Locations" + ", tries remaining %d", + sv_info_list_cbq_size, kLocationsToAwait, unblacklist_loops_remaining); + + for (int i = 0; i < sv_info_list_cbq_size; ++i) { + hidl_vec sv_info_vec; + gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout); + for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) { + const auto& gnss_sv = sv_info_vec[iSv]; + if ((gnss_sv.v2_0.v1_0.svid == source_to_blacklist.svid) && + (gnss_sv.v2_0.constellation == source_to_blacklist.constellation) && + (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX)) { + strongest_sv_is_reobserved = true; + break; + } + } + if (strongest_sv_is_reobserved) break; + } + } + EXPECT_TRUE(strongest_sv_is_reobserved); + StopAndClearLocations(); +} + +/* + * BlacklistConstellation: + * + * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding + * GnssStatus for any non-GPS constellations. + * 2a & b) Turns off location, and blacklist first non-GPS constellations. + * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding + * GnssStatus does not use any constellation but GPS. + * 4a & b) Clean up by turning off location, and send in empty blacklist. + */ +TEST_P(GnssHalTest, BlacklistConstellation) { + const int kLocationsToAwait = 3; + + gnss_cb_->location_cbq_.reset(); + StartAndCheckLocations(kLocationsToAwait); + const int location_called_count = gnss_cb_->location_cbq_.calledCount(); + + // Tolerate 1 less sv status to handle edge cases in reporting. + int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size(); + EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait); + ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)", + sv_info_list_cbq_size, kLocationsToAwait, location_called_count); + + // Find first non-GPS constellation to blacklist + const int kGnssSvInfoListTimeout = 2; + GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN; + for (int i = 0; i < sv_info_list_cbq_size; ++i) { + hidl_vec sv_info_vec; + gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout); + for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) { + const auto& gnss_sv = sv_info_vec[iSv]; + if ((gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX) && + (gnss_sv.v2_0.constellation != GnssConstellationType::UNKNOWN) && + (gnss_sv.v2_0.constellation != GnssConstellationType::GPS)) { + // found a non-GPS constellation + constellation_to_blacklist = gnss_sv.v2_0.constellation; + break; + } + } + if (constellation_to_blacklist != GnssConstellationType::UNKNOWN) { + break; + } + } + + // Turns off location + StopAndClearLocations(); + + if (constellation_to_blacklist == GnssConstellationType::UNKNOWN) { + ALOGI("No non-GPS constellations found, constellation blacklist test less effective."); + // Proceed functionally to blacklist something. + constellation_to_blacklist = GnssConstellationType::GLONASS; + } + IGnssConfiguration::BlacklistedSource source_to_blacklist_1; + source_to_blacklist_1.constellation = constellation_to_blacklist; + source_to_blacklist_1.svid = 0; // documented wildcard for all satellites in this constellation + + // IRNSS was added in 2.0. Always attempt to blacklist IRNSS to verify that the new enum is + // supported. + IGnssConfiguration::BlacklistedSource source_to_blacklist_2; + source_to_blacklist_2.constellation = GnssConstellationType::IRNSS; + source_to_blacklist_2.svid = 0; // documented wildcard for all satellites in this constellation + + auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_2_1(); + ASSERT_TRUE(gnss_configuration_hal_return.isOk()); + sp gnss_configuration_hal = gnss_configuration_hal_return; + ASSERT_NE(gnss_configuration_hal, nullptr); + + hidl_vec sources; + sources.resize(2); + sources[0] = source_to_blacklist_1; + sources[1] = source_to_blacklist_2; + + auto result = gnss_configuration_hal->setBlacklist_2_1(sources); + ASSERT_TRUE(result.isOk()); + EXPECT_TRUE(result); + + // retry and ensure constellation not used + gnss_cb_->sv_info_list_cbq_.reset(); + + gnss_cb_->location_cbq_.reset(); + StartAndCheckLocations(kLocationsToAwait); + + // Tolerate 1 less sv status to handle edge cases in reporting. + sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size(); + EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait); + ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations", sv_info_list_cbq_size, + kLocationsToAwait); + for (int i = 0; i < sv_info_list_cbq_size; ++i) { + hidl_vec sv_info_vec; + gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout); + for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) { + const auto& gnss_sv = sv_info_vec[iSv]; + EXPECT_FALSE((gnss_sv.v2_0.constellation == source_to_blacklist_1.constellation) && + (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX)); + EXPECT_FALSE((gnss_sv.v2_0.constellation == source_to_blacklist_2.constellation) && + (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX)); + } + } + + // clean up + StopAndClearLocations(); + sources.resize(0); + result = gnss_configuration_hal->setBlacklist_2_1(sources); + ASSERT_TRUE(result.isOk()); + EXPECT_TRUE(result); +} \ No newline at end of file diff --git a/gnss/common/utils/default/Utils.cpp b/gnss/common/utils/default/Utils.cpp index 6c6d696f3d..ccb91b100f 100644 --- a/gnss/common/utils/default/Utils.cpp +++ b/gnss/common/utils/default/Utils.cpp @@ -175,6 +175,11 @@ hidl_vec Utils::getMockSvInfoListV2_1() { 25.0, 66.0, 247.0), V2_0::GnssConstellationType::GLONASS), 20.0), + getMockSvInfoV2_1( + getMockSvInfoV2_0(getMockSvInfoV1_0(3, V1_0::GnssConstellationType::UNKNOWN, + 22.0, 35.0, 112.0), + V2_0::GnssConstellationType::IRNSS), + 19.7), }; return gnssSvInfoList; }