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