Add support to blacklist IRNSS in HAL 2.1

Test: atest VtsHalGnssV2_1TargetTest
Bug: 135042665

Change-Id: I10a12f5171c640e400af4ee66ce9ab63cf6e94f2
This commit is contained in:
Sasha Kuznetsov 2019-12-04 12:17:50 -08:00
parent dcd93513e6
commit 845f6d54e4
11 changed files with 679 additions and 3 deletions

View file

@ -595,8 +595,9 @@ f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardwar
4d85e814f94949dae4dc6cb82bbd7d6bb24ffafda6ddb2eac928d2a4fc2e21ce android.hardware.cas@1.2::types
66931c2506fbb5af61f20138cb05e0a09e7bf67d6964c231d27c648933bb33ec android.hardware.drm@1.3::ICryptoFactory
994d08ab27d613022c258a9ec48cece7adf2a305e92df5d76ef923e2c6665f64 android.hardware.drm@1.3::IDrmFactory
1bd8028b974bf1d65cfa102196a2b008afc5d42fe73fed2cb94fa7533d07f581 android.hardware.gnss@2.1::IGnss
3dacec7801968e1e4479724dc0180442d9e915466bff051f80996266b1a51c2c android.hardware.gnss@2.1::IGnss
ba62e1e8993bfb9f27fa04816fa0f2241ae2d01edfa3d0c04182e2e5de80045c android.hardware.gnss@2.1::IGnssCallback
ccdf3c0fb2c02a6d4dc57afb276c3497ae8172b80b00ebc0bf8a0238dd38b01d android.hardware.gnss@2.1::IGnssConfiguration
5a125c49ca83629e22afc8c39e865509343bfa2c38f0baea9a186bbac103492d android.hardware.gnss@2.1::IGnssMeasurement
0bfb291708dd4a7c6ec6b9883e2b8592357edde8d7e962ef83918e4a2154ce69 android.hardware.gnss@2.1::IGnssMeasurementCallback
ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth

View file

@ -11,6 +11,7 @@ hidl_interface {
"IGnssCallback.hal",
"IGnssMeasurement.hal",
"IGnssMeasurementCallback.hal",
"IGnssConfiguration.hal",
],
interfaces: [
"android.hardware.gnss.measurement_corrections@1.0",

View file

@ -20,6 +20,7 @@ import @2.0::IGnss;
import IGnssCallback;
import IGnssMeasurement;
import IGnssConfiguration;
/**
* Represents the standard GNSS (Global Navigation Satellite System) interface.
@ -50,4 +51,15 @@ interface IGnss extends @2.0::IGnss {
* @return gnssMeasurementIface Handle to the IGnssMeasurement interface.
*/
getExtensionGnssMeasurement_2_1() generates (IGnssMeasurement gnssMeasurementIface);
/**
* This method returns the IGnssConfiguration interface.
*
* At least one of getExtensionGnssConfiguration(), getExtensionGnssConfiguration_1_1(),
* getExtensionGnssConfiguration_2_0(), and getExtensionGnssConfiguration_2_1() methods must
* return a non-null handle, and the other methods must return nullptr.
*
* @return gnssConfigurationIface Handle to the IGnssConfiguration interface.
*/
getExtensionGnssConfiguration_2_1() generates (IGnssConfiguration gnssConfigurationIface);
};

View file

@ -0,0 +1,68 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.gnss@2.1;
import @2.0::IGnssConfiguration;
import @2.0::GnssConstellationType;
/**
* Extended interface for GNSS Configuration support.
*/
interface IGnssConfiguration extends @2.0::IGnssConfiguration {
/**
* Represents a blacklisted source, updating the GnssConstellationType to 2.0, which supports
* IRNSS.
*/
struct BlacklistedSource {
/**
* Defines the constellation of the given satellite(s).
*/
GnssConstellationType constellation;
/**
* Satellite (space vehicle) ID number, as defined in GnssSvInfo::svid
*
* Or 0 to blacklist all svid's for the specified constellation
*/
int16_t svid;
};
/**
* Injects a vector of BlacklistedSource(s) which the HAL must not use to calculate the
* GNSS location output.
*
* The superset of all satellite sources provided, including wildcards, in the latest call
* to this method, is the set of satellites sources that must not be used in calculating
* location.
*
* All measurements from the specified satellites, across frequency bands, are blacklisted
* together.
*
* If this method is never called after the IGnssConfiguration.hal connection is made on boot,
* or is called with an empty vector, then no satellites are to be blacklisted as a result of
* this API.
*
* This blacklist must be considered as an additional source of which satellites
* should not be trusted for location on top of existing sources of similar information
* such as satellite broadcast health being unhealthy and measurement outlier removal.
*
* @param blacklist The BlacklistedSource(s) of satellites the HAL must not use.
*
* @return success Whether the HAL accepts and abides by the provided blacklist.
*/
setBlacklist_2_1(vec<BlacklistedSource> blacklist) generates (bool success);
};

View file

@ -23,6 +23,7 @@ cc_binary {
srcs: [
"Gnss.cpp",
"GnssMeasurement.cpp",
"GnssConfiguration.cpp",
"service.cpp"
],
shared_libs: [

View file

@ -32,7 +32,7 @@ namespace implementation {
sp<V2_1::IGnssCallback> Gnss::sGnssCallback_2_1 = nullptr;
Gnss::Gnss() : mMinIntervalMs(1000) {}
Gnss::Gnss() : mMinIntervalMs(1000), mGnssConfiguration{new GnssConfiguration()} {}
Gnss::~Gnss() {
stop();
@ -48,7 +48,7 @@ Return<bool> Gnss::start() {
mIsActive = true;
mThread = std::thread([this]() {
while (mIsActive == true) {
auto svStatus = Utils::getMockSvInfoListV2_1();
auto svStatus = filterBlacklistedSatellitesV2_1(Utils::getMockSvInfoListV2_1());
this->reportSvStatus(svStatus);
const auto location = Utils::getMockLocationV2_0();
@ -60,6 +60,16 @@ Return<bool> Gnss::start() {
return true;
}
hidl_vec<GnssSvInfo> Gnss::filterBlacklistedSatellitesV2_1(hidl_vec<GnssSvInfo> gnssSvInfoList) {
for (uint32_t i = 0; i < gnssSvInfoList.size(); i++) {
if (mGnssConfiguration->isBlacklistedV2_1(gnssSvInfoList[i])) {
gnssSvInfoList[i].v2_0.v1_0.svFlag &=
~static_cast<uint8_t>(V1_0::IGnssCallback::GnssSvFlags::USED_IN_FIX);
}
}
return gnssSvInfoList;
}
Return<bool> Gnss::stop() {
ALOGD("stop");
mIsActive = false;
@ -270,6 +280,10 @@ Return<sp<V2_1::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_2_1() {
return new GnssMeasurement();
}
Return<sp<V2_1::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_2_1() {
return mGnssConfiguration;
}
void Gnss::reportSvStatus(const hidl_vec<GnssSvInfo>& svInfoList) const {
std::unique_lock<std::mutex> lock(mMutex);
if (sGnssCallback_2_1 == nullptr) {

View file

@ -22,6 +22,7 @@
#include <atomic>
#include <mutex>
#include <thread>
#include "GnssConfiguration.h"
namespace android {
namespace hardware {
@ -87,6 +88,7 @@ struct Gnss : public IGnss {
// Methods from V2_1::IGnss follow.
Return<bool> setCallback_2_1(const sp<V2_1::IGnssCallback>& callback) override;
Return<sp<V2_1::IGnssMeasurement>> getExtensionGnssMeasurement_2_1() override;
Return<sp<V2_1::IGnssConfiguration>> getExtensionGnssConfiguration_2_1() override;
private:
void reportLocation(const V2_0::GnssLocation&) const;
@ -94,9 +96,11 @@ struct Gnss : public IGnss {
static sp<V2_1::IGnssCallback> sGnssCallback_2_1;
std::atomic<long> mMinIntervalMs;
sp<GnssConfiguration> mGnssConfiguration;
std::atomic<bool> mIsActive;
std::thread mThread;
mutable std::mutex mMutex;
hidl_vec<GnssSvInfo> filterBlacklistedSatellitesV2_1(hidl_vec<GnssSvInfo> gnssSvInfoList);
};
} // namespace implementation

View file

@ -0,0 +1,106 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "GnssConfiguration"
#include "GnssConfiguration.h"
#include <log/log.h>
namespace android {
namespace hardware {
namespace gnss {
namespace V2_1 {
namespace implementation {
// Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow.
Return<bool> GnssConfiguration::setSuplEs(bool enable) {
ALOGD("setSuplEs enable: %d", enable);
// Method deprecated in 2.0 and not expected to be called by the framework.
return false;
}
Return<bool> GnssConfiguration::setSuplVersion(uint32_t) {
return true;
}
Return<bool> GnssConfiguration::setSuplMode(hidl_bitfield<SuplMode>) {
return true;
}
Return<bool> GnssConfiguration::setGpsLock(hidl_bitfield<GpsLock> gpsLock) {
ALOGD("setGpsLock gpsLock: %hhu", static_cast<GpsLock>(gpsLock));
// Method deprecated in 2.0 and not expected to be called by the framework.
return false;
}
Return<bool> GnssConfiguration::setLppProfile(hidl_bitfield<LppProfile>) {
return true;
}
Return<bool> GnssConfiguration::setGlonassPositioningProtocol(hidl_bitfield<GlonassPosProtocol>) {
return true;
}
Return<bool> GnssConfiguration::setEmergencySuplPdn(bool) {
return true;
}
// Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow.
Return<bool> GnssConfiguration::setBlacklist(
const hidl_vec<V1_1::IGnssConfiguration::BlacklistedSource>&) {
// TODO (b/122463906): Reuse 1.1 implementation.
return bool{};
}
// Methods from ::android::hardware::gnss::V2_0::IGnssConfiguration follow.
Return<bool> GnssConfiguration::setEsExtensionSec(uint32_t emergencyExtensionSeconds) {
ALOGD("setEsExtensionSec emergencyExtensionSeconds: %d", emergencyExtensionSeconds);
return true;
}
// Methods from ::android::hardware::gnss::V2_1::IGnssConfiguration follow.
Return<bool> GnssConfiguration::setBlacklist_2_1(
const hidl_vec<V2_1::IGnssConfiguration::BlacklistedSource>& sourceList) {
std::unique_lock<std::recursive_mutex> lock(mMutex);
mBlacklistedConstellationSet.clear();
mBlacklistedSourceSet.clear();
for (auto source : sourceList) {
if (source.svid == 0) {
// Wildcard blacklist, i.e., blacklist entire constellation.
mBlacklistedConstellationSet.insert(source.constellation);
} else {
mBlacklistedSourceSet.insert(source);
}
}
return true;
}
Return<bool> GnssConfiguration::isBlacklistedV2_1(const GnssSvInfoV2_1& gnssSvInfo) const {
std::unique_lock<std::recursive_mutex> lock(mMutex);
if (mBlacklistedConstellationSet.find(gnssSvInfo.v2_0.constellation) !=
mBlacklistedConstellationSet.end()) {
return true;
}
BlacklistedSourceV2_1 source = {.constellation = gnssSvInfo.v2_0.constellation,
.svid = gnssSvInfo.v2_0.v1_0.svid};
return (mBlacklistedSourceSet.find(source) != mBlacklistedSourceSet.end());
}
} // namespace implementation
} // namespace V2_1
} // namespace gnss
} // namespace hardware
} // namespace android

View file

@ -0,0 +1,101 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
#define ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
#include <android/hardware/gnss/2.1/IGnssCallback.h>
#include <android/hardware/gnss/2.1/IGnssConfiguration.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
#include <mutex>
#include <unordered_set>
namespace android {
namespace hardware {
namespace gnss {
namespace V2_1 {
namespace implementation {
using ::android::sp;
using ::android::hardware::hidl_array;
using ::android::hardware::hidl_memory;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using BlacklistedSourceV2_1 =
::android::hardware::gnss::V2_1::IGnssConfiguration::BlacklistedSource;
using GnssConstellationTypeV2_0 = V2_0::GnssConstellationType;
using GnssSvInfoV2_1 = V2_1::IGnssCallback::GnssSvInfo;
struct BlacklistedSourceHashV2_1 {
inline int operator()(const BlacklistedSourceV2_1& source) const {
return int(source.constellation) * 1000 + int(source.svid);
}
};
struct BlacklistedSourceEqualV2_1 {
inline bool operator()(const BlacklistedSourceV2_1& s1, const BlacklistedSourceV2_1& s2) const {
return (s1.constellation == s2.constellation) && (s1.svid == s2.svid);
}
};
using BlacklistedSourceSetV2_1 =
std::unordered_set<BlacklistedSourceV2_1, BlacklistedSourceHashV2_1,
BlacklistedSourceEqualV2_1>;
using BlacklistedConstellationSetV2_1 = std::unordered_set<GnssConstellationTypeV2_0>;
struct GnssConfiguration : public IGnssConfiguration {
// Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow.
Return<bool> setSuplEs(bool enabled) override;
Return<bool> setSuplVersion(uint32_t version) override;
Return<bool> setSuplMode(hidl_bitfield<SuplMode> mode) override;
Return<bool> setGpsLock(hidl_bitfield<GpsLock> lock) override;
Return<bool> setLppProfile(hidl_bitfield<LppProfile> lppProfile) override;
Return<bool> setGlonassPositioningProtocol(hidl_bitfield<GlonassPosProtocol> protocol) override;
Return<bool> setEmergencySuplPdn(bool enable) override;
// Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow.
Return<bool> setBlacklist(
const hidl_vec<V1_1::IGnssConfiguration::BlacklistedSource>& blacklist) override;
std::recursive_mutex& getMutex() const;
// Methods from ::android::hardware::gnss::V2_0::IGnssConfiguration follow.
Return<bool> setEsExtensionSec(uint32_t emergencyExtensionSeconds) override;
// Methods from ::android::hardware::gnss::V2_1::IGnssConfiguration follow.
Return<bool> setBlacklist_2_1(
const hidl_vec<V2_1::IGnssConfiguration::BlacklistedSource>& blacklist) override;
Return<bool> isBlacklistedV2_1(const GnssSvInfoV2_1& gnssSvInfo) const;
private:
mutable std::recursive_mutex mMutex;
BlacklistedSourceSetV2_1 mBlacklistedSourceSet;
BlacklistedConstellationSetV2_1 mBlacklistedConstellationSet;
};
} // namespace implementation
} // namespace V2_1
} // namespace gnss
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H

View file

@ -30,6 +30,13 @@ using IGnssMeasurement_2_1 = android::hardware::gnss::V2_1::IGnssMeasurement;
using IGnssMeasurement_2_0 = android::hardware::gnss::V2_0::IGnssMeasurement;
using IGnssMeasurement_1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
using IGnssMeasurement_1_0 = android::hardware::gnss::V1_0::IGnssMeasurement;
using IGnssConfiguration_2_1 = android::hardware::gnss::V2_1::IGnssConfiguration;
using IGnssConfiguration_2_0 = android::hardware::gnss::V2_0::IGnssConfiguration;
using IGnssConfiguration_1_1 = android::hardware::gnss::V1_1::IGnssConfiguration;
using IGnssConfiguration_1_0 = android::hardware::gnss::V1_0::IGnssConfiguration;
using android::hardware::gnss::V2_0::GnssConstellationType;
using android::hardware::gnss::V2_1::IGnssConfiguration;
/*
* SetupTeardownCreateCleanup:
@ -60,6 +67,27 @@ TEST_P(GnssHalTest, TestGnssMeasurementExtension) {
ASSERT_TRUE(numNonNull >= 1);
}
/*
* TestGnssConfigurationExtension:
* Gets the GnssConfigurationExtension and verifies that it returns an actual extension.
*/
TEST_P(GnssHalTest, TestGnssConfigurationExtension) {
auto gnssConfiguration_2_1 = gnss_hal_->getExtensionGnssConfiguration_2_1();
auto gnssConfiguration_2_0 = gnss_hal_->getExtensionGnssConfiguration_2_0();
auto gnssConfiguration_1_1 = gnss_hal_->getExtensionGnssConfiguration_1_1();
auto gnssConfiguration_1_0 = gnss_hal_->getExtensionGnssConfiguration();
ASSERT_TRUE(gnssConfiguration_2_1.isOk() && gnssConfiguration_2_0.isOk() &&
gnssConfiguration_1_1.isOk() && gnssConfiguration_1_0.isOk());
sp<IGnssConfiguration_2_1> iGnssConfig_2_1 = gnssConfiguration_2_1;
sp<IGnssConfiguration_2_0> iGnssConfig_2_0 = gnssConfiguration_2_0;
sp<IGnssConfiguration_1_1> iGnssConfig_1_1 = gnssConfiguration_1_1;
sp<IGnssConfiguration_1_0> iGnssConfig_1_0 = gnssConfiguration_1_0;
// At least one interface is non-null.
int numNonNull = (int)(iGnssConfig_2_1 != nullptr) + (int)(iGnssConfig_2_0 != nullptr) +
(int)(iGnssConfig_1_1 != nullptr) + (int)(iGnssConfig_1_0 != nullptr);
ASSERT_TRUE(numNonNull >= 1);
}
/*
* TestGnssMeasurementFields:
* Sets a GnssMeasurementCallback, waits for a measurement, and verifies
@ -126,3 +154,338 @@ TEST_P(GnssHalTest, TestGnssSvInfoFields) {
ASSERT_TRUE(nonZeroCn0Found);
StopAndClearLocations();
}
/*
* FindStrongFrequentNonGpsSource:
*
* Search through a GnssSvStatus list for the strongest non-GPS satellite observed enough times
*
* returns the strongest source,
* or a source with constellation == UNKNOWN if none are found sufficient times
* TODO(skz): create a template for this to reduce code duplication of v2.1 and v2.0 since both
* are using vectors.
*/
IGnssConfiguration::BlacklistedSource FindStrongFrequentNonGpsSource(
const std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_list,
const int min_observations) {
struct ComparableBlacklistedSource {
IGnssConfiguration::BlacklistedSource id;
ComparableBlacklistedSource() {
id.constellation = GnssConstellationType::UNKNOWN;
id.svid = 0;
}
bool operator<(const ComparableBlacklistedSource& compare) const {
return ((id.svid < compare.id.svid) || ((id.svid == compare.id.svid) &&
(id.constellation < compare.id.constellation)));
}
};
struct SignalCounts {
int observations;
float max_cn0_dbhz;
};
std::map<ComparableBlacklistedSource, SignalCounts> mapSignals;
for (const auto& sv_info_vec : sv_info_list) {
for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
const auto& gnss_sv = sv_info_vec[iSv];
if ((gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX) &&
(gnss_sv.v2_0.constellation != GnssConstellationType::GPS)) {
ComparableBlacklistedSource source;
source.id.svid = gnss_sv.v2_0.v1_0.svid;
source.id.constellation = gnss_sv.v2_0.constellation;
const auto& itSignal = mapSignals.find(source);
if (itSignal == mapSignals.end()) {
SignalCounts counts;
counts.observations = 1;
counts.max_cn0_dbhz = gnss_sv.v2_0.v1_0.cN0Dbhz;
mapSignals.insert(
std::pair<ComparableBlacklistedSource, SignalCounts>(source, counts));
} else {
itSignal->second.observations++;
if (itSignal->second.max_cn0_dbhz < gnss_sv.v2_0.v1_0.cN0Dbhz) {
itSignal->second.max_cn0_dbhz = gnss_sv.v2_0.v1_0.cN0Dbhz;
}
}
}
}
}
float max_cn0_dbhz_with_sufficient_count = 0.;
int total_observation_count = 0;
int blacklisted_source_count_observation = 0;
ComparableBlacklistedSource source_to_blacklist; // initializes to zero = UNKNOWN constellation
for (auto const& pairSignal : mapSignals) {
total_observation_count += pairSignal.second.observations;
if ((pairSignal.second.observations >= min_observations) &&
(pairSignal.second.max_cn0_dbhz > max_cn0_dbhz_with_sufficient_count)) {
source_to_blacklist = pairSignal.first;
blacklisted_source_count_observation = pairSignal.second.observations;
max_cn0_dbhz_with_sufficient_count = pairSignal.second.max_cn0_dbhz;
}
}
ALOGD("Among %d observations, chose svid %d, constellation %d, "
"with %d observations at %.1f max CNo",
total_observation_count, source_to_blacklist.id.svid,
(int)source_to_blacklist.id.constellation, blacklisted_source_count_observation,
max_cn0_dbhz_with_sufficient_count);
return source_to_blacklist.id;
}
/*
* BlacklistIndividualSatellites:
*
* 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
* GnssStatus for common satellites (strongest and one other.)
* 2a & b) Turns off location, and blacklists common satellites.
* 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
* GnssStatus does not use those satellites.
* 4a & b) Turns off location, and send in empty blacklist.
* 5a) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
* GnssStatus does re-use at least the previously strongest satellite
* 5b) Retry a few times, in case GNSS search strategy takes a while to reacquire even the
* formerly strongest satellite
*/
TEST_P(GnssHalTest, BlacklistIndividualSatellites) {
const int kLocationsToAwait = 3;
const int kRetriesToUnBlacklist = 10;
gnss_cb_->location_cbq_.reset();
StartAndCheckLocations(kLocationsToAwait);
int location_called_count = gnss_cb_->location_cbq_.calledCount();
// Tolerate 1 less sv status to handle edge cases in reporting.
int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)",
sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
/*
* Identify strongest SV seen at least kLocationsToAwait -1 times
* Why -1? To avoid test flakiness in case of (plausible) slight flakiness in strongest signal
* observability (one epoch RF null)
*/
const int kGnssSvInfoListTimeout = 2;
std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_vec_list;
int count = gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec_list, sv_info_list_cbq_size,
kGnssSvInfoListTimeout);
ASSERT_EQ(count, sv_info_list_cbq_size);
IGnssConfiguration::BlacklistedSource source_to_blacklist =
FindStrongFrequentNonGpsSource(sv_info_vec_list, kLocationsToAwait - 1);
if (source_to_blacklist.constellation == GnssConstellationType::UNKNOWN) {
// Cannot find a non-GPS satellite. Let the test pass.
ALOGD("Cannot find a non-GPS satellite. Letting the test pass.");
return;
}
// Stop locations, blacklist the common SV
StopAndClearLocations();
auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_2_1();
ASSERT_TRUE(gnss_configuration_hal_return.isOk());
sp<IGnssConfiguration> gnss_configuration_hal = gnss_configuration_hal_return;
ASSERT_NE(gnss_configuration_hal, nullptr);
hidl_vec<IGnssConfiguration::BlacklistedSource> sources;
sources.resize(1);
sources[0] = source_to_blacklist;
auto result = gnss_configuration_hal->setBlacklist_2_1(sources);
ASSERT_TRUE(result.isOk());
EXPECT_TRUE(result);
// retry and ensure satellite not used
gnss_cb_->sv_info_list_cbq_.reset();
gnss_cb_->location_cbq_.reset();
StartAndCheckLocations(kLocationsToAwait);
// early exit if test is being run with insufficient signal
location_called_count = gnss_cb_->location_cbq_.calledCount();
if (location_called_count == 0) {
ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
}
ASSERT_TRUE(location_called_count > 0);
// Tolerate 1 less sv status to handle edge cases in reporting.
sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)",
sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
for (int i = 0; i < sv_info_list_cbq_size; ++i) {
hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
const auto& gnss_sv = sv_info_vec[iSv];
EXPECT_FALSE((gnss_sv.v2_0.v1_0.svid == source_to_blacklist.svid) &&
(gnss_sv.v2_0.constellation == source_to_blacklist.constellation) &&
(gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
}
}
// clear blacklist and restart - this time updating the blacklist while location is still on
sources.resize(0);
result = gnss_configuration_hal->setBlacklist_2_1(sources);
ASSERT_TRUE(result.isOk());
EXPECT_TRUE(result);
bool strongest_sv_is_reobserved = false;
// do several loops awaiting a few locations, allowing non-immediate reacquisition strategies
int unblacklist_loops_remaining = kRetriesToUnBlacklist;
while (!strongest_sv_is_reobserved && (unblacklist_loops_remaining-- > 0)) {
StopAndClearLocations();
gnss_cb_->sv_info_list_cbq_.reset();
gnss_cb_->location_cbq_.reset();
StartAndCheckLocations(kLocationsToAwait);
// early exit loop if test is being run with insufficient signal
location_called_count = gnss_cb_->location_cbq_.calledCount();
if (location_called_count == 0) {
ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
}
ASSERT_TRUE(location_called_count > 0);
// Tolerate 1 less sv status to handle edge cases in reporting.
sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
ALOGD("Clear blacklist, observed %d GnssSvInfo, while awaiting %d Locations"
", tries remaining %d",
sv_info_list_cbq_size, kLocationsToAwait, unblacklist_loops_remaining);
for (int i = 0; i < sv_info_list_cbq_size; ++i) {
hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
const auto& gnss_sv = sv_info_vec[iSv];
if ((gnss_sv.v2_0.v1_0.svid == source_to_blacklist.svid) &&
(gnss_sv.v2_0.constellation == source_to_blacklist.constellation) &&
(gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX)) {
strongest_sv_is_reobserved = true;
break;
}
}
if (strongest_sv_is_reobserved) break;
}
}
EXPECT_TRUE(strongest_sv_is_reobserved);
StopAndClearLocations();
}
/*
* BlacklistConstellation:
*
* 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
* GnssStatus for any non-GPS constellations.
* 2a & b) Turns off location, and blacklist first non-GPS constellations.
* 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
* GnssStatus does not use any constellation but GPS.
* 4a & b) Clean up by turning off location, and send in empty blacklist.
*/
TEST_P(GnssHalTest, BlacklistConstellation) {
const int kLocationsToAwait = 3;
gnss_cb_->location_cbq_.reset();
StartAndCheckLocations(kLocationsToAwait);
const int location_called_count = gnss_cb_->location_cbq_.calledCount();
// Tolerate 1 less sv status to handle edge cases in reporting.
int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)",
sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
// Find first non-GPS constellation to blacklist
const int kGnssSvInfoListTimeout = 2;
GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN;
for (int i = 0; i < sv_info_list_cbq_size; ++i) {
hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
const auto& gnss_sv = sv_info_vec[iSv];
if ((gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX) &&
(gnss_sv.v2_0.constellation != GnssConstellationType::UNKNOWN) &&
(gnss_sv.v2_0.constellation != GnssConstellationType::GPS)) {
// found a non-GPS constellation
constellation_to_blacklist = gnss_sv.v2_0.constellation;
break;
}
}
if (constellation_to_blacklist != GnssConstellationType::UNKNOWN) {
break;
}
}
// Turns off location
StopAndClearLocations();
if (constellation_to_blacklist == GnssConstellationType::UNKNOWN) {
ALOGI("No non-GPS constellations found, constellation blacklist test less effective.");
// Proceed functionally to blacklist something.
constellation_to_blacklist = GnssConstellationType::GLONASS;
}
IGnssConfiguration::BlacklistedSource source_to_blacklist_1;
source_to_blacklist_1.constellation = constellation_to_blacklist;
source_to_blacklist_1.svid = 0; // documented wildcard for all satellites in this constellation
// IRNSS was added in 2.0. Always attempt to blacklist IRNSS to verify that the new enum is
// supported.
IGnssConfiguration::BlacklistedSource source_to_blacklist_2;
source_to_blacklist_2.constellation = GnssConstellationType::IRNSS;
source_to_blacklist_2.svid = 0; // documented wildcard for all satellites in this constellation
auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_2_1();
ASSERT_TRUE(gnss_configuration_hal_return.isOk());
sp<IGnssConfiguration> gnss_configuration_hal = gnss_configuration_hal_return;
ASSERT_NE(gnss_configuration_hal, nullptr);
hidl_vec<IGnssConfiguration::BlacklistedSource> sources;
sources.resize(2);
sources[0] = source_to_blacklist_1;
sources[1] = source_to_blacklist_2;
auto result = gnss_configuration_hal->setBlacklist_2_1(sources);
ASSERT_TRUE(result.isOk());
EXPECT_TRUE(result);
// retry and ensure constellation not used
gnss_cb_->sv_info_list_cbq_.reset();
gnss_cb_->location_cbq_.reset();
StartAndCheckLocations(kLocationsToAwait);
// Tolerate 1 less sv status to handle edge cases in reporting.
sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations", sv_info_list_cbq_size,
kLocationsToAwait);
for (int i = 0; i < sv_info_list_cbq_size; ++i) {
hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
const auto& gnss_sv = sv_info_vec[iSv];
EXPECT_FALSE((gnss_sv.v2_0.constellation == source_to_blacklist_1.constellation) &&
(gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
EXPECT_FALSE((gnss_sv.v2_0.constellation == source_to_blacklist_2.constellation) &&
(gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
}
}
// clean up
StopAndClearLocations();
sources.resize(0);
result = gnss_configuration_hal->setBlacklist_2_1(sources);
ASSERT_TRUE(result.isOk());
EXPECT_TRUE(result);
}

View file

@ -175,6 +175,11 @@ hidl_vec<GnssSvInfoV2_1> Utils::getMockSvInfoListV2_1() {
25.0, 66.0, 247.0),
V2_0::GnssConstellationType::GLONASS),
20.0),
getMockSvInfoV2_1(
getMockSvInfoV2_0(getMockSvInfoV1_0(3, V1_0::GnssConstellationType::UNKNOWN,
22.0, 35.0, 112.0),
V2_0::GnssConstellationType::IRNSS),
19.7),
};
return gnssSvInfoList;
}