gnss_manager.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. /*
  2. * Copyright (C) 2018 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. #include "chre/core/gnss_manager.h"
  17. #include "chre/core/event_loop_manager.h"
  18. #include "chre/platform/assert.h"
  19. #include "chre/platform/fatal_error.h"
  20. #include "chre/util/system/debug_dump.h"
  21. namespace chre {
  22. GnssManager::GnssManager()
  23. : mLocationSession(CHRE_EVENT_GNSS_LOCATION),
  24. mMeasurementSession(CHRE_EVENT_GNSS_DATA) {
  25. }
  26. void GnssManager::init() {
  27. mPlatformGnss.init();
  28. }
  29. uint32_t GnssManager::getCapabilities() {
  30. return mPlatformGnss.getCapabilities();
  31. }
  32. void GnssManager::logStateToBuffer(
  33. char *buffer, size_t *bufferPos, size_t bufferSize) const {
  34. debugDumpPrint(buffer, bufferPos, bufferSize,"\nGNSS:");
  35. mLocationSession.logStateToBuffer(buffer, bufferPos, bufferSize);
  36. mMeasurementSession.logStateToBuffer(buffer, bufferPos, bufferSize);
  37. }
  38. GnssSession::GnssSession(uint16_t reportEventType)
  39. : mReportEventType(reportEventType) {
  40. switch (mReportEventType) {
  41. case CHRE_EVENT_GNSS_LOCATION:
  42. mStartRequestType = CHRE_GNSS_REQUEST_TYPE_LOCATION_SESSION_START;
  43. mStopRequestType = CHRE_GNSS_REQUEST_TYPE_LOCATION_SESSION_STOP;
  44. mName = "Location";
  45. break;
  46. case CHRE_EVENT_GNSS_DATA:
  47. mStartRequestType = CHRE_GNSS_REQUEST_TYPE_MEASUREMENT_SESSION_START;
  48. mStopRequestType = CHRE_GNSS_REQUEST_TYPE_MEASUREMENT_SESSION_STOP;
  49. mName = "Measurement";
  50. break;
  51. default:
  52. CHRE_ASSERT_LOG(false, "Unsupported eventType %" PRIu16, reportEventType);
  53. }
  54. if (!mRequests.reserve(1)) {
  55. FATAL_ERROR_OOM();
  56. }
  57. }
  58. bool GnssSession::addRequest(Nanoapp *nanoapp, Milliseconds minInterval,
  59. Milliseconds minTimeToNext, const void *cookie) {
  60. CHRE_ASSERT(nanoapp);
  61. return configure(nanoapp, true /* enable */, minInterval, minTimeToNext,
  62. cookie);
  63. }
  64. bool GnssSession::removeRequest(Nanoapp *nanoapp, const void *cookie) {
  65. CHRE_ASSERT(nanoapp);
  66. return configure(nanoapp, false /* enable */, Milliseconds(UINT64_MAX),
  67. Milliseconds(UINT64_MAX), cookie);
  68. }
  69. void GnssSession::handleStatusChange(bool enabled, uint8_t errorCode) {
  70. struct CallbackState {
  71. bool enabled;
  72. uint8_t errorCode;
  73. GnssSession *session;
  74. };
  75. auto *cbState = memoryAlloc<CallbackState>();
  76. if (cbState == nullptr) {
  77. LOG_OOM();
  78. } else {
  79. cbState->enabled = enabled;
  80. cbState->errorCode = errorCode;
  81. cbState->session = this;
  82. auto callback = [](uint16_t /* eventType */, void *eventData) {
  83. auto *state = static_cast<CallbackState *>(eventData);
  84. state->session->handleStatusChangeSync(state->enabled, state->errorCode);
  85. memoryFree(state);
  86. };
  87. EventLoopManagerSingleton::get()->deferCallback(
  88. SystemCallbackType::GnssSessionStatusChange, cbState, callback);
  89. }
  90. }
  91. void GnssSession::handleReportEvent(void *event) {
  92. EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
  93. mReportEventType, event, freeReportEventCallback);
  94. }
  95. void GnssSession::logStateToBuffer(
  96. char *buffer, size_t *bufferPos, size_t bufferSize) const {
  97. debugDumpPrint(buffer, bufferPos, bufferSize,
  98. "\n %s: Current interval(ms)=%" PRIu64 "\n",
  99. mName, mCurrentInterval.getMilliseconds());
  100. debugDumpPrint(buffer, bufferPos, bufferSize, " Requests:\n");
  101. for (const auto& request : mRequests) {
  102. debugDumpPrint(buffer, bufferPos, bufferSize,
  103. " minInterval(ms)=%" PRIu64 " nanoappId=%"
  104. PRIu32 "\n",
  105. request.minInterval.getMilliseconds(),
  106. request.nanoappInstanceId);
  107. }
  108. debugDumpPrint(buffer, bufferPos, bufferSize, " Transition queue:\n");
  109. for (const auto& transition : mStateTransitions) {
  110. debugDumpPrint(buffer, bufferPos, bufferSize,
  111. " minInterval(ms)=%" PRIu64 " enable=%d"
  112. " nanoappId=%" PRIu32 "\n",
  113. transition.minInterval.getMilliseconds(),
  114. transition.enable, transition.nanoappInstanceId);
  115. }
  116. }
  117. bool GnssSession::configure(
  118. Nanoapp *nanoapp, bool enable, Milliseconds minInterval,
  119. Milliseconds minTimeToNext, const void *cookie) {
  120. bool success = false;
  121. uint32_t instanceId = nanoapp->getInstanceId();
  122. size_t requestIndex = 0;
  123. bool hasRequest = nanoappHasRequest(instanceId, &requestIndex);
  124. if (!mStateTransitions.empty()) {
  125. success = addRequestToQueue(instanceId, enable, minInterval, cookie);
  126. } else if (stateTransitionIsRequired(enable, minInterval, hasRequest,
  127. requestIndex)) {
  128. success = addRequestToQueue(instanceId, enable, minInterval, cookie);
  129. if (success) {
  130. success = controlPlatform(enable, minInterval, minTimeToNext);
  131. if (!success) {
  132. mStateTransitions.pop_back();
  133. LOGE("Failed to enable a GNSS session for nanoapp instance %" PRIu32,
  134. instanceId);
  135. }
  136. }
  137. } else {
  138. success = postAsyncResultEvent(
  139. instanceId, true /* success */, enable, minInterval, CHRE_ERROR_NONE,
  140. cookie);
  141. }
  142. return success;
  143. }
  144. bool GnssSession::nanoappHasRequest(
  145. uint32_t instanceId, size_t *requestIndex) const {
  146. bool hasRequest = false;
  147. for (size_t i = 0; i < mRequests.size(); i++) {
  148. if (mRequests[i].nanoappInstanceId == instanceId) {
  149. hasRequest = true;
  150. if (requestIndex != nullptr) {
  151. *requestIndex = i;
  152. }
  153. break;
  154. }
  155. }
  156. return hasRequest;
  157. }
  158. bool GnssSession::addRequestToQueue(
  159. uint32_t instanceId, bool enable, Milliseconds minInterval,
  160. const void *cookie) {
  161. StateTransition stateTransition;
  162. stateTransition.nanoappInstanceId = instanceId;
  163. stateTransition.enable = enable;
  164. stateTransition.minInterval = minInterval;
  165. stateTransition.cookie = cookie;
  166. bool success = mStateTransitions.push(stateTransition);
  167. if (!success) {
  168. LOGW("Too many session state transitions");
  169. }
  170. return success;
  171. }
  172. bool GnssSession::isEnabled() const {
  173. return !mRequests.empty();
  174. }
  175. bool GnssSession::stateTransitionIsRequired(
  176. bool requestedState, Milliseconds minInterval, bool nanoappHasRequest,
  177. size_t requestIndex) const {
  178. bool requestToEnable = (requestedState && !isEnabled());
  179. bool requestToIncreaseRate = (requestedState && isEnabled()
  180. && minInterval < mCurrentInterval);
  181. bool requestToDisable = (!requestedState && nanoappHasRequest
  182. && mRequests.size() == 1);
  183. // An effective rate decrease for the session can only occur if the nanoapp
  184. // has an existing request.
  185. bool requestToDecreaseRate = false;
  186. if (nanoappHasRequest) {
  187. // The nanoapp has an existing request. Check that the request does not
  188. // result in a rate decrease by checking if no other nanoapps have the
  189. // same request, the nanoapp's existing request is not equal to the current
  190. // requested interval and the new request is slower than the current
  191. // requested rate.
  192. size_t requestCount = 0;
  193. const auto& currentRequest = mRequests[requestIndex];
  194. for (size_t i = 0; i < mRequests.size(); i++) {
  195. const Request& request = mRequests[i];
  196. if (i != requestIndex
  197. && request.minInterval == currentRequest.minInterval) {
  198. requestCount++;
  199. }
  200. }
  201. requestToDecreaseRate = (minInterval > mCurrentInterval
  202. && currentRequest.minInterval == mCurrentInterval && requestCount == 0);
  203. }
  204. return (requestToEnable || requestToDisable || requestToIncreaseRate
  205. || requestToDecreaseRate);
  206. }
  207. bool GnssSession::updateRequests(
  208. bool enable, Milliseconds minInterval, uint32_t instanceId) {
  209. bool success = true;
  210. Nanoapp *nanoapp = EventLoopManagerSingleton::get()->getEventLoop()
  211. .findNanoappByInstanceId(instanceId);
  212. if (nanoapp == nullptr) {
  213. LOGW("Failed to update GNSS session request list for non-existent nanoapp");
  214. } else {
  215. size_t requestIndex;
  216. bool hasExistingRequest = nanoappHasRequest(instanceId, &requestIndex);
  217. if (enable) {
  218. if (hasExistingRequest) {
  219. // If the nanoapp has an open request ensure that the minInterval is
  220. // kept up to date.
  221. mRequests[requestIndex].minInterval = minInterval;
  222. } else {
  223. // The GNSS session was successfully enabled for this nanoapp and
  224. // there is no existing request. Add it to the list of GNSS session
  225. // nanoapps.
  226. Request request;
  227. request.nanoappInstanceId = instanceId;
  228. request.minInterval = minInterval;
  229. success = mRequests.push_back(request);
  230. if (!success) {
  231. LOG_OOM();
  232. } else {
  233. nanoapp->registerForBroadcastEvent(mReportEventType);
  234. }
  235. }
  236. } else if (hasExistingRequest) {
  237. // The session was successfully disabled for a previously enabled
  238. // nanoapp. Remove it from the list of requests.
  239. mRequests.erase(requestIndex);
  240. nanoapp->unregisterForBroadcastEvent(mReportEventType);
  241. } // else disabling an inactive request, treat as success per CHRE API
  242. }
  243. return success;
  244. }
  245. bool GnssSession::postAsyncResultEvent(
  246. uint32_t instanceId, bool success, bool enable, Milliseconds minInterval,
  247. uint8_t errorCode, const void *cookie) {
  248. bool eventPosted = false;
  249. if (!success || updateRequests(enable, minInterval, instanceId)) {
  250. chreAsyncResult *event = memoryAlloc<chreAsyncResult>();
  251. if (event == nullptr) {
  252. LOG_OOM();
  253. } else {
  254. event->requestType = enable ? mStartRequestType : mStopRequestType;
  255. event->success = success;
  256. event->errorCode = errorCode;
  257. event->reserved = 0;
  258. event->cookie = cookie;
  259. eventPosted =
  260. EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
  261. CHRE_EVENT_GNSS_ASYNC_RESULT, event, freeEventDataCallback,
  262. instanceId);
  263. if (!eventPosted) {
  264. memoryFree(event);
  265. }
  266. }
  267. }
  268. return eventPosted;
  269. }
  270. void GnssSession::postAsyncResultEventFatal(
  271. uint32_t instanceId, bool success, bool enable, Milliseconds minInterval,
  272. uint8_t errorCode, const void *cookie) {
  273. if (!postAsyncResultEvent(instanceId, success, enable, minInterval, errorCode,
  274. cookie)) {
  275. FATAL_ERROR("Failed to send GNSS session request async result event");
  276. }
  277. }
  278. void GnssSession::handleStatusChangeSync(bool enabled, uint8_t errorCode) {
  279. bool success = (errorCode == CHRE_ERROR_NONE);
  280. CHRE_ASSERT_LOG(!mStateTransitions.empty(),
  281. "handleStatusChangeSync called with no transitions");
  282. if (!mStateTransitions.empty()) {
  283. const auto& stateTransition = mStateTransitions.front();
  284. if (success) {
  285. mCurrentInterval = stateTransition.minInterval;
  286. }
  287. success &= (stateTransition.enable == enabled);
  288. postAsyncResultEventFatal(stateTransition.nanoappInstanceId, success,
  289. stateTransition.enable,
  290. stateTransition.minInterval,
  291. errorCode, stateTransition.cookie);
  292. mStateTransitions.pop();
  293. }
  294. while (!mStateTransitions.empty()) {
  295. const auto& stateTransition = mStateTransitions.front();
  296. size_t requestIndex;
  297. bool hasRequest = nanoappHasRequest(
  298. stateTransition.nanoappInstanceId, &requestIndex);
  299. if (stateTransitionIsRequired(stateTransition.enable,
  300. stateTransition.minInterval,
  301. hasRequest, requestIndex)) {
  302. if (controlPlatform(stateTransition.enable, stateTransition.minInterval,
  303. Milliseconds(0))) {
  304. break;
  305. } else {
  306. LOGE("Failed to enable a GNSS session for nanoapp instance %" PRIu32,
  307. stateTransition.nanoappInstanceId);
  308. postAsyncResultEventFatal(
  309. stateTransition.nanoappInstanceId, false /* success */,
  310. stateTransition.enable, stateTransition.minInterval,
  311. CHRE_ERROR, stateTransition.cookie);
  312. mStateTransitions.pop();
  313. }
  314. } else {
  315. postAsyncResultEventFatal(
  316. stateTransition.nanoappInstanceId, true /* success */,
  317. stateTransition.enable, stateTransition.minInterval,
  318. CHRE_ERROR_NONE, stateTransition.cookie);
  319. mStateTransitions.pop();
  320. }
  321. }
  322. }
  323. void GnssSession::freeReportEventCallback(uint16_t eventType, void *eventData) {
  324. switch (eventType) {
  325. case CHRE_EVENT_GNSS_LOCATION:
  326. EventLoopManagerSingleton::get()->getGnssManager().mPlatformGnss
  327. .releaseLocationEvent(
  328. static_cast<chreGnssLocationEvent *>(eventData));
  329. break;
  330. case CHRE_EVENT_GNSS_DATA:
  331. EventLoopManagerSingleton::get()->getGnssManager().mPlatformGnss
  332. .releaseMeasurementDataEvent(
  333. static_cast<chreGnssDataEvent *>(eventData));
  334. break;
  335. default:
  336. CHRE_ASSERT_LOG(false, "Unhandled event type %" PRIu16, eventType);
  337. }
  338. }
  339. bool GnssSession::controlPlatform(
  340. bool enable, Milliseconds minInterval, Milliseconds /* minTimeToNext */) {
  341. bool success = false;
  342. switch (mReportEventType) {
  343. case CHRE_EVENT_GNSS_LOCATION:
  344. // TODO: Provide support for min time to next report. It is currently sent
  345. // to the platform as zero.
  346. success = EventLoopManagerSingleton::get()->getGnssManager().mPlatformGnss
  347. .controlLocationSession(enable, minInterval, Milliseconds(0));
  348. break;
  349. case CHRE_EVENT_GNSS_DATA:
  350. success = EventLoopManagerSingleton::get()->getGnssManager().mPlatformGnss
  351. .controlMeasurementSession(enable, minInterval);
  352. break;
  353. default:
  354. CHRE_ASSERT_LOG(false, "Unhandled event type %" PRIu16, mReportEventType);
  355. }
  356. return success;
  357. }
  358. } // namespace chre