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