1 /*
2 * Copyright (C) 2017 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 <gnss_hal_test.h>
20
21 #include <VtsHalHidlTargetTestBase.h>
22
23 #include <android/hardware/gnss/1.1/IGnssConfiguration.h>
24
25 using android::hardware::hidl_vec;
26
27 using android::hardware::gnss::V1_0::GnssConstellationType;
28 using android::hardware::gnss::V1_0::GnssLocation;
29 using android::hardware::gnss::V1_0::IGnssDebug;
30 using android::hardware::gnss::V1_1::IGnssConfiguration;
31 using android::hardware::gnss::V1_1::IGnssMeasurement;
32
33 /*
34 * SetupTeardownCreateCleanup:
35 * Requests the gnss HAL then calls cleanup
36 *
37 * Empty test fixture to verify basic Setup & Teardown
38 */
TEST_F(GnssHalTest,SetupTeardownCreateCleanup)39 TEST_F(GnssHalTest, SetupTeardownCreateCleanup) {}
40
41 /*
42 * TestGnssMeasurementCallback:
43 * Gets the GnssMeasurementExtension and verify that it returns an actual extension.
44 */
TEST_F(GnssHalTest,TestGnssMeasurementCallback)45 TEST_F(GnssHalTest, TestGnssMeasurementCallback) {
46 auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_1_1();
47 ASSERT_TRUE(gnssMeasurement.isOk());
48 if (last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS) {
49 sp<IGnssMeasurement> iGnssMeas = gnssMeasurement;
50 EXPECT_NE(iGnssMeas, nullptr);
51 }
52 }
53
54 /*
55 * GetLocationLowPower:
56 * Turns on location, waits for at least 5 locations allowing max of LOCATION_TIMEOUT_SUBSEQUENT_SEC
57 * between one location and the next. Also ensure that MIN_INTERVAL_MSEC is respected by waiting
58 * NO_LOCATION_PERIOD_SEC and verfiy that no location is received. Also perform validity checks on
59 * each received location.
60 */
TEST_F(GnssHalTest,GetLocationLowPower)61 TEST_F(GnssHalTest, GetLocationLowPower) {
62 const int kMinIntervalMsec = 5000;
63 const int kLocationTimeoutSubsequentSec = (kMinIntervalMsec / 1000) * 2;
64 const int kNoLocationPeriodSec = (kMinIntervalMsec / 1000) / 2;
65 const int kLocationsToCheck = 5;
66 const bool kLowPowerMode = true;
67
68 // Warmup period - VTS doesn't have AGPS access via GnssLocationProvider
69 StartAndCheckLocations(5);
70 StopAndClearLocations();
71
72 // Start of Low Power Mode test
73 SetPositionMode(kMinIntervalMsec, kLowPowerMode);
74
75 // Don't expect true - as without AGPS access
76 if (!StartAndCheckFirstLocation()) {
77 ALOGW("GetLocationLowPower test - no first low power location received.");
78 }
79
80 for (int i = 1; i < kLocationsToCheck; i++) {
81 // Verify that kMinIntervalMsec is respected by waiting kNoLocationPeriodSec and
82 // ensure that no location is received yet
83
84 wait(kNoLocationPeriodSec);
85 // Tolerate (ignore) one extra location right after the first one
86 // to handle startup edge case scheduling limitations in some implementations
87 if ((i == 1) && (location_called_count_ == 2)) {
88 CheckLocation(last_location_, true);
89 continue; // restart the quiet wait period after this too-fast location
90 }
91 EXPECT_LE(location_called_count_, i);
92 if (location_called_count_ != i) {
93 ALOGW("GetLocationLowPower test - not enough locations received. %d vs. %d expected ",
94 location_called_count_, i);
95 }
96
97 if (std::cv_status::no_timeout !=
98 wait(kLocationTimeoutSubsequentSec - kNoLocationPeriodSec)) {
99 ALOGW("GetLocationLowPower test - timeout awaiting location %d", i);
100 } else {
101 CheckLocation(last_location_, true);
102 }
103 }
104
105 StopAndClearLocations();
106 }
107
108 /*
109 * FindStrongFrequentNonGpsSource:
110 *
111 * Search through a GnssSvStatus list for the strongest non-GPS satellite observed enough times
112 *
113 * returns the strongest source,
114 * or a source with constellation == UNKNOWN if none are found sufficient times
115 */
116
FindStrongFrequentNonGpsSource(const list<IGnssCallback::GnssSvStatus> list_gnss_sv_status,const int min_observations)117 IGnssConfiguration::BlacklistedSource FindStrongFrequentNonGpsSource(
118 const list<IGnssCallback::GnssSvStatus> list_gnss_sv_status, const int min_observations) {
119 struct ComparableBlacklistedSource {
120 IGnssConfiguration::BlacklistedSource id;
121
122 ComparableBlacklistedSource() {
123 id.constellation = GnssConstellationType::UNKNOWN;
124 id.svid = 0;
125 }
126
127 bool operator<(const ComparableBlacklistedSource& compare) const {
128 return ((id.svid < compare.id.svid) || ((id.svid == compare.id.svid) &&
129 (id.constellation < compare.id.constellation)));
130 }
131 };
132
133 struct SignalCounts {
134 int observations;
135 float max_cn0_dbhz;
136 };
137
138 std::map<ComparableBlacklistedSource, SignalCounts> mapSignals;
139
140 for (const auto& gnss_sv_status : list_gnss_sv_status) {
141 for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
142 const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
143 if ((gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) &&
144 (gnss_sv.constellation != GnssConstellationType::GPS)) {
145 ComparableBlacklistedSource source;
146 source.id.svid = gnss_sv.svid;
147 source.id.constellation = gnss_sv.constellation;
148
149 const auto& itSignal = mapSignals.find(source);
150 if (itSignal == mapSignals.end()) {
151 SignalCounts counts;
152 counts.observations = 1;
153 counts.max_cn0_dbhz = gnss_sv.cN0Dbhz;
154 mapSignals.insert(
155 std::pair<ComparableBlacklistedSource, SignalCounts>(source, counts));
156 } else {
157 itSignal->second.observations++;
158 if (itSignal->second.max_cn0_dbhz < gnss_sv.cN0Dbhz) {
159 itSignal->second.max_cn0_dbhz = gnss_sv.cN0Dbhz;
160 }
161 }
162 }
163 }
164 }
165
166 float max_cn0_dbhz_with_sufficient_count = 0.;
167 int total_observation_count = 0;
168 int blacklisted_source_count_observation = 0;
169
170 ComparableBlacklistedSource source_to_blacklist; // initializes to zero = UNKNOWN constellation
171 for (auto const& pairSignal : mapSignals) {
172 total_observation_count += pairSignal.second.observations;
173 if ((pairSignal.second.observations >= min_observations) &&
174 (pairSignal.second.max_cn0_dbhz > max_cn0_dbhz_with_sufficient_count)) {
175 source_to_blacklist = pairSignal.first;
176 blacklisted_source_count_observation = pairSignal.second.observations;
177 max_cn0_dbhz_with_sufficient_count = pairSignal.second.max_cn0_dbhz;
178 }
179 }
180 ALOGD(
181 "Among %d observations, chose svid %d, constellation %d, "
182 "with %d observations at %.1f max CNo",
183 total_observation_count, source_to_blacklist.id.svid,
184 (int)source_to_blacklist.id.constellation, blacklisted_source_count_observation,
185 max_cn0_dbhz_with_sufficient_count);
186
187 return source_to_blacklist.id;
188 }
189
190 /*
191 * BlacklistIndividualSatellites:
192 *
193 * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
194 * GnssStatus for common satellites (strongest and one other.)
195 * 2a & b) Turns off location, and blacklists common satellites.
196 * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
197 * GnssStatus does not use those satellites.
198 * 4a & b) Turns off location, and send in empty blacklist.
199 * 5a) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
200 * GnssStatus does re-use at least the previously strongest satellite
201 * 5b) Retry a few times, in case GNSS search strategy takes a while to reacquire even the
202 * formerly strongest satellite
203 */
TEST_F(GnssHalTest,BlacklistIndividualSatellites)204 TEST_F(GnssHalTest, BlacklistIndividualSatellites) {
205 const int kLocationsToAwait = 3;
206 const int kRetriesToUnBlacklist = 10;
207
208 StartAndCheckLocations(kLocationsToAwait);
209
210 // Tolerate 1 less sv status to handle edge cases in reporting.
211 EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
212 ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
213 (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_);
214
215 /*
216 * Identify strongest SV seen at least kLocationsToAwait -1 times
217 * Why -1? To avoid test flakiness in case of (plausible) slight flakiness in strongest signal
218 * observability (one epoch RF null)
219 */
220
221 IGnssConfiguration::BlacklistedSource source_to_blacklist =
222 FindStrongFrequentNonGpsSource(list_gnss_sv_status_, kLocationsToAwait - 1);
223
224 if (source_to_blacklist.constellation == GnssConstellationType::UNKNOWN) {
225 // Cannot find a non-GPS satellite. Let the test pass.
226 return;
227 }
228
229 // Stop locations, blacklist the common SV
230 StopAndClearLocations();
231
232 auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_1_1();
233 ASSERT_TRUE(gnss_configuration_hal_return.isOk());
234 sp<IGnssConfiguration> gnss_configuration_hal = gnss_configuration_hal_return;
235 ASSERT_NE(gnss_configuration_hal, nullptr);
236
237 hidl_vec<IGnssConfiguration::BlacklistedSource> sources;
238 sources.resize(1);
239 sources[0] = source_to_blacklist;
240
241 auto result = gnss_configuration_hal->setBlacklist(sources);
242 ASSERT_TRUE(result.isOk());
243 EXPECT_TRUE(result);
244
245 // retry and ensure satellite not used
246 list_gnss_sv_status_.clear();
247
248 StartAndCheckLocations(kLocationsToAwait);
249
250 // early exit if test is being run with insufficient signal
251 if (location_called_count_ == 0) {
252 ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
253 }
254 ASSERT_TRUE(location_called_count_ > 0);
255
256 // Tolerate 1 less sv status to handle edge cases in reporting.
257 EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
258 ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
259 (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_);
260 for (const auto& gnss_sv_status : list_gnss_sv_status_) {
261 for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
262 const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
263 EXPECT_FALSE((gnss_sv.svid == source_to_blacklist.svid) &&
264 (gnss_sv.constellation == source_to_blacklist.constellation) &&
265 (gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX));
266 }
267 }
268
269 // clear blacklist and restart - this time updating the blacklist while location is still on
270 sources.resize(0);
271
272 result = gnss_configuration_hal->setBlacklist(sources);
273 ASSERT_TRUE(result.isOk());
274 EXPECT_TRUE(result);
275
276 bool strongest_sv_is_reobserved = false;
277 // do several loops awaiting a few locations, allowing non-immediate reacquisition strategies
278 int unblacklist_loops_remaining = kRetriesToUnBlacklist;
279 while (!strongest_sv_is_reobserved && (unblacklist_loops_remaining-- > 0)) {
280 StopAndClearLocations();
281 list_gnss_sv_status_.clear();
282
283 StartAndCheckLocations(kLocationsToAwait);
284
285 // early exit loop if test is being run with insufficient signal
286 if (location_called_count_ == 0) {
287 ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
288 }
289 ASSERT_TRUE(location_called_count_ > 0);
290
291 // Tolerate 1 less sv status to handle edge cases in reporting.
292 EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
293 ALOGD(
294 "Clear blacklist, observed %d GnssSvStatus, while awaiting %d Locations"
295 ", tries remaining %d",
296 (int)list_gnss_sv_status_.size(), kLocationsToAwait, unblacklist_loops_remaining);
297
298 for (const auto& gnss_sv_status : list_gnss_sv_status_) {
299 for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
300 const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
301 if ((gnss_sv.svid == source_to_blacklist.svid) &&
302 (gnss_sv.constellation == source_to_blacklist.constellation) &&
303 (gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX)) {
304 strongest_sv_is_reobserved = true;
305 break;
306 }
307 }
308 if (strongest_sv_is_reobserved) break;
309 }
310 }
311 EXPECT_TRUE(strongest_sv_is_reobserved);
312 StopAndClearLocations();
313 }
314
315 /*
316 * BlacklistConstellation:
317 *
318 * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
319 * GnssStatus for any non-GPS constellations.
320 * 2a & b) Turns off location, and blacklist first non-GPS constellations.
321 * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
322 * GnssStatus does not use any constellation but GPS.
323 * 4a & b) Clean up by turning off location, and send in empty blacklist.
324 */
TEST_F(GnssHalTest,BlacklistConstellation)325 TEST_F(GnssHalTest, BlacklistConstellation) {
326 const int kLocationsToAwait = 3;
327
328 StartAndCheckLocations(kLocationsToAwait);
329
330 // Tolerate 1 less sv status to handle edge cases in reporting.
331 EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
332 ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
333 (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_);
334
335 // Find first non-GPS constellation to blacklist
336 GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN;
337 for (const auto& gnss_sv_status : list_gnss_sv_status_) {
338 for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
339 const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
340 if ((gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) &&
341 (gnss_sv.constellation != GnssConstellationType::UNKNOWN) &&
342 (gnss_sv.constellation != GnssConstellationType::GPS)) {
343 // found a non-GPS constellation
344 constellation_to_blacklist = gnss_sv.constellation;
345 break;
346 }
347 }
348 if (constellation_to_blacklist != GnssConstellationType::UNKNOWN) {
349 break;
350 }
351 }
352
353 if (constellation_to_blacklist == GnssConstellationType::UNKNOWN) {
354 ALOGI("No non-GPS constellations found, constellation blacklist test less effective.");
355 // Proceed functionally to blacklist something.
356 constellation_to_blacklist = GnssConstellationType::GLONASS;
357 }
358 IGnssConfiguration::BlacklistedSource source_to_blacklist;
359 source_to_blacklist.constellation = constellation_to_blacklist;
360 source_to_blacklist.svid = 0; // documented wildcard for all satellites in this constellation
361
362 auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_1_1();
363 ASSERT_TRUE(gnss_configuration_hal_return.isOk());
364 sp<IGnssConfiguration> gnss_configuration_hal = gnss_configuration_hal_return;
365 ASSERT_NE(gnss_configuration_hal, nullptr);
366
367 hidl_vec<IGnssConfiguration::BlacklistedSource> sources;
368 sources.resize(1);
369 sources[0] = source_to_blacklist;
370
371 auto result = gnss_configuration_hal->setBlacklist(sources);
372 ASSERT_TRUE(result.isOk());
373 EXPECT_TRUE(result);
374
375 // retry and ensure constellation not used
376 list_gnss_sv_status_.clear();
377
378 location_called_count_ = 0;
379 StartAndCheckLocations(kLocationsToAwait);
380
381 // Tolerate 1 less sv status to handle edge cases in reporting.
382 EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
383 ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", (int)list_gnss_sv_status_.size(),
384 kLocationsToAwait);
385 for (const auto& gnss_sv_status : list_gnss_sv_status_) {
386 for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
387 const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
388 EXPECT_FALSE((gnss_sv.constellation == source_to_blacklist.constellation) &&
389 (gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX));
390 }
391 }
392
393 // clean up
394 StopAndClearLocations();
395 sources.resize(0);
396 result = gnss_configuration_hal->setBlacklist(sources);
397 ASSERT_TRUE(result.isOk());
398 EXPECT_TRUE(result);
399 }
400
401 /*
402 * InjectBestLocation
403 *
404 * Ensure successfully injecting a location.
405 */
TEST_F(GnssHalTest,InjectBestLocation)406 TEST_F(GnssHalTest, InjectBestLocation) {
407 StartAndCheckLocations(1);
408 GnssLocation gnssLocation = last_location_;
409 CheckLocation(gnssLocation, true);
410
411 auto result = gnss_hal_->injectBestLocation(gnssLocation);
412
413 ASSERT_TRUE(result.isOk());
414 EXPECT_TRUE(result);
415
416 auto resultVoid = gnss_hal_->deleteAidingData(IGnss::GnssAidingData::DELETE_POSITION);
417
418 ASSERT_TRUE(resultVoid.isOk());
419 }
420
421 /*
422 * GnssDebugValuesSanityTest:
423 * Ensures that GnssDebug values make sense.
424 */
TEST_F(GnssHalTest,GnssDebugValuesSanityTest)425 TEST_F(GnssHalTest, GnssDebugValuesSanityTest) {
426 auto gnssDebug = gnss_hal_->getExtensionGnssDebug();
427 ASSERT_TRUE(gnssDebug.isOk());
428 if (info_called_count_ > 0 && last_info_.yearOfHw >= 2017) {
429 sp<IGnssDebug> iGnssDebug = gnssDebug;
430 EXPECT_NE(iGnssDebug, nullptr);
431
432 IGnssDebug::DebugData data;
433 iGnssDebug->getDebugData(
434 [&data](const IGnssDebug::DebugData& debugData) { data = debugData; });
435
436 if (data.position.valid) {
437 EXPECT_GE(data.position.latitudeDegrees, -90);
438 EXPECT_LE(data.position.latitudeDegrees, 90);
439
440 EXPECT_GE(data.position.longitudeDegrees, -180);
441 EXPECT_LE(data.position.longitudeDegrees, 180);
442
443 EXPECT_GE(data.position.altitudeMeters, -1000); // Dead Sea: -414m
444 EXPECT_LE(data.position.altitudeMeters, 20000); // Mount Everest: 8850m
445
446 EXPECT_GE(data.position.speedMetersPerSec, 0);
447 EXPECT_LE(data.position.speedMetersPerSec, 600);
448
449 EXPECT_GE(data.position.bearingDegrees, -360);
450 EXPECT_LE(data.position.bearingDegrees, 360);
451
452 EXPECT_GT(data.position.horizontalAccuracyMeters, 0);
453 EXPECT_LE(data.position.horizontalAccuracyMeters, 20000000);
454
455 EXPECT_GT(data.position.verticalAccuracyMeters, 0);
456 EXPECT_LE(data.position.verticalAccuracyMeters, 20000);
457
458 EXPECT_GT(data.position.speedAccuracyMetersPerSecond, 0);
459 EXPECT_LE(data.position.speedAccuracyMetersPerSecond, 500);
460
461 EXPECT_GT(data.position.bearingAccuracyDegrees, 0);
462 EXPECT_LE(data.position.bearingAccuracyDegrees, 180);
463
464 EXPECT_GE(data.position.ageSeconds, 0);
465 }
466
467 EXPECT_GE(data.time.timeEstimate, 1483228800000); // Jan 01 2017 00:00:00 GMT.
468
469 EXPECT_GT(data.time.timeUncertaintyNs, 0);
470
471 EXPECT_GT(data.time.frequencyUncertaintyNsPerSec, 0);
472 EXPECT_LE(data.time.frequencyUncertaintyNsPerSec, 2.0e5); // 200 ppm
473 }
474 }
475