Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 72a431ef authored by Yu-Han Yang's avatar Yu-Han Yang
Browse files

Add more GnssDebug validity tests

Bug: 326293710
Test: atest VtsHalGnssTargetTest
Change-Id: Ie20d0ce369bc7d03ccfb7f7e01a4e28ed54a5d4d
parent 379d7c1e
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -162,12 +162,13 @@ ScopedAStatus Gnss::close() {
    return ScopedAStatus::ok();
}

void Gnss::reportLocation(const GnssLocation& location) const {
void Gnss::reportLocation(const GnssLocation& location) {
    std::unique_lock<std::mutex> lock(mMutex);
    if (sGnssCallback == nullptr) {
        ALOGE("%s: GnssCallback is null.", __func__);
        return;
    }
    mLastLocation = std::make_shared<GnssLocation>(location);
    auto status = sGnssCallback->gnssLocationCb(location);
    if (!status.isOk()) {
        ALOGE("%s: Unable to invoke gnssLocationCb", __func__);
@@ -359,7 +360,6 @@ ScopedAStatus Gnss::getExtensionGnssNavigationMessage(

ndk::ScopedAStatus Gnss::getExtensionGnssDebug(std::shared_ptr<IGnssDebug>* iGnssDebug) {
    ALOGD("Gnss::getExtensionGnssDebug");

    *iGnssDebug = SharedRefBase::make<GnssDebug>();
    return ndk::ScopedAStatus::ok();
}
@@ -398,4 +398,8 @@ void Gnss::setGnssMeasurementInterval(const long intervalMs) {
    mGnssMeasurementIntervalMs = intervalMs;
}

std::shared_ptr<GnssLocation> Gnss::getLastLocation() const {
    return mLastLocation;
}

}  // namespace aidl::android::hardware::gnss
+5 −3
Original line number Diff line number Diff line
@@ -87,18 +87,19 @@ class Gnss : public BnGnss {
    void reportSvStatus() const;
    void setGnssMeasurementEnabled(const bool enabled);
    void setGnssMeasurementInterval(const long intervalMs);
    std::shared_ptr<GnssLocation> getLastLocation() const;
    std::shared_ptr<GnssConfiguration> mGnssConfiguration;
    std::shared_ptr<GnssPowerIndication> mGnssPowerIndication;
    std::shared_ptr<GnssMeasurementInterface> mGnssMeasurementInterface;

  private:
    void reportLocation(const GnssLocation&) const;
    void reportLocation(const GnssLocation&);
    void reportSvStatus(const std::vector<IGnssCallback::GnssSvInfo>& svInfoList) const;
    void reportGnssStatusValue(const IGnssCallback::GnssStatusValue gnssStatusValue) const;
    void reportNmea() const;
    std::vector<IGnssCallback::GnssSvInfo> filterBlocklistedSatellites(
            std::vector<IGnssCallback::GnssSvInfo> gnssSvInfoList) const;
    void reportGnssStatusValue(const IGnssCallback::GnssStatusValue gnssStatusValue) const;
    std::unique_ptr<GnssLocation> getLocationFromHW();
    void reportNmea() const;

    static std::shared_ptr<IGnssCallback> sGnssCallback;

@@ -109,6 +110,7 @@ class Gnss : public BnGnss {
    std::atomic<bool> mIsNmeaActive;
    std::atomic<bool> mFirstFixReceived;
    std::atomic<bool> mGnssMeasurementEnabled;
    std::shared_ptr<GnssLocation> mLastLocation;
    std::thread mThread;
    ::android::hardware::gnss::common::ThreadBlocker mThreadBlocker;

+92 −3
Original line number Diff line number Diff line
@@ -18,10 +18,15 @@

#include "GnssDebug.h"
#include <log/log.h>
#include <utils/SystemClock.h>
#include "Constants.h"
#include "Gnss.h"
#include "MockLocation.h"

namespace aidl::android::hardware::gnss {

using ::android::hardware::gnss::common::kMockTimestamp;

ndk::ScopedAStatus GnssDebug::getDebugData(DebugData* debugData) {
    ALOGD("GnssDebug::getDebugData");

@@ -36,10 +41,94 @@ ndk::ScopedAStatus GnssDebug::getDebugData(DebugData* debugData) {
                                   .speedAccuracyMetersPerSecond = 1,
                                   .bearingAccuracyDegrees = 90,
                                   .ageSeconds = 0.99};
    TimeDebug timeDebug = {.timeEstimateMs = 1519930775453L,
    TimeDebug timeDebug = {.timeEstimateMs = static_cast<int64_t>(
                                   kMockTimestamp + ::android::elapsedRealtimeNano() / 1e6),
                           .timeUncertaintyNs = 1000,
                           .frequencyUncertaintyNsPerSec = 5.0e4};
    std::vector<SatelliteData> satelliteDataArrayDebug = {};
                           .frequencyUncertaintyNsPerSec = 800};
    SatelliteData satelliteData1 = {
            .svid = 3,
            .constellation = GnssConstellationType::GPS,
            .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
            .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
            .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
            .ephemerisAgeSeconds = 12,
            .serverPredictionIsAvailable = true,
            .serverPredictionAgeSeconds = 30};
    SatelliteData satelliteData2 = {
            .svid = 5,
            .constellation = GnssConstellationType::GPS,
            .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
            .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
            .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
            .ephemerisAgeSeconds = 12,
            .serverPredictionIsAvailable = true,
            .serverPredictionAgeSeconds = 30};
    SatelliteData satelliteData3 = {
            .svid = 17,
            .constellation = GnssConstellationType::GPS,
            .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
            .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
            .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
            .ephemerisAgeSeconds = 12,
            .serverPredictionIsAvailable = true,
            .serverPredictionAgeSeconds = 30};
    SatelliteData satelliteData4 = {
            .svid = 26,
            .constellation = GnssConstellationType::GPS,
            .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
            .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
            .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
            .ephemerisAgeSeconds = 12,
            .serverPredictionIsAvailable = true,
            .serverPredictionAgeSeconds = 30};
    SatelliteData satelliteData5 = {
            .svid = 5,
            .constellation = GnssConstellationType::GLONASS,
            .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
            .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
            .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
            .ephemerisAgeSeconds = 12,
            .serverPredictionIsAvailable = true,
            .serverPredictionAgeSeconds = 30};
    SatelliteData satelliteData6 = {
            .svid = 17,
            .constellation = GnssConstellationType::GLONASS,
            .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
            .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
            .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
            .ephemerisAgeSeconds = 12,
            .serverPredictionIsAvailable = true,
            .serverPredictionAgeSeconds = 30};
    SatelliteData satelliteData7 = {
            .svid = 18,
            .constellation = GnssConstellationType::GLONASS,
            .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
            .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
            .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
            .ephemerisAgeSeconds = 12,
            .serverPredictionIsAvailable = true,
            .serverPredictionAgeSeconds = 30};
    SatelliteData satelliteData8 = {
            .svid = 10,
            .constellation = GnssConstellationType::GLONASS,
            .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
            .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
            .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
            .ephemerisAgeSeconds = 12,
            .serverPredictionIsAvailable = true,
            .serverPredictionAgeSeconds = 30};
    SatelliteData satelliteData9 = {
            .svid = 3,
            .constellation = GnssConstellationType::IRNSS,
            .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
            .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
            .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
            .ephemerisAgeSeconds = 12,
            .serverPredictionIsAvailable = true,
            .serverPredictionAgeSeconds = 30};
    std::vector<SatelliteData> satelliteDataArrayDebug = {
            satelliteData1, satelliteData2, satelliteData3, satelliteData4, satelliteData5,
            satelliteData6, satelliteData7, satelliteData8, satelliteData9};
    debugData->position = positionDebug;
    debugData->time = timeDebug;
    debugData->satelliteDataArray = satelliteDataArrayDebug;
+2 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@

namespace aidl::android::hardware::gnss {

class Gnss;

struct GnssDebug : public BnGnssDebug {
  public:
    ndk::ScopedAStatus getDebugData(DebugData* debugData) override;
+128 −29
Original line number Diff line number Diff line
@@ -1149,41 +1149,140 @@ TEST_P(GnssHalTest, GnssDebugValuesSanityTest) {
    sp<IGnssDebug> iGnssDebug;
    auto status = aidl_gnss_hal_->getExtensionGnssDebug(&iGnssDebug);
    ASSERT_TRUE(status.isOk());

    if (!IsAutomotiveDevice()) {
    if (IsAutomotiveDevice()) {
        return;
    }
    ASSERT_TRUE(iGnssDebug != nullptr);

    IGnssDebug::DebugData data;
        auto status = iGnssDebug->getDebugData(&data);
        ASSERT_TRUE(status.isOk());

        if (data.position.valid) {
            ASSERT_TRUE(data.position.latitudeDegrees >= -90 &&
                        data.position.latitudeDegrees <= 90);
            ASSERT_TRUE(data.position.longitudeDegrees >= -180 &&
                        data.position.longitudeDegrees <= 180);
            ASSERT_TRUE(data.position.altitudeMeters >= -1000 &&  // Dead Sea: -414m
                        data.position.altitudeMeters <= 20000);   // Mount Everest: 8850m
            ASSERT_TRUE(data.position.speedMetersPerSec >= 0 &&
                        data.position.speedMetersPerSec <= 600);
            ASSERT_TRUE(data.position.bearingDegrees >= -360 &&
                        data.position.bearingDegrees <= 360);
            ASSERT_TRUE(data.position.horizontalAccuracyMeters > 0 &&
                        data.position.horizontalAccuracyMeters <= 20000000);
            ASSERT_TRUE(data.position.verticalAccuracyMeters > 0 &&
                        data.position.verticalAccuracyMeters <= 20000);
            ASSERT_TRUE(data.position.speedAccuracyMetersPerSecond > 0 &&
                        data.position.speedAccuracyMetersPerSecond <= 500);
            ASSERT_TRUE(data.position.bearingAccuracyDegrees > 0 &&
                        data.position.bearingAccuracyDegrees <= 180);
            ASSERT_TRUE(data.position.ageSeconds >= 0);
        }
        ASSERT_TRUE(data.time.timeEstimateMs >= 1483228800000);  // Jan 01 2017 00:00:00 GMT.
        ASSERT_TRUE(data.time.timeUncertaintyNs > 0);
        ASSERT_TRUE(data.time.frequencyUncertaintyNsPerSec > 0 &&
                    data.time.frequencyUncertaintyNsPerSec <= 2.0e5);  // 200 ppm
    status = iGnssDebug->getDebugData(&data);
    ASSERT_TRUE(status.isOk());
    Utils::checkPositionDebug(data);

    // Additional GnssDebug tests for AIDL version >= 4 (launched in Android 15(V)+)
    if (aidl_gnss_hal_->getInterfaceVersion() <= 3) {
        return;
    }

    // Start location and check the consistency between SvStatus and DebugData
    aidl_gnss_cb_->location_cbq_.reset();
    aidl_gnss_cb_->sv_info_list_cbq_.reset();
    StartAndCheckLocations(/* count= */ 2);
    int location_called_count = aidl_gnss_cb_->location_cbq_.calledCount();
    ALOGD("Observed %d GnssSvStatus, while awaiting 2 locations (%d received)",
          aidl_gnss_cb_->sv_info_list_cbq_.size(), location_called_count);

    // Wait for up to kNumSvInfoLists events for kTimeoutSeconds for each event.
    int kTimeoutSeconds = 2;
    int kNumSvInfoLists = 4;
    std::list<std::vector<IGnssCallback::GnssSvInfo>> sv_info_lists;
    std::vector<IGnssCallback::GnssSvInfo> last_sv_info_list;

    do {
        EXPECT_GT(aidl_gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_lists, kNumSvInfoLists,
                                                            kTimeoutSeconds),
                  0);
        if (!sv_info_lists.empty()) {
            last_sv_info_list = sv_info_lists.back();
            ALOGD("last_sv_info size = %d", (int)last_sv_info_list.size());
        }
    } while (!sv_info_lists.empty() && last_sv_info_list.size() == 0);

    StopAndClearLocations();

    status = iGnssDebug->getDebugData(&data);
    Utils::checkPositionDebug(data);

    // Validate SatelliteEphemerisType, SatelliteEphemerisSource, SatelliteEphemerisHealth
    for (auto sv_info : last_sv_info_list) {
        if ((sv_info.svFlag & static_cast<int>(IGnssCallback::GnssSvFlags::USED_IN_FIX)) == 0) {
            continue;
        }
        ALOGD("Found usedInFix const: %d, svid: %d", static_cast<int>(sv_info.constellation),
              sv_info.svid);
        bool foundDebugData = false;
        for (auto satelliteData : data.satelliteDataArray) {
            if (satelliteData.constellation == sv_info.constellation &&
                satelliteData.svid == sv_info.svid) {
                foundDebugData = true;
                ALOGD("Found GnssDebug data for this sv.");
                EXPECT_TRUE(satelliteData.serverPredictionIsAvailable ||
                            satelliteData.ephemerisType ==
                                    IGnssDebug::SatelliteEphemerisType::EPHEMERIS);
                // for satellites with ephType=0, they need ephHealth=0 if used-in-fix
                if (satelliteData.ephemerisType == IGnssDebug::SatelliteEphemerisType::EPHEMERIS) {
                    EXPECT_TRUE(satelliteData.ephemerisHealth ==
                                IGnssDebug::SatelliteEphemerisHealth::GOOD);
                }
                break;
            }
        }
        // Every Satellite where GnssStatus says it is used-in-fix has a valid ephemeris - i.e. it's
        // it shows either a serverPredAvail: 1, or a ephType=0
        EXPECT_TRUE(foundDebugData);
    }

    bool hasServerPredictionAvailable = false;
    bool hasNoneZeroServerPredictionAgeSeconds = false;
    bool hasNoneDemodEphSource = false;
    for (auto satelliteData : data.satelliteDataArray) {
        // for satellites with serverPredAvail: 1, the serverPredAgeSec: is not 0 for all
        // satellites (at least not on 2 fixes in a row - it could get lucky once)
        if (satelliteData.serverPredictionIsAvailable) {
            hasServerPredictionAvailable = true;
            if (satelliteData.serverPredictionAgeSeconds != 0) {
                hasNoneZeroServerPredictionAgeSeconds = true;
            }
        }
        // for satellites with ephType=0, they need ephSource 0-3
        if (satelliteData.ephemerisType == IGnssDebug::SatelliteEphemerisType::EPHEMERIS) {
            EXPECT_TRUE(satelliteData.ephemerisSource >=
                                SatellitePvt::SatelliteEphemerisSource::DEMODULATED &&
                        satelliteData.ephemerisSource <=
                                SatellitePvt::SatelliteEphemerisSource::OTHER);
            if (satelliteData.ephemerisSource !=
                SatellitePvt::SatelliteEphemerisSource::DEMODULATED) {
                hasNoneDemodEphSource = true;
            }
        }
    }
    if (hasNoneDemodEphSource && hasServerPredictionAvailable) {
        EXPECT_TRUE(hasNoneZeroServerPredictionAgeSeconds);
    }

    /**
    - Gnss Location Data:: should show some valid information, ideally reasonably close (+/-1km) to
        the Location output - at least after the 2nd valid location output (maybe in general, wait
        for 2 good Location outputs before checking this, in case they don't update the assistance
        until after they output the Location)
    */
    double distanceM =
            Utils::distanceMeters(data.position.latitudeDegrees, data.position.longitudeDegrees,
                                  aidl_gnss_cb_->last_location_.latitudeDegrees,
                                  aidl_gnss_cb_->last_location_.longitudeDegrees);
    ALOGD("distance between debug position and last position: %.2lf", distanceM);
    EXPECT_LT(distanceM, 1000.0);  // 1km

    /**
    - Gnss Time Data:: timeEstimate should be reasonably close to the current GPS time.
    - Gnss Time Data:: timeUncertaintyNs should always be > 0 and < 5e9 (could be large due
        to solve-for-time type solutions)
    - Gnss Time Data:: frequencyUncertaintyNsPerSec: should always be > 0 and < 1000 (1000 ns/s
        corresponds to roughly a 300 m/s speed error, which should be pretty rare)
    */
    ALOGD("debug time: %" PRId64 ", position time: %" PRId64, data.time.timeEstimateMs,
          aidl_gnss_cb_->last_location_.timestampMillis);
    // Allowing 5s between the last location time and the current GPS time
    EXPECT_LT(abs(data.time.timeEstimateMs - aidl_gnss_cb_->last_location_.timestampMillis), 5000);

    ALOGD("debug time uncertainty: %f ns", data.time.timeUncertaintyNs);
    EXPECT_GT(data.time.timeUncertaintyNs, 0);
    EXPECT_LT(data.time.timeUncertaintyNs, 5e9);

    ALOGD("debug freq uncertainty: %f ns/s", data.time.frequencyUncertaintyNsPerSec);
    EXPECT_GT(data.time.frequencyUncertaintyNsPerSec, 0);
    EXPECT_LT(data.time.frequencyUncertaintyNsPerSec, 1000);
}

/*
 * TestGnssVisibilityControlExtension:
Loading