1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "GnssHAL_GnssBatchingInterface"
18
19 #include "GnssBatching.h"
20 #include <Gnss.h> // for wakelock consolidation
21 #include <GnssUtils.h>
22
23 #include <android/log.h> // for ALOGE
24 #include <vector>
25
26 namespace android {
27 namespace hardware {
28 namespace gnss {
29 namespace V1_0 {
30 namespace implementation {
31
32 sp<IGnssBatchingCallback> GnssBatching::sGnssBatchingCbIface = nullptr;
33 bool GnssBatching::sFlpSupportsBatching = false;
34
35 FlpCallbacks GnssBatching::sFlpCb = {
36 .size = sizeof(FlpCallbacks),
37 .location_cb = locationCb,
38 .acquire_wakelock_cb = acquireWakelockCb,
39 .release_wakelock_cb = releaseWakelockCb,
40 .set_thread_event_cb = setThreadEventCb,
41 .flp_capabilities_cb = flpCapabilitiesCb,
42 .flp_status_cb = flpStatusCb,
43 };
44
GnssBatching(const FlpLocationInterface * flpLocationIface)45 GnssBatching::GnssBatching(const FlpLocationInterface* flpLocationIface) :
46 mFlpLocationIface(flpLocationIface) {
47 }
48
49 /*
50 * This enum is used locally by various methods below. It is only used by the default
51 * implementation and is not part of the GNSS interface.
52 */
53 enum BatchingValues : uint16_t {
54 // Numbers 0-3 were used in earlier implementations - using 4 to be distinct to the HAL
55 FLP_GNSS_BATCHING_CLIENT_ID = 4,
56 // Tech. mask of GNSS, and sensor aiding, for legacy HAL to fit with GnssBatching API
57 FLP_TECH_MASK_GNSS_AND_SENSORS = FLP_TECH_MASK_GNSS | FLP_TECH_MASK_SENSORS,
58 // Putting a cap to avoid possible memory issues. Unlikely values this high are supported.
59 MAX_LOCATIONS_PER_BATCH = 1000
60 };
61
locationCb(int32_t locationsCount,FlpLocation ** locations)62 void GnssBatching::locationCb(int32_t locationsCount, FlpLocation** locations) {
63 if (sGnssBatchingCbIface == nullptr) {
64 ALOGE("%s: GNSS Batching Callback Interface configured incorrectly", __func__);
65 return;
66 }
67
68 if (locations == nullptr) {
69 ALOGE("%s: Invalid locations from GNSS HAL", __func__);
70 return;
71 }
72
73 if (locationsCount < 0) {
74 ALOGE("%s: Negative location count: %d set to 0", __func__, locationsCount);
75 locationsCount = 0;
76 } else if (locationsCount > MAX_LOCATIONS_PER_BATCH) {
77 ALOGW("%s: Unexpected high location count: %d set to %d", __func__, locationsCount,
78 MAX_LOCATIONS_PER_BATCH);
79 locationsCount = MAX_LOCATIONS_PER_BATCH;
80 }
81
82 /**
83 * Note:
84 * Some existing implementations may drop duplicate locations. These could be expanded here
85 * but as there's ambiguity between no-GPS-fix vs. dropped duplicates in that implementation,
86 * and that's not specified by the fused_location.h, that isn't safe to do here.
87 * Fortunately, this shouldn't be a major issue in cases where GNSS batching is typically
88 * used (e.g. when user is likely in vehicle/bicycle.)
89 */
90 std::vector<android::hardware::gnss::V1_0::GnssLocation> gnssLocations;
91 for (int iLocation = 0; iLocation < locationsCount; iLocation++) {
92 if (locations[iLocation] == nullptr) {
93 ALOGE("%s: Null location at slot: %d of %d, skipping", __func__, iLocation,
94 locationsCount);
95 continue;
96 }
97 if ((locations[iLocation]->sources_used & ~FLP_TECH_MASK_GNSS_AND_SENSORS) != 0)
98 {
99 ALOGE("%s: Unrequested location type %d at slot: %d of %d, skipping", __func__,
100 locations[iLocation]->sources_used, iLocation, locationsCount);
101 continue;
102 }
103 gnssLocations.push_back(convertToGnssLocation(locations[iLocation]));
104 }
105
106 auto ret = sGnssBatchingCbIface->gnssLocationBatchCb(gnssLocations);
107 if (!ret.isOk()) {
108 ALOGE("%s: Unable to invoke callback", __func__);
109 }
110 }
111
acquireWakelockCb()112 void GnssBatching::acquireWakelockCb() {
113 Gnss::acquireWakelockFused();
114 }
115
releaseWakelockCb()116 void GnssBatching::releaseWakelockCb() {
117 Gnss::releaseWakelockFused();
118 }
119
120 // this can just return success, because threads are now set up on demand in the jni layer
setThreadEventCb(ThreadEvent)121 int32_t GnssBatching::setThreadEventCb(ThreadEvent /*event*/) {
122 return FLP_RESULT_SUCCESS;
123 }
124
flpCapabilitiesCb(int32_t capabilities)125 void GnssBatching::flpCapabilitiesCb(int32_t capabilities) {
126 ALOGD("%s capabilities %d", __func__, capabilities);
127
128 if (capabilities & CAPABILITY_GNSS) {
129 // once callback is received and capabilities high enough, we know version is
130 // high enough for flush()
131 sFlpSupportsBatching = true;
132 }
133 }
134
flpStatusCb(int32_t status)135 void GnssBatching::flpStatusCb(int32_t status) {
136 ALOGD("%s (default implementation) not forwarding status: %d", __func__, status);
137 }
138
139 // Methods from ::android::hardware::gnss::V1_0::IGnssBatching follow.
init(const sp<IGnssBatchingCallback> & callback)140 Return<bool> GnssBatching::init(const sp<IGnssBatchingCallback>& callback) {
141 if (mFlpLocationIface == nullptr) {
142 ALOGE("%s: Flp batching is unavailable", __func__);
143 return false;
144 }
145
146 sGnssBatchingCbIface = callback;
147
148 return (mFlpLocationIface->init(&sFlpCb) == 0);
149 }
150
getBatchSize()151 Return<uint16_t> GnssBatching::getBatchSize() {
152 if (mFlpLocationIface == nullptr) {
153 ALOGE("%s: Flp batching interface is unavailable", __func__);
154 return 0;
155 }
156
157 return mFlpLocationIface->get_batch_size();
158 }
159
start(const IGnssBatching::Options & options)160 Return<bool> GnssBatching::start(const IGnssBatching::Options& options) {
161 if (mFlpLocationIface == nullptr) {
162 ALOGE("%s: Flp batching interface is unavailable", __func__);
163 return false;
164 }
165
166 if (!sFlpSupportsBatching) {
167 ALOGE("%s: Flp batching interface not supported, no capabilities callback received",
168 __func__);
169 return false;
170 }
171
172 FlpBatchOptions optionsHw;
173 // Legacy code used 9999 mW for High accuracy, and 21 mW for balanced.
174 // New GNSS API just expects reasonable GNSS chipset behavior - do something efficient
175 // given the interval. This 100 mW limit should be quite sufficient (esp. given legacy code
176 // implementations may not even use this value.)
177 optionsHw.max_power_allocation_mW = 100;
178 optionsHw.sources_to_use = FLP_TECH_MASK_GNSS_AND_SENSORS;
179 optionsHw.flags = 0;
180 if (options.flags & Flag::WAKEUP_ON_FIFO_FULL) {
181 optionsHw.flags |= FLP_BATCH_WAKEUP_ON_FIFO_FULL;
182 }
183 optionsHw.period_ns = options.periodNanos;
184 optionsHw.smallest_displacement_meters = 0; // Zero offset - just use time interval
185
186 return (mFlpLocationIface->start_batching(FLP_GNSS_BATCHING_CLIENT_ID, &optionsHw)
187 == FLP_RESULT_SUCCESS);
188 }
189
flush()190 Return<void> GnssBatching::flush() {
191 if (mFlpLocationIface == nullptr) {
192 ALOGE("%s: Flp batching interface is unavailable", __func__);
193 return Void();
194 }
195
196 mFlpLocationIface->flush_batched_locations();
197
198 return Void();
199 }
200
stop()201 Return<bool> GnssBatching::stop() {
202 if (mFlpLocationIface == nullptr) {
203 ALOGE("%s: Flp batching interface is unavailable", __func__);
204 return false;
205 }
206
207 return (mFlpLocationIface->stop_batching(FLP_GNSS_BATCHING_CLIENT_ID) == FLP_RESULT_SUCCESS);
208 }
209
cleanup()210 Return<void> GnssBatching::cleanup() {
211 if (mFlpLocationIface == nullptr) {
212 ALOGE("%s: Flp batching interface is unavailable", __func__);
213 return Void();
214 }
215
216 mFlpLocationIface->cleanup();
217
218 return Void();
219 }
220
221 } // namespace implementation
222 } // namespace V1_0
223 } // namespace gnss
224 } // namespace hardware
225 } // namespace android
226