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