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