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

Commit 8791e7bf authored by Wyatt Riley's avatar Wyatt Riley
Browse files

GNSS Batching - Default implementation

Connecting GnssBatching from fused_location.h
through to the IGnss(Batching).hal

Test: Basic regular GNSS and batched GNSS
      functional tests on Pixel

Change-Id: I3ff72c626acece891fd9e5ef2802b3489dac5dd2
parent 72ba4742
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -136,7 +136,8 @@ interface IGnssBatching {

    /**
     * Closes the interface. If any batch operations are in progress,
     * they should be stopped.
     * they must be stopped.  If any locations are in the hardware batch, they
     * must be deleted (and not sent via callback.)
     *
     * init() may be called again, after this, if the interface is to be restored
     */
+69 −9
Original line number Diff line number Diff line
@@ -28,6 +28,8 @@ namespace implementation {
std::vector<std::unique_ptr<ThreadFuncArgs>> Gnss::sThreadFuncArgsList;
sp<IGnssCallback> Gnss::sGnssCbIface = nullptr;
bool Gnss::sInterfaceExists = false;
bool Gnss::sWakelockHeldGnss = false;
bool Gnss::sWakelockHeldFused = false;

GpsCallbacks Gnss::sGnssCb = {
    .size = sizeof(GpsCallbacks),
@@ -253,22 +255,63 @@ void Gnss::setCapabilitiesCb(uint32_t capabilities) {
}

void Gnss::acquireWakelockCb() {
    if (sGnssCbIface == nullptr) {
        ALOGE("%s: GNSS Callback Interface configured incorrectly", __func__);
        return;
    acquireWakelockGnss();
}

    sGnssCbIface->gnssAcquireWakelockCb();
void Gnss::releaseWakelockCb() {
    releaseWakelockGnss();
}

void Gnss::releaseWakelockCb() {

void Gnss::acquireWakelockGnss() {
    sWakelockHeldGnss = true;
    updateWakelock();
}

void Gnss::releaseWakelockGnss() {
    sWakelockHeldGnss = false;
    updateWakelock();
}

void Gnss::acquireWakelockFused() {
    sWakelockHeldFused = true;
    updateWakelock();
}

void Gnss::releaseWakelockFused() {
    sWakelockHeldFused = false;
    updateWakelock();
}

void Gnss::updateWakelock() {
    // Track the state of the last request - in case the wake lock in the layer above is reference
    // counted.
    static bool sWakelockHeld = false;

    if (sGnssCbIface == nullptr) {
        ALOGE("%s: GNSS Callback Interface configured incorrectly", __func__);
        return;
    }

    if (sWakelockHeldGnss || sWakelockHeldFused) {
        if (!sWakelockHeld) {
            ALOGI("%s: GNSS HAL Wakelock acquired due to gps: %d, fused: %d", __func__,
                    sWakelockHeldGnss, sWakelockHeldFused);
            sWakelockHeld = true;
            sGnssCbIface->gnssAcquireWakelockCb();
        }
    } else {
        if (sWakelockHeld) {
            ALOGI("%s: GNSS HAL Wakelock released", __func__);
        } else  {
            // To avoid burning power, always release, even if logic got here with sWakelock false
            // which it shouldn't, unless underlying *.h implementation makes duplicate requests.
            ALOGW("%s: GNSS HAL Wakelock released, duplicate request", __func__);
        }
        sWakelockHeld = false;
        sGnssCbIface->gnssReleaseWakelockCb();
    }
}

void Gnss::requestUtcTimeCb() {
    if (sGnssCbIface == nullptr) {
@@ -541,8 +584,26 @@ Return<sp<IGnssBatching>> Gnss::getExtensionGnssBatching() {
    if (mGnssIface == nullptr) {
        ALOGE("%s: Gnss interface is unavailable", __func__);
    } else {
        // TODO(b/34133439): actually get an flpLocationIface
        hw_module_t* module;
        const FlpLocationInterface* flpLocationIface = nullptr;
        int err = hw_get_module(FUSED_LOCATION_HARDWARE_MODULE_ID, (hw_module_t const**)&module);

        if (err != 0) {
            ALOGE("gnss flp hw_get_module failed: %d", err);
        } else if (module == nullptr) {
            ALOGE("Fused Location hw_get_module returned null module");
        } else if (module->methods == nullptr) {
            ALOGE("Fused Location hw_get_module returned null methods");
        } else {
            hw_device_t* device;
            err = module->methods->open(module, FUSED_LOCATION_HARDWARE_MODULE_ID, &device);
            if (err != 0) {
                ALOGE("flpDevice open failed: %d", err);
            } else {
                flp_device_t * flpDevice = reinterpret_cast<flp_device_t*>(device);
                flpLocationIface = flpDevice->get_flp_interface(flpDevice);
            }
        }

        if (flpLocationIface == nullptr) {
            ALOGE("%s: GnssBatching interface is not implemented by HAL", __func__);
@@ -550,7 +611,6 @@ Return<sp<IGnssBatching>> Gnss::getExtensionGnssBatching() {
            mGnssBatching = new GnssBatching(flpLocationIface);
        }
    }

    return mGnssBatching;
}

+16 −1
Original line number Diff line number Diff line
@@ -53,7 +53,6 @@ using LegacyGnssSystemInfo = ::GnssSystemInfo;
 * IGnssCallback interface to be passed into the conventional implementation of the GNSS HAL.
 */
struct Gnss : public IGnss {
    // TODO: Add flp_device_t, either in ctor, or later attach?
    Gnss(gps_device_t* gnss_device);
    ~Gnss();

@@ -108,12 +107,28 @@ struct Gnss : public IGnss {
    static void gpsSvStatusCb(GpsSvStatus* status);
    static void setSystemInfoCb(const LegacyGnssSystemInfo* info);

    /*
     * Wakelock consolidation, only needed for dual use of a gps.h & fused_location.h HAL
     *
     * Ensures that if the last call from either legacy .h was to acquire a wakelock, that a
     * wakelock is held.  Otherwise releases it.
     */
    static void acquireWakelockFused();
    static void releaseWakelockFused();

    /*
     * Holds function pointers to the callback methods.
     */
    static GpsCallbacks sGnssCb;

 private:
    // for wakelock consolidation, see above
    static void acquireWakelockGnss();
    static void releaseWakelockGnss();
    static void updateWakelock();
    static bool sWakelockHeldGnss;
    static bool sWakelockHeldFused;

    sp<GnssXtra> mGnssXtraIface = nullptr;
    sp<AGnssRil> mGnssRil = nullptr;
    sp<GnssGeofencing> mGnssGeofencingIface = nullptr;
+185 −11
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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 "GnssHAL_GnssBatchingInterface"

#include "GnssBatching.h"
#include <Gnss.h> // for wakelock consolidation
#include <GnssUtils.h>

#include <cutils/log.h>  // for ALOGE
#include <vector>

namespace android {
namespace hardware {
@@ -6,38 +29,189 @@ namespace gnss {
namespace V1_0 {
namespace implementation {

sp<IGnssBatchingCallback> GnssBatching::sGnssBatchingCbIface = nullptr;
bool GnssBatching::sFlpSupportsBatching = false;

FlpCallbacks GnssBatching::sFlpCb = {
    .size = sizeof(FlpCallbacks),
    .location_cb = locationCb,
    .acquire_wakelock_cb = acquireWakelockCb,
    .release_wakelock_cb = releaseWakelockCb,
    .set_thread_event_cb = setThreadEventCb,
    .flp_capabilities_cb = flpCapabilitiesCb,
    .flp_status_cb = flpStatusCb,
};

GnssBatching::GnssBatching(const FlpLocationInterface* flpLocationIface) :
    mFlpLocationIface(flpLocationIface) {}
    mFlpLocationIface(flpLocationIface) {
}

/*
 * This enum is used locally by various methods below. It is only used by the default
 * implementation and is not part of the GNSS interface.
 */
enum BatchingValues : uint16_t {
    // Numbers 0-3 were used in earlier implementations - using 4 to be distinct to the HAL
    FLP_GNSS_BATCHING_CLIENT_ID = 4,
    // Tech. mask of GNSS, and sensor aiding, for legacy HAL to fit with GnssBatching API
    FLP_TECH_MASK_GNSS_AND_SENSORS = FLP_TECH_MASK_GNSS | FLP_TECH_MASK_SENSORS,
    // Putting a cap to avoid possible memory issues.  Unlikely values this high are supported.
    MAX_LOCATIONS_PER_BATCH = 1000
};

void GnssBatching::locationCb(int32_t locationsCount, FlpLocation** locations) {
    if (sGnssBatchingCbIface == nullptr) {
        ALOGE("%s: GNSS Batching Callback Interface configured incorrectly", __func__);
        return;
    }

    if (locations == nullptr) {
        ALOGE("%s: Invalid locations from GNSS HAL", __func__);
        return;
    }

    if (locationsCount < 0) {
        ALOGE("%s: Negative location count: %d set to 0", __func__, locationsCount);
        locationsCount = 0;
    } else if (locationsCount > MAX_LOCATIONS_PER_BATCH) {
        ALOGW("%s: Unexpected high location count: %d set to %d", __func__, locationsCount,
                MAX_LOCATIONS_PER_BATCH);
        locationsCount = MAX_LOCATIONS_PER_BATCH;
    }

    /**
     * Note:
     * Some existing implementations may drop duplicate locations.  These could be expanded here
     * but as there's ambiguity between no-GPS-fix vs. dropped duplicates in that implementation,
     * and that's not specified by the fused_location.h, that isn't safe to do here.
     * Fortunately, this shouldn't be a major issue in cases where GNSS batching is typically
     * used (e.g. when user is likely in vehicle/bicycle.)
     */
    std::vector<android::hardware::gnss::V1_0::GnssLocation> gnssLocations;
    for (int iLocation = 0; iLocation < locationsCount; iLocation++) {
        if (locations[iLocation] == nullptr) {
            ALOGE("%s: Null location at slot: %d of %d, skipping", __func__, iLocation,
                    locationsCount);
            continue;
        }
        if ((locations[iLocation]->sources_used & ~FLP_TECH_MASK_GNSS_AND_SENSORS) != 0)
        {
            ALOGE("%s: Unrequested location type %d at slot: %d of %d, skipping", __func__,
                    locations[iLocation]->sources_used, iLocation, locationsCount);
            continue;
        }
        gnssLocations.push_back(convertToGnssLocation(locations[iLocation]));
    }

    sGnssBatchingCbIface->gnssLocationBatchCb(gnssLocations);
}

void GnssBatching::acquireWakelockCb() {
    Gnss::acquireWakelockFused();
}

void GnssBatching::releaseWakelockCb() {
    Gnss::releaseWakelockFused();
}

// this can just return success, because threads are now set up on demand in the jni layer
int32_t GnssBatching::setThreadEventCb(ThreadEvent event) {
    return FLP_RESULT_SUCCESS;
}

void GnssBatching::flpCapabilitiesCb(int32_t capabilities) {
    ALOGD("%s capabilities %d", __func__, capabilities);

    if (capabilities & CAPABILITY_GNSS) {
        // once callback is received and capabilities high enough, we know version is
        // high enough for flush()
        sFlpSupportsBatching = true;
    }
}

void GnssBatching::flpStatusCb(int32_t status) {
    ALOGD("%s (default implementation) not forwarding status: %d", __func__, status);
}

// Methods from ::android::hardware::gnss::V1_0::IGnssBatching follow.
Return<bool> GnssBatching::init(const sp<IGnssBatchingCallback>& callback) {
    // TODO(b/34133439) implement
    if (mFlpLocationIface == nullptr) {
        ALOGE("%s: Flp batching is unavailable", __func__);
        return false;
    }

    sGnssBatchingCbIface = callback;

    return (mFlpLocationIface->init(&sFlpCb) == 0);
}

Return<uint16_t> GnssBatching::getBatchSize() {
    // TODO(b/34133439) implement
    if (mFlpLocationIface == nullptr) {
        ALOGE("%s: Flp batching interface is unavailable", __func__);
        return 0;
    }

    return mFlpLocationIface->get_batch_size();
}

Return<bool> GnssBatching::start(const IGnssBatching::Options& options) {
    // TODO(b/34133439) implement
    if (mFlpLocationIface == nullptr) {
        ALOGE("%s: Flp batching interface is unavailable", __func__);
        return false;
    }

    if (!sFlpSupportsBatching) {
        ALOGE("%s: Flp batching interface not supported, no capabilities callback received",
                __func__);
        return false;
    }

    FlpBatchOptions optionsHw;
    // Legacy code used 9999 mW for High accuracy, and 21 mW for balanced.
    // New GNSS API just expects reasonable GNSS chipset behavior - do something efficient
    // given the interval.  This 100 mW limit should be quite sufficient (esp. given legacy code
    // implementations may not even use this value.)
    optionsHw.max_power_allocation_mW = 100;
    optionsHw.sources_to_use = FLP_TECH_MASK_GNSS_AND_SENSORS;
    optionsHw.flags = 0;
    if (options.flags & Flag::WAKEUP_ON_FIFO_FULL) {
        optionsHw.flags |= FLP_BATCH_WAKEUP_ON_FIFO_FULL;
    }
    optionsHw.period_ns = options.periodNanos;
    optionsHw.smallest_displacement_meters = 0; // Zero offset - just use time interval

    return (mFlpLocationIface->start_batching(FLP_GNSS_BATCHING_CLIENT_ID, &optionsHw)
            == FLP_RESULT_SUCCESS);
}

Return<void> GnssBatching::flush() {
    // TODO(b/34133439) implement
    if (mFlpLocationIface == nullptr) {
        ALOGE("%s: Flp batching interface is unavailable", __func__);
        return Void();
    }

    mFlpLocationIface->flush_batched_locations();

    return Void();
}

Return<bool> GnssBatching::stop() {
    // TODO(b/34133439) implement
    if (mFlpLocationIface == nullptr) {
        ALOGE("%s: Flp batching interface is unavailable", __func__);
        return false;
    }

    return (mFlpLocationIface->stop_batching(FLP_GNSS_BATCHING_CLIENT_ID) == FLP_RESULT_SUCCESS);
}

Return<void> GnssBatching::cleanup() {
    // TODO(b/34133439) implement
    if (mFlpLocationIface == nullptr) {
        ALOGE("%s: Flp batching interface is unavailable", __func__);
        return Void();
    }

    mFlpLocationIface->cleanup();

    return Void();
}

+18 −1
Original line number Diff line number Diff line
@@ -6,7 +6,6 @@
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>


namespace android {
namespace hardware {
namespace gnss {
@@ -35,8 +34,26 @@ struct GnssBatching : public IGnssBatching {
    Return<bool> stop() override;
    Return<void> cleanup() override;

    /*
     * Callback methods to be passed into the conventional FLP HAL by the default
     * implementation. These methods are not part of the IGnssBatching base class.
     */
    static void locationCb(int32_t locationsCount, FlpLocation** locations);
    static void acquireWakelockCb();
    static void releaseWakelockCb();
    static int32_t setThreadEventCb(ThreadEvent event);
    static void flpCapabilitiesCb(int32_t capabilities);
    static void flpStatusCb(int32_t status);

    /*
     * Holds function pointers to the callback methods.
     */
    static FlpCallbacks sFlpCb;

 private:
    const FlpLocationInterface* mFlpLocationIface = nullptr;
    static sp<IGnssBatchingCallback> sGnssBatchingCbIface;
    static bool sFlpSupportsBatching;
};

extern "C" IGnssBatching* HIDL_FETCH_IGnssBatching(const char* name);
Loading