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

Commit 53a9a09a authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add more GnssDebug validity tests" into main

parents b91c5364 72a431ef
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,40 +1149,139 @@ 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);
}

/*
Loading