1 /* Copyright (c) 2017-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 
30 #define LOG_NDEBUG 0
31 #define LOG_TAG "LocSvc_BatchingAPIClient"
32 
33 #include <inttypes.h>
34 #include <log_util.h>
35 #include <loc_cfg.h>
36 #include <thread>
37 #include "LocationUtil.h"
38 #include "BatchingAPIClient.h"
39 
40 #include "limits.h"
41 
42 
43 namespace android {
44 namespace hardware {
45 namespace gnss {
46 namespace V2_1 {
47 namespace implementation {
48 
49 using ::android::hardware::gnss::V2_0::IGnssBatching;
50 using ::android::hardware::gnss::V2_0::IGnssBatchingCallback;
51 using ::android::hardware::gnss::V2_0::GnssLocation;
52 
53 static void convertBatchOption(const IGnssBatching::Options& in, LocationOptions& out,
54         LocationCapabilitiesMask mask);
55 
BatchingAPIClient(const sp<V1_0::IGnssBatchingCallback> & callback)56 BatchingAPIClient::BatchingAPIClient(const sp<V1_0::IGnssBatchingCallback>& callback) :
57     LocationAPIClientBase(),
58     mGnssBatchingCbIface(nullptr),
59     mDefaultId(UINT_MAX),
60     mLocationCapabilitiesMask(0),
61     mGnssBatchingCbIface_2_0(nullptr)
62 {
63     LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
64 
65     gnssUpdateCallbacks(callback);
66 }
67 
BatchingAPIClient(const sp<V2_0::IGnssBatchingCallback> & callback)68 BatchingAPIClient::BatchingAPIClient(const sp<V2_0::IGnssBatchingCallback>& callback) :
69     LocationAPIClientBase(),
70     mGnssBatchingCbIface(nullptr),
71     mDefaultId(UINT_MAX),
72     mLocationCapabilitiesMask(0),
73     mGnssBatchingCbIface_2_0(nullptr)
74 {
75     LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
76 
77     gnssUpdateCallbacks_2_0(callback);
78 }
79 
~BatchingAPIClient()80 BatchingAPIClient::~BatchingAPIClient()
81 {
82     LOC_LOGD("%s]: ()", __FUNCTION__);
83 }
84 
getBatchSize()85 int BatchingAPIClient::getBatchSize() {
86     int batchSize = locAPIGetBatchSize();
87     LOC_LOGd("batchSize: %d", batchSize);
88     return batchSize;
89 }
90 
setCallbacks()91 void BatchingAPIClient::setCallbacks()
92 {
93     LocationCallbacks locationCallbacks;
94     memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
95     locationCallbacks.size = sizeof(LocationCallbacks);
96 
97     locationCallbacks.trackingCb = nullptr;
98     locationCallbacks.batchingCb = nullptr;
99     locationCallbacks.batchingCb = [this](size_t count, Location* location,
100         BatchingOptions batchOptions) {
101         onBatchingCb(count, location, batchOptions);
102     };
103     locationCallbacks.geofenceBreachCb = nullptr;
104     locationCallbacks.geofenceStatusCb = nullptr;
105     locationCallbacks.gnssLocationInfoCb = nullptr;
106     locationCallbacks.gnssNiCb = nullptr;
107     locationCallbacks.gnssSvCb = nullptr;
108     locationCallbacks.gnssNmeaCb = nullptr;
109     locationCallbacks.gnssMeasurementsCb = nullptr;
110 
111     locAPISetCallbacks(locationCallbacks);
112 }
113 
gnssUpdateCallbacks(const sp<V1_0::IGnssBatchingCallback> & callback)114 void BatchingAPIClient::gnssUpdateCallbacks(const sp<V1_0::IGnssBatchingCallback>& callback)
115 {
116     mMutex.lock();
117     mGnssBatchingCbIface = callback;
118     mMutex.unlock();
119 
120     if (mGnssBatchingCbIface != nullptr) {
121         setCallbacks();
122     }
123 }
124 
gnssUpdateCallbacks_2_0(const sp<V2_0::IGnssBatchingCallback> & callback)125 void BatchingAPIClient::gnssUpdateCallbacks_2_0(const sp<V2_0::IGnssBatchingCallback>& callback)
126 {
127     mMutex.lock();
128     mGnssBatchingCbIface_2_0 = callback;
129     mMutex.unlock();
130 
131     if (mGnssBatchingCbIface_2_0 != nullptr) {
132         setCallbacks();
133     }
134 }
135 
startSession(const IGnssBatching::Options & opts)136 int BatchingAPIClient::startSession(const IGnssBatching::Options& opts) {
137     mMutex.lock();
138     mState = STARTED;
139     mMutex.unlock();
140     LOC_LOGD("%s]: (%lld %d)", __FUNCTION__,
141             static_cast<long long>(opts.periodNanos), static_cast<uint8_t>(opts.flags));
142     int retVal = -1;
143     LocationOptions options;
144     convertBatchOption(opts, options, mLocationCapabilitiesMask);
145     uint32_t mode = 0;
146     if (opts.flags == static_cast<uint8_t>(IGnssBatching::Flag::WAKEUP_ON_FIFO_FULL)) {
147         mode = SESSION_MODE_ON_FULL;
148     }
149     if (locAPIStartSession(mDefaultId, mode, options) == LOCATION_ERROR_SUCCESS) {
150         retVal = 1;
151     }
152     return retVal;
153 }
154 
updateSessionOptions(const IGnssBatching::Options & opts)155 int BatchingAPIClient::updateSessionOptions(const IGnssBatching::Options& opts)
156 {
157     LOC_LOGD("%s]: (%lld %d)", __FUNCTION__,
158             static_cast<long long>(opts.periodNanos), static_cast<uint8_t>(opts.flags));
159     int retVal = -1;
160     LocationOptions options;
161     convertBatchOption(opts, options, mLocationCapabilitiesMask);
162 
163     uint32_t mode = 0;
164     if (opts.flags == static_cast<uint8_t>(IGnssBatching::Flag::WAKEUP_ON_FIFO_FULL)) {
165         mode = SESSION_MODE_ON_FULL;
166     }
167     if (locAPIUpdateSessionOptions(mDefaultId, mode, options) == LOCATION_ERROR_SUCCESS) {
168         retVal = 1;
169     }
170     return retVal;
171 }
172 
stopSession()173 int BatchingAPIClient::stopSession() {
174     mMutex.lock();
175     mState = STOPPING;
176     mMutex.unlock();
177     LOC_LOGD("%s]: ", __FUNCTION__);
178     int retVal = -1;
179     locAPIGetBatchedLocations(mDefaultId, SIZE_MAX);
180     if (locAPIStopSession(mDefaultId) == LOCATION_ERROR_SUCCESS) {
181         retVal = 1;
182     }
183     return retVal;
184 }
185 
getBatchedLocation(int last_n_locations)186 void BatchingAPIClient::getBatchedLocation(int last_n_locations)
187 {
188     LOC_LOGD("%s]: (%d)", __FUNCTION__, last_n_locations);
189     locAPIGetBatchedLocations(mDefaultId, last_n_locations);
190 }
191 
flushBatchedLocations()192 void BatchingAPIClient::flushBatchedLocations() {
193     LOC_LOGD("%s]: ()", __FUNCTION__);
194     uint32_t retVal = locAPIGetBatchedLocations(mDefaultId, SIZE_MAX);
195     // when flush a stopped session or one doesn't exist, just report an empty batch.
196     if (LOCATION_ERROR_ID_UNKNOWN == retVal) {
197         BatchingOptions opt = {};
198         ::std::thread thd(&BatchingAPIClient::onBatchingCb, this, 0, nullptr, opt);
199         thd.detach();
200     }
201 }
202 
onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask)203 void BatchingAPIClient::onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask)
204 {
205     LOC_LOGD("%s]: (%" PRIu64 ")", __FUNCTION__, capabilitiesMask);
206     mLocationCapabilitiesMask = capabilitiesMask;
207 }
208 
onBatchingCb(size_t count,Location * location,BatchingOptions)209 void BatchingAPIClient::onBatchingCb(size_t count, Location* location,
210         BatchingOptions /*batchOptions*/) {
211     bool processReport = false;
212     LOC_LOGd("(count: %zu)", count);
213     mMutex.lock();
214     // back to back stop() and flush() could bring twice onBatchingCb(). Each one might come first.
215     // Combine them both (the first goes to cache, the second in location*) before report to FW
216     switch (mState) {
217         case STOPPING:
218             mState = STOPPED;
219             for (size_t i = 0; i < count; i++) {
220                 mBatchedLocationInCache.push_back(location[i]);
221             }
222             break;
223         case STARTED:
224         case STOPPED: // flush() always trigger report, even on a stopped session
225             processReport = true;
226             break;
227         default:
228             break;
229     }
230     // report location batch when in STARTED state or flush(), combined with cache in last stop()
231     if (processReport) {
232         auto gnssBatchingCbIface(mGnssBatchingCbIface);
233         auto gnssBatchingCbIface_2_0(mGnssBatchingCbIface_2_0);
234         size_t batchCacheCnt = mBatchedLocationInCache.size();
235         LOC_LOGd("(batchCacheCnt: %zu)", batchCacheCnt);
236         if (gnssBatchingCbIface_2_0 != nullptr) {
237             hidl_vec<V2_0::GnssLocation> locationVec;
238             if (count+batchCacheCnt > 0) {
239                 locationVec.resize(count+batchCacheCnt);
240                 for (size_t i = 0; i < batchCacheCnt; ++i) {
241                     convertGnssLocation(mBatchedLocationInCache[i], locationVec[i]);
242                 }
243                 for (size_t i = 0; i < count; i++) {
244                     convertGnssLocation(location[i], locationVec[i+batchCacheCnt]);
245                 }
246             }
247             auto r = gnssBatchingCbIface_2_0->gnssLocationBatchCb(locationVec);
248             if (!r.isOk()) {
249                 LOC_LOGE("%s] Error from gnssLocationBatchCb 2_0 description=%s",
250                         __func__, r.description().c_str());
251             }
252         } else if (gnssBatchingCbIface != nullptr) {
253             hidl_vec<V1_0::GnssLocation> locationVec;
254             if (count+batchCacheCnt > 0) {
255                 locationVec.resize(count+batchCacheCnt);
256                 for (size_t i = 0; i < batchCacheCnt; ++i) {
257                     convertGnssLocation(mBatchedLocationInCache[i], locationVec[i]);
258                 }
259                 for (size_t i = 0; i < count; i++) {
260                     convertGnssLocation(location[i], locationVec[i+batchCacheCnt]);
261                 }
262             }
263             auto r = gnssBatchingCbIface->gnssLocationBatchCb(locationVec);
264             if (!r.isOk()) {
265                 LOC_LOGE("%s] Error from gnssLocationBatchCb 1.0 description=%s",
266                         __func__, r.description().c_str());
267             }
268         }
269         mBatchedLocationInCache.clear();
270     }
271     mMutex.unlock();
272 }
273 
convertBatchOption(const IGnssBatching::Options & in,LocationOptions & out,LocationCapabilitiesMask mask)274 static void convertBatchOption(const IGnssBatching::Options& in, LocationOptions& out,
275         LocationCapabilitiesMask mask)
276 {
277     memset(&out, 0, sizeof(LocationOptions));
278     out.size = sizeof(LocationOptions);
279     out.minInterval = (uint32_t)(in.periodNanos / 1000000L);
280     out.minDistance = 0;
281     out.mode = GNSS_SUPL_MODE_STANDALONE;
282     if (mask & LOCATION_CAPABILITIES_GNSS_MSA_BIT)
283         out.mode = GNSS_SUPL_MODE_MSA;
284     if (mask & LOCATION_CAPABILITIES_GNSS_MSB_BIT)
285         out.mode = GNSS_SUPL_MODE_MSB;
286 }
287 
288 }  // namespace implementation
289 }  // namespace V2_1
290 }  // namespace gnss
291 }  // namespace hardware
292 }  // namespace android
293