You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1051 lines
41 KiB
1051 lines
41 KiB
/* 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);
|
|
}
|
|
}
|
|
}
|