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