1 /* Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
2  *
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are
5  * met:
6  *     * Redistributions of source code must retain the above copyright
7  *       notice, this list of conditions and the following disclaimer.
8  *     * Redistributions in binary form must reproduce the above
9  *       copyright notice, this list of conditions and the following
10  *       disclaimer in the documentation and/or other materials provided
11  *       with the distribution.
12  *     * Neither the name of The Linux Foundation, nor the names of its
13  *       contributors may be used to endorse or promote products derived
14  *       from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  */
29 #define LOG_TAG "LocSvc_GeofenceAdapter"
30 
31 #include <GeofenceAdapter.h>
32 #include "loc_log.h"
33 #include <log_util.h>
34 #include <string>
35 
36 using namespace loc_core;
37 
GeofenceAdapter()38 GeofenceAdapter::GeofenceAdapter() :
39     LocAdapterBase(0,
40                    LocContext::getLocContext(LocContext::mLocationHalName),
41                    true /*isMaster*/)
42 {
43     LOC_LOGD("%s]: Constructor", __func__);
44 }
45 
46 void
stopClientSessions(LocationAPI * client)47 GeofenceAdapter::stopClientSessions(LocationAPI* client)
48 {
49     LOC_LOGD("%s]: client %p", __func__, client);
50 
51 
52     for (auto it = mGeofenceIds.begin(); it != mGeofenceIds.end();) {
53         uint32_t hwId = it->second;
54         GeofenceKey key(it->first);
55         if (client == key.client) {
56             it = mGeofenceIds.erase(it);
57             mLocApi->removeGeofence(hwId, key.id,
58                     new LocApiResponse(*getContext(),
59                     [this, hwId] (LocationError err) {
60                 if (LOCATION_ERROR_SUCCESS == err) {
61                     auto it2 = mGeofences.find(hwId);
62                     if (it2 != mGeofences.end()) {
63                         mGeofences.erase(it2);
64                     } else {
65                         LOC_LOGE("%s]:geofence item to erase not found. hwId %u", __func__, hwId);
66                     }
67                 }
68             }));
69             continue;
70         }
71         ++it; // increment only when not erasing an iterator
72     }
73 
74 }
75 
76 void
updateClientsEventMask()77 GeofenceAdapter::updateClientsEventMask()
78 {
79     LOC_API_ADAPTER_EVENT_MASK_T mask = 0;
80     for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
81         if (it->second.geofenceBreachCb != nullptr) {
82             mask |= LOC_API_ADAPTER_BIT_BATCHED_GENFENCE_BREACH_REPORT;
83             mask |= LOC_API_ADAPTER_BIT_REPORT_GENFENCE_DWELL;
84         }
85         if (it->second.geofenceStatusCb != nullptr) {
86             mask |= LOC_API_ADAPTER_BIT_GEOFENCE_GEN_ALERT;
87         }
88     }
89     updateEvtMask(mask, LOC_REGISTRATION_MASK_SET);
90 }
91 
92 LocationError
getHwIdFromClient(LocationAPI * client,uint32_t clientId,uint32_t & hwId)93 GeofenceAdapter::getHwIdFromClient(LocationAPI* client, uint32_t clientId, uint32_t& hwId)
94 {
95     GeofenceKey key(client, clientId);
96     auto it = mGeofenceIds.find(key);
97     if (it != mGeofenceIds.end()) {
98         hwId = it->second;
99         return LOCATION_ERROR_SUCCESS;
100     }
101     return LOCATION_ERROR_ID_UNKNOWN;
102 }
103 
104 LocationError
getGeofenceKeyFromHwId(uint32_t hwId,GeofenceKey & key)105 GeofenceAdapter::getGeofenceKeyFromHwId(uint32_t hwId, GeofenceKey& key)
106 {
107     auto it = mGeofences.find(hwId);
108     if (it != mGeofences.end()) {
109         key = it->second.key;
110         return LOCATION_ERROR_SUCCESS;
111     }
112     return LOCATION_ERROR_ID_UNKNOWN;
113 }
114 
115 void
handleEngineUpEvent()116 GeofenceAdapter::handleEngineUpEvent()
117 {
118     struct MsgSSREvent : public LocMsg {
119         GeofenceAdapter& mAdapter;
120         inline MsgSSREvent(GeofenceAdapter& adapter) :
121             LocMsg(),
122             mAdapter(adapter) {}
123         virtual void proc() const {
124             mAdapter.setEngineCapabilitiesKnown(true);
125             mAdapter.broadcastCapabilities(mAdapter.getCapabilities());
126             mAdapter.restartGeofences();
127             for (auto msg: mAdapter.mPendingMsgs) {
128                 mAdapter.sendMsg(msg);
129             }
130             mAdapter.mPendingMsgs.clear();
131         }
132     };
133 
134     sendMsg(new MsgSSREvent(*this));
135 }
136 
137 void
restartGeofences()138 GeofenceAdapter::restartGeofences()
139 {
140     if (mGeofences.empty()) {
141         return;
142     }
143 
144     GeofencesMap oldGeofences(mGeofences);
145     mGeofences.clear();
146     mGeofenceIds.clear();
147 
148     for (auto it = oldGeofences.begin(); it != oldGeofences.end(); it++) {
149         GeofenceObject object = it->second;
150         GeofenceOption options = {sizeof(GeofenceOption),
151                                    object.breachMask,
152                                    object.responsiveness,
153                                    object.dwellTime};
154         GeofenceInfo info = {sizeof(GeofenceInfo),
155                              object.latitude,
156                              object.longitude,
157                              object.radius};
158         mLocApi->addGeofence(object.key.id,
159                               options,
160                               info,
161                               new LocApiResponseData<LocApiGeofenceData>(*getContext(),
162                 [this, object, options, info] (LocationError err, LocApiGeofenceData data) {
163             if (LOCATION_ERROR_SUCCESS == err) {
164                 if (true == object.paused) {
165                     mLocApi->pauseGeofence(data.hwId, object.key.id,
166                             new LocApiResponse(*getContext(), [] (LocationError err ) {}));
167                 }
168                 saveGeofenceItem(object.key.client, object.key.id, data.hwId, options, info);
169             }
170         }));
171     }
172 }
173 
174 void
reportResponse(LocationAPI * client,size_t count,LocationError * errs,uint32_t * ids)175 GeofenceAdapter::reportResponse(LocationAPI* client, size_t count, LocationError* errs,
176         uint32_t* ids)
177 {
178     IF_LOC_LOGD {
179         std::string idsString = "[";
180         std::string errsString = "[";
181         if (NULL != ids && NULL != errs) {
182             for (size_t i=0; i < count; ++i) {
183                 idsString += std::to_string(ids[i]) + " ";
184                 errsString += std::to_string(errs[i]) + " ";
185             }
186         }
187         idsString += "]";
188         errsString += "]";
189 
190         LOC_LOGD("%s]: client %p ids %s errs %s",
191                  __func__, client, idsString.c_str(), errsString.c_str());
192     }
193 
194     auto it = mClientData.find(client);
195     if (it != mClientData.end() && it->second.collectiveResponseCb != nullptr) {
196         it->second.collectiveResponseCb(count, errs, ids);
197     } else {
198         LOC_LOGE("%s]: client %p response not found in info", __func__, client);
199     }
200 }
201 
202 uint32_t*
addGeofencesCommand(LocationAPI * client,size_t count,GeofenceOption * options,GeofenceInfo * infos)203 GeofenceAdapter::addGeofencesCommand(LocationAPI* client, size_t count, GeofenceOption* options,
204         GeofenceInfo* infos)
205 {
206     LOC_LOGD("%s]: client %p count %zu", __func__, client, count);
207 
208     struct MsgAddGeofences : public LocMsg {
209         GeofenceAdapter& mAdapter;
210         LocApiBase& mApi;
211         LocationAPI* mClient;
212         size_t mCount;
213         uint32_t* mIds;
214         GeofenceOption* mOptions;
215         GeofenceInfo* mInfos;
216         inline MsgAddGeofences(GeofenceAdapter& adapter,
217                                LocApiBase& api,
218                                LocationAPI* client,
219                                size_t count,
220                                uint32_t* ids,
221                                GeofenceOption* options,
222                                GeofenceInfo* infos) :
223             LocMsg(),
224             mAdapter(adapter),
225             mApi(api),
226             mClient(client),
227             mCount(count),
228             mIds(ids),
229             mOptions(options),
230             mInfos(infos) {}
231         inline virtual void proc() const {
232             LocationError* errs = new LocationError[mCount];
233             if (nullptr == errs) {
234                 LOC_LOGE("%s]: new failed to allocate errs", __func__);
235                 return;
236             }
237             for (size_t i=0; i < mCount; ++i) {
238                 if (NULL == mIds || NULL == mOptions || NULL == mInfos) {
239                     errs[i] = LOCATION_ERROR_INVALID_PARAMETER;
240                 } else {
241                     mApi.addToCallQueue(new LocApiResponse(*mAdapter.getContext(),
242                             [&mAdapter = mAdapter, mCount = mCount, mClient = mClient,
243                             mOptions = mOptions, mInfos = mInfos, mIds = mIds, &mApi = mApi,
244                             errs, i] (LocationError err ) {
245                         mApi.addGeofence(mIds[i], mOptions[i], mInfos[i],
246                         new LocApiResponseData<LocApiGeofenceData>(*mAdapter.getContext(),
247                         [&mAdapter = mAdapter, mOptions = mOptions, mClient = mClient,
248                         mCount = mCount, mIds = mIds, mInfos = mInfos, errs, i]
249                         (LocationError err, LocApiGeofenceData data) {
250                             if (LOCATION_ERROR_SUCCESS == err) {
251                                 mAdapter.saveGeofenceItem(mClient,
252                                 mIds[i],
253                                 data.hwId,
254                                 mOptions[i],
255                                 mInfos[i]);
256                             }
257                             errs[i] = err;
258 
259                             // Send aggregated response on last item and cleanup
260                             if (i == mCount-1) {
261                                 mAdapter.reportResponse(mClient, mCount, errs, mIds);
262                                 delete[] errs;
263                                 delete[] mIds;
264                                 delete[] mOptions;
265                                 delete[] mInfos;
266                             }
267                         }));
268                     }));
269                 }
270             }
271         }
272     };
273 
274     if (0 == count) {
275         return NULL;
276     }
277     uint32_t* ids = new uint32_t[count];
278     if (nullptr == ids) {
279         LOC_LOGE("%s]: new failed to allocate ids", __func__);
280         return NULL;
281     }
282     if (NULL != ids) {
283         for (size_t i=0; i < count; ++i) {
284             ids[i] = generateSessionId();
285         }
286     }
287     GeofenceOption* optionsCopy;
288     if (options == NULL) {
289         optionsCopy = NULL;
290     } else {
291         optionsCopy = new GeofenceOption[count];
292         if (nullptr == optionsCopy) {
293             LOC_LOGE("%s]: new failed to allocate optionsCopy", __func__);
294             return NULL;
295         }
296         COPY_IF_NOT_NULL(optionsCopy, options, count);
297     }
298     GeofenceInfo* infosCopy;
299     if (infos == NULL) {
300         infosCopy = NULL;
301     } else {
302         infosCopy = new GeofenceInfo[count];
303         if (nullptr == infosCopy) {
304             LOC_LOGE("%s]: new failed to allocate infosCopy", __func__);
305             return NULL;
306         }
307         COPY_IF_NOT_NULL(infosCopy, infos, count);
308     }
309 
310     sendMsg(new MsgAddGeofences(*this, *mLocApi, client, count, ids, optionsCopy, infosCopy));
311     return ids;
312 }
313 
314 void
removeGeofencesCommand(LocationAPI * client,size_t count,uint32_t * ids)315 GeofenceAdapter::removeGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids)
316 {
317     LOC_LOGD("%s]: client %p count %zu", __func__, client, count);
318 
319     struct MsgRemoveGeofences : public LocMsg {
320         GeofenceAdapter& mAdapter;
321         LocApiBase& mApi;
322         LocationAPI* mClient;
323         size_t mCount;
324         uint32_t* mIds;
325         inline MsgRemoveGeofences(GeofenceAdapter& adapter,
326                                   LocApiBase& api,
327                                   LocationAPI* client,
328                                   size_t count,
329                                   uint32_t* ids) :
330             LocMsg(),
331             mAdapter(adapter),
332             mApi(api),
333             mClient(client),
334             mCount(count),
335             mIds(ids) {}
336         inline virtual void proc() const  {
337             LocationError* errs = new LocationError[mCount];
338             if (nullptr == errs) {
339                 LOC_LOGE("%s]: new failed to allocate errs", __func__);
340                 return;
341             }
342             for (size_t i=0; i < mCount; ++i) {
343                 mApi.addToCallQueue(new LocApiResponse(*mAdapter.getContext(),
344                         [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, mIds = mIds,
345                         &mApi = mApi, errs, i] (LocationError err ) {
346                     uint32_t hwId = 0;
347                     errs[i] = mAdapter.getHwIdFromClient(mClient, mIds[i], hwId);
348                     if (LOCATION_ERROR_SUCCESS == errs[i]) {
349                         mApi.removeGeofence(hwId, mIds[i],
350                         new LocApiResponse(*mAdapter.getContext(),
351                         [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, mIds = mIds,
352                         hwId, errs, i] (LocationError err ) {
353                             if (LOCATION_ERROR_SUCCESS == err) {
354                                 mAdapter.removeGeofenceItem(hwId);
355                             }
356                             errs[i] = err;
357 
358                             // Send aggregated response on last item and cleanup
359                             if (i == mCount-1) {
360                                 mAdapter.reportResponse(mClient, mCount, errs, mIds);
361                                 delete[] errs;
362                                 delete[] mIds;
363                             }
364                         }));
365                     } else {
366                         // Send aggregated response on last item and cleanup
367                         if (i == mCount-1) {
368                             mAdapter.reportResponse(mClient, mCount, errs, mIds);
369                             delete[] errs;
370                             delete[] mIds;
371                         }
372                     }
373                 }));
374             }
375         }
376     };
377 
378     if (0 == count) {
379         return;
380     }
381     uint32_t* idsCopy = new uint32_t[count];
382     if (nullptr == idsCopy) {
383         LOC_LOGE("%s]: new failed to allocate idsCopy", __func__);
384         return;
385     }
386     COPY_IF_NOT_NULL(idsCopy, ids, count);
387     sendMsg(new MsgRemoveGeofences(*this, *mLocApi, client, count, idsCopy));
388 }
389 
390 void
pauseGeofencesCommand(LocationAPI * client,size_t count,uint32_t * ids)391 GeofenceAdapter::pauseGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids)
392 {
393     LOC_LOGD("%s]: client %p count %zu", __func__, client, count);
394 
395     struct MsgPauseGeofences : public LocMsg {
396         GeofenceAdapter& mAdapter;
397         LocApiBase& mApi;
398         LocationAPI* mClient;
399         size_t mCount;
400         uint32_t* mIds;
401         inline MsgPauseGeofences(GeofenceAdapter& adapter,
402                                  LocApiBase& api,
403                                  LocationAPI* client,
404                                  size_t count,
405                                  uint32_t* ids) :
406             LocMsg(),
407             mAdapter(adapter),
408             mApi(api),
409             mClient(client),
410             mCount(count),
411             mIds(ids) {}
412         inline virtual void proc() const  {
413             LocationError* errs = new LocationError[mCount];
414             if (nullptr == errs) {
415                 LOC_LOGE("%s]: new failed to allocate errs", __func__);
416                 return;
417             }
418             for (size_t i=0; i < mCount; ++i) {
419                 mApi.addToCallQueue(new LocApiResponse(*mAdapter.getContext(),
420                         [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, mIds = mIds,
421                         &mApi = mApi, errs, i] (LocationError err ) {
422                     uint32_t hwId = 0;
423                     errs[i] = mAdapter.getHwIdFromClient(mClient, mIds[i], hwId);
424                     if (LOCATION_ERROR_SUCCESS == errs[i]) {
425                         mApi.pauseGeofence(hwId, mIds[i], new LocApiResponse(*mAdapter.getContext(),
426                         [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, mIds = mIds,
427                         hwId, errs, i] (LocationError err ) {
428                             if (LOCATION_ERROR_SUCCESS == err) {
429                                 mAdapter.pauseGeofenceItem(hwId);
430                             }
431                             errs[i] = err;
432 
433                             // Send aggregated response on last item and cleanup
434                             if (i == mCount-1) {
435                                 mAdapter.reportResponse(mClient, mCount, errs, mIds);
436                                 delete[] errs;
437                                 delete[] mIds;
438                             }
439                         }));
440                     } else {
441                         // Send aggregated response on last item and cleanup
442                         if (i == mCount-1) {
443                             mAdapter.reportResponse(mClient, mCount, errs, mIds);
444                             delete[] errs;
445                             delete[] mIds;
446                         }
447                     }
448                 }));
449             }
450         }
451     };
452 
453     if (0 == count) {
454         return;
455     }
456     uint32_t* idsCopy = new uint32_t[count];
457     if (nullptr == idsCopy) {
458         LOC_LOGE("%s]: new failed to allocate idsCopy", __func__);
459         return;
460     }
461     COPY_IF_NOT_NULL(idsCopy, ids, count);
462     sendMsg(new MsgPauseGeofences(*this, *mLocApi, client, count, idsCopy));
463 }
464 
465 void
resumeGeofencesCommand(LocationAPI * client,size_t count,uint32_t * ids)466 GeofenceAdapter::resumeGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids)
467 {
468     LOC_LOGD("%s]: client %p count %zu", __func__, client, count);
469 
470     struct MsgResumeGeofences : public LocMsg {
471         GeofenceAdapter& mAdapter;
472         LocApiBase& mApi;
473         LocationAPI* mClient;
474         size_t mCount;
475         uint32_t* mIds;
476         inline MsgResumeGeofences(GeofenceAdapter& adapter,
477                                   LocApiBase& api,
478                                   LocationAPI* client,
479                                   size_t count,
480                                   uint32_t* ids) :
481             LocMsg(),
482             mAdapter(adapter),
483             mApi(api),
484             mClient(client),
485             mCount(count),
486             mIds(ids) {}
487         inline virtual void proc() const  {
488             LocationError* errs = new LocationError[mCount];
489             if (nullptr == errs) {
490                 LOC_LOGE("%s]: new failed to allocate errs", __func__);
491                 return;
492             }
493             for (size_t i=0; i < mCount; ++i) {
494                 mApi.addToCallQueue(new LocApiResponse(*mAdapter.getContext(),
495                         [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, mIds = mIds,
496                         &mApi = mApi, errs, i] (LocationError err ) {
497                     uint32_t hwId = 0;
498                     errs[i] = mAdapter.getHwIdFromClient(mClient, mIds[i], hwId);
499                     if (LOCATION_ERROR_SUCCESS == errs[i]) {
500                         mApi.resumeGeofence(hwId, mIds[i],
501                                 new LocApiResponse(*mAdapter.getContext(),
502                                 [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, hwId,
503                                 errs, mIds = mIds, i] (LocationError err ) {
504                             if (LOCATION_ERROR_SUCCESS == err) {
505                                 errs[i] = err;
506 
507                                 mAdapter.resumeGeofenceItem(hwId);
508                                 // Send aggregated response on last item and cleanup
509                                 if (i == mCount-1) {
510                                     mAdapter.reportResponse(mClient, mCount, errs, mIds);
511                                     delete[] errs;
512                                     delete[] mIds;
513                                 }
514                             }
515                         }));
516                     } else {
517                         // Send aggregated response on last item and cleanup
518                         if (i == mCount-1) {
519                             mAdapter.reportResponse(mClient, mCount, errs, mIds);
520                             delete[] errs;
521                             delete[] mIds;
522                         }
523                     }
524                 }));
525             }
526         }
527     };
528 
529     if (0 == count) {
530         return;
531     }
532     uint32_t* idsCopy = new uint32_t[count];
533     if (nullptr == idsCopy) {
534         LOC_LOGE("%s]: new failed to allocate idsCopy", __func__);
535         return;
536     }
537     COPY_IF_NOT_NULL(idsCopy, ids, count);
538     sendMsg(new MsgResumeGeofences(*this, *mLocApi, client, count, idsCopy));
539 }
540 
541 void
modifyGeofencesCommand(LocationAPI * client,size_t count,uint32_t * ids,GeofenceOption * options)542 GeofenceAdapter::modifyGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids,
543         GeofenceOption* options)
544 {
545     LOC_LOGD("%s]: client %p count %zu", __func__, client, count);
546 
547     struct MsgModifyGeofences : public LocMsg {
548         GeofenceAdapter& mAdapter;
549         LocApiBase& mApi;
550         LocationAPI* mClient;
551         size_t mCount;
552         uint32_t* mIds;
553         GeofenceOption* mOptions;
554         inline MsgModifyGeofences(GeofenceAdapter& adapter,
555                                   LocApiBase& api,
556                                   LocationAPI* client,
557                                   size_t count,
558                                   uint32_t* ids,
559                                   GeofenceOption* options) :
560             LocMsg(),
561             mAdapter(adapter),
562             mApi(api),
563             mClient(client),
564             mCount(count),
565             mIds(ids),
566             mOptions(options) {}
567         inline virtual void proc() const  {
568             LocationError* errs = new LocationError[mCount];
569             if (nullptr == errs) {
570                 LOC_LOGE("%s]: new failed to allocate errs", __func__);
571                 return;
572             }
573             for (size_t i=0; i < mCount; ++i) {
574                 if (NULL == mIds || NULL == mOptions) {
575                     errs[i] = LOCATION_ERROR_INVALID_PARAMETER;
576                 } else {
577                     mApi.addToCallQueue(new LocApiResponse(*mAdapter.getContext(),
578                             [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, mIds = mIds,
579                             &mApi = mApi, mOptions = mOptions, errs, i] (LocationError err ) {
580                         uint32_t hwId = 0;
581                         errs[i] = mAdapter.getHwIdFromClient(mClient, mIds[i], hwId);
582                         if (LOCATION_ERROR_SUCCESS == errs[i]) {
583                             mApi.modifyGeofence(hwId, mIds[i], mOptions[i],
584                                     new LocApiResponse(*mAdapter.getContext(),
585                                     [&mAdapter = mAdapter, mCount = mCount, mClient = mClient,
586                                     mIds = mIds, mOptions = mOptions, hwId, errs, i]
587                                     (LocationError err ) {
588                                 if (LOCATION_ERROR_SUCCESS == err) {
589                                     errs[i] = err;
590 
591                                     mAdapter.modifyGeofenceItem(hwId, mOptions[i]);
592                                 }
593                                 // Send aggregated response on last item and cleanup
594                                 if (i == mCount-1) {
595                                     mAdapter.reportResponse(mClient, mCount, errs, mIds);
596                                     delete[] errs;
597                                     delete[] mIds;
598                                     delete[] mOptions;
599                                 }
600                             }));
601                         } else {
602                             // Send aggregated response on last item and cleanup
603                             if (i == mCount-1) {
604                                 mAdapter.reportResponse(mClient, mCount, errs, mIds);
605                                 delete[] errs;
606                                 delete[] mIds;
607                                 delete[] mOptions;
608                             }
609                         }
610                     }));
611                 }
612             }
613         }
614     };
615 
616     if (0 == count) {
617         return;
618     }
619     uint32_t* idsCopy = new uint32_t[count];
620     if (nullptr == idsCopy) {
621         LOC_LOGE("%s]: new failed to allocate idsCopy", __func__);
622         return;
623     }
624     COPY_IF_NOT_NULL(idsCopy, ids, count);
625     GeofenceOption* optionsCopy;
626     if (options == NULL) {
627         optionsCopy = NULL;
628     } else {
629         optionsCopy = new GeofenceOption[count];
630         if (nullptr == optionsCopy) {
631             LOC_LOGE("%s]: new failed to allocate optionsCopy", __func__);
632             return;
633         }
634         COPY_IF_NOT_NULL(optionsCopy, options, count);
635     }
636 
637     sendMsg(new MsgModifyGeofences(*this, *mLocApi, client, count, idsCopy, optionsCopy));
638 }
639 
640 void
saveGeofenceItem(LocationAPI * client,uint32_t clientId,uint32_t hwId,const GeofenceOption & options,const GeofenceInfo & info)641 GeofenceAdapter::saveGeofenceItem(LocationAPI* client, uint32_t clientId, uint32_t hwId,
642         const GeofenceOption& options, const GeofenceInfo& info)
643 {
644     LOC_LOGD("%s]: hwId %u client %p clientId %u", __func__, hwId, client, clientId);
645     GeofenceKey key(client, clientId);
646     GeofenceObject object = {key,
647                              options.breachTypeMask,
648                              options.responsiveness,
649                              options.dwellTime,
650                              info.latitude,
651                              info.longitude,
652                              info.radius,
653                              false};
654     mGeofences[hwId] = object;
655     mGeofenceIds[key] = hwId;
656     dump();
657 }
658 
659 void
removeGeofenceItem(uint32_t hwId)660 GeofenceAdapter::removeGeofenceItem(uint32_t hwId)
661 {
662     GeofenceKey key;
663     LocationError err = getGeofenceKeyFromHwId(hwId, key);
664     if (LOCATION_ERROR_SUCCESS != err) {
665         LOC_LOGE("%s]: can not find the key for hwId %u", __func__, hwId);
666     } else {
667         auto it1 = mGeofenceIds.find(key);
668         if (it1 != mGeofenceIds.end()) {
669             mGeofenceIds.erase(it1);
670 
671             auto it2 = mGeofences.find(hwId);
672             if (it2 != mGeofences.end()) {
673                 mGeofences.erase(it2);
674                 dump();
675             } else {
676                 LOC_LOGE("%s]:geofence item to erase not found. hwId %u", __func__, hwId);
677             }
678         } else {
679             LOC_LOGE("%s]: geofence item to erase not found. hwId %u", __func__, hwId);
680         }
681     }
682 }
683 
684 void
pauseGeofenceItem(uint32_t hwId)685 GeofenceAdapter::pauseGeofenceItem(uint32_t hwId)
686 {
687     auto it = mGeofences.find(hwId);
688     if (it != mGeofences.end()) {
689         it->second.paused = true;
690         dump();
691     } else {
692         LOC_LOGE("%s]: geofence item to pause not found. hwId %u", __func__, hwId);
693     }
694 }
695 
696 void
resumeGeofenceItem(uint32_t hwId)697 GeofenceAdapter::resumeGeofenceItem(uint32_t hwId)
698 {
699     auto it = mGeofences.find(hwId);
700     if (it != mGeofences.end()) {
701         it->second.paused = false;
702         dump();
703     } else {
704         LOC_LOGE("%s]: geofence item to resume not found. hwId %u", __func__, hwId);
705     }
706 }
707 
708 void
modifyGeofenceItem(uint32_t hwId,const GeofenceOption & options)709 GeofenceAdapter::modifyGeofenceItem(uint32_t hwId, const GeofenceOption& options)
710 {
711     auto it = mGeofences.find(hwId);
712     if (it != mGeofences.end()) {
713         it->second.breachMask = options.breachTypeMask;
714         it->second.responsiveness = options.responsiveness;
715         it->second.dwellTime = options.dwellTime;
716         dump();
717     } else {
718         LOC_LOGE("%s]: geofence item to modify not found. hwId %u", __func__, hwId);
719     }
720 }
721 
722 
723 void
geofenceBreachEvent(size_t count,uint32_t * hwIds,Location & location,GeofenceBreachType breachType,uint64_t timestamp)724 GeofenceAdapter::geofenceBreachEvent(size_t count, uint32_t* hwIds, Location& location,
725         GeofenceBreachType breachType, uint64_t timestamp)
726 {
727 
728     IF_LOC_LOGD {
729         std::string idsString = "[";
730         if (NULL != hwIds) {
731             for (size_t i=0; i < count; ++i) {
732                 idsString += std::to_string(hwIds[i]) + " ";
733             }
734         }
735         idsString += "]";
736         LOC_LOGD("%s]: breachType %u count %zu ids %s",
737                  __func__, breachType, count, idsString.c_str());
738     }
739 
740     if (0 == count || NULL == hwIds)
741         return;
742 
743     struct MsgGeofenceBreach : public LocMsg {
744         GeofenceAdapter& mAdapter;
745         size_t mCount;
746         uint32_t* mHwIds;
747         Location mLocation;
748         GeofenceBreachType mBreachType;
749         uint64_t mTimestamp;
750         inline MsgGeofenceBreach(GeofenceAdapter& adapter,
751                                  size_t count,
752                                  uint32_t* hwIds,
753                                  Location& location,
754                                  GeofenceBreachType breachType,
755                                  uint64_t timestamp) :
756             LocMsg(),
757             mAdapter(adapter),
758             mCount(count),
759             mHwIds(new uint32_t[count]),
760             mLocation(location),
761             mBreachType(breachType),
762             mTimestamp(timestamp)
763         {
764             if (nullptr == mHwIds) {
765                 LOC_LOGE("%s]: new failed to allocate mHwIds", __func__);
766                 return;
767             }
768             COPY_IF_NOT_NULL(mHwIds, hwIds, mCount);
769         }
770         inline virtual ~MsgGeofenceBreach() {
771             delete[] mHwIds;
772         }
773         inline virtual void proc() const {
774             mAdapter.geofenceBreach(mCount, mHwIds, mLocation, mBreachType, mTimestamp);
775         }
776     };
777 
778     sendMsg(new MsgGeofenceBreach(*this, count, hwIds, location, breachType, timestamp));
779 
780 }
781 
782 void
geofenceBreach(size_t count,uint32_t * hwIds,const Location & location,GeofenceBreachType breachType,uint64_t timestamp)783 GeofenceAdapter::geofenceBreach(size_t count, uint32_t* hwIds, const Location& location,
784         GeofenceBreachType breachType, uint64_t timestamp)
785 {
786 
787     for (auto it = mClientData.begin(); it != mClientData.end(); ++it) {
788         uint32_t* clientIds = new uint32_t[count];
789         if (nullptr == clientIds) {
790             return;
791         }
792         uint32_t index = 0;
793         for (size_t i=0; i < count; ++i) {
794             GeofenceKey key;
795             LocationError err = getGeofenceKeyFromHwId(hwIds[i], key);
796             if (LOCATION_ERROR_SUCCESS == err) {
797                 if (key.client == it->first) {
798                     clientIds[index++] = key.id;
799                 }
800             }
801         }
802         if (index > 0 && it->second.geofenceBreachCb != nullptr) {
803             GeofenceBreachNotification notify = {sizeof(GeofenceBreachNotification),
804                                                  index,
805                                                  clientIds,
806                                                  location,
807                                                  breachType,
808                                                  timestamp};
809 
810             it->second.geofenceBreachCb(notify);
811         }
812         delete[] clientIds;
813     }
814 }
815 
816 void
geofenceStatusEvent(GeofenceStatusAvailable available)817 GeofenceAdapter::geofenceStatusEvent(GeofenceStatusAvailable available)
818 {
819     LOC_LOGD("%s]: available %u ", __func__, available);
820 
821     struct MsgGeofenceStatus : public LocMsg {
822         GeofenceAdapter& mAdapter;
823         GeofenceStatusAvailable mAvailable;
824         inline MsgGeofenceStatus(GeofenceAdapter& adapter,
825                                  GeofenceStatusAvailable available) :
826             LocMsg(),
827             mAdapter(adapter),
828             mAvailable(available) {}
829         inline virtual void proc() const {
830             mAdapter.geofenceStatus(mAvailable);
831         }
832     };
833 
834     sendMsg(new MsgGeofenceStatus(*this, available));
835 }
836 
837 void
geofenceStatus(GeofenceStatusAvailable available)838 GeofenceAdapter::geofenceStatus(GeofenceStatusAvailable available)
839 {
840     for (auto it = mClientData.begin(); it != mClientData.end(); ++it) {
841         if (it->second.geofenceStatusCb != nullptr) {
842             GeofenceStatusNotification notify = {sizeof(GeofenceStatusNotification),
843                                                  available,
844                                                  LOCATION_TECHNOLOGY_TYPE_GNSS};
845             it->second.geofenceStatusCb(notify);
846         }
847     }
848 }
849 
850 void
dump()851 GeofenceAdapter::dump()
852 {
853     IF_LOC_LOGV {
854         LOC_LOGV(
855             "HAL | hwId  | mask | respon | latitude | longitude | radius | paused |  Id  | client");
856         for (auto it = mGeofences.begin(); it != mGeofences.end(); ++it) {
857             uint32_t hwId = it->first;
858             GeofenceObject object = it->second;
859             LOC_LOGV("    | %5u | %4u | %6u | %8.2f | %9.2f | %6.2f | %6u | %04x | %p ",
860                     hwId, object.breachMask, object.responsiveness,
861                     object.latitude, object.longitude, object.radius,
862                     object.paused, object.key.id, object.key.client);
863         }
864     }
865 }
866 
867