/* * Copyright (C) 2018 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 "Utils.h" #include using android::hardware::hidl_string; using android::hardware::hidl_vec; using IGnssConfiguration_2_0 = android::hardware::gnss::V2_0::IGnssConfiguration; using IGnssConfiguration_1_1 = android::hardware::gnss::V1_1::IGnssConfiguration; using IAGnssRil_2_0 = android::hardware::gnss::V2_0::IAGnssRil; 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 IAGnssRil_2_0 = android::hardware::gnss::V2_0::IAGnssRil; using IAGnssRil_1_0 = android::hardware::gnss::V1_0::IAGnssRil; using IAGnss_2_0 = android::hardware::gnss::V2_0::IAGnss; using IAGnss_1_0 = android::hardware::gnss::V1_0::IAGnss; using IAGnssCallback_2_0 = android::hardware::gnss::V2_0::IAGnssCallback; using android::hardware::gnss::common::Utils; using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections; using android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections; using android::hardware::gnss::V1_0::IGnssNi; using android::hardware::gnss::V2_0::ElapsedRealtimeFlags; using android::hardware::gnss::V2_0::IGnssCallback; using android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl; /* * 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_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_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 deice is not required " "to support GNSS measurements."); return; } 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_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 by * calling a method. * * The GNSS HAL 2.0 implementation must support @2.0::IGnssConfiguration interface due to * the deprecation of some methods in @1.0::IGnssConfiguration interface. */ TEST_P(GnssHalTest, TestGnssConfigurationExtension) { auto gnssConfiguration = gnss_hal_->getExtensionGnssConfiguration_2_0(); ASSERT_TRUE(gnssConfiguration.isOk()); sp iGnssConfiguration = gnssConfiguration; ASSERT_NE(iGnssConfiguration, nullptr); auto result = iGnssConfiguration->setEsExtensionSec(180); ASSERT_TRUE(result.isOk()); // Expected result can be true or false depending on whether HAL implementation supports // detecting emergency sessions without involving the framework. } /* * TestGnssConfiguration_setSuplEs_Deprecation: * Calls setSuplEs and verifies that it returns false. */ TEST_P(GnssHalTest, TestGnssConfiguration_setSuplEs_Deprecation) { auto gnssConfiguration = gnss_hal_->getExtensionGnssConfiguration_2_0(); ASSERT_TRUE(gnssConfiguration.isOk()); sp iGnssConfiguration = gnssConfiguration; ASSERT_NE(iGnssConfiguration, nullptr); auto result = iGnssConfiguration->setSuplEs(false); ASSERT_TRUE(result.isOk()); EXPECT_FALSE(result); } /* * TestGnssConfiguration_setGpsLock_Deprecation: * Calls setGpsLock and verifies that it returns false. */ TEST_P(GnssHalTest, TestGnssConfiguration_setGpsLock_Deprecation) { auto gnssConfiguration = gnss_hal_->getExtensionGnssConfiguration_2_0(); ASSERT_TRUE(gnssConfiguration.isOk()); sp iGnssConfiguration = gnssConfiguration; ASSERT_NE(iGnssConfiguration, nullptr); auto result = iGnssConfiguration->setGpsLock(0); ASSERT_TRUE(result.isOk()); EXPECT_FALSE(result); } /* * TestAGnssRilExtension: * Gets the AGnssRilExtension and verifies that it returns an actual extension. * * If IAGnssRil interface is supported, then the GNSS HAL 2.0 implementation must support * @2.0::IAGnssRil interface due to the deprecation of framework network API methods needed * to support the @1.0::IAGnssRil interface. */ TEST_P(GnssHalTest, TestAGnssRilExtension) { auto agnssRil_2_0 = gnss_hal_->getExtensionAGnssRil_2_0(); ASSERT_TRUE(agnssRil_2_0.isOk()); sp iAGnssRil_2_0 = agnssRil_2_0; if (iAGnssRil_2_0 == nullptr) { // Verify IAGnssRil 1.0 is not supported. auto agnssRil_1_0 = gnss_hal_->getExtensionAGnssRil(); ASSERT_TRUE(agnssRil_1_0.isOk()); sp iAGnssRil_1_0 = agnssRil_1_0; ASSERT_EQ(iAGnssRil_1_0, nullptr); } } /* * TestAGnssRil_UpdateNetworkState_2_0: * 1. Updates GNSS HAL that a network has connected. * 2. Updates GNSS HAL that network has disconnected. */ TEST_P(GnssHalTest, TestAGnssRil_UpdateNetworkState_2_0) { auto agnssRil = gnss_hal_->getExtensionAGnssRil_2_0(); ASSERT_TRUE(agnssRil.isOk()); sp iAGnssRil = agnssRil; if (iAGnssRil == nullptr) { return; } // Update GNSS HAL that a network has connected. IAGnssRil_2_0::NetworkAttributes networkAttributes = { .networkHandle = static_cast(7700664333), .isConnected = true, .capabilities = static_cast(IAGnssRil_2_0::NetworkCapability::NOT_ROAMING), .apn = "dummy-apn"}; auto result = iAGnssRil->updateNetworkState_2_0(networkAttributes); ASSERT_TRUE(result.isOk()); EXPECT_TRUE(result); // Update GNSS HAL that network has disconnected. networkAttributes.isConnected = false; result = iAGnssRil->updateNetworkState_2_0(networkAttributes); ASSERT_TRUE(result.isOk()); EXPECT_TRUE(result); } /* * TestGnssMeasurementFields: * Sets a GnssMeasurementCallback, waits for a measurement, and verifies * 1. codeType is valid, * 2. constellation is valid. * 3. state is valid. */ TEST_P(GnssHalTest, TestGnssMeasurementFields) { if (!IsGnssHalVersion_2_0()) { ALOGI("Test GnssMeasurementFields skipped. GNSS HAL version is greater than 2.0."); return; } const int kFirstGnssMeasurementTimeoutSeconds = 10; auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_2_0(); if (!gnssMeasurement.isOk()) { return; } sp iGnssMeasurement = gnssMeasurement; if (iGnssMeasurement == nullptr) { return; } sp callback = new GnssMeasurementCallback(); auto result = iGnssMeasurement->setCallback_2_0(callback, /* enableFullTracking= */ true); ASSERT_TRUE(result.isOk()); EXPECT_EQ(result, IGnssMeasurement_1_0::GnssMeasurementStatus::SUCCESS); IGnssMeasurementCallback_2_0::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 CodeType is valid. ASSERT_NE(measurement.codeType, ""); // Verify ConstellationType is valid. ASSERT_TRUE(static_cast(measurement.constellation) >= static_cast(GnssConstellationType_2_0::UNKNOWN) && static_cast(measurement.constellation) <= static_cast(GnssConstellationType_2_0::IRNSS)); // Verify State is valid. ASSERT_TRUE( static_cast(measurement.state) >= static_cast(IGnssMeasurementCallback_2_0::GnssMeasurementState:: STATE_UNKNOWN) && static_cast(measurement.state) < (static_cast(IGnssMeasurementCallback_2_0::GnssMeasurementState:: STATE_2ND_CODE_LOCK) << 1)); } iGnssMeasurement->close(); } /* * TestAGnssExtension: * Gets the AGnssExtension and verifies that it returns an actual extension. * * If IAGnss interface is supported, then the GNSS HAL 2.0 implementation must support * @2.0::IAGnss interface due to the deprecation of framework network API methods needed * to support the @1.0::IAGnss interface. */ TEST_P(GnssHalTest, TestAGnssExtension) { auto agnss_2_0 = gnss_hal_->getExtensionAGnss_2_0(); ASSERT_TRUE(agnss_2_0.isOk()); sp iAGnss_2_0 = agnss_2_0; if (iAGnss_2_0 == nullptr) { // Verify IAGnss 1.0 is not supported. auto agnss_1_0 = gnss_hal_->getExtensionAGnss(); ASSERT_TRUE(agnss_1_0.isOk()); sp iAGnss_1_0 = agnss_1_0; ASSERT_EQ(iAGnss_1_0, nullptr); return; } // Set SUPL server host/port auto result = iAGnss_2_0->setServer(IAGnssCallback_2_0::AGnssType::SUPL, "supl.google.com", 7275); ASSERT_TRUE(result.isOk()); EXPECT_TRUE(result); } /* * TestGnssNiExtension_Deprecation: * Gets the @1.0::IGnssNi extension and verifies that it is a nullptr. */ TEST_P(GnssHalTest, TestGnssNiExtension_Deprecation) { // Verify IGnssNi 1.0 is not supported. auto gnssNi = gnss_hal_->getExtensionGnssNi(); ASSERT_TRUE(!gnssNi.isOk() || ((sp)gnssNi) == nullptr); } /* * TestGnssVisibilityControlExtension: * Gets the GnssVisibilityControlExtension and if it is not null, verifies that it supports * the gnss.visibility_control@1.0::IGnssVisibilityControl interface by invoking a method. */ TEST_P(GnssHalTest, TestGnssVisibilityControlExtension) { auto gnssVisibilityControl = gnss_hal_->getExtensionVisibilityControl(); ASSERT_TRUE(gnssVisibilityControl.isOk()); sp iGnssVisibilityControl = gnssVisibilityControl; if (iGnssVisibilityControl == nullptr) { return; } // Set non-framework proxy apps. hidl_vec proxyApps{"com.example.ims", "com.example.mdt"}; auto result = iGnssVisibilityControl->enableNfwLocationAccess(proxyApps); ASSERT_TRUE(result.isOk()); EXPECT_TRUE(result); } /* * TestGnssMeasurementCorrectionsCapabilities: * If measurement corrections capability is supported, verifies that the measurement corrections * capabilities are reported and the mandatory LOS_SATS or the EXCESS_PATH_LENGTH * capability flag is set. */ TEST_P(GnssHalTest, TestGnssMeasurementCorrectionsCapabilities) { if (!IsGnssHalVersion_2_0()) { ALOGI("Test GnssMeasurementCorrectionsCapabilities skipped. GNSS HAL version is greater " "than 2.0."); return; } if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENT_CORRECTIONS)) { return; } auto measurementCorrections = gnss_hal_->getExtensionMeasurementCorrections(); ASSERT_TRUE(measurementCorrections.isOk()); sp iMeasurementCorrections = measurementCorrections; ASSERT_NE(iMeasurementCorrections, nullptr); // Setup measurement corrections callback. 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); using Capabilities = IMeasurementCorrectionsCallback::Capabilities; ASSERT_TRUE((callback->last_capabilities_ & (Capabilities::LOS_SATS | Capabilities::EXCESS_PATH_LENGTH)) != 0); } /* * TestGnssMeasurementCorrections: * If measurement corrections capability is supported, verifies that it supports the * gnss.measurement_corrections@1.0::IMeasurementCorrections interface by invoking a method. */ TEST_P(GnssHalTest, TestGnssMeasurementCorrections) { if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENT_CORRECTIONS)) { return; } // Verify IMeasurementCorrections is supported. auto measurementCorrections = gnss_hal_->getExtensionMeasurementCorrections(); 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(Utils::getMockMeasurementCorrections()); ASSERT_TRUE(result.isOk()); EXPECT_TRUE(result); } /* * TestGnssDataElapsedRealtimeFlags: * Sets a GnssMeasurementCallback, waits for a GnssData object, and verifies the flags in member * elapsedRealitme are valid. */ TEST_P(GnssHalTest, TestGnssDataElapsedRealtimeFlags) { const int kFirstGnssMeasurementTimeoutSeconds = 10; auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_2_0(); if (!gnssMeasurement.isOk()) { return; } sp iGnssMeasurement = gnssMeasurement; if (iGnssMeasurement == nullptr) { return; } sp callback = new GnssMeasurementCallback(); auto result = iGnssMeasurement->setCallback_2_0(callback, /* enableFullTracking= */ true); ASSERT_TRUE(result.isOk()); EXPECT_EQ(result, IGnssMeasurement_1_0::GnssMeasurementStatus::SUCCESS); IGnssMeasurementCallback_2_0::GnssData lastMeasurement; ASSERT_TRUE(callback->measurement_cbq_.retrieve(lastMeasurement, kFirstGnssMeasurementTimeoutSeconds)); EXPECT_EQ(callback->measurement_cbq_.calledCount(), 1); ASSERT_TRUE((int)lastMeasurement.elapsedRealtime.flags <= (int)(ElapsedRealtimeFlags::HAS_TIMESTAMP_NS | ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS)); // We expect a non-zero timestamp when set. if (lastMeasurement.elapsedRealtime.flags & ElapsedRealtimeFlags::HAS_TIMESTAMP_NS) { ASSERT_TRUE(lastMeasurement.elapsedRealtime.timestampNs != 0); } iGnssMeasurement->close(); } TEST_P(GnssHalTest, TestGnssLocationElapsedRealtime) { StartAndCheckFirstLocation(/* strict= */ true, /* min_interval_msec= */ 1000, /* low_power_mode= */ false); ASSERT_TRUE((int)gnss_cb_->last_location_.elapsedRealtime.flags <= (int)(ElapsedRealtimeFlags::HAS_TIMESTAMP_NS | ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS)); // We expect a non-zero timestamp when set. if (gnss_cb_->last_location_.elapsedRealtime.flags & ElapsedRealtimeFlags::HAS_TIMESTAMP_NS) { ASSERT_TRUE(gnss_cb_->last_location_.elapsedRealtime.timestampNs != 0); } StopAndClearLocations(); } // This test only verify that injectBestLocation_2_0 does not crash. TEST_P(GnssHalTest, TestInjectBestLocation_2_0) { StartAndCheckFirstLocation(/* strict= */ true, /* min_interval_msec= */ 1000, /* low_power_mode= */ false); gnss_hal_->injectBestLocation_2_0(gnss_cb_->last_location_); StopAndClearLocations(); } /* * TestGnssBatchingExtension: * Gets the @2.0::IGnssBatching extension and verifies that it doesn't return an error. Support * for this interface is optional. */ TEST_P(GnssHalTest, TestGnssBatchingExtension) { auto gnssBatching_2_0 = gnss_hal_->getExtensionGnssBatching_2_0(); ASSERT_TRUE(gnssBatching_2_0.isOk()); } /* * GetLocationLowPower: * 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_P(GnssHalTest, GetLocationLowPower) { if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::LOW_POWER_MODE)) { ALOGI("Test GetLocationLowPower skipped. LOW_POWER_MODE capability not supported."); return; } const int kMinIntervalMsec = 5000; const int kLocationTimeoutSubsequentSec = (kMinIntervalMsec / 1000) * 2; const int kNoLocationPeriodSec = (kMinIntervalMsec / 1000) / 2; const int kLocationsToCheck = 5; const bool kLowPowerMode = true; // Warmup period - VTS doesn't have AGPS access via GnssLocationProvider gnss_cb_->location_cbq_.reset(); StartAndCheckLocations(kLocationsToCheck); StopAndClearLocations(); gnss_cb_->location_cbq_.reset(); // Start of Low Power Mode test // Don't expect true - as without AGPS access if (!StartAndCheckFirstLocation(/* strict= */ false, /* min_interval_msec= */ kMinIntervalMsec, /* low_power_mode= */ kLowPowerMode)) { ALOGW("GetLocationLowPower test - no first low power location received."); } for (int i = 1; i < kLocationsToCheck; i++) { // Verify that kMinIntervalMsec is respected by waiting kNoLocationPeriodSec and // ensure that no location is received yet gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, kNoLocationPeriodSec); const int location_called_count = gnss_cb_->location_cbq_.calledCount(); // Tolerate (ignore) one extra location right after the first one // to handle startup edge case scheduling limitations in some implementations if ((i == 1) && (location_called_count == 2)) { CheckLocation(gnss_cb_->last_location_, true); continue; // restart the quiet wait period after this too-fast location } EXPECT_LE(location_called_count, i); if (location_called_count != i) { ALOGW("GetLocationLowPower test - too many locations received. %d vs. %d expected ", location_called_count, i); } if (!gnss_cb_->location_cbq_.retrieve( gnss_cb_->last_location_, kLocationTimeoutSubsequentSec - kNoLocationPeriodSec)) { ALOGW("GetLocationLowPower test - timeout awaiting location %d", i); } else { CheckLocation(gnss_cb_->last_location_, true); } } 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 */ IGnssConfiguration_1_1::BlacklistedSource FindStrongFrequentNonGpsSource( const std::list>& sv_info_lists, const int min_observations) { struct ComparableBlacklistedSource { IGnssConfiguration_1_1::BlacklistedSource id; ComparableBlacklistedSource() { id.constellation = GnssConstellationType_1_0::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_list : sv_info_lists) { for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) { if ((sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) && (sv_info.constellation != GnssConstellationType_2_0::IRNSS) && (sv_info.constellation != GnssConstellationType_2_0::GPS)) { ComparableBlacklistedSource source; source.id.svid = sv_info.v1_0.svid; source.id.constellation = Utils::mapConstellationType(sv_info.constellation); const auto& itSignal = mapSignals.find(source); if (itSignal == mapSignals.end()) { SignalCounts counts; counts.observations = 1; counts.max_cn0_dbhz = sv_info.v1_0.cN0Dbhz; mapSignals.insert( std::pair(source, counts)); } else { itSignal->second.observations++; if (itSignal->second.max_cn0_dbhz < sv_info.v1_0.cN0Dbhz) { itSignal->second.max_cn0_dbhz = sv_info.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) { if (!IsGnssHalVersion_2_0()) { ALOGI("Test BlacklistIndividualSatellites skipped. GNSS HAL version is greater than 2.0."); return; } if (!(gnss_cb_->last_capabilities_ & IGnssCallback::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 GnssSvStatus, 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 kGnssSvStatusTimeout = 2; std::list> sv_info_lists; int count = gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_lists, sv_info_list_cbq_size, kGnssSvStatusTimeout); ASSERT_EQ(count, sv_info_list_cbq_size); IGnssConfiguration_1_1::BlacklistedSource source_to_blacklist = FindStrongFrequentNonGpsSource(sv_info_lists, kLocationsToAwait - 1); if (source_to_blacklist.constellation == GnssConstellationType_1_0::UNKNOWN) { // Cannot find a non-GPS satellite. Let the test pass. return; } // Stop locations, blacklist the common SV StopAndClearLocations(); auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_1_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(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 GnssSvStatus, 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_list; gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout); for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) { auto constellation = Utils::mapConstellationType(sv_info.constellation); EXPECT_FALSE((sv_info.v1_0.svid == source_to_blacklist.svid) && (constellation == source_to_blacklist.constellation) && (sv_info.v1_0.svFlag & IGnssCallback::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(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 GnssSvStatus, 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_list; gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout); for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) { auto constellation = Utils::mapConstellationType(sv_info.constellation); if ((sv_info.v1_0.svid == source_to_blacklist.svid) && (constellation == source_to_blacklist.constellation) && (sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX)) { strongest_sv_is_reobserved = true; break; } } if (strongest_sv_is_reobserved) break; } } EXPECT_TRUE(strongest_sv_is_reobserved); StopAndClearLocations(); } /* * BlacklistConstellationWithLocationOff: * * 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, BlacklistConstellationWithLocationOff) { if (!IsGnssHalVersion_2_0()) { ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 2.0."); return; } if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) { ALOGI("Test BlacklistConstellation skipped. SATELLITE_BLACKLIST capability not supported."); return; } const int kLocationsToAwait = 3; // Find first non-GPS constellation to blacklist GnssConstellationType_1_0 constellation_to_blacklist = startLocationAndGetNonGpsConstellation(); // Turns off location StopAndClearLocations(); IGnssConfiguration_1_1::BlacklistedSource source_to_blacklist; source_to_blacklist.constellation = constellation_to_blacklist; source_to_blacklist.svid = 0; // documented wildcard for all satellites in this constellation auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_1_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; // setBlacklist when location is off. auto result = gnss_configuration_hal->setBlacklist(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 GnssSvStatus, while awaiting %d Locations", sv_info_list_cbq_size, kLocationsToAwait); const int kGnssSvStatusTimeout = 2; for (int i = 0; i < sv_info_list_cbq_size; ++i) { hidl_vec sv_info_list; gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout); for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) { auto constellation = Utils::mapConstellationType(sv_info.constellation); EXPECT_FALSE((constellation == source_to_blacklist.constellation) && (sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX)); } } // clean up StopAndClearLocations(); sources.resize(0); result = gnss_configuration_hal->setBlacklist(sources); ASSERT_TRUE(result.isOk()); EXPECT_TRUE(result); } /* * BlacklistConstellationWithLocationOn: * * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding * GnssStatus for any non-GPS constellations. * 2a & b) Blacklist first non-GPS constellations, and turns 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 blacklist. */ TEST_P(GnssHalTest, BlacklistConstellationWithLocationOn) { if (!IsGnssHalVersion_2_0()) { ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 2.0."); return; } if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) { ALOGI("Test BlacklistConstellation skipped. SATELLITE_BLACKLIST capability not supported."); return; } const int kLocationsToAwait = 3; // Find first non-GPS constellation to blacklist GnssConstellationType_1_0 constellation_to_blacklist = startLocationAndGetNonGpsConstellation(); IGnssConfiguration_1_1::BlacklistedSource source_to_blacklist; source_to_blacklist.constellation = constellation_to_blacklist; source_to_blacklist.svid = 0; // documented wildcard for all satellites in this constellation auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_1_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; // setBlacklist when location is on. auto result = gnss_configuration_hal->setBlacklist(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 GnssSvStatus, while awaiting %d Locations", sv_info_list_cbq_size, kLocationsToAwait); const int kGnssSvStatusTimeout = 2; for (int i = 0; i < sv_info_list_cbq_size; ++i) { hidl_vec sv_info_list; gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout); for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) { auto constellation = Utils::mapConstellationType(sv_info.constellation); EXPECT_FALSE((constellation == source_to_blacklist.constellation) && (sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX)); } } // clean up StopAndClearLocations(); sources.resize(0); result = gnss_configuration_hal->setBlacklist(sources); ASSERT_TRUE(result.isOk()); EXPECT_TRUE(result); }