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