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