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