blob: 4fdacda0b402b03ba17a58cb66e6d09a6607de71 [file] [log] [blame]
/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation, nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/*
Changes from Qualcomm Innovation Center are provided under the following license:
Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted (subject to the limitations in the
disclaimer below) provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Qualcomm Innovation Center, Inc. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define LOG_NDEBUG 0
#define LOG_TAG "LocSvc_BatchingAdapter"
#include <loc_pla.h>
#include <log_util.h>
#include <LocContext.h>
#include <BatchingAdapter.h>
using namespace loc_core;
BatchingAdapter::BatchingAdapter() :
LocAdapterBase(0,
LocContext::getLocContext(LocContext::mLocationHalName),
false, nullptr, true),
mOngoingTripDistance(0),
mOngoingTripTBFInterval(0),
mTripWithOngoingTBFDropped(false),
mTripWithOngoingTripDistanceDropped(false),
mBatchingTimeout(0),
mBatchingAccuracy(1),
mBatchSize(0),
mTripBatchSize(0)
{
LOC_LOGD("%s]: Constructor", __func__);
readConfigCommand();
setConfigCommand();
// at last step, let us inform adapater base that we are done
// with initialization, e.g.: ready to process handleEngineUpEvent
doneInit();
}
void
BatchingAdapter::readConfigCommand()
{
LOC_LOGD("%s]: ", __func__);
struct MsgReadConfig : public LocMsg {
BatchingAdapter& mAdapter;
inline MsgReadConfig(BatchingAdapter& adapter) :
LocMsg(),
mAdapter(adapter) {}
inline virtual void proc() const {
uint32_t batchingTimeout = 0;
uint32_t batchingAccuracy = 0;
uint32_t batchSize = 0;
uint32_t tripBatchSize = 0;
static const loc_param_s_type flp_conf_param_table[] =
{
{"BATCH_SIZE", &batchSize, NULL, 'n'},
{"OUTDOOR_TRIP_BATCH_SIZE", &tripBatchSize, NULL, 'n'},
{"BATCH_SESSION_TIMEOUT", &batchingTimeout, NULL, 'n'},
{"ACCURACY", &batchingAccuracy, NULL, 'n'},
};
UTIL_READ_CONF(LOC_PATH_FLP_CONF, flp_conf_param_table);
LOC_LOGD("%s]: batchSize %u tripBatchSize %u batchingAccuracy %u batchingTimeout %u ",
__func__, batchSize, tripBatchSize, batchingAccuracy, batchingTimeout);
mAdapter.setBatchSize(batchSize);
mAdapter.setTripBatchSize(tripBatchSize);
mAdapter.setBatchingTimeout(batchingTimeout);
mAdapter.setBatchingAccuracy(batchingAccuracy);
}
};
sendMsg(new MsgReadConfig(*this));
}
void
BatchingAdapter::setConfigCommand()
{
LOC_LOGD("%s]: ", __func__);
struct MsgSetConfig : public LocMsg {
BatchingAdapter& mAdapter;
LocApiBase& mApi;
inline MsgSetConfig(BatchingAdapter& adapter,
LocApiBase& api) :
LocMsg(),
mAdapter(adapter),
mApi(api) {}
inline virtual void proc() const {
mApi.setBatchSize(mAdapter.getBatchSize());
mApi.setTripBatchSize(mAdapter.getTripBatchSize());
}
};
sendMsg(new MsgSetConfig(*this, *mLocApi));
}
void
BatchingAdapter::stopClientSessions(LocationAPI* client)
{
LOC_LOGD("%s]: client %p", __func__, client);
typedef struct pairKeyBatchMode {
LocationAPI* client;
uint32_t id;
BatchingMode batchingMode;
inline pairKeyBatchMode(LocationAPI* _client, uint32_t _id, BatchingMode _bMode) :
client(_client), id(_id), batchingMode(_bMode) {}
} pairKeyBatchMode;
std::vector<pairKeyBatchMode> vBatchingClient;
for (auto it : mBatchingSessions) {
if (client == it.first.client) {
vBatchingClient.emplace_back(it.first.client, it.first.id, it.second.batchingMode);
}
}
for (auto keyBatchingMode : vBatchingClient) {
if (keyBatchingMode.batchingMode != BATCHING_MODE_TRIP) {
stopBatching(keyBatchingMode.client, keyBatchingMode.id);
} else {
stopTripBatchingMultiplex(keyBatchingMode.client, keyBatchingMode.id);
}
}
}
void
BatchingAdapter::updateClientsEventMask()
{
LOC_API_ADAPTER_EVENT_MASK_T mask = 0;
for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
// we don't register LOC_API_ADAPTER_BIT_BATCH_FULL until we
// start batching with ROUTINE or TRIP option
if (it->second.batchingCb != nullptr) {
mask |= LOC_API_ADAPTER_BIT_BATCH_STATUS;
}
}
if (autoReportBatchingSessionsCount() > 0) {
mask |= LOC_API_ADAPTER_BIT_BATCH_FULL;
}
updateEvtMask(mask, LOC_REGISTRATION_MASK_SET);
}
void
BatchingAdapter::handleEngineLockStatusEvent(EngineLockState engineLockState) {
LOC_LOGD("%s]: Old Engine state %d, New Engine state : %d,", __func__,
mLocApi->getEngineLockState(), engineLockState);
struct MsgEngineLockStateEvent : public LocMsg {
BatchingAdapter& mAdapter;
EngineLockState mEngineLockState;
inline MsgEngineLockStateEvent(BatchingAdapter& adapter, EngineLockState engineLockState) :
LocMsg(),
mAdapter(adapter),
mEngineLockState(engineLockState){}
virtual void proc() const {
mAdapter.handleEngineLockStatus(mEngineLockState);
}
};
sendMsg(new MsgEngineLockStateEvent(*this, engineLockState));
}
void
BatchingAdapter::handleEngineLockStatus(EngineLockState engineLockState) {
LOC_LOGd("lock state %d, pending msgs %zu", engineLockState, mPendingGnssEnabledMsgs.size());
if (ENGINE_LOCK_STATE_ENABLED == engineLockState) {
for (auto msg: mPendingGnssEnabledMsgs) {
sendMsg(msg);
}
mPendingGnssEnabledMsgs.clear();
}
}
void
BatchingAdapter::handleEngineUpEvent()
{
struct MsgSSREvent : public LocMsg {
BatchingAdapter& mAdapter;
LocApiBase& mApi;
inline MsgSSREvent(BatchingAdapter& adapter,
LocApiBase& api) :
LocMsg(),
mAdapter(adapter),
mApi(api) {}
virtual void proc() const {
mAdapter.setEngineCapabilitiesKnown(true);
mAdapter.broadcastCapabilities(mAdapter.getCapabilities());
mApi.setBatchSize(mAdapter.getBatchSize());
mApi.setTripBatchSize(mAdapter.getTripBatchSize());
if (ENGINE_LOCK_STATE_ENABLED == mApi.getEngineLockState()) {
mAdapter.restartSessions();
for (auto msg: mAdapter.mPendingMsgs) {
mAdapter.sendMsg(msg);
}
mAdapter.mPendingMsgs.clear();
}
}
};
sendMsg(new MsgSSREvent(*this, *mLocApi));
}
void
BatchingAdapter::restartSessions()
{
LOC_LOGD("%s]: ", __func__);
if (autoReportBatchingSessionsCount() > 0) {
updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
LOC_REGISTRATION_MASK_ENABLED);
}
for (auto it = mBatchingSessions.begin();
it != mBatchingSessions.end(); ++it) {
if (it->second.batchingMode != BATCHING_MODE_TRIP) {
mLocApi->startBatching(it->first.id, it->second,
getBatchingAccuracy(), getBatchingTimeout(),
new LocApiResponse(*getContext(),
[] (LocationError /*err*/) {}));
}
}
if (mTripSessions.size() > 0) {
// restart outdoor trip batching session if any.
mOngoingTripDistance = 0;
mOngoingTripTBFInterval = 0;
// record the min trip distance and min tbf interval of all ongoing sessions
for (auto tripSession : mTripSessions) {
TripSessionStatus &tripSessStatus = tripSession.second;
if ((0 == mOngoingTripDistance) ||
(mOngoingTripDistance >
(tripSessStatus.tripDistance - tripSessStatus.accumulatedDistanceThisTrip))) {
mOngoingTripDistance = tripSessStatus.tripDistance -
tripSessStatus.accumulatedDistanceThisTrip;
}
if ((0 == mOngoingTripTBFInterval) ||
(mOngoingTripTBFInterval > tripSessStatus.tripTBFInterval)) {
mOngoingTripTBFInterval = tripSessStatus.tripTBFInterval;
}
// reset the accumulatedDistanceOngoingBatch for each session
tripSessStatus.accumulatedDistanceOngoingBatch = 0;
}
mLocApi->startOutdoorTripBatching(mOngoingTripDistance, mOngoingTripTBFInterval,
getBatchingTimeout(), new LocApiResponse(*getContext(), [this] (LocationError err) {
if (LOCATION_ERROR_SUCCESS != err) {
mOngoingTripDistance = 0;
mOngoingTripTBFInterval = 0;
}
printTripReport();
}));
}
}
bool
BatchingAdapter::hasBatchingCallback(LocationAPI* client)
{
auto it = mClientData.find(client);
return (it != mClientData.end() && it->second.batchingCb);
}
bool
BatchingAdapter::isBatchingSession(LocationAPI* client, uint32_t sessionId)
{
LocationSessionKey key(client, sessionId);
return (mBatchingSessions.find(key) != mBatchingSessions.end());
}
bool
BatchingAdapter::isTripSession(uint32_t sessionId) {
return (mTripSessions.find(sessionId) != mTripSessions.end());
}
void
BatchingAdapter::saveBatchingSession(LocationAPI* client, uint32_t sessionId,
const BatchingOptions& batchingOptions)
{
LocationSessionKey key(client, sessionId);
mBatchingSessions[key] = batchingOptions;
}
void
BatchingAdapter::eraseBatchingSession(LocationAPI* client, uint32_t sessionId)
{
LocationSessionKey key(client, sessionId);
auto it = mBatchingSessions.find(key);
if (it != mBatchingSessions.end()) {
mBatchingSessions.erase(it);
}
}
void
BatchingAdapter::reportResponse(LocationAPI* client, LocationError err, uint32_t sessionId)
{
LOC_LOGD("%s]: client %p id %u err %u", __func__, client, sessionId, err);
auto it = mClientData.find(client);
if (it != mClientData.end() &&
it->second.responseCb != nullptr) {
it->second.responseCb(err, sessionId);
} else {
LOC_LOGE("%s]: client %p id %u not found in data", __func__, client, sessionId);
}
}
uint32_t
BatchingAdapter::autoReportBatchingSessionsCount()
{
uint32_t count = 0;
for (auto batchingSession: mBatchingSessions) {
if (batchingSession.second.batchingMode != BATCHING_MODE_NO_AUTO_REPORT) {
count++;
}
}
count += mTripSessions.size();
return count;
}
uint32_t
BatchingAdapter::startBatchingCommand(
LocationAPI* client, BatchingOptions& batchOptions)
{
uint32_t sessionId = generateSessionId();
LOC_LOGD("%s]: client %p id %u minInterval %u minDistance %u mode %u Batching Mode %d",
__func__, client, sessionId, batchOptions.minInterval, batchOptions.minDistance,
batchOptions.mode,batchOptions.batchingMode);
struct MsgStartBatching : public LocMsg {
BatchingAdapter& mAdapter;
LocApiBase& mApi;
LocationAPI* mClient;
uint32_t mSessionId;
BatchingOptions mBatchingOptions;
inline MsgStartBatching(BatchingAdapter& adapter,
LocApiBase& api,
LocationAPI* client,
uint32_t sessionId,
BatchingOptions batchOptions) :
LocMsg(),
mAdapter(adapter),
mApi(api),
mClient(client),
mSessionId(sessionId),
mBatchingOptions(batchOptions) {}
inline virtual void proc() const {
if (!mAdapter.isEngineCapabilitiesKnown()) {
mAdapter.mPendingMsgs.push_back(new MsgStartBatching(*this));
return;
}
LocationError err = LOCATION_ERROR_SUCCESS;
if (!mAdapter.hasBatchingCallback(mClient)) {
err = LOCATION_ERROR_CALLBACK_MISSING;
} else if (0 == mBatchingOptions.size) {
err = LOCATION_ERROR_INVALID_PARAMETER;
} else if (!ContextBase::isMessageSupported(
LOC_API_ADAPTER_MESSAGE_DISTANCE_BASE_LOCATION_BATCHING)) {
err = LOCATION_ERROR_NOT_SUPPORTED;
}
if (LOCATION_ERROR_SUCCESS == err) {
if (mBatchingOptions.batchingMode == BATCHING_MODE_ROUTINE ||
mBatchingOptions.batchingMode == BATCHING_MODE_NO_AUTO_REPORT) {
mAdapter.startBatching(
mClient, mSessionId, mBatchingOptions, new MsgStartBatching(*this));
} else if (mBatchingOptions.batchingMode == BATCHING_MODE_TRIP) {
mAdapter.startTripBatchingMultiplex(mClient, mSessionId, mBatchingOptions);
} else {
mAdapter.reportResponse(mClient, LOCATION_ERROR_INVALID_PARAMETER, mSessionId);
}
}
}
};
sendMsg(new MsgStartBatching(*this, *mLocApi, client, sessionId, batchOptions));
return sessionId;
}
void
BatchingAdapter::startBatching(LocationAPI* client, uint32_t sessionId,
const BatchingOptions& batchingOptions, LocMsg* pendingMsg)
{
if (batchingOptions.batchingMode != BATCHING_MODE_NO_AUTO_REPORT &&
0 == autoReportBatchingSessionsCount()) {
// if there is currenty no batching sessions interested in batch full event, then this
// new session will need to register for batch full event
updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
LOC_REGISTRATION_MASK_ENABLED);
}
// Assume start will be OK, remove session if not
saveBatchingSession(client, sessionId, batchingOptions);
mLocApi->startBatching(sessionId, batchingOptions, getBatchingAccuracy(), getBatchingTimeout(),
new LocApiResponse(*getContext(),
[this, client, sessionId, batchingOptions, pendingMsg] (LocationError err) {
if (ENGINE_LOCK_STATE_ENABLED == mLocApi->getEngineLockState() &&
LOCATION_ERROR_SUCCESS != err) {
eraseBatchingSession(client, sessionId);
}
if (LOCATION_ERROR_SUCCESS != err &&
batchingOptions.batchingMode != BATCHING_MODE_NO_AUTO_REPORT &&
0 == autoReportBatchingSessionsCount()) {
// if we fail to start batching and we have already registered batch full event
// we need to undo that since no sessions are now interested in batch full event
updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
LOC_REGISTRATION_MASK_DISABLED);
}
if (LOCATION_ERROR_GNSS_DISABLED == err && pendingMsg != nullptr) {
LOC_LOGd("GNSS_DISABLED, add request to pending queue");
mPendingGnssEnabledMsgs.push_back(pendingMsg);
} else if (pendingMsg != nullptr) {
delete pendingMsg;
}
reportResponse(client, err, sessionId);
}));
}
void
BatchingAdapter::updateBatchingOptionsCommand(LocationAPI* client, uint32_t id,
BatchingOptions& batchOptions)
{
LOC_LOGD("%s]: client %p id %u minInterval %u minDistance %u mode %u batchMode %u",
__func__, client, id, batchOptions.minInterval,
batchOptions.minDistance, batchOptions.mode,
batchOptions.batchingMode);
struct MsgUpdateBatching : public LocMsg {
BatchingAdapter& mAdapter;
LocApiBase& mApi;
LocationAPI* mClient;
uint32_t mSessionId;
BatchingOptions mBatchOptions;
inline MsgUpdateBatching(BatchingAdapter& adapter,
LocApiBase& api,
LocationAPI* client,
uint32_t sessionId,
BatchingOptions batchOptions) :
LocMsg(),
mAdapter(adapter),
mApi(api),
mClient(client),
mSessionId(sessionId),
mBatchOptions(batchOptions) {}
inline virtual void proc() const {
if (!mAdapter.isEngineCapabilitiesKnown()) {
mAdapter.mPendingMsgs.push_back(new MsgUpdateBatching(*this));
return;
}
LocationError err = LOCATION_ERROR_SUCCESS;
if (!mAdapter.isBatchingSession(mClient, mSessionId)) {
err = LOCATION_ERROR_ID_UNKNOWN;
} else if ((0 == mBatchOptions.size) ||
(mBatchOptions.batchingMode > BATCHING_MODE_NO_AUTO_REPORT)) {
err = LOCATION_ERROR_INVALID_PARAMETER;
}
if (LOCATION_ERROR_SUCCESS == err) {
if (!mAdapter.isTripSession(mSessionId)) {
mAdapter.stopBatching(mClient, mSessionId, true, mBatchOptions);
} else {
mAdapter.stopTripBatchingMultiplex(mClient, mSessionId, true, mBatchOptions);
}
}
}
};
sendMsg(new MsgUpdateBatching(*this, *mLocApi, client, id, batchOptions));
}
void
BatchingAdapter::stopBatchingCommand(LocationAPI* client, uint32_t id)
{
LOC_LOGD("%s]: client %p id %u", __func__, client, id);
struct MsgStopBatching : public LocMsg {
BatchingAdapter& mAdapter;
LocApiBase& mApi;
LocationAPI* mClient;
uint32_t mSessionId;
inline MsgStopBatching(BatchingAdapter& adapter,
LocApiBase& api,
LocationAPI* client,
uint32_t sessionId) :
LocMsg(),
mAdapter(adapter),
mApi(api),
mClient(client),
mSessionId(sessionId) {}
inline virtual void proc() const {
if (!mAdapter.isEngineCapabilitiesKnown()) {
mAdapter.mPendingMsgs.push_back(new MsgStopBatching(*this));
return;
}
LocationError err = LOCATION_ERROR_SUCCESS;
if (!mAdapter.isBatchingSession(mClient, mSessionId)) {
err = LOCATION_ERROR_ID_UNKNOWN;
}
if (LOCATION_ERROR_SUCCESS == err) {
if (mAdapter.isTripSession(mSessionId)) {
mAdapter.stopTripBatchingMultiplex(mClient, mSessionId);
} else {
mAdapter.stopBatching(mClient, mSessionId);
}
}
}
};
sendMsg(new MsgStopBatching(*this, *mLocApi, client, id));
}
void
BatchingAdapter::stopBatching(LocationAPI* client, uint32_t sessionId, bool restartNeeded,
const BatchingOptions& batchOptions)
{
LocationSessionKey key(client, sessionId);
auto it = mBatchingSessions.find(key);
if (it != mBatchingSessions.end()) {
auto flpOptions = it->second;
// Assume stop will be OK, restore session if not
eraseBatchingSession(client, sessionId);
mLocApi->stopBatching(sessionId,
new LocApiResponse(*getContext(),
[this, client, sessionId, flpOptions, restartNeeded, batchOptions]
(LocationError err) {
if (ENGINE_LOCK_STATE_ENABLED == mLocApi->getEngineLockState() &&
LOCATION_ERROR_SUCCESS != err) {
saveBatchingSession(client, sessionId, batchOptions);
} else {
// if stopBatching is success, unregister for batch full event if this was the last
// batching session that is interested in batch full event
if (0 == autoReportBatchingSessionsCount() &&
flpOptions.batchingMode != BATCHING_MODE_NO_AUTO_REPORT) {
updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
LOC_REGISTRATION_MASK_DISABLED);
}
if (restartNeeded) {
if (batchOptions.batchingMode == BATCHING_MODE_ROUTINE ||
batchOptions.batchingMode == BATCHING_MODE_NO_AUTO_REPORT) {
startBatching(client, sessionId, batchOptions);
} else if (batchOptions.batchingMode == BATCHING_MODE_TRIP) {
startTripBatchingMultiplex(client, sessionId, batchOptions);
}
}
}
reportResponse(client, err, sessionId);
}));
}
}
void
BatchingAdapter::getBatchedLocationsCommand(LocationAPI* client, uint32_t id, size_t count)
{
LOC_LOGD("%s]: client %p id %u count %zu", __func__, client, id, count);
struct MsgGetBatchedLocations : public LocMsg {
BatchingAdapter& mAdapter;
LocApiBase& mApi;
LocationAPI* mClient;
uint32_t mSessionId;
size_t mCount;
inline MsgGetBatchedLocations(BatchingAdapter& adapter,
LocApiBase& api,
LocationAPI* client,
uint32_t sessionId,
size_t count) :
LocMsg(),
mAdapter(adapter),
mApi(api),
mClient(client),
mSessionId(sessionId),
mCount(count) {}
inline virtual void proc() const {
if (!mAdapter.isEngineCapabilitiesKnown()) {
mAdapter.mPendingMsgs.push_back(new MsgGetBatchedLocations(*this));
return;
}
LocationError err = LOCATION_ERROR_SUCCESS;
if (!mAdapter.hasBatchingCallback(mClient)) {
err = LOCATION_ERROR_CALLBACK_MISSING;
} else if (!mAdapter.isBatchingSession(mClient, mSessionId)) {
err = LOCATION_ERROR_ID_UNKNOWN;
}
if (LOCATION_ERROR_SUCCESS == err) {
if (mAdapter.isTripSession(mSessionId)) {
mApi.getBatchedTripLocations(mCount, 0,
new LocApiResponse(*mAdapter.getContext(),
[&mAdapter = mAdapter, mSessionId = mSessionId,
mClient = mClient] (LocationError err) {
mAdapter.reportResponse(mClient, err, mSessionId);
}));
} else {
mApi.getBatchedLocations(mCount, new LocApiResponse(*mAdapter.getContext(),
[&mAdapter = mAdapter, mSessionId = mSessionId,
mClient = mClient] (LocationError err) {
mAdapter.reportResponse(mClient, err, mSessionId);
}));
}
} else {
mAdapter.reportResponse(mClient, err, mSessionId);
}
}
};
sendMsg(new MsgGetBatchedLocations(*this, *mLocApi, client, id, count));
}
void
BatchingAdapter::reportLocationsEvent(const Location* locations, size_t count,
BatchingMode batchingMode)
{
LOC_LOGD("%s]: count %zu batchMode %d", __func__, count, batchingMode);
struct MsgReportLocations : public LocMsg {
BatchingAdapter& mAdapter;
Location* mLocations;
size_t mCount;
BatchingMode mBatchingMode;
inline MsgReportLocations(BatchingAdapter& adapter,
const Location* locations,
size_t count,
BatchingMode batchingMode) :
LocMsg(),
mAdapter(adapter),
mLocations(new Location[count]),
mCount(count),
mBatchingMode(batchingMode)
{
if (nullptr == mLocations) {
LOC_LOGE("%s]: new failed to allocate mLocations", __func__);
return;
}
for (size_t i=0; i < mCount; ++i) {
mLocations[i] = locations[i];
}
}
inline virtual ~MsgReportLocations() {
if (nullptr != mLocations)
delete[] mLocations;
}
inline virtual void proc() const {
mAdapter.reportLocations(mLocations, mCount, mBatchingMode);
}
};
sendMsg(new MsgReportLocations(*this, locations, count, batchingMode));
}
void
BatchingAdapter::reportLocations(Location* locations, size_t count, BatchingMode batchingMode)
{
BatchingOptions batchOptions = {sizeof(BatchingOptions), batchingMode};
for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
if (nullptr != it->second.batchingCb) {
it->second.batchingCb(count, locations, batchOptions);
}
}
}
void
BatchingAdapter::reportCompletedTripsEvent(uint32_t accumulated_distance)
{
struct MsgReportCompletedTrips : public LocMsg {
BatchingAdapter& mAdapter;
uint32_t mAccumulatedDistance;
inline MsgReportCompletedTrips(BatchingAdapter& adapter,
uint32_t accumulated_distance) :
LocMsg(),
mAdapter(adapter),
mAccumulatedDistance(accumulated_distance)
{
}
inline virtual ~MsgReportCompletedTrips() {
}
inline virtual void proc() const {
// Check if any trips are completed
std::list<uint32_t> completedTripsList;
completedTripsList.clear();
for(auto itt = mAdapter.mTripSessions.begin(); itt != mAdapter.mTripSessions.end();)
{
TripSessionStatus &tripSession = itt->second;
tripSession.accumulatedDistanceThisTrip =
tripSession.accumulatedDistanceOnTripRestart
+ (mAccumulatedDistance - tripSession.accumulatedDistanceOngoingBatch);
if (tripSession.tripDistance <= tripSession.accumulatedDistanceThisTrip) {
// trip is completed
completedTripsList.push_back(itt->first);
itt = mAdapter.mTripSessions.erase(itt);
if (tripSession.tripTBFInterval == mAdapter.mOngoingTripTBFInterval) {
// trip with ongoing TBF interval is completed
mAdapter.mTripWithOngoingTBFDropped = true;
}
if (tripSession.tripDistance == mAdapter.mOngoingTripDistance) {
// trip with ongoing trip distance is completed
mAdapter.mTripWithOngoingTripDistanceDropped = true;
}
} else {
itt++;
}
}
if (completedTripsList.size() > 0) {
mAdapter.reportBatchStatusChange(BATCHING_STATUS_TRIP_COMPLETED,
completedTripsList);
mAdapter.restartTripBatching(false, mAccumulatedDistance, 0);
} else {
mAdapter.printTripReport();
}
}
};
LOC_LOGD("%s]: Accumulated Distance so far: %u",
__func__, accumulated_distance);
sendMsg(new MsgReportCompletedTrips(*this, accumulated_distance));
}
void
BatchingAdapter::reportBatchStatusChange(BatchingStatus batchStatus,
std::list<uint32_t> & completedTripsList)
{
BatchingStatusInfo batchStatusInfo =
{sizeof(BatchingStatusInfo), batchStatus};
for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
if (nullptr != it->second.batchingStatusCb) {
it->second.batchingStatusCb(batchStatusInfo, completedTripsList);
}
}
}
void
BatchingAdapter::reportBatchStatusChangeEvent(BatchingStatus batchStatus)
{
struct MsgReportBatchStatus : public LocMsg {
BatchingAdapter& mAdapter;
BatchingStatus mBatchStatus;
inline MsgReportBatchStatus(BatchingAdapter& adapter,
BatchingStatus batchStatus) :
LocMsg(),
mAdapter(adapter),
mBatchStatus(batchStatus)
{
}
inline virtual ~MsgReportBatchStatus() {
}
inline virtual void proc() const {
std::list<uint32_t> tempList;
tempList.clear();
mAdapter.reportBatchStatusChange(mBatchStatus, tempList);
}
};
sendMsg(new MsgReportBatchStatus(*this, batchStatus));
}
void
BatchingAdapter::startTripBatchingMultiplex(LocationAPI* client, uint32_t sessionId,
const BatchingOptions& batchingOptions)
{
if (mTripSessions.size() == 0) {
// if there is currenty no batching sessions interested in batch full event, then this
// new session will need to register for batch full event
if (0 == autoReportBatchingSessionsCount()) {
updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
LOC_REGISTRATION_MASK_ENABLED);
}
// Assume start will be OK, remove session if not
saveBatchingSession(client, sessionId, batchingOptions);
mTripSessions[sessionId] = { 0, 0, 0, batchingOptions.minDistance,
batchingOptions.minInterval};
mLocApi->startOutdoorTripBatching(batchingOptions.minDistance,
batchingOptions.minInterval, getBatchingTimeout(), new LocApiResponse(*getContext(),
[this, client, sessionId, batchingOptions] (LocationError err) {
if (ENGINE_LOCK_STATE_DISABLED == mLocApi->getEngineLockState() ||
err == LOCATION_ERROR_SUCCESS) {
mOngoingTripDistance = batchingOptions.minDistance;
mOngoingTripTBFInterval = batchingOptions.minInterval;
LOC_LOGD("%s] New Trip started ...", __func__);
printTripReport();
} else {
eraseBatchingSession(client, sessionId);
mTripSessions.erase(sessionId);
// if we fail to start batching and we have already registered batch full event
// we need to undo that since no sessions are now interested in batch full event
if (0 == autoReportBatchingSessionsCount()) {
updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
LOC_REGISTRATION_MASK_DISABLED);
}
}
reportResponse(client, err, sessionId);
}));
} else {
// query accumulated distance
mLocApi->queryAccumulatedTripDistance(
new LocApiResponseData<LocApiBatchData>(*getContext(),
[this, batchingOptions, sessionId, client]
(LocationError err, LocApiBatchData data) {
uint32_t accumulatedDistanceOngoingBatch = 0;
uint32_t numOfBatchedPositions = 0;
uint32_t ongoingTripDistance = mOngoingTripDistance;
uint32_t ongoingTripInterval = mOngoingTripTBFInterval;
bool needsRestart = false;
// check if TBF of new session is lesser than ongoing TBF interval
if (ongoingTripInterval > batchingOptions.minInterval) {
ongoingTripInterval = batchingOptions.minInterval;
needsRestart = true;
}
accumulatedDistanceOngoingBatch = data.accumulatedDistance;
numOfBatchedPositions = data.numOfBatchedPositions;
TripSessionStatus newTripSession = { accumulatedDistanceOngoingBatch, 0, 0,
batchingOptions.minDistance,
batchingOptions.minInterval};
if (err != LOCATION_ERROR_SUCCESS) {
// unable to query accumulated distance, assume remaining distance in
// ongoing batch is mongoingTripDistance.
if (batchingOptions.minDistance < ongoingTripDistance) {
ongoingTripDistance = batchingOptions.minDistance;
needsRestart = true;
}
} else {
// compute the remaining distance
uint32_t ongoing_trip_remaining_distance = ongoingTripDistance -
accumulatedDistanceOngoingBatch;
// check if new trip distance is lesser than the ongoing batch remaining distance
if (batchingOptions.minDistance < ongoing_trip_remaining_distance) {
ongoingTripDistance = batchingOptions.minDistance;
needsRestart = true;
} else if (needsRestart == true) {
// needsRestart is anyways true , may be because of lesser TBF of new session.
ongoingTripDistance = ongoing_trip_remaining_distance;
}
mTripSessions[sessionId] = newTripSession;
LOC_LOGD("%s] New Trip started ...", __func__);
printTripReport();
}
if (needsRestart) {
mOngoingTripDistance = ongoingTripDistance;
mOngoingTripTBFInterval = ongoingTripInterval;
// reset the accumulatedDistanceOngoingBatch for each session,
// and record the total accumulated distance so far for the session.
for (auto itt = mTripSessions.begin(); itt != mTripSessions.end(); itt++) {
TripSessionStatus &tripSessStatus = itt->second;
tripSessStatus.accumulatedDistanceOngoingBatch = 0;
tripSessStatus.accumulatedDistanceOnTripRestart =
tripSessStatus.accumulatedDistanceThisTrip;
}
mLocApi->reStartOutdoorTripBatching(ongoingTripDistance, ongoingTripInterval,
getBatchingTimeout(), new LocApiResponse(*getContext(),
[this, client, sessionId] (LocationError err) {
if (err != LOCATION_ERROR_SUCCESS) {
LOC_LOGE("%s] New Trip restart failed!", __func__);
}
reportResponse(client, err, sessionId);
}));
} else {
reportResponse(client, LOCATION_ERROR_SUCCESS, sessionId);
}
}));
}
}
void
BatchingAdapter::stopTripBatchingMultiplex(LocationAPI* client, uint32_t sessionId,
bool restartNeeded, const BatchingOptions& batchOptions)
{
LocationError err = LOCATION_ERROR_SUCCESS;
if (mTripSessions.size() == 1) {
mLocApi->stopOutdoorTripBatching(true, new LocApiResponse(*getContext(),
[this, restartNeeded, client, sessionId, batchOptions]
(LocationError err) {
if (LOCATION_ERROR_SUCCESS == err) {
// if stopOutdoorTripBatching is success, unregister for batch full event if this
// was the last batching session that is interested in batch full event
if (1 == autoReportBatchingSessionsCount()) {
updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
LOC_REGISTRATION_MASK_DISABLED);
}
}
stopTripBatchingMultiplexCommon(err, client, sessionId, restartNeeded, batchOptions);
}));
return;
}
stopTripBatchingMultiplexCommon(err, client, sessionId, restartNeeded, batchOptions);
}
void
BatchingAdapter::stopTripBatchingMultiplexCommon(LocationError err, LocationAPI* client,
uint32_t sessionId, bool restartNeeded, const BatchingOptions& batchOptions)
{
auto itt = mTripSessions.find(sessionId);
TripSessionStatus tripSess = itt->second;
if (tripSess.tripTBFInterval == mOngoingTripTBFInterval) {
// trip with ongoing trip interval is stopped
mTripWithOngoingTBFDropped = true;
}
if (tripSess.tripDistance == mOngoingTripDistance) {
// trip with ongoing trip distance is stopped
mTripWithOngoingTripDistanceDropped = true;
}
mTripSessions.erase(sessionId);
if (mTripSessions.size() == 0) {
mOngoingTripDistance = 0;
mOngoingTripTBFInterval = 0;
} else {
restartTripBatching(true);
}
if (restartNeeded) {
eraseBatchingSession(client, sessionId);
if (batchOptions.batchingMode == BATCHING_MODE_ROUTINE ||
batchOptions.batchingMode == BATCHING_MODE_NO_AUTO_REPORT) {
startBatching(client, sessionId, batchOptions);
} else if (batchOptions.batchingMode == BATCHING_MODE_TRIP) {
startTripBatchingMultiplex(client, sessionId, batchOptions);
}
}
reportResponse(client, err, sessionId);
}
void
BatchingAdapter::restartTripBatching(bool queryAccumulatedDistance, uint32_t accDist,
uint32_t numbatchedPos)
{
// does batch need restart with new trip distance / TBF interval
uint32_t minRemainingDistance = 0;
uint32_t minTBFInterval = 0;
// if no more trips left, stop the ongoing trip
if (mTripSessions.size() == 0) {
mLocApi->stopOutdoorTripBatching(true, new LocApiResponse(*getContext(),
[] (LocationError /*err*/) {}));
mOngoingTripDistance = 0;
mOngoingTripTBFInterval = 0;
// unregister for batch full event if there are no more
// batching session that is interested in batch full event
if (0 == autoReportBatchingSessionsCount()) {
updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
LOC_REGISTRATION_MASK_DISABLED);
}
return;
}
// record the min trip distance and min tbf interval of all ongoing sessions
for (auto itt = mTripSessions.begin(); itt != mTripSessions.end(); itt++) {
TripSessionStatus tripSessStatus = itt->second;
if ((minRemainingDistance == 0) ||
(minRemainingDistance > (tripSessStatus.tripDistance
- tripSessStatus.accumulatedDistanceThisTrip))) {
minRemainingDistance = tripSessStatus.tripDistance -
tripSessStatus.accumulatedDistanceThisTrip;
}
if ((minTBFInterval == 0) ||
(minTBFInterval > tripSessStatus.tripTBFInterval)) {
minTBFInterval = tripSessStatus.tripTBFInterval;
}
}
mLocApi->queryAccumulatedTripDistance(
new LocApiResponseData<LocApiBatchData>(*getContext(),
[this, queryAccumulatedDistance, minRemainingDistance, minTBFInterval, accDist,
numbatchedPos] (LocationError /*err*/, LocApiBatchData data) {
bool needsRestart = false;
uint32_t ongoingTripDistance = mOngoingTripDistance;
uint32_t ongoingTripInterval = mOngoingTripTBFInterval;
uint32_t accumulatedDistance = accDist;
uint32_t numOfBatchedPositions = numbatchedPos;
if (queryAccumulatedDistance) {
accumulatedDistance = data.accumulatedDistance;
numOfBatchedPositions = data.numOfBatchedPositions;
}
if ((!mTripWithOngoingTripDistanceDropped) &&
(ongoingTripDistance - accumulatedDistance != 0)) {
// if ongoing trip is already not completed still,
// check the min distance against the remaining distance
if (minRemainingDistance <
(ongoingTripDistance - accumulatedDistance)) {
ongoingTripDistance = minRemainingDistance;
needsRestart = true;
}
} else if (minRemainingDistance != 0) {
// else if ongoing trip is already completed / dropped,
// use the minRemainingDistance of ongoing sessions
ongoingTripDistance = minRemainingDistance;
needsRestart = true;
}
if ((minTBFInterval < ongoingTripInterval) ||
((minTBFInterval != ongoingTripInterval) &&
(mTripWithOngoingTBFDropped))) {
ongoingTripInterval = minTBFInterval;
needsRestart = true;
}
if (needsRestart) {
mLocApi->reStartOutdoorTripBatching(ongoingTripDistance, ongoingTripInterval,
getBatchingTimeout(), new LocApiResponse(*getContext(),
[this, accumulatedDistance, ongoingTripDistance, ongoingTripInterval]
(LocationError err) {
if (err == LOCATION_ERROR_SUCCESS) {
for(auto itt = mTripSessions.begin(); itt != mTripSessions.end(); itt++) {
TripSessionStatus &tripSessStatus = itt->second;
tripSessStatus.accumulatedDistanceThisTrip =
tripSessStatus.accumulatedDistanceOnTripRestart +
(accumulatedDistance -
tripSessStatus.accumulatedDistanceOngoingBatch);
tripSessStatus.accumulatedDistanceOngoingBatch = 0;
tripSessStatus.accumulatedDistanceOnTripRestart =
tripSessStatus.accumulatedDistanceThisTrip;
}
mOngoingTripDistance = ongoingTripDistance;
mOngoingTripTBFInterval = ongoingTripInterval;
}
}));
}
}));
}
void
BatchingAdapter::printTripReport()
{
IF_LOC_LOGD {
LOC_LOGD("Ongoing Trip Distance = %u, Ongoing Trip TBF Interval = %u",
mOngoingTripDistance, mOngoingTripTBFInterval);
for (auto itt = mTripSessions.begin(); itt != mTripSessions.end(); itt++) {
TripSessionStatus tripSessStatus = itt->second;
LOC_LOGD("tripDistance:%u tripTBFInterval:%u"
" trip accumulated Distance:%u"
" trip accumualted distance ongoing batch:%u"
" trip accumulated distance on trip restart %u \r\n",
tripSessStatus.tripDistance, tripSessStatus.tripTBFInterval,
tripSessStatus.accumulatedDistanceThisTrip,
tripSessStatus.accumulatedDistanceOngoingBatch,
tripSessStatus.accumulatedDistanceOnTripRestart);
}
}
}