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 <cutils/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 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 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 112 void GnssBatching::acquireWakelockCb() { 113 Gnss::acquireWakelockFused(); 114 } 115 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 121 int32_t GnssBatching::setThreadEventCb(ThreadEvent /*event*/) { 122 return FLP_RESULT_SUCCESS; 123 } 124 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 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. 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 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 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 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 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 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