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