1 /* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation, nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29 #define LOG_NDEBUG 0
30 #define LOG_TAG "LocSvc_BatchingAdapter"
31
32 #include <loc_pla.h>
33 #include <log_util.h>
34 #include <LocContext.h>
35 #include <BatchingAdapter.h>
36
37 using namespace loc_core;
38
BatchingAdapter()39 BatchingAdapter::BatchingAdapter() :
40 LocAdapterBase(0, LocContext::getLocContext(LocContext::mLocationHalName)),
41 mOngoingTripDistance(0),
42 mOngoingTripTBFInterval(0),
43 mTripWithOngoingTBFDropped(false),
44 mTripWithOngoingTripDistanceDropped(false),
45 mBatchingTimeout(0),
46 mBatchingAccuracy(1),
47 mBatchSize(0),
48 mTripBatchSize(0)
49 {
50 LOC_LOGD("%s]: Constructor", __func__);
51 readConfigCommand();
52 setConfigCommand();
53 }
54
55 void
readConfigCommand()56 BatchingAdapter::readConfigCommand()
57 {
58 LOC_LOGD("%s]: ", __func__);
59
60 struct MsgReadConfig : public LocMsg {
61 BatchingAdapter& mAdapter;
62 inline MsgReadConfig(BatchingAdapter& adapter) :
63 LocMsg(),
64 mAdapter(adapter) {}
65 inline virtual void proc() const {
66 uint32_t batchingTimeout = 0;
67 uint32_t batchingAccuracy = 0;
68 uint32_t batchSize = 0;
69 uint32_t tripBatchSize = 0;
70 static const loc_param_s_type flp_conf_param_table[] =
71 {
72 {"BATCH_SIZE", &batchSize, NULL, 'n'},
73 {"OUTDOOR_TRIP_BATCH_SIZE", &tripBatchSize, NULL, 'n'},
74 {"BATCH_SESSION_TIMEOUT", &batchingTimeout, NULL, 'n'},
75 {"ACCURACY", &batchingAccuracy, NULL, 'n'},
76 };
77 UTIL_READ_CONF(LOC_PATH_FLP_CONF, flp_conf_param_table);
78
79 LOC_LOGD("%s]: batchSize %u tripBatchSize %u batchingAccuracy %u batchingTimeout %u ",
80 __func__, batchSize, tripBatchSize, batchingAccuracy, batchingTimeout);
81
82 mAdapter.setBatchSize(batchSize);
83 mAdapter.setTripBatchSize(tripBatchSize);
84 mAdapter.setBatchingTimeout(batchingTimeout);
85 mAdapter.setBatchingAccuracy(batchingAccuracy);
86 }
87 };
88
89 sendMsg(new MsgReadConfig(*this));
90
91 }
92
93 void
setConfigCommand()94 BatchingAdapter::setConfigCommand()
95 {
96 LOC_LOGD("%s]: ", __func__);
97
98 struct MsgSetConfig : public LocMsg {
99 BatchingAdapter& mAdapter;
100 LocApiBase& mApi;
101 inline MsgSetConfig(BatchingAdapter& adapter,
102 LocApiBase& api) :
103 LocMsg(),
104 mAdapter(adapter),
105 mApi(api) {}
106 inline virtual void proc() const {
107 mApi.setBatchSize(mAdapter.getBatchSize());
108 mApi.setTripBatchSize(mAdapter.getTripBatchSize());
109 }
110 };
111
112 sendMsg(new MsgSetConfig(*this, *mLocApi));
113 }
114
115 void
stopClientSessions(LocationAPI * client)116 BatchingAdapter::stopClientSessions(LocationAPI* client)
117 {
118 LOC_LOGD("%s]: client %p", __func__, client);
119
120 typedef struct pairKeyBatchMode {
121 LocationAPI* client;
122 uint32_t id;
123 BatchingMode batchingMode;
124 inline pairKeyBatchMode(LocationAPI* _client, uint32_t _id, BatchingMode _bMode) :
125 client(_client), id(_id), batchingMode(_bMode) {}
126 } pairKeyBatchMode;
127 std::vector<pairKeyBatchMode> vBatchingClient;
128 for (auto it : mBatchingSessions) {
129 if (client == it.first.client) {
130 vBatchingClient.emplace_back(it.first.client, it.first.id, it.second.batchingMode);
131 }
132 }
133 for (auto keyBatchingMode : vBatchingClient) {
134 if (keyBatchingMode.batchingMode != BATCHING_MODE_TRIP) {
135 stopBatching(keyBatchingMode.client, keyBatchingMode.id);
136 } else {
137 stopTripBatchingMultiplex(keyBatchingMode.client, keyBatchingMode.id);
138 }
139 }
140 }
141
142 void
updateClientsEventMask()143 BatchingAdapter::updateClientsEventMask()
144 {
145 LOC_API_ADAPTER_EVENT_MASK_T mask = 0;
146 for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
147 // we don't register LOC_API_ADAPTER_BIT_BATCH_FULL until we
148 // start batching with ROUTINE or TRIP option
149 if (it->second.batchingCb != nullptr) {
150 mask |= LOC_API_ADAPTER_BIT_BATCH_STATUS;
151 }
152 }
153 if (autoReportBatchingSessionsCount() > 0) {
154 mask |= LOC_API_ADAPTER_BIT_BATCH_FULL;
155 }
156 updateEvtMask(mask, LOC_REGISTRATION_MASK_SET);
157 }
158
159 void
handleEngineUpEvent()160 BatchingAdapter::handleEngineUpEvent()
161 {
162 struct MsgSSREvent : public LocMsg {
163 BatchingAdapter& mAdapter;
164 LocApiBase& mApi;
165 inline MsgSSREvent(BatchingAdapter& adapter,
166 LocApiBase& api) :
167 LocMsg(),
168 mAdapter(adapter),
169 mApi(api) {}
170 virtual void proc() const {
171 mAdapter.setEngineCapabilitiesKnown(true);
172 mAdapter.broadcastCapabilities(mAdapter.getCapabilities());
173 mApi.setBatchSize(mAdapter.getBatchSize());
174 mApi.setTripBatchSize(mAdapter.getTripBatchSize());
175 mAdapter.restartSessions();
176 for (auto msg: mAdapter.mPendingMsgs) {
177 mAdapter.sendMsg(msg);
178 }
179 mAdapter.mPendingMsgs.clear();
180 }
181 };
182
183 sendMsg(new MsgSSREvent(*this, *mLocApi));
184 }
185
186 void
restartSessions()187 BatchingAdapter::restartSessions()
188 {
189 LOC_LOGD("%s]: ", __func__);
190
191 if (autoReportBatchingSessionsCount() > 0) {
192 updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
193 LOC_REGISTRATION_MASK_ENABLED);
194 }
195 for (auto it = mBatchingSessions.begin();
196 it != mBatchingSessions.end(); ++it) {
197 if (it->second.batchingMode != BATCHING_MODE_TRIP) {
198 mLocApi->startBatching(it->first.id, it->second,
199 getBatchingAccuracy(), getBatchingTimeout(),
200 new LocApiResponse(*getContext(),
201 [] (LocationError /*err*/) {}));
202 }
203 }
204
205 if (mTripSessions.size() > 0) {
206 // restart outdoor trip batching session if any.
207 mOngoingTripDistance = 0;
208 mOngoingTripTBFInterval = 0;
209
210 // record the min trip distance and min tbf interval of all ongoing sessions
211 for (auto tripSession : mTripSessions) {
212
213 TripSessionStatus &tripSessStatus = tripSession.second;
214
215 if ((0 == mOngoingTripDistance) ||
216 (mOngoingTripDistance >
217 (tripSessStatus.tripDistance - tripSessStatus.accumulatedDistanceThisTrip))) {
218 mOngoingTripDistance = tripSessStatus.tripDistance -
219 tripSessStatus.accumulatedDistanceThisTrip;
220 }
221
222 if ((0 == mOngoingTripTBFInterval) ||
223 (mOngoingTripTBFInterval > tripSessStatus.tripTBFInterval)) {
224 mOngoingTripTBFInterval = tripSessStatus.tripTBFInterval;
225 }
226
227 // reset the accumulatedDistanceOngoingBatch for each session
228 tripSessStatus.accumulatedDistanceOngoingBatch = 0;
229
230 }
231
232 mLocApi->startOutdoorTripBatching(mOngoingTripDistance, mOngoingTripTBFInterval,
233 getBatchingTimeout(), new LocApiResponse(*getContext(), [this] (LocationError err) {
234 if (LOCATION_ERROR_SUCCESS != err) {
235 mOngoingTripDistance = 0;
236 mOngoingTripTBFInterval = 0;
237 }
238 printTripReport();
239 }));
240 }
241 }
242
243 bool
hasBatchingCallback(LocationAPI * client)244 BatchingAdapter::hasBatchingCallback(LocationAPI* client)
245 {
246 auto it = mClientData.find(client);
247 return (it != mClientData.end() && it->second.batchingCb);
248 }
249
250 bool
isBatchingSession(LocationAPI * client,uint32_t sessionId)251 BatchingAdapter::isBatchingSession(LocationAPI* client, uint32_t sessionId)
252 {
253 LocationSessionKey key(client, sessionId);
254 return (mBatchingSessions.find(key) != mBatchingSessions.end());
255 }
256
257 bool
isTripSession(uint32_t sessionId)258 BatchingAdapter::isTripSession(uint32_t sessionId) {
259 return (mTripSessions.find(sessionId) != mTripSessions.end());
260 }
261
262 void
saveBatchingSession(LocationAPI * client,uint32_t sessionId,const BatchingOptions & batchingOptions)263 BatchingAdapter::saveBatchingSession(LocationAPI* client, uint32_t sessionId,
264 const BatchingOptions& batchingOptions)
265 {
266 LocationSessionKey key(client, sessionId);
267 mBatchingSessions[key] = batchingOptions;
268 }
269
270 void
eraseBatchingSession(LocationAPI * client,uint32_t sessionId)271 BatchingAdapter::eraseBatchingSession(LocationAPI* client, uint32_t sessionId)
272 {
273 LocationSessionKey key(client, sessionId);
274 auto it = mBatchingSessions.find(key);
275 if (it != mBatchingSessions.end()) {
276 mBatchingSessions.erase(it);
277 }
278 }
279
280 void
reportResponse(LocationAPI * client,LocationError err,uint32_t sessionId)281 BatchingAdapter::reportResponse(LocationAPI* client, LocationError err, uint32_t sessionId)
282 {
283 LOC_LOGD("%s]: client %p id %u err %u", __func__, client, sessionId, err);
284
285 auto it = mClientData.find(client);
286 if (it != mClientData.end() &&
287 it->second.responseCb != nullptr) {
288 it->second.responseCb(err, sessionId);
289 } else {
290 LOC_LOGE("%s]: client %p id %u not found in data", __func__, client, sessionId);
291 }
292 }
293
294 uint32_t
autoReportBatchingSessionsCount()295 BatchingAdapter::autoReportBatchingSessionsCount()
296 {
297 uint32_t count = 0;
298 for (auto batchingSession: mBatchingSessions) {
299 if (batchingSession.second.batchingMode != BATCHING_MODE_NO_AUTO_REPORT) {
300 count++;
301 }
302 }
303 count += mTripSessions.size();
304 return count;
305 }
306
307 uint32_t
startBatchingCommand(LocationAPI * client,BatchingOptions & batchOptions)308 BatchingAdapter::startBatchingCommand(
309 LocationAPI* client, BatchingOptions& batchOptions)
310 {
311 uint32_t sessionId = generateSessionId();
312 LOC_LOGD("%s]: client %p id %u minInterval %u minDistance %u mode %u Batching Mode %d",
313 __func__, client, sessionId, batchOptions.minInterval, batchOptions.minDistance,
314 batchOptions.mode,batchOptions.batchingMode);
315
316 struct MsgStartBatching : public LocMsg {
317 BatchingAdapter& mAdapter;
318 LocApiBase& mApi;
319 LocationAPI* mClient;
320 uint32_t mSessionId;
321 BatchingOptions mBatchingOptions;
322 inline MsgStartBatching(BatchingAdapter& adapter,
323 LocApiBase& api,
324 LocationAPI* client,
325 uint32_t sessionId,
326 BatchingOptions batchOptions) :
327 LocMsg(),
328 mAdapter(adapter),
329 mApi(api),
330 mClient(client),
331 mSessionId(sessionId),
332 mBatchingOptions(batchOptions) {}
333 inline virtual void proc() const {
334 if (!mAdapter.isEngineCapabilitiesKnown()) {
335 mAdapter.mPendingMsgs.push_back(new MsgStartBatching(*this));
336 return;
337 }
338 LocationError err = LOCATION_ERROR_SUCCESS;
339
340 if (!mAdapter.hasBatchingCallback(mClient)) {
341 err = LOCATION_ERROR_CALLBACK_MISSING;
342 } else if (0 == mBatchingOptions.size) {
343 err = LOCATION_ERROR_INVALID_PARAMETER;
344 } else if (!ContextBase::isMessageSupported(
345 LOC_API_ADAPTER_MESSAGE_DISTANCE_BASE_LOCATION_BATCHING)) {
346 err = LOCATION_ERROR_NOT_SUPPORTED;
347 }
348 if (LOCATION_ERROR_SUCCESS == err) {
349 if (mBatchingOptions.batchingMode == BATCHING_MODE_ROUTINE ||
350 mBatchingOptions.batchingMode == BATCHING_MODE_NO_AUTO_REPORT) {
351 mAdapter.startBatching(mClient, mSessionId, mBatchingOptions);
352 } else if (mBatchingOptions.batchingMode == BATCHING_MODE_TRIP) {
353 mAdapter.startTripBatchingMultiplex(mClient, mSessionId, mBatchingOptions);
354 } else {
355 mAdapter.reportResponse(mClient, LOCATION_ERROR_INVALID_PARAMETER, mSessionId);
356 }
357 }
358 }
359 };
360
361 sendMsg(new MsgStartBatching(*this, *mLocApi, client, sessionId, batchOptions));
362
363 return sessionId;
364 }
365
366 void
startBatching(LocationAPI * client,uint32_t sessionId,const BatchingOptions & batchingOptions)367 BatchingAdapter::startBatching(LocationAPI* client, uint32_t sessionId,
368 const BatchingOptions& batchingOptions)
369 {
370 if (batchingOptions.batchingMode != BATCHING_MODE_NO_AUTO_REPORT &&
371 0 == autoReportBatchingSessionsCount()) {
372 // if there is currenty no batching sessions interested in batch full event, then this
373 // new session will need to register for batch full event
374 updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
375 LOC_REGISTRATION_MASK_ENABLED);
376 }
377
378 // Assume start will be OK, remove session if not
379 saveBatchingSession(client, sessionId, batchingOptions);
380 mLocApi->startBatching(sessionId, batchingOptions, getBatchingAccuracy(), getBatchingTimeout(),
381 new LocApiResponse(*getContext(),
382 [this, client, sessionId, batchingOptions] (LocationError err) {
383 if (LOCATION_ERROR_SUCCESS != err) {
384 eraseBatchingSession(client, sessionId);
385 }
386
387 if (LOCATION_ERROR_SUCCESS != err &&
388 batchingOptions.batchingMode != BATCHING_MODE_NO_AUTO_REPORT &&
389 0 == autoReportBatchingSessionsCount()) {
390 // if we fail to start batching and we have already registered batch full event
391 // we need to undo that since no sessions are now interested in batch full event
392 updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
393 LOC_REGISTRATION_MASK_DISABLED);
394 }
395
396 reportResponse(client, err, sessionId);
397 }));
398 }
399
400 void
updateBatchingOptionsCommand(LocationAPI * client,uint32_t id,BatchingOptions & batchOptions)401 BatchingAdapter::updateBatchingOptionsCommand(LocationAPI* client, uint32_t id,
402 BatchingOptions& batchOptions)
403 {
404 LOC_LOGD("%s]: client %p id %u minInterval %u minDistance %u mode %u batchMode %u",
405 __func__, client, id, batchOptions.minInterval,
406 batchOptions.minDistance, batchOptions.mode,
407 batchOptions.batchingMode);
408
409 struct MsgUpdateBatching : public LocMsg {
410 BatchingAdapter& mAdapter;
411 LocApiBase& mApi;
412 LocationAPI* mClient;
413 uint32_t mSessionId;
414 BatchingOptions mBatchOptions;
415 inline MsgUpdateBatching(BatchingAdapter& adapter,
416 LocApiBase& api,
417 LocationAPI* client,
418 uint32_t sessionId,
419 BatchingOptions batchOptions) :
420 LocMsg(),
421 mAdapter(adapter),
422 mApi(api),
423 mClient(client),
424 mSessionId(sessionId),
425 mBatchOptions(batchOptions) {}
426 inline virtual void proc() const {
427 if (!mAdapter.isEngineCapabilitiesKnown()) {
428 mAdapter.mPendingMsgs.push_back(new MsgUpdateBatching(*this));
429 return;
430 }
431 LocationError err = LOCATION_ERROR_SUCCESS;
432 if (!mAdapter.isBatchingSession(mClient, mSessionId)) {
433 err = LOCATION_ERROR_ID_UNKNOWN;
434 } else if ((0 == mBatchOptions.size) ||
435 (mBatchOptions.batchingMode > BATCHING_MODE_NO_AUTO_REPORT)) {
436 err = LOCATION_ERROR_INVALID_PARAMETER;
437 }
438 if (LOCATION_ERROR_SUCCESS == err) {
439 if (!mAdapter.isTripSession(mSessionId)) {
440 mAdapter.stopBatching(mClient, mSessionId, true, mBatchOptions);
441 } else {
442 mAdapter.stopTripBatchingMultiplex(mClient, mSessionId, true, mBatchOptions);
443 }
444 }
445 }
446 };
447
448 sendMsg(new MsgUpdateBatching(*this, *mLocApi, client, id, batchOptions));
449 }
450
451 void
stopBatchingCommand(LocationAPI * client,uint32_t id)452 BatchingAdapter::stopBatchingCommand(LocationAPI* client, uint32_t id)
453 {
454 LOC_LOGD("%s]: client %p id %u", __func__, client, id);
455
456 struct MsgStopBatching : public LocMsg {
457 BatchingAdapter& mAdapter;
458 LocApiBase& mApi;
459 LocationAPI* mClient;
460 uint32_t mSessionId;
461 inline MsgStopBatching(BatchingAdapter& adapter,
462 LocApiBase& api,
463 LocationAPI* client,
464 uint32_t sessionId) :
465 LocMsg(),
466 mAdapter(adapter),
467 mApi(api),
468 mClient(client),
469 mSessionId(sessionId) {}
470 inline virtual void proc() const {
471 if (!mAdapter.isEngineCapabilitiesKnown()) {
472 mAdapter.mPendingMsgs.push_back(new MsgStopBatching(*this));
473 return;
474 }
475 LocationError err = LOCATION_ERROR_SUCCESS;
476 if (!mAdapter.isBatchingSession(mClient, mSessionId)) {
477 err = LOCATION_ERROR_ID_UNKNOWN;
478 }
479 if (LOCATION_ERROR_SUCCESS == err) {
480 if (mAdapter.isTripSession(mSessionId)) {
481 mAdapter.stopTripBatchingMultiplex(mClient, mSessionId);
482 } else {
483 mAdapter.stopBatching(mClient, mSessionId);
484 }
485 }
486 }
487 };
488
489 sendMsg(new MsgStopBatching(*this, *mLocApi, client, id));
490 }
491
492 void
stopBatching(LocationAPI * client,uint32_t sessionId,bool restartNeeded,const BatchingOptions & batchOptions)493 BatchingAdapter::stopBatching(LocationAPI* client, uint32_t sessionId, bool restartNeeded,
494 const BatchingOptions& batchOptions)
495 {
496 LocationSessionKey key(client, sessionId);
497 auto it = mBatchingSessions.find(key);
498 if (it != mBatchingSessions.end()) {
499 auto flpOptions = it->second;
500 // Assume stop will be OK, restore session if not
501 eraseBatchingSession(client, sessionId);
502 mLocApi->stopBatching(sessionId,
503 new LocApiResponse(*getContext(),
504 [this, client, sessionId, flpOptions, restartNeeded, batchOptions]
505 (LocationError err) {
506 if (LOCATION_ERROR_SUCCESS != err) {
507 saveBatchingSession(client, sessionId, batchOptions);
508 } else {
509 // if stopBatching is success, unregister for batch full event if this was the last
510 // batching session that is interested in batch full event
511 if (0 == autoReportBatchingSessionsCount() &&
512 flpOptions.batchingMode != BATCHING_MODE_NO_AUTO_REPORT) {
513 updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
514 LOC_REGISTRATION_MASK_DISABLED);
515 }
516
517 if (restartNeeded) {
518 if (batchOptions.batchingMode == BATCHING_MODE_ROUTINE ||
519 batchOptions.batchingMode == BATCHING_MODE_NO_AUTO_REPORT) {
520 startBatching(client, sessionId, batchOptions);
521 } else if (batchOptions.batchingMode == BATCHING_MODE_TRIP) {
522 startTripBatchingMultiplex(client, sessionId, batchOptions);
523 }
524 }
525 }
526 reportResponse(client, err, sessionId);
527 }));
528 }
529 }
530
531 void
getBatchedLocationsCommand(LocationAPI * client,uint32_t id,size_t count)532 BatchingAdapter::getBatchedLocationsCommand(LocationAPI* client, uint32_t id, size_t count)
533 {
534 LOC_LOGD("%s]: client %p id %u count %zu", __func__, client, id, count);
535
536 struct MsgGetBatchedLocations : public LocMsg {
537 BatchingAdapter& mAdapter;
538 LocApiBase& mApi;
539 LocationAPI* mClient;
540 uint32_t mSessionId;
541 size_t mCount;
542 inline MsgGetBatchedLocations(BatchingAdapter& adapter,
543 LocApiBase& api,
544 LocationAPI* client,
545 uint32_t sessionId,
546 size_t count) :
547 LocMsg(),
548 mAdapter(adapter),
549 mApi(api),
550 mClient(client),
551 mSessionId(sessionId),
552 mCount(count) {}
553 inline virtual void proc() const {
554 if (!mAdapter.isEngineCapabilitiesKnown()) {
555 mAdapter.mPendingMsgs.push_back(new MsgGetBatchedLocations(*this));
556 return;
557 }
558 LocationError err = LOCATION_ERROR_SUCCESS;
559 if (!mAdapter.hasBatchingCallback(mClient)) {
560 err = LOCATION_ERROR_CALLBACK_MISSING;
561 } else if (!mAdapter.isBatchingSession(mClient, mSessionId)) {
562 err = LOCATION_ERROR_ID_UNKNOWN;
563 }
564 if (LOCATION_ERROR_SUCCESS == err) {
565 if (mAdapter.isTripSession(mSessionId)) {
566 mApi.getBatchedTripLocations(mCount, 0,
567 new LocApiResponse(*mAdapter.getContext(),
568 [&mAdapter = mAdapter, mSessionId = mSessionId,
569 mClient = mClient] (LocationError err) {
570 mAdapter.reportResponse(mClient, err, mSessionId);
571 }));
572 } else {
573 mApi.getBatchedLocations(mCount, new LocApiResponse(*mAdapter.getContext(),
574 [&mAdapter = mAdapter, mSessionId = mSessionId,
575 mClient = mClient] (LocationError err) {
576 mAdapter.reportResponse(mClient, err, mSessionId);
577 }));
578 }
579 } else {
580 mAdapter.reportResponse(mClient, err, mSessionId);
581 }
582 }
583 };
584
585 sendMsg(new MsgGetBatchedLocations(*this, *mLocApi, client, id, count));
586 }
587
588 void
reportLocationsEvent(const Location * locations,size_t count,BatchingMode batchingMode)589 BatchingAdapter::reportLocationsEvent(const Location* locations, size_t count,
590 BatchingMode batchingMode)
591 {
592 LOC_LOGD("%s]: count %zu batchMode %d", __func__, count, batchingMode);
593
594 struct MsgReportLocations : public LocMsg {
595 BatchingAdapter& mAdapter;
596 Location* mLocations;
597 size_t mCount;
598 BatchingMode mBatchingMode;
599 inline MsgReportLocations(BatchingAdapter& adapter,
600 const Location* locations,
601 size_t count,
602 BatchingMode batchingMode) :
603 LocMsg(),
604 mAdapter(adapter),
605 mLocations(new Location[count]),
606 mCount(count),
607 mBatchingMode(batchingMode)
608 {
609 if (nullptr == mLocations) {
610 LOC_LOGE("%s]: new failed to allocate mLocations", __func__);
611 return;
612 }
613 for (size_t i=0; i < mCount; ++i) {
614 mLocations[i] = locations[i];
615 }
616 }
617 inline virtual ~MsgReportLocations() {
618 if (nullptr != mLocations)
619 delete[] mLocations;
620 }
621 inline virtual void proc() const {
622 mAdapter.reportLocations(mLocations, mCount, mBatchingMode);
623 }
624 };
625
626 sendMsg(new MsgReportLocations(*this, locations, count, batchingMode));
627 }
628
629 void
reportLocations(Location * locations,size_t count,BatchingMode batchingMode)630 BatchingAdapter::reportLocations(Location* locations, size_t count, BatchingMode batchingMode)
631 {
632 BatchingOptions batchOptions = {sizeof(BatchingOptions), batchingMode};
633
634 for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
635 if (nullptr != it->second.batchingCb) {
636 it->second.batchingCb(count, locations, batchOptions);
637 }
638 }
639 }
640
641 void
reportCompletedTripsEvent(uint32_t accumulated_distance)642 BatchingAdapter::reportCompletedTripsEvent(uint32_t accumulated_distance)
643 {
644 struct MsgReportCompletedTrips : public LocMsg {
645 BatchingAdapter& mAdapter;
646 uint32_t mAccumulatedDistance;
647 inline MsgReportCompletedTrips(BatchingAdapter& adapter,
648 uint32_t accumulated_distance) :
649 LocMsg(),
650 mAdapter(adapter),
651 mAccumulatedDistance(accumulated_distance)
652 {
653 }
654 inline virtual ~MsgReportCompletedTrips() {
655 }
656 inline virtual void proc() const {
657
658 // Check if any trips are completed
659 std::list<uint32_t> completedTripsList;
660 completedTripsList.clear();
661
662 for(auto itt = mAdapter.mTripSessions.begin(); itt != mAdapter.mTripSessions.end();)
663 {
664 TripSessionStatus &tripSession = itt->second;
665
666 tripSession.accumulatedDistanceThisTrip =
667 tripSession.accumulatedDistanceOnTripRestart
668 + (mAccumulatedDistance - tripSession.accumulatedDistanceOngoingBatch);
669 if (tripSession.tripDistance <= tripSession.accumulatedDistanceThisTrip) {
670 // trip is completed
671 completedTripsList.push_back(itt->first);
672 itt = mAdapter.mTripSessions.erase(itt);
673
674 if (tripSession.tripTBFInterval == mAdapter.mOngoingTripTBFInterval) {
675 // trip with ongoing TBF interval is completed
676 mAdapter.mTripWithOngoingTBFDropped = true;
677 }
678
679 if (tripSession.tripDistance == mAdapter.mOngoingTripDistance) {
680 // trip with ongoing trip distance is completed
681 mAdapter.mTripWithOngoingTripDistanceDropped = true;
682 }
683 } else {
684 itt++;
685 }
686 }
687
688 if (completedTripsList.size() > 0) {
689 mAdapter.reportBatchStatusChange(BATCHING_STATUS_TRIP_COMPLETED,
690 completedTripsList);
691 mAdapter.restartTripBatching(false, mAccumulatedDistance, 0);
692 } else {
693 mAdapter.printTripReport();
694 }
695 }
696 };
697
698 LOC_LOGD("%s]: Accumulated Distance so far: %u",
699 __func__, accumulated_distance);
700
701 sendMsg(new MsgReportCompletedTrips(*this, accumulated_distance));
702 }
703
704 void
reportBatchStatusChange(BatchingStatus batchStatus,std::list<uint32_t> & completedTripsList)705 BatchingAdapter::reportBatchStatusChange(BatchingStatus batchStatus,
706 std::list<uint32_t> & completedTripsList)
707 {
708 BatchingStatusInfo batchStatusInfo =
709 {sizeof(BatchingStatusInfo), batchStatus};
710
711 for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
712 if (nullptr != it->second.batchingStatusCb) {
713 it->second.batchingStatusCb(batchStatusInfo, completedTripsList);
714 }
715 }
716 }
717
718 void
reportBatchStatusChangeEvent(BatchingStatus batchStatus)719 BatchingAdapter::reportBatchStatusChangeEvent(BatchingStatus batchStatus)
720 {
721 struct MsgReportBatchStatus : public LocMsg {
722 BatchingAdapter& mAdapter;
723 BatchingStatus mBatchStatus;
724 inline MsgReportBatchStatus(BatchingAdapter& adapter,
725 BatchingStatus batchStatus) :
726 LocMsg(),
727 mAdapter(adapter),
728 mBatchStatus(batchStatus)
729 {
730 }
731 inline virtual ~MsgReportBatchStatus() {
732 }
733 inline virtual void proc() const {
734 std::list<uint32_t> tempList;
735 tempList.clear();
736 mAdapter.reportBatchStatusChange(mBatchStatus, tempList);
737 }
738 };
739
740 sendMsg(new MsgReportBatchStatus(*this, batchStatus));
741 }
742
743 void
startTripBatchingMultiplex(LocationAPI * client,uint32_t sessionId,const BatchingOptions & batchingOptions)744 BatchingAdapter::startTripBatchingMultiplex(LocationAPI* client, uint32_t sessionId,
745 const BatchingOptions& batchingOptions)
746 {
747 if (mTripSessions.size() == 0) {
748 // if there is currenty no batching sessions interested in batch full event, then this
749 // new session will need to register for batch full event
750 if (0 == autoReportBatchingSessionsCount()) {
751 updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
752 LOC_REGISTRATION_MASK_ENABLED);
753 }
754
755 // Assume start will be OK, remove session if not
756 saveBatchingSession(client, sessionId, batchingOptions);
757
758 mTripSessions[sessionId] = { 0, 0, 0, batchingOptions.minDistance,
759 batchingOptions.minInterval};
760 mLocApi->startOutdoorTripBatching(batchingOptions.minDistance,
761 batchingOptions.minInterval, getBatchingTimeout(), new LocApiResponse(*getContext(),
762 [this, client, sessionId, batchingOptions] (LocationError err) {
763 if (err == LOCATION_ERROR_SUCCESS) {
764 mOngoingTripDistance = batchingOptions.minDistance;
765 mOngoingTripTBFInterval = batchingOptions.minInterval;
766 LOC_LOGD("%s] New Trip started ...", __func__);
767 printTripReport();
768 } else {
769 eraseBatchingSession(client, sessionId);
770 mTripSessions.erase(sessionId);
771 // if we fail to start batching and we have already registered batch full event
772 // we need to undo that since no sessions are now interested in batch full event
773 if (0 == autoReportBatchingSessionsCount()) {
774 updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
775 LOC_REGISTRATION_MASK_DISABLED);
776 }
777 }
778 reportResponse(client, err, sessionId);
779 }));
780 } else {
781 // query accumulated distance
782 mLocApi->queryAccumulatedTripDistance(
783 new LocApiResponseData<LocApiBatchData>(*getContext(),
784 [this, batchingOptions, sessionId, client]
785 (LocationError err, LocApiBatchData data) {
786 uint32_t accumulatedDistanceOngoingBatch = 0;
787 uint32_t numOfBatchedPositions = 0;
788 uint32_t ongoingTripDistance = mOngoingTripDistance;
789 uint32_t ongoingTripInterval = mOngoingTripTBFInterval;
790 bool needsRestart = false;
791
792 // check if TBF of new session is lesser than ongoing TBF interval
793 if (ongoingTripInterval > batchingOptions.minInterval) {
794 ongoingTripInterval = batchingOptions.minInterval;
795 needsRestart = true;
796 }
797 accumulatedDistanceOngoingBatch = data.accumulatedDistance;
798 numOfBatchedPositions = data.numOfBatchedPositions;
799 TripSessionStatus newTripSession = { accumulatedDistanceOngoingBatch, 0, 0,
800 batchingOptions.minDistance,
801 batchingOptions.minInterval};
802 if (err != LOCATION_ERROR_SUCCESS) {
803 // unable to query accumulated distance, assume remaining distance in
804 // ongoing batch is mongoingTripDistance.
805 if (batchingOptions.minDistance < ongoingTripDistance) {
806 ongoingTripDistance = batchingOptions.minDistance;
807 needsRestart = true;
808 }
809 } else {
810 // compute the remaining distance
811 uint32_t ongoing_trip_remaining_distance = ongoingTripDistance -
812 accumulatedDistanceOngoingBatch;
813
814 // check if new trip distance is lesser than the ongoing batch remaining distance
815 if (batchingOptions.minDistance < ongoing_trip_remaining_distance) {
816 ongoingTripDistance = batchingOptions.minDistance;
817 needsRestart = true;
818 } else if (needsRestart == true) {
819 // needsRestart is anyways true , may be because of lesser TBF of new session.
820 ongoingTripDistance = ongoing_trip_remaining_distance;
821 }
822 mTripSessions[sessionId] = newTripSession;
823 LOC_LOGD("%s] New Trip started ...", __func__);
824 printTripReport();
825 }
826
827 if (needsRestart) {
828 mOngoingTripDistance = ongoingTripDistance;
829 mOngoingTripTBFInterval = ongoingTripInterval;
830
831 // reset the accumulatedDistanceOngoingBatch for each session,
832 // and record the total accumulated distance so far for the session.
833 for (auto itt = mTripSessions.begin(); itt != mTripSessions.end(); itt++) {
834 TripSessionStatus &tripSessStatus = itt->second;
835 tripSessStatus.accumulatedDistanceOngoingBatch = 0;
836 tripSessStatus.accumulatedDistanceOnTripRestart =
837 tripSessStatus.accumulatedDistanceThisTrip;
838 }
839 mLocApi->reStartOutdoorTripBatching(ongoingTripDistance, ongoingTripInterval,
840 getBatchingTimeout(), new LocApiResponse(*getContext(),
841 [this, client, sessionId] (LocationError err) {
842 if (err != LOCATION_ERROR_SUCCESS) {
843 LOC_LOGE("%s] New Trip restart failed!", __func__);
844 }
845 reportResponse(client, err, sessionId);
846 }));
847 } else {
848 reportResponse(client, LOCATION_ERROR_SUCCESS, sessionId);
849 }
850 }));
851 }
852 }
853
854 void
stopTripBatchingMultiplex(LocationAPI * client,uint32_t sessionId,bool restartNeeded,const BatchingOptions & batchOptions)855 BatchingAdapter::stopTripBatchingMultiplex(LocationAPI* client, uint32_t sessionId,
856 bool restartNeeded, const BatchingOptions& batchOptions)
857 {
858 LocationError err = LOCATION_ERROR_SUCCESS;
859
860 if (mTripSessions.size() == 1) {
861 mLocApi->stopOutdoorTripBatching(true, new LocApiResponse(*getContext(),
862 [this, restartNeeded, client, sessionId, batchOptions]
863 (LocationError err) {
864 if (LOCATION_ERROR_SUCCESS == err) {
865 // if stopOutdoorTripBatching is success, unregister for batch full event if this
866 // was the last batching session that is interested in batch full event
867 if (1 == autoReportBatchingSessionsCount()) {
868 updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
869 LOC_REGISTRATION_MASK_DISABLED);
870 }
871 }
872 stopTripBatchingMultiplexCommon(err, client, sessionId, restartNeeded, batchOptions);
873 }));
874 return;
875 }
876
877 stopTripBatchingMultiplexCommon(err, client, sessionId, restartNeeded, batchOptions);
878 }
879
880 void
stopTripBatchingMultiplexCommon(LocationError err,LocationAPI * client,uint32_t sessionId,bool restartNeeded,const BatchingOptions & batchOptions)881 BatchingAdapter::stopTripBatchingMultiplexCommon(LocationError err, LocationAPI* client,
882 uint32_t sessionId, bool restartNeeded, const BatchingOptions& batchOptions)
883 {
884 auto itt = mTripSessions.find(sessionId);
885 TripSessionStatus tripSess = itt->second;
886 if (tripSess.tripTBFInterval == mOngoingTripTBFInterval) {
887 // trip with ongoing trip interval is stopped
888 mTripWithOngoingTBFDropped = true;
889 }
890
891 if (tripSess.tripDistance == mOngoingTripDistance) {
892 // trip with ongoing trip distance is stopped
893 mTripWithOngoingTripDistanceDropped = true;
894 }
895
896 mTripSessions.erase(sessionId);
897
898 if (mTripSessions.size() == 0) {
899 mOngoingTripDistance = 0;
900 mOngoingTripTBFInterval = 0;
901 } else {
902 restartTripBatching(true);
903 }
904
905 if (restartNeeded) {
906 eraseBatchingSession(client, sessionId);
907 if (batchOptions.batchingMode == BATCHING_MODE_ROUTINE ||
908 batchOptions.batchingMode == BATCHING_MODE_NO_AUTO_REPORT) {
909 startBatching(client, sessionId, batchOptions);
910 } else if (batchOptions.batchingMode == BATCHING_MODE_TRIP) {
911 startTripBatchingMultiplex(client, sessionId, batchOptions);
912 }
913 }
914 reportResponse(client, err, sessionId);
915 }
916
917
918 void
restartTripBatching(bool queryAccumulatedDistance,uint32_t accDist,uint32_t numbatchedPos)919 BatchingAdapter::restartTripBatching(bool queryAccumulatedDistance, uint32_t accDist,
920 uint32_t numbatchedPos)
921 {
922 // does batch need restart with new trip distance / TBF interval
923 uint32_t minRemainingDistance = 0;
924 uint32_t minTBFInterval = 0;
925
926 // if no more trips left, stop the ongoing trip
927 if (mTripSessions.size() == 0) {
928 mLocApi->stopOutdoorTripBatching(true, new LocApiResponse(*getContext(),
929 [] (LocationError /*err*/) {}));
930 mOngoingTripDistance = 0;
931 mOngoingTripTBFInterval = 0;
932 // unregister for batch full event if there are no more
933 // batching session that is interested in batch full event
934 if (0 == autoReportBatchingSessionsCount()) {
935 updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
936 LOC_REGISTRATION_MASK_DISABLED);
937 }
938 return;
939 }
940
941 // record the min trip distance and min tbf interval of all ongoing sessions
942 for (auto itt = mTripSessions.begin(); itt != mTripSessions.end(); itt++) {
943
944 TripSessionStatus tripSessStatus = itt->second;
945
946 if ((minRemainingDistance == 0) ||
947 (minRemainingDistance > (tripSessStatus.tripDistance
948 - tripSessStatus.accumulatedDistanceThisTrip))) {
949 minRemainingDistance = tripSessStatus.tripDistance -
950 tripSessStatus.accumulatedDistanceThisTrip;
951 }
952
953 if ((minTBFInterval == 0) ||
954 (minTBFInterval > tripSessStatus.tripTBFInterval)) {
955 minTBFInterval = tripSessStatus.tripTBFInterval;
956 }
957 }
958
959 mLocApi->queryAccumulatedTripDistance(
960 new LocApiResponseData<LocApiBatchData>(*getContext(),
961 [this, queryAccumulatedDistance, minRemainingDistance, minTBFInterval, accDist,
962 numbatchedPos] (LocationError /*err*/, LocApiBatchData data) {
963 bool needsRestart = false;
964
965 uint32_t ongoingTripDistance = mOngoingTripDistance;
966 uint32_t ongoingTripInterval = mOngoingTripTBFInterval;
967 uint32_t accumulatedDistance = accDist;
968 uint32_t numOfBatchedPositions = numbatchedPos;
969
970 if (queryAccumulatedDistance) {
971 accumulatedDistance = data.accumulatedDistance;
972 numOfBatchedPositions = data.numOfBatchedPositions;
973 }
974
975 if ((!mTripWithOngoingTripDistanceDropped) &&
976 (ongoingTripDistance - accumulatedDistance != 0)) {
977 // if ongoing trip is already not completed still,
978 // check the min distance against the remaining distance
979 if (minRemainingDistance <
980 (ongoingTripDistance - accumulatedDistance)) {
981 ongoingTripDistance = minRemainingDistance;
982 needsRestart = true;
983 }
984 } else if (minRemainingDistance != 0) {
985 // else if ongoing trip is already completed / dropped,
986 // use the minRemainingDistance of ongoing sessions
987 ongoingTripDistance = minRemainingDistance;
988 needsRestart = true;
989 }
990
991 if ((minTBFInterval < ongoingTripInterval) ||
992 ((minTBFInterval != ongoingTripInterval) &&
993 (mTripWithOngoingTBFDropped))) {
994 ongoingTripInterval = minTBFInterval;
995 needsRestart = true;
996 }
997
998 if (needsRestart) {
999 mLocApi->reStartOutdoorTripBatching(ongoingTripDistance, ongoingTripInterval,
1000 getBatchingTimeout(), new LocApiResponse(*getContext(),
1001 [this, accumulatedDistance, ongoingTripDistance, ongoingTripInterval]
1002 (LocationError err) {
1003
1004 if (err == LOCATION_ERROR_SUCCESS) {
1005 for(auto itt = mTripSessions.begin(); itt != mTripSessions.end(); itt++) {
1006 TripSessionStatus &tripSessStatus = itt->second;
1007 tripSessStatus.accumulatedDistanceThisTrip =
1008 tripSessStatus.accumulatedDistanceOnTripRestart +
1009 (accumulatedDistance -
1010 tripSessStatus.accumulatedDistanceOngoingBatch);
1011
1012 tripSessStatus.accumulatedDistanceOngoingBatch = 0;
1013 tripSessStatus.accumulatedDistanceOnTripRestart =
1014 tripSessStatus.accumulatedDistanceThisTrip;
1015 }
1016
1017 mOngoingTripDistance = ongoingTripDistance;
1018 mOngoingTripTBFInterval = ongoingTripInterval;
1019 }
1020 }));
1021 }
1022 }));
1023 }
1024
1025 void
printTripReport()1026 BatchingAdapter::printTripReport()
1027 {
1028 IF_LOC_LOGD {
1029 LOC_LOGD("Ongoing Trip Distance = %u, Ongoing Trip TBF Interval = %u",
1030 mOngoingTripDistance, mOngoingTripTBFInterval);
1031
1032 for (auto itt = mTripSessions.begin(); itt != mTripSessions.end(); itt++) {
1033 TripSessionStatus tripSessStatus = itt->second;
1034
1035 LOC_LOGD("tripDistance:%u tripTBFInterval:%u"
1036 " trip accumulated Distance:%u"
1037 " trip accumualted distance ongoing batch:%u"
1038 " trip accumulated distance on trip restart %u \r\n",
1039 tripSessStatus.tripDistance, tripSessStatus.tripTBFInterval,
1040 tripSessStatus.accumulatedDistanceThisTrip,
1041 tripSessStatus.accumulatedDistanceOngoingBatch,
1042 tripSessStatus.accumulatedDistanceOnTripRestart);
1043 }
1044 }
1045 }
1046