• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "GnssHalTestCases"
18 
19 #include <android/hardware/gnss/IGnss.h>
20 #include <android/hardware/gnss/IGnssMeasurementCallback.h>
21 #include <android/hardware/gnss/IGnssMeasurementInterface.h>
22 #include <android/hardware/gnss/IGnssPowerIndication.h>
23 #include <android/hardware/gnss/IGnssPsds.h>
24 #include "GnssMeasurementCallbackAidl.h"
25 #include "GnssPowerIndicationCallback.h"
26 #include "gnss_hal_test.h"
27 
28 using android::sp;
29 using android::hardware::gnss::BlocklistedSource;
30 using android::hardware::gnss::ElapsedRealtime;
31 using android::hardware::gnss::GnssClock;
32 using android::hardware::gnss::GnssData;
33 using android::hardware::gnss::GnssMeasurement;
34 using android::hardware::gnss::GnssPowerStats;
35 using android::hardware::gnss::IGnss;
36 using android::hardware::gnss::IGnssConfiguration;
37 using android::hardware::gnss::IGnssMeasurementCallback;
38 using android::hardware::gnss::IGnssMeasurementInterface;
39 using android::hardware::gnss::IGnssPowerIndication;
40 using android::hardware::gnss::IGnssPsds;
41 using android::hardware::gnss::PsdsType;
42 using android::hardware::gnss::SatellitePvt;
43 
44 using GnssConstellationTypeAidl = android::hardware::gnss::GnssConstellationType;
45 
46 /*
47  * SetupTeardownCreateCleanup:
48  * Requests the gnss HAL then calls cleanup
49  *
50  * Empty test fixture to verify basic Setup & Teardown
51  */
TEST_P(GnssHalTest,SetupTeardownCreateCleanup)52 TEST_P(GnssHalTest, SetupTeardownCreateCleanup) {}
53 
54 /*
55  * TestPsdsExtension:
56  * 1. Gets the PsdsExtension and verifies that it returns a non-null extension.
57  * 2. Injects empty PSDS data and verifies that it returns an error.
58  */
TEST_P(GnssHalTest,TestPsdsExtension)59 TEST_P(GnssHalTest, TestPsdsExtension) {
60     sp<IGnssPsds> iGnssPsds;
61     auto status = aidl_gnss_hal_->getExtensionPsds(&iGnssPsds);
62     ASSERT_TRUE(status.isOk());
63     ASSERT_TRUE(iGnssPsds != nullptr);
64 
65     status = iGnssPsds->injectPsdsData(PsdsType::LONG_TERM, std::vector<uint8_t>());
66     ASSERT_FALSE(status.isOk());
67 }
68 
CheckSatellitePvt(const SatellitePvt & satellitePvt)69 void CheckSatellitePvt(const SatellitePvt& satellitePvt) {
70     const double kMaxOrbitRadiusMeters = 43000000.0;
71     const double kMaxVelocityMps = 4000.0;
72     // The below values are determined using GPS ICD Table 20-1
73     const double kMinHardwareCodeBiasMeters = -17.869;
74     const double kMaxHardwareCodeBiasMeters = 17.729;
75     const double kMaxTimeCorrelationMeters = 3e6;
76     const double kMaxSatClkDriftMps = 1.117;
77 
78     ASSERT_TRUE(satellitePvt.flags & SatellitePvt::HAS_POSITION_VELOCITY_CLOCK_INFO ||
79                 satellitePvt.flags & SatellitePvt::HAS_IONO ||
80                 satellitePvt.flags & SatellitePvt::HAS_TROPO);
81     if (satellitePvt.flags & SatellitePvt::HAS_POSITION_VELOCITY_CLOCK_INFO) {
82         ALOGD("Found HAS_POSITION_VELOCITY_CLOCK_INFO");
83         ASSERT_TRUE(satellitePvt.satPosEcef.posXMeters >= -kMaxOrbitRadiusMeters &&
84                     satellitePvt.satPosEcef.posXMeters <= kMaxOrbitRadiusMeters);
85         ASSERT_TRUE(satellitePvt.satPosEcef.posYMeters >= -kMaxOrbitRadiusMeters &&
86                     satellitePvt.satPosEcef.posYMeters <= kMaxOrbitRadiusMeters);
87         ASSERT_TRUE(satellitePvt.satPosEcef.posZMeters >= -kMaxOrbitRadiusMeters &&
88                     satellitePvt.satPosEcef.posZMeters <= kMaxOrbitRadiusMeters);
89         ASSERT_TRUE(satellitePvt.satPosEcef.ureMeters > 0);
90         ASSERT_TRUE(satellitePvt.satVelEcef.velXMps >= -kMaxVelocityMps &&
91                     satellitePvt.satVelEcef.velXMps <= kMaxVelocityMps);
92         ASSERT_TRUE(satellitePvt.satVelEcef.velYMps >= -kMaxVelocityMps &&
93                     satellitePvt.satVelEcef.velYMps <= kMaxVelocityMps);
94         ASSERT_TRUE(satellitePvt.satVelEcef.velZMps >= -kMaxVelocityMps &&
95                     satellitePvt.satVelEcef.velZMps <= kMaxVelocityMps);
96         ASSERT_TRUE(satellitePvt.satVelEcef.ureRateMps > 0);
97         ASSERT_TRUE(
98                 satellitePvt.satClockInfo.satHardwareCodeBiasMeters > kMinHardwareCodeBiasMeters &&
99                 satellitePvt.satClockInfo.satHardwareCodeBiasMeters < kMaxHardwareCodeBiasMeters);
100         ASSERT_TRUE(satellitePvt.satClockInfo.satTimeCorrectionMeters >
101                             -kMaxTimeCorrelationMeters &&
102                     satellitePvt.satClockInfo.satTimeCorrectionMeters < kMaxTimeCorrelationMeters);
103         ASSERT_TRUE(satellitePvt.satClockInfo.satClkDriftMps > -kMaxSatClkDriftMps &&
104                     satellitePvt.satClockInfo.satClkDriftMps < kMaxSatClkDriftMps);
105     }
106     if (satellitePvt.flags & SatellitePvt::HAS_IONO) {
107         ALOGD("Found HAS_IONO");
108         ASSERT_TRUE(satellitePvt.ionoDelayMeters > 0 && satellitePvt.ionoDelayMeters < 100);
109     }
110     if (satellitePvt.flags & SatellitePvt::HAS_TROPO) {
111         ALOGD("Found HAS_TROPO");
112         ASSERT_TRUE(satellitePvt.tropoDelayMeters > 0 && satellitePvt.tropoDelayMeters < 100);
113     }
114 }
115 
CheckGnssMeasurementClockFields(const GnssData & measurement)116 void CheckGnssMeasurementClockFields(const GnssData& measurement) {
117     ASSERT_TRUE(measurement.elapsedRealtime.flags >= 0 &&
118                 measurement.elapsedRealtime.flags <= (ElapsedRealtime::HAS_TIMESTAMP_NS |
119                                                       ElapsedRealtime::HAS_TIME_UNCERTAINTY_NS));
120     if (measurement.elapsedRealtime.flags & ElapsedRealtime::HAS_TIMESTAMP_NS) {
121         ASSERT_TRUE(measurement.elapsedRealtime.timestampNs > 0);
122     }
123     if (measurement.elapsedRealtime.flags & ElapsedRealtime::HAS_TIME_UNCERTAINTY_NS) {
124         ASSERT_TRUE(measurement.elapsedRealtime.timeUncertaintyNs > 0);
125     }
126     ASSERT_TRUE(measurement.clock.gnssClockFlags >= 0 &&
127                 measurement.clock.gnssClockFlags <=
128                         (GnssClock::HAS_LEAP_SECOND | GnssClock::HAS_TIME_UNCERTAINTY |
129                          GnssClock::HAS_FULL_BIAS | GnssClock::HAS_BIAS |
130                          GnssClock::HAS_BIAS_UNCERTAINTY | GnssClock::HAS_DRIFT |
131                          GnssClock::HAS_DRIFT_UNCERTAINTY));
132 }
133 
CheckGnssMeasurementFlags(const GnssMeasurement & measurement)134 void CheckGnssMeasurementFlags(const GnssMeasurement& measurement) {
135     ASSERT_TRUE(measurement.flags >= 0 &&
136                 measurement.flags <=
137                         (GnssMeasurement::HAS_SNR | GnssMeasurement::HAS_CARRIER_FREQUENCY |
138                          GnssMeasurement::HAS_CARRIER_CYCLES | GnssMeasurement::HAS_CARRIER_PHASE |
139                          GnssMeasurement::HAS_CARRIER_PHASE_UNCERTAINTY |
140                          GnssMeasurement::HAS_AUTOMATIC_GAIN_CONTROL |
141                          GnssMeasurement::HAS_FULL_ISB | GnssMeasurement::HAS_FULL_ISB_UNCERTAINTY |
142                          GnssMeasurement::HAS_SATELLITE_ISB |
143                          GnssMeasurement::HAS_SATELLITE_ISB_UNCERTAINTY |
144                          GnssMeasurement::HAS_SATELLITE_PVT |
145                          GnssMeasurement::HAS_CORRELATION_VECTOR));
146 }
147 
148 /*
149  * TestGnssMeasurementExtensionAndSatellitePvt:
150  * 1. Gets the GnssMeasurementExtension and verifies that it returns a non-null extension.
151  * 2. Sets a GnssMeasurementCallback, waits for a measurement, and verifies mandatory fields are
152  *    valid.
153  * 3. If SatellitePvt is supported, waits for a measurement with SatellitePvt, and verifies the
154  *    fields are valid.
155  */
TEST_P(GnssHalTest,TestGnssMeasurementExtensionAndSatellitePvt)156 TEST_P(GnssHalTest, TestGnssMeasurementExtensionAndSatellitePvt) {
157     const bool kIsSatellitePvtSupported =
158             aidl_gnss_cb_->last_capabilities_ & (int)GnssCallbackAidl::CAPABILITY_SATELLITE_PVT;
159     ALOGD("SatellitePvt supported: %s", kIsSatellitePvtSupported ? "true" : "false");
160     const int kFirstGnssMeasurementTimeoutSeconds = 10;
161     const int kNumMeasurementEvents = 75;
162 
163     sp<IGnssMeasurementInterface> iGnssMeasurement;
164     auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
165     ASSERT_TRUE(status.isOk());
166     ASSERT_TRUE(iGnssMeasurement != nullptr);
167 
168     auto callback = sp<GnssMeasurementCallbackAidl>::make();
169     status = iGnssMeasurement->setCallback(callback, /* enableFullTracking= */ true,
170                                            /* enableCorrVecOutputs */ false);
171     ASSERT_TRUE(status.isOk());
172 
173     bool satellitePvtFound = false;
174     for (int i = 0; i < kNumMeasurementEvents; i++) {
175         if (i > 0 && (!kIsSatellitePvtSupported || satellitePvtFound)) {
176             break;
177         }
178         GnssData lastMeasurement;
179         ASSERT_TRUE(callback->gnss_data_cbq_.retrieve(lastMeasurement,
180                                                       kFirstGnssMeasurementTimeoutSeconds));
181         EXPECT_EQ(callback->gnss_data_cbq_.calledCount(), i + 1);
182         ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
183 
184         // Validity check GnssData fields
185         CheckGnssMeasurementClockFields(lastMeasurement);
186 
187         for (const auto& measurement : lastMeasurement.measurements) {
188             CheckGnssMeasurementFlags(measurement);
189             if (measurement.flags & GnssMeasurement::HAS_SATELLITE_PVT &&
190                 kIsSatellitePvtSupported == true) {
191                 ALOGD("Found a measurement with SatellitePvt");
192                 satellitePvtFound = true;
193                 CheckSatellitePvt(measurement.satellitePvt);
194             }
195         }
196     }
197     if (kIsSatellitePvtSupported) {
198         ASSERT_TRUE(satellitePvtFound);
199     }
200 
201     status = iGnssMeasurement->close();
202     ASSERT_TRUE(status.isOk());
203 }
204 
205 /*
206  * TestCorrelationVector:
207  * 1. Gets the GnssMeasurementExtension and verifies that it returns a non-null extension.
208  * 2. Sets a GnssMeasurementCallback, waits for GnssMeasurements with CorrelationVector, and
209  *    verifies fields are valid.
210  */
TEST_P(GnssHalTest,TestCorrelationVector)211 TEST_P(GnssHalTest, TestCorrelationVector) {
212     const bool kIsCorrelationVectorSupported = aidl_gnss_cb_->last_capabilities_ &
213                                                (int)GnssCallbackAidl::CAPABILITY_CORRELATION_VECTOR;
214     const int kNumMeasurementEvents = 75;
215     // Pass the test if CorrelationVector is not supported
216     if (!kIsCorrelationVectorSupported) {
217         return;
218     }
219 
220     const int kFirstGnssMeasurementTimeoutSeconds = 10;
221     sp<IGnssMeasurementInterface> iGnssMeasurement;
222     auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
223     ASSERT_TRUE(status.isOk());
224     ASSERT_TRUE(iGnssMeasurement != nullptr);
225 
226     auto callback = sp<GnssMeasurementCallbackAidl>::make();
227     status =
228             iGnssMeasurement->setCallback(callback, /* enableFullTracking= */ true,
229                                           /* enableCorrVecOutputs */ kIsCorrelationVectorSupported);
230     ASSERT_TRUE(status.isOk());
231 
232     bool correlationVectorFound = false;
233     for (int i = 0; i < kNumMeasurementEvents; i++) {
234         // Pass the test if at least one CorrelationVector has been found.
235         if (correlationVectorFound) {
236             break;
237         }
238         GnssData lastMeasurement;
239         ASSERT_TRUE(callback->gnss_data_cbq_.retrieve(lastMeasurement,
240                                                       kFirstGnssMeasurementTimeoutSeconds));
241         EXPECT_EQ(callback->gnss_data_cbq_.calledCount(), i + 1);
242         ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
243 
244         // Validity check GnssData fields
245         CheckGnssMeasurementClockFields(lastMeasurement);
246 
247         for (const auto& measurement : lastMeasurement.measurements) {
248             CheckGnssMeasurementFlags(measurement);
249             if (measurement.flags & GnssMeasurement::HAS_CORRELATION_VECTOR) {
250                 correlationVectorFound = true;
251                 ASSERT_TRUE(measurement.correlationVectors.size() > 0);
252                 for (const auto& correlationVector : measurement.correlationVectors) {
253                     ASSERT_GE(correlationVector.frequencyOffsetMps, 0);
254                     ASSERT_GT(correlationVector.samplingWidthM, 0);
255                     ASSERT_TRUE(correlationVector.magnitude.size() > 0);
256                     for (const auto& magnitude : correlationVector.magnitude) {
257                         ASSERT_TRUE(magnitude >= -32768 && magnitude <= 32767);
258                     }
259                 }
260             }
261         }
262     }
263     ASSERT_TRUE(correlationVectorFound);
264 
265     status = iGnssMeasurement->close();
266     ASSERT_TRUE(status.isOk());
267 }
268 
269 /*
270  * TestGnssPowerIndication
271  * 1. Gets the GnssPowerIndicationExtension.
272  * 2. Sets a GnssPowerIndicationCallback.
273  * 3. Requests and verifies the 1st GnssPowerStats is received.
274  * 4. Gets a location.
275  * 5. Requests the 2nd GnssPowerStats, and verifies it has larger values than the 1st one.
276  */
TEST_P(GnssHalTest,TestGnssPowerIndication)277 TEST_P(GnssHalTest, TestGnssPowerIndication) {
278     // Set up gnssPowerIndication and callback
279     sp<IGnssPowerIndication> iGnssPowerIndication;
280     auto status = aidl_gnss_hal_->getExtensionGnssPowerIndication(&iGnssPowerIndication);
281     ASSERT_TRUE(status.isOk());
282     ASSERT_TRUE(iGnssPowerIndication != nullptr);
283 
284     auto gnssPowerIndicationCallback = sp<GnssPowerIndicationCallback>::make();
285     status = iGnssPowerIndication->setCallback(gnssPowerIndicationCallback);
286     ASSERT_TRUE(status.isOk());
287 
288     const int kTimeoutSec = 2;
289     EXPECT_TRUE(gnssPowerIndicationCallback->capabilities_cbq_.retrieve(
290             gnssPowerIndicationCallback->last_capabilities_, kTimeoutSec));
291 
292     EXPECT_EQ(gnssPowerIndicationCallback->capabilities_cbq_.calledCount(), 1);
293 
294     // Request and verify a GnssPowerStats is received
295     gnssPowerIndicationCallback->gnss_power_stats_cbq_.reset();
296     iGnssPowerIndication->requestGnssPowerStats();
297 
298     EXPECT_TRUE(gnssPowerIndicationCallback->gnss_power_stats_cbq_.retrieve(
299             gnssPowerIndicationCallback->last_gnss_power_stats_, kTimeoutSec));
300     EXPECT_EQ(gnssPowerIndicationCallback->gnss_power_stats_cbq_.calledCount(), 1);
301     auto powerStats1 = gnssPowerIndicationCallback->last_gnss_power_stats_;
302 
303     // Get a location and request another GnssPowerStats
304     gnss_cb_->location_cbq_.reset();
305     StartAndCheckFirstLocation(/* min_interval_msec= */ 1000, /* low_power_mode= */ false);
306 
307     // Request and verify the 2nd GnssPowerStats has larger values than the 1st one
308     iGnssPowerIndication->requestGnssPowerStats();
309 
310     EXPECT_TRUE(gnssPowerIndicationCallback->gnss_power_stats_cbq_.retrieve(
311             gnssPowerIndicationCallback->last_gnss_power_stats_, kTimeoutSec));
312     EXPECT_EQ(gnssPowerIndicationCallback->gnss_power_stats_cbq_.calledCount(), 2);
313 
314     auto powerStats2 = gnssPowerIndicationCallback->last_gnss_power_stats_;
315 
316     if ((gnssPowerIndicationCallback->last_capabilities_ &
317          (int)GnssPowerIndicationCallback::CAPABILITY_TOTAL)) {
318         // Elapsed realtime must increase
319         EXPECT_GT(powerStats2.elapsedRealtime.timestampNs, powerStats1.elapsedRealtime.timestampNs);
320 
321         // Total energy must increase
322         EXPECT_GT(powerStats2.totalEnergyMilliJoule, powerStats1.totalEnergyMilliJoule);
323     }
324 
325     // At least oone of singleband and multiband acquisition energy must increase
326     bool singlebandAcqEnergyIncreased = powerStats2.singlebandAcquisitionModeEnergyMilliJoule >
327                                         powerStats1.singlebandAcquisitionModeEnergyMilliJoule;
328     bool multibandAcqEnergyIncreased = powerStats2.multibandAcquisitionModeEnergyMilliJoule >
329                                        powerStats1.multibandAcquisitionModeEnergyMilliJoule;
330 
331     if ((gnssPowerIndicationCallback->last_capabilities_ &
332          (int)GnssPowerIndicationCallback::CAPABILITY_SINGLEBAND_ACQUISITION) ||
333         (gnssPowerIndicationCallback->last_capabilities_ &
334          (int)GnssPowerIndicationCallback::CAPABILITY_MULTIBAND_ACQUISITION)) {
335         EXPECT_TRUE(singlebandAcqEnergyIncreased || multibandAcqEnergyIncreased);
336     }
337 
338     // At least one of singleband and multiband tracking energy must increase
339     bool singlebandTrackingEnergyIncreased = powerStats2.singlebandTrackingModeEnergyMilliJoule >
340                                              powerStats1.singlebandTrackingModeEnergyMilliJoule;
341     bool multibandTrackingEnergyIncreased = powerStats2.multibandTrackingModeEnergyMilliJoule >
342                                             powerStats1.multibandTrackingModeEnergyMilliJoule;
343     if ((gnssPowerIndicationCallback->last_capabilities_ &
344          (int)GnssPowerIndicationCallback::CAPABILITY_SINGLEBAND_TRACKING) ||
345         (gnssPowerIndicationCallback->last_capabilities_ &
346          (int)GnssPowerIndicationCallback::CAPABILITY_MULTIBAND_TRACKING)) {
347         EXPECT_TRUE(singlebandTrackingEnergyIncreased || multibandTrackingEnergyIncreased);
348     }
349 
350     // Clean up
351     StopAndClearLocations();
352 }
353 
354 /*
355  * FindStrongFrequentNonGpsSource:
356  *
357  * Search through a GnssSvStatus list for the strongest non-GPS satellite observed enough times
358  *
359  * returns the strongest source,
360  *         or a source with constellation == UNKNOWN if none are found sufficient times
361  */
FindStrongFrequentNonGpsSource(const std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_list,const int min_observations)362 BlocklistedSource FindStrongFrequentNonGpsSource(
363         const std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_list,
364         const int min_observations) {
365     struct ComparableBlocklistedSource {
366         BlocklistedSource id;
367 
368         ComparableBlocklistedSource() {
369             id.constellation = GnssConstellationTypeAidl::UNKNOWN;
370             id.svid = 0;
371         }
372 
373         bool operator<(const ComparableBlocklistedSource& compare) const {
374             return ((id.svid < compare.id.svid) || ((id.svid == compare.id.svid) &&
375                                                     (id.constellation < compare.id.constellation)));
376         }
377     };
378 
379     struct SignalCounts {
380         int observations;
381         float max_cn0_dbhz;
382     };
383 
384     std::map<ComparableBlocklistedSource, SignalCounts> mapSignals;
385 
386     for (const auto& sv_info_vec : sv_info_list) {
387         for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
388             const auto& gnss_sv = sv_info_vec[iSv];
389             if ((gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX) &&
390                 (gnss_sv.v2_0.constellation != GnssConstellationType::GPS)) {
391                 ComparableBlocklistedSource source;
392                 source.id.svid = gnss_sv.v2_0.v1_0.svid;
393                 source.id.constellation =
394                         static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation);
395 
396                 const auto& itSignal = mapSignals.find(source);
397                 if (itSignal == mapSignals.end()) {
398                     SignalCounts counts;
399                     counts.observations = 1;
400                     counts.max_cn0_dbhz = gnss_sv.v2_0.v1_0.cN0Dbhz;
401                     mapSignals.insert(
402                             std::pair<ComparableBlocklistedSource, SignalCounts>(source, counts));
403                 } else {
404                     itSignal->second.observations++;
405                     if (itSignal->second.max_cn0_dbhz < gnss_sv.v2_0.v1_0.cN0Dbhz) {
406                         itSignal->second.max_cn0_dbhz = gnss_sv.v2_0.v1_0.cN0Dbhz;
407                     }
408                 }
409             }
410         }
411     }
412 
413     float max_cn0_dbhz_with_sufficient_count = 0.;
414     int total_observation_count = 0;
415     int blocklisted_source_count_observation = 0;
416 
417     ComparableBlocklistedSource source_to_blocklist;  // initializes to zero = UNKNOWN constellation
418     for (auto const& pairSignal : mapSignals) {
419         total_observation_count += pairSignal.second.observations;
420         if ((pairSignal.second.observations >= min_observations) &&
421             (pairSignal.second.max_cn0_dbhz > max_cn0_dbhz_with_sufficient_count)) {
422             source_to_blocklist = pairSignal.first;
423             blocklisted_source_count_observation = pairSignal.second.observations;
424             max_cn0_dbhz_with_sufficient_count = pairSignal.second.max_cn0_dbhz;
425         }
426     }
427     ALOGD("Among %d observations, chose svid %d, constellation %d, "
428           "with %d observations at %.1f max CNo",
429           total_observation_count, source_to_blocklist.id.svid,
430           (int)source_to_blocklist.id.constellation, blocklisted_source_count_observation,
431           max_cn0_dbhz_with_sufficient_count);
432 
433     return source_to_blocklist.id;
434 }
435 
436 /*
437  * BlocklistIndividualSatellites:
438  *
439  * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
440  * GnssStatus for common satellites (strongest and one other.)
441  * 2a & b) Turns off location, and blocklists common satellites.
442  * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
443  * GnssStatus does not use those satellites.
444  * 4a & b) Turns off location, and send in empty blocklist.
445  * 5a) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
446  * GnssStatus does re-use at least the previously strongest satellite
447  * 5b) Retry a few times, in case GNSS search strategy takes a while to reacquire even the
448  * formerly strongest satellite
449  */
TEST_P(GnssHalTest,BlocklistIndividualSatellites)450 TEST_P(GnssHalTest, BlocklistIndividualSatellites) {
451     if (!(aidl_gnss_cb_->last_capabilities_ &
452           (int)GnssCallbackAidl::CAPABILITY_SATELLITE_BLOCKLIST)) {
453         ALOGI("Test BlocklistIndividualSatellites skipped. SATELLITE_BLOCKLIST capability not "
454               "supported.");
455         return;
456     }
457 
458     const int kLocationsToAwait = 3;
459     const int kRetriesToUnBlocklist = 10;
460 
461     gnss_cb_->location_cbq_.reset();
462     StartAndCheckLocations(kLocationsToAwait);
463     int location_called_count = gnss_cb_->location_cbq_.calledCount();
464 
465     // Tolerate 1 less sv status to handle edge cases in reporting.
466     int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
467     EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
468     ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)",
469           sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
470 
471     /*
472      * Identify strongest SV seen at least kLocationsToAwait -1 times
473      * Why -1?  To avoid test flakiness in case of (plausible) slight flakiness in strongest signal
474      * observability (one epoch RF null)
475      */
476 
477     const int kGnssSvInfoListTimeout = 2;
478     std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_vec_list;
479     int count = gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec_list, sv_info_list_cbq_size,
480                                                      kGnssSvInfoListTimeout);
481 
482     ASSERT_EQ(count, sv_info_list_cbq_size);
483 
484     BlocklistedSource source_to_blocklist =
485             FindStrongFrequentNonGpsSource(sv_info_vec_list, kLocationsToAwait - 1);
486 
487     if (source_to_blocklist.constellation == GnssConstellationTypeAidl::UNKNOWN) {
488         // Cannot find a non-GPS satellite. Let the test pass.
489         ALOGD("Cannot find a non-GPS satellite. Letting the test pass.");
490         return;
491     }
492 
493     // Stop locations, blocklist the common SV
494     StopAndClearLocations();
495 
496     sp<IGnssConfiguration> gnss_configuration_hal;
497     auto status = aidl_gnss_hal_->getExtensionGnssConfiguration(&gnss_configuration_hal);
498     ASSERT_TRUE(status.isOk());
499     ASSERT_NE(gnss_configuration_hal, nullptr);
500 
501     std::vector<BlocklistedSource> sources;
502     sources.resize(1);
503     sources[0] = source_to_blocklist;
504 
505     status = gnss_configuration_hal->setBlocklist(sources);
506     ASSERT_TRUE(status.isOk());
507 
508     // retry and ensure satellite not used
509     gnss_cb_->sv_info_list_cbq_.reset();
510 
511     gnss_cb_->location_cbq_.reset();
512     StartAndCheckLocations(kLocationsToAwait);
513 
514     // early exit if test is being run with insufficient signal
515     location_called_count = gnss_cb_->location_cbq_.calledCount();
516     if (location_called_count == 0) {
517         ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
518     }
519     ASSERT_TRUE(location_called_count > 0);
520 
521     // Tolerate 1 less sv status to handle edge cases in reporting.
522     sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
523     EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
524     ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)",
525           sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
526     for (int i = 0; i < sv_info_list_cbq_size; ++i) {
527         hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
528         gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
529         for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
530             const auto& gnss_sv = sv_info_vec[iSv];
531             EXPECT_FALSE((gnss_sv.v2_0.v1_0.svid == source_to_blocklist.svid) &&
532                          (static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
533                           source_to_blocklist.constellation) &&
534                          (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
535         }
536     }
537 
538     // clear blocklist and restart - this time updating the blocklist while location is still on
539     sources.resize(0);
540 
541     status = gnss_configuration_hal->setBlocklist(sources);
542     ASSERT_TRUE(status.isOk());
543 
544     bool strongest_sv_is_reobserved = false;
545     // do several loops awaiting a few locations, allowing non-immediate reacquisition strategies
546     int unblocklist_loops_remaining = kRetriesToUnBlocklist;
547     while (!strongest_sv_is_reobserved && (unblocklist_loops_remaining-- > 0)) {
548         StopAndClearLocations();
549         gnss_cb_->sv_info_list_cbq_.reset();
550 
551         gnss_cb_->location_cbq_.reset();
552         StartAndCheckLocations(kLocationsToAwait);
553 
554         // early exit loop if test is being run with insufficient signal
555         location_called_count = gnss_cb_->location_cbq_.calledCount();
556         if (location_called_count == 0) {
557             ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
558         }
559         ASSERT_TRUE(location_called_count > 0);
560 
561         // Tolerate 1 less sv status to handle edge cases in reporting.
562         sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
563         EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
564         ALOGD("Clear blocklist, observed %d GnssSvInfo, while awaiting %d Locations"
565               ", tries remaining %d",
566               sv_info_list_cbq_size, kLocationsToAwait, unblocklist_loops_remaining);
567 
568         for (int i = 0; i < sv_info_list_cbq_size; ++i) {
569             hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
570             gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
571             for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
572                 const auto& gnss_sv = sv_info_vec[iSv];
573                 if ((gnss_sv.v2_0.v1_0.svid == source_to_blocklist.svid) &&
574                     (static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
575                      source_to_blocklist.constellation) &&
576                     (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX)) {
577                     strongest_sv_is_reobserved = true;
578                     break;
579                 }
580             }
581             if (strongest_sv_is_reobserved) break;
582         }
583     }
584     EXPECT_TRUE(strongest_sv_is_reobserved);
585     StopAndClearLocations();
586 }
587 
588 /*
589  * BlocklistConstellationLocationOff:
590  *
591  * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
592  * GnssStatus for any non-GPS constellations.
593  * 2a & b) Turns off location, and blocklist first non-GPS constellations.
594  * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
595  * GnssStatus does not use any constellation but GPS.
596  * 4a & b) Clean up by turning off location, and send in empty blocklist.
597  */
TEST_P(GnssHalTest,BlocklistConstellationLocationOff)598 TEST_P(GnssHalTest, BlocklistConstellationLocationOff) {
599     if (!(aidl_gnss_cb_->last_capabilities_ &
600           (int)GnssCallbackAidl::CAPABILITY_SATELLITE_BLOCKLIST)) {
601         ALOGI("Test BlocklistConstellationLocationOff skipped. SATELLITE_BLOCKLIST capability not "
602               "supported.");
603         return;
604     }
605 
606     const int kLocationsToAwait = 3;
607     const int kGnssSvInfoListTimeout = 2;
608 
609     // Find first non-GPS constellation to blocklist
610     GnssConstellationTypeAidl constellation_to_blocklist = static_cast<GnssConstellationTypeAidl>(
611             startLocationAndGetNonGpsConstellation(kLocationsToAwait, kGnssSvInfoListTimeout));
612 
613     // Turns off location
614     StopAndClearLocations();
615 
616     BlocklistedSource source_to_blocklist_1;
617     source_to_blocklist_1.constellation = constellation_to_blocklist;
618     source_to_blocklist_1.svid = 0;  // documented wildcard for all satellites in this constellation
619 
620     // IRNSS was added in 2.0. Always attempt to blocklist IRNSS to verify that the new enum is
621     // supported.
622     BlocklistedSource source_to_blocklist_2;
623     source_to_blocklist_2.constellation = GnssConstellationTypeAidl::IRNSS;
624     source_to_blocklist_2.svid = 0;  // documented wildcard for all satellites in this constellation
625 
626     sp<IGnssConfiguration> gnss_configuration_hal;
627     auto status = aidl_gnss_hal_->getExtensionGnssConfiguration(&gnss_configuration_hal);
628     ASSERT_TRUE(status.isOk());
629     ASSERT_NE(gnss_configuration_hal, nullptr);
630 
631     hidl_vec<BlocklistedSource> sources;
632     sources.resize(2);
633     sources[0] = source_to_blocklist_1;
634     sources[1] = source_to_blocklist_2;
635 
636     status = gnss_configuration_hal->setBlocklist(sources);
637     ASSERT_TRUE(status.isOk());
638 
639     // retry and ensure constellation not used
640     gnss_cb_->sv_info_list_cbq_.reset();
641 
642     gnss_cb_->location_cbq_.reset();
643     StartAndCheckLocations(kLocationsToAwait);
644 
645     // Tolerate 1 less sv status to handle edge cases in reporting.
646     int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
647     EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
648     ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations", sv_info_list_cbq_size,
649           kLocationsToAwait);
650     for (int i = 0; i < sv_info_list_cbq_size; ++i) {
651         hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
652         gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
653         for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
654             const auto& gnss_sv = sv_info_vec[iSv];
655             EXPECT_FALSE((static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
656                           source_to_blocklist_1.constellation) &&
657                          (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
658             EXPECT_FALSE((static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
659                           source_to_blocklist_2.constellation) &&
660                          (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
661         }
662     }
663 
664     // clean up
665     StopAndClearLocations();
666     sources.resize(0);
667     status = gnss_configuration_hal->setBlocklist(sources);
668     ASSERT_TRUE(status.isOk());
669 }
670 
671 /*
672  * BlocklistConstellationLocationOn:
673  *
674  * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
675  * GnssStatus for any non-GPS constellations.
676  * 2a & b) Blocklist first non-GPS constellation, and turn off location.
677  * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
678  * GnssStatus does not use any constellation but GPS.
679  * 4a & b) Clean up by turning off location, and send in empty blocklist.
680  */
TEST_P(GnssHalTest,BlocklistConstellationLocationOn)681 TEST_P(GnssHalTest, BlocklistConstellationLocationOn) {
682     if (!(aidl_gnss_cb_->last_capabilities_ &
683           (int)GnssCallbackAidl::CAPABILITY_SATELLITE_BLOCKLIST)) {
684         ALOGI("Test BlocklistConstellationLocationOn skipped. SATELLITE_BLOCKLIST capability not "
685               "supported.");
686         return;
687     }
688 
689     const int kLocationsToAwait = 3;
690     const int kGnssSvInfoListTimeout = 2;
691 
692     // Find first non-GPS constellation to blocklist
693     GnssConstellationTypeAidl constellation_to_blocklist = static_cast<GnssConstellationTypeAidl>(
694             startLocationAndGetNonGpsConstellation(kLocationsToAwait, kGnssSvInfoListTimeout));
695 
696     BlocklistedSource source_to_blocklist_1;
697     source_to_blocklist_1.constellation = constellation_to_blocklist;
698     source_to_blocklist_1.svid = 0;  // documented wildcard for all satellites in this constellation
699 
700     // IRNSS was added in 2.0. Always attempt to blocklist IRNSS to verify that the new enum is
701     // supported.
702     BlocklistedSource source_to_blocklist_2;
703     source_to_blocklist_2.constellation = GnssConstellationTypeAidl::IRNSS;
704     source_to_blocklist_2.svid = 0;  // documented wildcard for all satellites in this constellation
705 
706     sp<IGnssConfiguration> gnss_configuration_hal;
707     auto status = aidl_gnss_hal_->getExtensionGnssConfiguration(&gnss_configuration_hal);
708     ASSERT_TRUE(status.isOk());
709     ASSERT_NE(gnss_configuration_hal, nullptr);
710 
711     hidl_vec<BlocklistedSource> sources;
712     sources.resize(2);
713     sources[0] = source_to_blocklist_1;
714     sources[1] = source_to_blocklist_2;
715 
716     status = gnss_configuration_hal->setBlocklist(sources);
717     ASSERT_TRUE(status.isOk());
718 
719     // Turns off location
720     StopAndClearLocations();
721 
722     // retry and ensure constellation not used
723     gnss_cb_->sv_info_list_cbq_.reset();
724 
725     gnss_cb_->location_cbq_.reset();
726     StartAndCheckLocations(kLocationsToAwait);
727 
728     // Tolerate 1 less sv status to handle edge cases in reporting.
729     int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
730     EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
731     ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations", sv_info_list_cbq_size,
732           kLocationsToAwait);
733     for (int i = 0; i < sv_info_list_cbq_size; ++i) {
734         hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
735         gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
736         for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
737             const auto& gnss_sv = sv_info_vec[iSv];
738             EXPECT_FALSE((static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
739                           source_to_blocklist_1.constellation) &&
740                          (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
741             EXPECT_FALSE((static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
742                           source_to_blocklist_2.constellation) &&
743                          (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
744         }
745     }
746 
747     // clean up
748     StopAndClearLocations();
749     sources.resize(0);
750     status = gnss_configuration_hal->setBlocklist(sources);
751     ASSERT_TRUE(status.isOk());
752 }
753