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