diff options
Diffstat (limited to 'batching/BatchingAdapter.cpp')
-rw-r--r-- | batching/BatchingAdapter.cpp | 1050 |
1 files changed, 1050 insertions, 0 deletions
diff --git a/batching/BatchingAdapter.cpp b/batching/BatchingAdapter.cpp new file mode 100644 index 0000000..135f0ed --- /dev/null +++ b/batching/BatchingAdapter.cpp @@ -0,0 +1,1050 @@ +/* Copyright (c) 2017-2019, 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. + * + */ +#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( + NULL, + NULL, + LocContext::mLocationHalName, + false)), + mOngoingTripDistance(0), + mOngoingTripTBFInterval(0), + mTripWithOngoingTBFDropped(false), + mTripWithOngoingTripDistanceDropped(false), + mBatchingTimeout(0), + mBatchingAccuracy(1), + mBatchSize(0), + mTripBatchSize(0) +{ + LOC_LOGD("%s]: Constructor", __func__); + readConfigCommand(); + setConfigCommand(); +} + +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::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()); + 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); + } 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) +{ + 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] (LocationError err) { + if (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); + } + + 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 (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 (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); + } + } +} |