/* * 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 "GnssHalTestCases" #include #include #include "Utils.h" #include using android::hardware::hidl_string; using android::hardware::hidl_vec; using android::hardware::gnss::common::Utils; using android::hardware::gnss::V2_1::IGnssAntennaInfo; using android::hardware::gnss::V2_1::IGnssAntennaInfoCallback; 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; using GnssMeasurementFlags = IGnssMeasurementCallback_2_1::GnssMeasurementFlags; using IMeasurementCorrections_1_1 = android::hardware::gnss::measurement_corrections::V1_1::IMeasurementCorrections; /* * SetupTeardownCreateCleanup: * Requests the gnss HAL then calls cleanup * * Empty test fixture to verify basic Setup & Teardown */ TEST_P(GnssHalTest, SetupTeardownCreateCleanup) {} /* * TestGnssMeasurementExtension: * Gets the GnssMeasurementExtension and verifies that it returns an actual extension. */ TEST_P(GnssHalTest, TestGnssMeasurementExtension) { auto gnssMeasurement_2_1 = gnss_hal_->getExtensionGnssMeasurement_2_1(); auto gnssMeasurement_2_0 = gnss_hal_->getExtensionGnssMeasurement_2_0(); auto gnssMeasurement_1_1 = gnss_hal_->getExtensionGnssMeasurement_1_1(); auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement(); ASSERT_TRUE(gnssMeasurement_2_1.isOk() && gnssMeasurement_2_0.isOk() && gnssMeasurement_1_1.isOk() && gnssMeasurement_1_0.isOk()); // CDD does not require Android Automotive OS devices to support // GnssMeasurements. if (Utils::isAutomotiveDevice()) { ALOGI("Test GnssMeasurementExtension skipped. Android Automotive OS de ice is not " "required to support GNSS measurements."); return; } sp iGnssMeas_2_1 = gnssMeasurement_2_1; sp iGnssMeas_2_0 = gnssMeasurement_2_0; sp iGnssMeas_1_1 = gnssMeasurement_1_1; sp iGnssMeas_1_0 = gnssMeasurement_1_0; // At least one interface is non-null. int numNonNull = (int)(iGnssMeas_2_1 != nullptr) + (int)(iGnssMeas_2_0 != nullptr) + (int)(iGnssMeas_1_1 != nullptr) + (int)(iGnssMeas_1_0 != nullptr); ASSERT_TRUE(numNonNull >= 1); } /* * TestGnssConfigurationExtension: * Gets the GnssConfigurationExtension and verifies that it returns an actual extension. */ TEST_P(GnssHalTest, TestGnssConfigurationExtension) { if (!IsGnssHalVersion_2_1()) { ALOGI("Test TestGnssConfigurationExtension skipped. GNSS HAL version is greater than 2.1."); return; } 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 * 1. basebandCN0DbHz is valid * 2. ISB fields are valid */ TEST_P(GnssHalTest, TestGnssMeasurementFields) { const int kFirstGnssMeasurementTimeoutSeconds = 10; auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_2_1(); ASSERT_TRUE(gnssMeasurement.isOk()); // Skip test if GnssMeasurement v2.1 is not supported sp iGnssMeasurement = gnssMeasurement; if (iGnssMeasurement == nullptr) { return; } sp callback = new GnssMeasurementCallback(); auto result = iGnssMeasurement->setCallback_2_1(callback, /* enableFullTracking= */ true); ASSERT_TRUE(result.isOk()); EXPECT_EQ(result, IGnssMeasurement_1_0::GnssMeasurementStatus::SUCCESS); IGnssMeasurementCallback_2_1::GnssData lastMeasurement; ASSERT_TRUE(callback->measurement_cbq_.retrieve(lastMeasurement, kFirstGnssMeasurementTimeoutSeconds)); EXPECT_EQ(callback->measurement_cbq_.calledCount(), 1); ASSERT_TRUE(lastMeasurement.measurements.size() > 0); for (auto measurement : lastMeasurement.measurements) { // Verify basebandCn0DbHz is valid. ASSERT_TRUE(measurement.basebandCN0DbHz > 0.0 && measurement.basebandCN0DbHz <= 65.0); if (((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_FULL_ISB) > 0) && ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_FULL_ISB_UNCERTAINTY) > 0) && ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_SATELLITE_ISB) > 0) && ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_SATELLITE_ISB_UNCERTAINTY) > 0)) { GnssConstellationType referenceConstellation = lastMeasurement.clock.referenceSignalTypeForIsb.constellation; double carrierFrequencyHz = lastMeasurement.clock.referenceSignalTypeForIsb.carrierFrequencyHz; std::string codeType = lastMeasurement.clock.referenceSignalTypeForIsb.codeType; ASSERT_TRUE(referenceConstellation >= GnssConstellationType::UNKNOWN && referenceConstellation <= GnssConstellationType::IRNSS); ASSERT_TRUE(carrierFrequencyHz > 0); ASSERT_TRUE(codeType != ""); ASSERT_TRUE(std::abs(measurement.fullInterSignalBiasNs) < 1.0e6); ASSERT_TRUE(measurement.fullInterSignalBiasUncertaintyNs >= 0); ASSERT_TRUE(std::abs(measurement.satelliteInterSignalBiasNs) < 1.0e6); ASSERT_TRUE(measurement.satelliteInterSignalBiasUncertaintyNs >= 0); } } iGnssMeasurement->close(); } /* * TestGnssAntennaInfo: * Sets a GnssAntennaInfoCallback, waits for report, and verifies * 1. phaseCenterOffsetCoordinateMillimeters is valid * 2. phaseCenterOffsetCoordinateUncertaintyMillimeters is valid. * PhaseCenterVariationCorrections and SignalGainCorrections are optional. */ TEST_P(GnssHalTest, TestGnssAntennaInfo) { const int kAntennaInfoTimeoutSeconds = 2; auto gnssAntennaInfo = gnss_hal_->getExtensionGnssAntennaInfo(); ASSERT_TRUE(gnssAntennaInfo.isOk()); // Skip test if GnssAntennaInfo v2.1 is not supported sp iGnssAntennaInfo = gnssAntennaInfo; if (!(gnss_cb_->last_capabilities_ & IGnssCallback_2_1::Capabilities::ANTENNA_INFO) || iGnssAntennaInfo == nullptr) { ALOGD("GnssAntennaInfo v2.1 is not supported."); return; } sp callback = new GnssAntennaInfoCallback(); auto result = iGnssAntennaInfo->setCallback(callback); ASSERT_TRUE(result.isOk()); EXPECT_EQ(result, IGnssAntennaInfo::GnssAntennaInfoStatus::SUCCESS); hidl_vec antennaInfos; ASSERT_TRUE(callback->antenna_info_cbq_.retrieve(antennaInfos, kAntennaInfoTimeoutSeconds)); EXPECT_EQ(callback->antenna_info_cbq_.calledCount(), 1); ASSERT_TRUE(antennaInfos.size() > 0); for (auto antennaInfo : antennaInfos) { // Remaining fields are optional if (antennaInfo.phaseCenterVariationCorrectionMillimeters != NULL) { int numRows = antennaInfo.phaseCenterVariationCorrectionMillimeters.size(); int numColumns = antennaInfo.phaseCenterVariationCorrectionMillimeters[0].row.size(); // Must have at least 1 row and 2 columns ASSERT_TRUE(numRows >= 1 && numColumns >= 2); // Corrections and uncertainties must have same dimensions ASSERT_TRUE(antennaInfo.phaseCenterVariationCorrectionMillimeters.size() == antennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters.size()); ASSERT_TRUE( antennaInfo.phaseCenterVariationCorrectionMillimeters[0].row.size() == antennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters[0].row.size()); // Must be rectangular for (auto row : antennaInfo.phaseCenterVariationCorrectionMillimeters) { ASSERT_TRUE(row.row.size() == numColumns); } for (auto row : antennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters) { ASSERT_TRUE(row.row.size() == numColumns); } } if (antennaInfo.signalGainCorrectionDbi != NULL) { int numRows = antennaInfo.signalGainCorrectionDbi.size(); int numColumns = antennaInfo.signalGainCorrectionUncertaintyDbi[0].row.size(); // Must have at least 1 row and 2 columns ASSERT_TRUE(numRows >= 1 && numColumns >= 2); // Corrections and uncertainties must have same dimensions ASSERT_TRUE(antennaInfo.signalGainCorrectionDbi.size() == antennaInfo.signalGainCorrectionUncertaintyDbi.size()); ASSERT_TRUE(antennaInfo.signalGainCorrectionDbi[0].row.size() == antennaInfo.signalGainCorrectionUncertaintyDbi[0].row.size()); // Must be rectangular for (auto row : antennaInfo.signalGainCorrectionDbi) { ASSERT_TRUE(row.row.size() == numColumns); } for (auto row : antennaInfo.signalGainCorrectionUncertaintyDbi) { ASSERT_TRUE(row.row.size() == numColumns); } } } iGnssAntennaInfo->close(); } /* * TestGnssSvInfoFields: * Gets 1 location and a (non-empty) GnssSvInfo, and verifies basebandCN0DbHz is valid. */ TEST_P(GnssHalTest, TestGnssSvInfoFields) { gnss_cb_->location_cbq_.reset(); gnss_cb_->sv_info_list_cbq_.reset(); StartAndCheckFirstLocation(/* min_interval_msec= */ 1000, /* low_power_mode= */ false); int location_called_count = gnss_cb_->location_cbq_.calledCount(); ALOGD("Observed %d GnssSvStatus, while awaiting one location (%d received)", gnss_cb_->sv_info_list_cbq_.size(), location_called_count); // Wait for up to kNumSvInfoLists events for kTimeoutSeconds for each event. int kTimeoutSeconds = 2; int kNumSvInfoLists = 4; std::list> sv_info_lists; hidl_vec last_sv_info_list; do { EXPECT_GT(gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_lists, kNumSvInfoLists, kTimeoutSeconds), 0); last_sv_info_list = sv_info_lists.back(); } while (last_sv_info_list.size() == 0); ALOGD("last_sv_info size = %d", (int)last_sv_info_list.size()); bool nonZeroCn0Found = false; for (auto sv_info : last_sv_info_list) { EXPECT_TRUE(sv_info.basebandCN0DbHz >= 0.0 && sv_info.basebandCN0DbHz <= 65.0); if (sv_info.basebandCN0DbHz > 0.0) { nonZeroCn0Found = true; } } // Assert at least one value is non-zero. Zero is ok in status as it's possibly // reporting a searched but not found satellite. EXPECT_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; } /* * BlocklistIndividualSatellites: * * 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 blocklists 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 blocklist. * 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, BlocklistIndividualSatellites) { if (!IsGnssHalVersion_2_1()) { ALOGI("Test BlocklistIndividualSatellites skipped. GNSS HAL version is greater than 2.1."); return; } if (!(gnss_cb_->last_capabilities_ & IGnssCallback_2_1::Capabilities::SATELLITE_BLACKLIST)) { ALOGI("Test BlacklistIndividualSatellites skipped. SATELLITE_BLACKLIST capability not " "supported."); return; } 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(); } /* * BlocklistConstellationLocationOff: * * 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 blocklist 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 blocklist. */ TEST_P(GnssHalTest, BlocklistConstellationLocationOff) { if (!IsGnssHalVersion_2_1()) { ALOGI("Test BlocklistConstellationLocationOff skipped. GNSS HAL version is greater than " "2.1."); return; } if (!(gnss_cb_->last_capabilities_ & IGnssCallback_2_1::Capabilities::SATELLITE_BLACKLIST)) { ALOGI("Test BlacklistConstellationLocationOff skipped. SATELLITE_BLACKLIST capability not " "supported."); return; } const int kLocationsToAwait = 3; const int kGnssSvInfoListTimeout = 2; // Find first non-GPS constellation to blacklist GnssConstellationType constellation_to_blacklist = startLocationAndGetNonGpsConstellation(kLocationsToAwait, kGnssSvInfoListTimeout); // Turns off location StopAndClearLocations(); 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. 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", 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); } /* * BlocklistConstellationLocationOn: * * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding * GnssStatus for any non-GPS constellations. * 2a & b) Blocklist first non-GPS constellation, and turn off location. * 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 blocklist. */ TEST_P(GnssHalTest, BlocklistConstellationLocationOn) { if (!IsGnssHalVersion_2_1()) { ALOGI("Test BlocklistConstellationLocationOn skipped. GNSS HAL version is greater than " "2.1."); return; } if (!(gnss_cb_->last_capabilities_ & IGnssCallback_2_1::Capabilities::SATELLITE_BLACKLIST)) { ALOGI("Test BlacklistConstellationLocationOn skipped. SATELLITE_BLACKLIST capability not " "supported."); return; } const int kLocationsToAwait = 3; const int kGnssSvInfoListTimeout = 2; // Find first non-GPS constellation to blacklist GnssConstellationType constellation_to_blacklist = startLocationAndGetNonGpsConstellation(kLocationsToAwait, kGnssSvInfoListTimeout); 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); // Turns off location StopAndClearLocations(); // 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. 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", 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); } /* * TestGnssMeasurementCorrections: * If measurement corrections capability is supported, verifies that it supports the * gnss.measurement_corrections@1.1::IMeasurementCorrections interface by invoking a method. */ TEST_P(GnssHalTest, TestGnssMeasurementCorrections) { if (!(gnss_cb_->last_capabilities_ & IGnssCallback_2_1::Capabilities::MEASUREMENT_CORRECTIONS)) { return; } // Verify IMeasurementCorrections is supported. auto measurementCorrections = gnss_hal_->getExtensionMeasurementCorrections_1_1(); ASSERT_TRUE(measurementCorrections.isOk()); sp iMeasurementCorrections = measurementCorrections; ASSERT_NE(iMeasurementCorrections, nullptr); sp callback = new GnssMeasurementCorrectionsCallback(); iMeasurementCorrections->setCallback(callback); const int kMeasurementCorrectionsCapabilitiesTimeoutSeconds = 5; callback->capabilities_cbq_.retrieve(callback->last_capabilities_, kMeasurementCorrectionsCapabilitiesTimeoutSeconds); ASSERT_TRUE(callback->capabilities_cbq_.calledCount() > 0); // Set a mock MeasurementCorrections. auto result = iMeasurementCorrections->setCorrections_1_1(Utils::getMockMeasurementCorrections_1_1()); ASSERT_TRUE(result.isOk()); EXPECT_TRUE(result); }