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