xref: /aosp_15_r20/system/chre/core/event_loop.cc (revision 84e339476a462649f82315436d70fd732297a399)
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 #include "chre/core/event_loop.h"
18 #include <cinttypes>
19 #include <cstdint>
20 #include <type_traits>
21 
22 #include "chre/core/event.h"
23 #include "chre/core/event_loop_manager.h"
24 #include "chre/core/nanoapp.h"
25 #include "chre/platform/assert.h"
26 #include "chre/platform/context.h"
27 #include "chre/platform/event_loop_hooks.h"
28 #include "chre/platform/fatal_error.h"
29 #include "chre/platform/system_time.h"
30 #include "chre/util/conditional_lock_guard.h"
31 #include "chre/util/lock_guard.h"
32 #include "chre/util/system/debug_dump.h"
33 #include "chre/util/system/event_callbacks.h"
34 #include "chre/util/system/stats_container.h"
35 #include "chre/util/throttle.h"
36 #include "chre/util/time.h"
37 #include "chre_api/chre/version.h"
38 
39 using ::chre::message::EndpointInfo;
40 using ::chre::message::EndpointType;
41 
42 namespace chre {
43 
44 // Out of line declaration required for nonintegral static types
45 constexpr Nanoseconds EventLoop::kIntervalWakeupBucket;
46 
47 namespace {
48 
49 #ifndef CHRE_STATIC_EVENT_LOOP
50 using DynamicMemoryPool =
51     SynchronizedExpandableMemoryPool<Event, CHRE_EVENT_PER_BLOCK,
52                                      CHRE_MAX_EVENT_BLOCKS>;
53 #endif
54 // TODO(b/264108686): Make this a compile time parameter.
55 // How many low priority event to remove if the event queue is full
56 // and a new event needs to be pushed.
57 constexpr size_t targetLowPriorityEventRemove = 4;
58 
59 /**
60  * Populates a chreNanoappInfo structure using info from the given Nanoapp
61  * instance.
62  *
63  * @param app A potentially null pointer to the Nanoapp to read from
64  * @param info The structure to populate - should not be null, but this function
65  *        will handle that input
66  *
67  * @return true if neither app nor info were null, and info was populated
68  */
populateNanoappInfo(const Nanoapp * app,struct chreNanoappInfo * info)69 bool populateNanoappInfo(const Nanoapp *app, struct chreNanoappInfo *info) {
70   bool success = false;
71 
72   if (app != nullptr && info != nullptr) {
73     info->appId = app->getAppId();
74     info->version = app->getAppVersion();
75     info->instanceId = app->getInstanceId();
76     if (app->getTargetApiVersion() >= CHRE_API_VERSION_1_8) {
77       CHRE_ASSERT(app->getRpcServices().size() <= Nanoapp::kMaxRpcServices);
78       info->rpcServiceCount =
79           static_cast<uint8_t>(app->getRpcServices().size());
80       info->rpcServices = app->getRpcServices().data();
81       memset(&info->reserved, 0, sizeof(info->reserved));
82     }
83     success = true;
84   }
85 
86   return success;
87 }
88 
89 #ifndef CHRE_STATIC_EVENT_LOOP
90 /**
91  * @return true if a event is a low priority event and is not from nanoapp.
92  * Note: data and extraData are needed here to match the
93  * matching function signature. Both are not used here, but
94  * are used in other applications of
95  * SegmentedQueue::removeMatchedFromBack.
96  */
isNonNanoappLowPriorityEvent(Event * event,void *,void *)97 bool isNonNanoappLowPriorityEvent(Event *event, void * /* data */,
98                                   void * /* extraData */) {
99   CHRE_ASSERT_NOT_NULL(event);
100   return event->isLowPriority && event->senderInstanceId == kSystemInstanceId;
101 }
102 
deallocateFromMemoryPool(Event * event,void * memoryPool)103 void deallocateFromMemoryPool(Event *event, void *memoryPool) {
104   static_cast<DynamicMemoryPool *>(memoryPool)->deallocate(event);
105 }
106 #endif
107 
108 }  // anonymous namespace
109 
findNanoappInstanceIdByAppId(uint64_t appId,uint16_t * instanceId) const110 bool EventLoop::findNanoappInstanceIdByAppId(uint64_t appId,
111                                              uint16_t *instanceId) const {
112   CHRE_ASSERT(instanceId != nullptr);
113   ConditionalLockGuard<Mutex> lock(mNanoappsLock, !inEventLoopThread());
114 
115   bool found = false;
116   for (const UniquePtr<Nanoapp> &app : mNanoapps) {
117     if (app->getAppId() == appId) {
118       *instanceId = app->getInstanceId();
119       found = true;
120       break;
121     }
122   }
123 
124   return found;
125 }
126 
forEachNanoapp(NanoappCallbackFunction * callback,void * data)127 void EventLoop::forEachNanoapp(NanoappCallbackFunction *callback, void *data) {
128   ConditionalLockGuard<Mutex> lock(mNanoappsLock, !inEventLoopThread());
129 
130   for (const UniquePtr<Nanoapp> &nanoapp : mNanoapps) {
131     callback(nanoapp.get(), data);
132   }
133 }
134 
invokeMessageFreeFunction(uint64_t appId,chreMessageFreeFunction * freeFunction,void * message,size_t messageSize)135 void EventLoop::invokeMessageFreeFunction(uint64_t appId,
136                                           chreMessageFreeFunction *freeFunction,
137                                           void *message, size_t messageSize) {
138   Nanoapp *nanoapp = lookupAppByAppId(appId);
139   if (nanoapp == nullptr) {
140     LOGE("Couldn't find app 0x%016" PRIx64 " for message free callback", appId);
141   } else {
142     auto prevCurrentApp = mCurrentApp;
143     mCurrentApp = nanoapp;
144     freeFunction(message, messageSize);
145     mCurrentApp = prevCurrentApp;
146   }
147 }
148 
run()149 void EventLoop::run() {
150   LOGI("EventLoop start");
151 
152   while (mRunning) {
153     // Events are delivered in a single stage: they arrive in the inbound event
154     // queue mEvents (potentially posted from another thread), then within
155     // this context these events are distributed to all interested Nanoapps,
156     // with their free callback invoked after distribution.
157     mEventPoolUsage.addValue(static_cast<uint32_t>(mEvents.size()));
158 
159     // mEvents.pop() will be a blocking call if mEvents.empty()
160     Event *event = mEvents.pop();
161     // Need size() + 1 since the to-be-processed event has already been removed.
162     mPowerControlManager.preEventLoopProcess(mEvents.size() + 1);
163     distributeEvent(event);
164 
165     mPowerControlManager.postEventLoopProcess(mEvents.size());
166   }
167 
168   // Purge the main queue of events pending distribution. All nanoapps should be
169   // prevented from sending events or messages at this point via
170   // currentNanoappIsStopping() returning true.
171   while (!mEvents.empty()) {
172     freeEvent(mEvents.pop());
173   }
174 
175   // Unload all running nanoapps
176   while (!mNanoapps.empty()) {
177     unloadNanoappAtIndex(mNanoapps.size() - 1);
178   }
179 
180   LOGI("Exiting EventLoop");
181 }
182 
startNanoapp(UniquePtr<Nanoapp> & nanoapp)183 bool EventLoop::startNanoapp(UniquePtr<Nanoapp> &nanoapp) {
184   CHRE_ASSERT(!nanoapp.isNull());
185   bool success = false;
186   auto *eventLoopManager = EventLoopManagerSingleton::get();
187   EventLoop &eventLoop = eventLoopManager->getEventLoop();
188   uint16_t existingInstanceId;
189 
190   if (nanoapp.isNull()) {
191     // no-op, invalid argument
192   } else if (nanoapp->getTargetApiVersion() <
193              CHRE_FIRST_SUPPORTED_API_VERSION) {
194     LOGE("Incompatible nanoapp (target ver 0x%" PRIx32
195          ", first supported ver 0x%" PRIx32 ")",
196          nanoapp->getTargetApiVersion(),
197          static_cast<uint32_t>(CHRE_FIRST_SUPPORTED_API_VERSION));
198   } else if (eventLoop.findNanoappInstanceIdByAppId(nanoapp->getAppId(),
199                                                     &existingInstanceId)) {
200     LOGE("App with ID 0x%016" PRIx64 " already exists as instance ID %" PRIu16,
201          nanoapp->getAppId(), existingInstanceId);
202   } else {
203     Nanoapp *newNanoapp = nanoapp.get();
204     {
205       LockGuard<Mutex> lock(mNanoappsLock);
206       success = mNanoapps.push_back(std::move(nanoapp));
207       // After this point, nanoapp is null as we've transferred ownership into
208       // mNanoapps.back() - use newNanoapp to reference it
209     }
210     if (!success) {
211       LOG_OOM();
212     } else {
213       mCurrentApp = newNanoapp;
214       success = newNanoapp->start();
215       mCurrentApp = nullptr;
216       if (!success) {
217         LOGE("Nanoapp %" PRIu16 " failed to start",
218              newNanoapp->getInstanceId());
219         unloadNanoapp(newNanoapp->getInstanceId(),
220                       /*allowSystemNanoappUnload=*/true,
221                       /*nanoappStarted=*/false);
222       } else {
223         notifyAppStatusChange(CHRE_EVENT_NANOAPP_STARTED, *newNanoapp);
224       }
225     }
226   }
227 
228   return success;
229 }
230 
unloadNanoapp(uint16_t instanceId,bool allowSystemNanoappUnload,bool nanoappStarted)231 bool EventLoop::unloadNanoapp(uint16_t instanceId,
232                               bool allowSystemNanoappUnload,
233                               bool nanoappStarted) {
234   bool unloaded = false;
235 
236   for (size_t i = 0; i < mNanoapps.size(); i++) {
237     if (instanceId == mNanoapps[i]->getInstanceId()) {
238       if (!allowSystemNanoappUnload && mNanoapps[i]->isSystemNanoapp()) {
239         LOGE("Refusing to unload system nanoapp");
240       } else {
241         // Make sure all messages sent by this nanoapp at least have their
242         // associated free callback processing pending in the event queue (i.e.
243         // there are no messages pending delivery to the host)
244         EventLoopManagerSingleton::get()
245             ->getHostCommsManager()
246             .flushNanoappMessages(*mNanoapps[i]);
247 
248         // Mark that this nanoapp is stopping early, so it can't send events or
249         // messages during the nanoapp event queue flush
250         mStoppingNanoapp = mNanoapps[i].get();
251 
252         if (nanoappStarted) {
253           // Distribute all inbound events we have at this time - here we're
254           // interested in handling any message free callbacks generated by
255           // flushNanoappMessages()
256           flushInboundEventQueue();
257 
258           // Post the unload event now (so we can reference the Nanoapp instance
259           // directly), but nanoapps won't get it until after the unload
260           // completes. No need to notify status change if nanoapps failed to
261           // start.
262           notifyAppStatusChange(CHRE_EVENT_NANOAPP_STOPPED, *mStoppingNanoapp);
263         }
264 
265         // Finally, we are at a point where there should not be any pending
266         // events or messages sent by the app that could potentially reference
267         // the nanoapp's memory, so we are safe to unload it
268         unloadNanoappAtIndex(i, nanoappStarted);
269         mStoppingNanoapp = nullptr;
270 
271         LOGD("Unloaded nanoapp with instanceId %" PRIu16, instanceId);
272         unloaded = true;
273       }
274       break;
275     }
276   }
277 
278   return unloaded;
279 }
280 
removeNonNanoappLowPriorityEventsFromBack(size_t removeNum)281 bool EventLoop::removeNonNanoappLowPriorityEventsFromBack(
282     [[maybe_unused]] size_t removeNum) {
283 #ifdef CHRE_STATIC_EVENT_LOOP
284   return false;
285 #else
286   if (removeNum == 0) {
287     return true;
288   }
289 
290   size_t numRemovedEvent = mEvents.removeMatchedFromBack(
291       isNonNanoappLowPriorityEvent, /* data= */ nullptr,
292       /* extraData= */ nullptr, removeNum, deallocateFromMemoryPool,
293       &mEventPool);
294   if (numRemovedEvent == 0 || numRemovedEvent == SIZE_MAX) {
295     LOGW("Cannot remove any low priority event");
296   } else {
297     mNumDroppedLowPriEvents += numRemovedEvent;
298   }
299   return numRemovedEvent > 0;
300 #endif
301 }
302 
hasNoSpaceForHighPriorityEvent()303 bool EventLoop::hasNoSpaceForHighPriorityEvent() {
304   return mEventPool.full() && !removeNonNanoappLowPriorityEventsFromBack(
305                                   targetLowPriorityEventRemove);
306 }
307 
distributeEventSync(uint16_t eventType,void * eventData,uint16_t targetInstanceId,uint16_t targetGroupMask)308 bool EventLoop::distributeEventSync(uint16_t eventType, void *eventData,
309                                     uint16_t targetInstanceId,
310                                     uint16_t targetGroupMask) {
311   CHRE_ASSERT(inEventLoopThread());
312   Event event(eventType, eventData,
313               /* freeCallback= */ nullptr,
314               /* isLowPriority= */ false,
315               /* senderInstanceId= */ kSystemInstanceId, targetInstanceId,
316               targetGroupMask);
317   return distributeEventCommon(&event);
318 }
319 
320 // TODO(b/264108686): Refactor this function and postSystemEvent
postEventOrDie(uint16_t eventType,void * eventData,chreEventCompleteFunction * freeCallback,uint16_t targetInstanceId,uint16_t targetGroupMask)321 void EventLoop::postEventOrDie(uint16_t eventType, void *eventData,
322                                chreEventCompleteFunction *freeCallback,
323                                uint16_t targetInstanceId,
324                                uint16_t targetGroupMask) {
325   if (mRunning) {
326     if (hasNoSpaceForHighPriorityEvent() ||
327         !allocateAndPostEvent(eventType, eventData, freeCallback,
328                               /* isLowPriority= */ false, kSystemInstanceId,
329                               targetInstanceId, targetGroupMask)) {
330       CHRE_HANDLE_FAILED_SYSTEM_EVENT_ENQUEUE(
331           this, eventType, eventData, freeCallback, kSystemInstanceId,
332           targetInstanceId, targetGroupMask);
333       FATAL_ERROR("Failed to post critical system event 0x%" PRIx16, eventType);
334     }
335   } else if (freeCallback != nullptr) {
336     freeCallback(eventType, eventData);
337   }
338 }
339 
postSystemEvent(uint16_t eventType,void * eventData,SystemEventCallbackFunction * callback,void * extraData)340 bool EventLoop::postSystemEvent(uint16_t eventType, void *eventData,
341                                 SystemEventCallbackFunction *callback,
342                                 void *extraData) {
343   if (!mRunning) {
344     return false;
345   }
346 
347   if (hasNoSpaceForHighPriorityEvent()) {
348     CHRE_HANDLE_EVENT_QUEUE_FULL_DURING_SYSTEM_POST(this, eventType, eventData,
349                                                     callback, extraData);
350     FATAL_ERROR("Failed to post critical system event 0x%" PRIx16
351                 ": Full of high priority "
352                 "events",
353                 eventType);
354   }
355 
356   Event *event = mEventPool.allocate(eventType, eventData, callback, extraData);
357   if (event == nullptr || !mEvents.push(event)) {
358     CHRE_HANDLE_FAILED_SYSTEM_EVENT_ENQUEUE(
359         this, eventType, eventData, callback, kSystemInstanceId,
360         kBroadcastInstanceId, kDefaultTargetGroupMask);
361     FATAL_ERROR("Failed to post critical system event 0x%" PRIx16
362                 ": out of memory",
363                 eventType);
364   }
365 
366   return true;
367 }
368 
postLowPriorityEventOrFree(uint16_t eventType,void * eventData,chreEventCompleteFunction * freeCallback,uint16_t senderInstanceId,uint16_t targetInstanceId,uint16_t targetGroupMask)369 bool EventLoop::postLowPriorityEventOrFree(
370     uint16_t eventType, void *eventData,
371     chreEventCompleteFunction *freeCallback, uint16_t senderInstanceId,
372     uint16_t targetInstanceId, uint16_t targetGroupMask) {
373   bool eventPosted = false;
374 
375   if (mRunning) {
376     eventPosted =
377         allocateAndPostEvent(eventType, eventData, freeCallback,
378                              /* isLowPriority= */ true, senderInstanceId,
379                              targetInstanceId, targetGroupMask);
380     if (!eventPosted) {
381       LOGE("Failed to allocate event 0x%" PRIx16 " to instanceId %" PRIu16,
382            eventType, targetInstanceId);
383       CHRE_HANDLE_LOW_PRIORITY_ENQUEUE_FAILURE(
384           this, eventType, eventData, freeCallback, senderInstanceId,
385           targetInstanceId, targetGroupMask);
386       ++mNumDroppedLowPriEvents;
387     }
388   }
389 
390   if (!eventPosted && freeCallback != nullptr) {
391     freeCallback(eventType, eventData);
392   }
393 
394   return eventPosted;
395 }
396 
stop()397 void EventLoop::stop() {
398   auto callback = [](uint16_t /*type*/, void *data, void * /*extraData*/) {
399     auto *obj = static_cast<EventLoop *>(data);
400     obj->onStopComplete();
401   };
402 
403   // Stop accepting new events and tell the main loop to finish
404   postSystemEvent(static_cast<uint16_t>(SystemCallbackType::Shutdown),
405                   /*eventData=*/this, callback, /*extraData=*/nullptr);
406 }
407 
onStopComplete()408 void EventLoop::onStopComplete() {
409   mRunning = false;
410 }
411 
findNanoappByInstanceId(uint16_t instanceId) const412 Nanoapp *EventLoop::findNanoappByInstanceId(uint16_t instanceId) const {
413   ConditionalLockGuard<Mutex> lock(mNanoappsLock, !inEventLoopThread());
414   return lookupAppByInstanceId(instanceId);
415 }
416 
findNanoappByAppId(uint64_t appId) const417 Nanoapp *EventLoop::findNanoappByAppId(uint64_t appId) const {
418   ConditionalLockGuard<Mutex> lock(mNanoappsLock, !inEventLoopThread());
419   return lookupAppByAppId(appId);
420 }
421 
populateNanoappInfoForAppId(uint64_t appId,struct chreNanoappInfo * info) const422 bool EventLoop::populateNanoappInfoForAppId(
423     uint64_t appId, struct chreNanoappInfo *info) const {
424   ConditionalLockGuard<Mutex> lock(mNanoappsLock, !inEventLoopThread());
425   Nanoapp *app = lookupAppByAppId(appId);
426   return populateNanoappInfo(app, info);
427 }
428 
populateNanoappInfoForInstanceId(uint16_t instanceId,struct chreNanoappInfo * info) const429 bool EventLoop::populateNanoappInfoForInstanceId(
430     uint16_t instanceId, struct chreNanoappInfo *info) const {
431   ConditionalLockGuard<Mutex> lock(mNanoappsLock, !inEventLoopThread());
432   Nanoapp *app = lookupAppByInstanceId(instanceId);
433   return populateNanoappInfo(app, info);
434 }
435 
currentNanoappIsStopping() const436 bool EventLoop::currentNanoappIsStopping() const {
437   return (mCurrentApp == mStoppingNanoapp || !mRunning);
438 }
439 
logStateToBuffer(DebugDumpWrapper & debugDump) const440 void EventLoop::logStateToBuffer(DebugDumpWrapper &debugDump) const {
441   debugDump.print("\nEvent Loop:\n");
442   debugDump.print("  Max event pool usage: %" PRIu32 "/%zu\n",
443                   mEventPoolUsage.getMax(), kMaxEventCount);
444   debugDump.print("  Number of low priority events dropped: %" PRIu32 "\n",
445                   mNumDroppedLowPriEvents);
446 
447   Nanoseconds timeSince =
448       SystemTime::getMonotonicTime() - mTimeLastWakeupBucketCycled;
449   uint64_t timeSinceMins =
450       timeSince.toRawNanoseconds() / kOneMinuteInNanoseconds;
451   uint64_t durationMins =
452       kIntervalWakeupBucket.toRawNanoseconds() / kOneMinuteInNanoseconds;
453   debugDump.print("  Nanoapp host wakeup tracking: cycled %" PRIu64
454                   " mins ago, bucketDuration=%" PRIu64 "mins\n",
455                   timeSinceMins, durationMins);
456 
457   debugDump.print("\nNanoapps:\n");
458 
459   if (mNanoapps.size()) {
460     for (const UniquePtr<Nanoapp> &app : mNanoapps) {
461       app->logStateToBuffer(debugDump);
462     }
463 
464     mNanoapps[0]->logMemAndComputeHeader(debugDump);
465     for (const UniquePtr<Nanoapp> &app : mNanoapps) {
466       app->logMemAndComputeEntry(debugDump);
467     }
468 
469     mNanoapps[0]->logMessageHistoryHeader(debugDump);
470     for (const UniquePtr<Nanoapp> &app : mNanoapps) {
471       app->logMessageHistoryEntry(debugDump);
472     }
473   }
474 }
475 
onMatchingNanoappEndpoint(const pw::Function<bool (const EndpointInfo &)> & function)476 void EventLoop::onMatchingNanoappEndpoint(
477     const pw::Function<bool(const EndpointInfo &)> &function) {
478   ConditionalLockGuard<Mutex> lock(mNanoappsLock, !inEventLoopThread());
479 
480   for (const UniquePtr<Nanoapp> &app : mNanoapps) {
481     if (function(getEndpointInfoFromNanoappLocked(*app.get()))) {
482       break;
483     }
484   }
485 }
486 
getEndpointInfo(uint64_t appId)487 std::optional<EndpointInfo> EventLoop::getEndpointInfo(uint64_t appId) {
488   ConditionalLockGuard<Mutex> lock(mNanoappsLock, !inEventLoopThread());
489   Nanoapp *app = lookupAppByAppId(appId);
490   return app == nullptr
491              ? std::nullopt
492              : std::make_optional(getEndpointInfoFromNanoappLocked(*app));
493 }
494 
allocateAndPostEvent(uint16_t eventType,void * eventData,chreEventCompleteFunction * freeCallback,bool isLowPriority,uint16_t senderInstanceId,uint16_t targetInstanceId,uint16_t targetGroupMask)495 bool EventLoop::allocateAndPostEvent(uint16_t eventType, void *eventData,
496                                      chreEventCompleteFunction *freeCallback,
497                                      bool isLowPriority,
498                                      uint16_t senderInstanceId,
499                                      uint16_t targetInstanceId,
500                                      uint16_t targetGroupMask) {
501   bool success = false;
502 
503   Event *event =
504       mEventPool.allocate(eventType, eventData, freeCallback, isLowPriority,
505                           senderInstanceId, targetInstanceId, targetGroupMask);
506   if (event != nullptr) {
507     success = mEvents.push(event);
508   }
509   if (!success) {
510     LOG_OOM();
511   }
512 
513   return success;
514 }
515 
deliverNextEvent(const UniquePtr<Nanoapp> & app,Event * event)516 void EventLoop::deliverNextEvent(const UniquePtr<Nanoapp> &app, Event *event) {
517   constexpr Seconds kLatencyThreshold = Seconds(1);
518   constexpr Seconds kThrottleInterval(1);
519   constexpr uint16_t kThrottleCount = 10;
520 
521   // Handle time rollover. If Event ever changes the type used to store the
522   // received time, this will need to be updated.
523   uint32_t now = Event::getTimeMillis();
524   static_assert(
525       std::is_same<decltype(event->receivedTimeMillis), const uint16_t>::value);
526   if (now < event->receivedTimeMillis) {
527     now += UINT16_MAX + 1;
528   }
529   Milliseconds latency(now - event->receivedTimeMillis);
530 
531   if (latency >= kLatencyThreshold) {
532     CHRE_THROTTLE(LOGW("Delayed event 0x%" PRIx16 " from instanceId %" PRIu16
533                        "->%" PRIu16 " took %" PRIu64 "ms to deliver",
534                        event->eventType, event->senderInstanceId,
535                        event->targetInstanceId, latency.getMilliseconds()),
536                   kThrottleInterval, kThrottleCount,
537                   SystemTime::getMonotonicTime());
538   }
539 
540   // TODO: cleaner way to set/clear this? RAII-style?
541   mCurrentApp = app.get();
542   app->processEvent(event);
543   mCurrentApp = nullptr;
544 }
545 
distributeEvent(Event * event)546 void EventLoop::distributeEvent(Event *event) {
547   distributeEventCommon(event);
548   CHRE_ASSERT(event->isUnreferenced());
549   freeEvent(event);
550 }
551 
distributeEventCommon(Event * event)552 bool EventLoop::distributeEventCommon(Event *event) {
553   bool eventDelivered = false;
554   if (event->targetInstanceId == kBroadcastInstanceId) {
555     for (const UniquePtr<Nanoapp> &app : mNanoapps) {
556       if (app->isRegisteredForBroadcastEvent(event)) {
557         eventDelivered = true;
558         deliverNextEvent(app, event);
559       }
560     }
561   } else {
562     for (const UniquePtr<Nanoapp> &app : mNanoapps) {
563       if (event->targetInstanceId == app->getInstanceId()) {
564         eventDelivered = true;
565         deliverNextEvent(app, event);
566         break;
567       }
568     }
569   }
570   // Log if an event unicast to a nanoapp isn't delivered, as this is could be
571   // a bug (e.g. something isn't properly keeping track of when nanoapps are
572   // unloaded), though it could just be a harmless transient issue (e.g. race
573   // condition with nanoapp unload, where we post an event to a nanoapp just
574   // after queues are flushed while it's unloading)
575   if (!eventDelivered && event->targetInstanceId != kBroadcastInstanceId &&
576       event->targetInstanceId != kSystemInstanceId) {
577     LOGW("Dropping event 0x%" PRIx16 " from instanceId %" PRIu16 "->%" PRIu16,
578          event->eventType, event->senderInstanceId, event->targetInstanceId);
579   }
580   return eventDelivered;
581 }
582 
flushInboundEventQueue()583 void EventLoop::flushInboundEventQueue() {
584   while (!mEvents.empty()) {
585     distributeEvent(mEvents.pop());
586   }
587 }
588 
freeEvent(Event * event)589 void EventLoop::freeEvent(Event *event) {
590   if (event->hasFreeCallback()) {
591     // TODO: find a better way to set the context to the creator of the event
592     mCurrentApp = lookupAppByInstanceId(event->senderInstanceId);
593     event->invokeFreeCallback();
594     mCurrentApp = nullptr;
595   }
596 
597   mEventPool.deallocate(event);
598 }
599 
lookupAppByAppId(uint64_t appId) const600 Nanoapp *EventLoop::lookupAppByAppId(uint64_t appId) const {
601   for (const UniquePtr<Nanoapp> &app : mNanoapps) {
602     if (app->getAppId() == appId) {
603       return app.get();
604     }
605   }
606 
607   return nullptr;
608 }
609 
lookupAppByInstanceId(uint16_t instanceId) const610 Nanoapp *EventLoop::lookupAppByInstanceId(uint16_t instanceId) const {
611   // The system instance ID always has nullptr as its Nanoapp pointer, so can
612   // skip iterating through the nanoapp list for that case
613   if (instanceId != kSystemInstanceId) {
614     for (const UniquePtr<Nanoapp> &app : mNanoapps) {
615       if (app->getInstanceId() == instanceId) {
616         return app.get();
617       }
618     }
619   }
620 
621   return nullptr;
622 }
623 
notifyAppStatusChange(uint16_t eventType,const Nanoapp & nanoapp)624 void EventLoop::notifyAppStatusChange(uint16_t eventType,
625                                       const Nanoapp &nanoapp) {
626   auto *info = memoryAlloc<chreNanoappInfo>();
627   if (info == nullptr) {
628     LOG_OOM();
629   } else {
630     info->appId = nanoapp.getAppId();
631     info->version = nanoapp.getAppVersion();
632     info->instanceId = nanoapp.getInstanceId();
633 
634     postEventOrDie(eventType, info, freeEventDataCallback);
635   }
636 }
637 
unloadNanoappAtIndex(size_t index,bool nanoappStarted)638 void EventLoop::unloadNanoappAtIndex(size_t index, bool nanoappStarted) {
639   const UniquePtr<Nanoapp> &nanoapp = mNanoapps[index];
640 
641   // Lock here to prevent the nanoapp instance from being accessed between the
642   // time it is ended and fully erased
643   LockGuard<Mutex> lock(mNanoappsLock);
644 
645   // Let the app know it's going away
646   mCurrentApp = nanoapp.get();
647 
648   // nanoappEnd() is not invoked for nanoapps that return false in
649   // nanoappStart(), per CHRE API
650   if (nanoappStarted) {
651     nanoapp->end();
652   }
653 
654   // Cleanup resources.
655 #ifdef CHRE_WIFI_SUPPORT_ENABLED
656   const uint32_t numDisabledWifiSubscriptions =
657       EventLoopManagerSingleton::get()
658           ->getWifiRequestManager()
659           .disableAllSubscriptions(nanoapp.get());
660   logDanglingResources("WIFI subscriptions", numDisabledWifiSubscriptions);
661 #endif  // CHRE_WIFI_SUPPORT_ENABLED
662 
663 #ifdef CHRE_GNSS_SUPPORT_ENABLED
664   const uint32_t numDisabledGnssSubscriptions =
665       EventLoopManagerSingleton::get()
666           ->getGnssManager()
667           .disableAllSubscriptions(nanoapp.get());
668   logDanglingResources("GNSS subscriptions", numDisabledGnssSubscriptions);
669 #endif  // CHRE_GNSS_SUPPORT_ENABLED
670 
671 #ifdef CHRE_SENSORS_SUPPORT_ENABLED
672   const uint32_t numDisabledSensorSubscriptions =
673       EventLoopManagerSingleton::get()
674           ->getSensorRequestManager()
675           .disableAllSubscriptions(nanoapp.get());
676   logDanglingResources("Sensor subscriptions", numDisabledSensorSubscriptions);
677 #endif  // CHRE_SENSORS_SUPPORT_ENABLED
678 
679 #ifdef CHRE_AUDIO_SUPPORT_ENABLED
680   const uint32_t numDisabledAudioRequests =
681       EventLoopManagerSingleton::get()
682           ->getAudioRequestManager()
683           .disableAllAudioRequests(nanoapp.get());
684   logDanglingResources("Audio requests", numDisabledAudioRequests);
685 #endif  // CHRE_AUDIO_SUPPORT_ENABLED
686 
687 #ifdef CHRE_BLE_SUPPORT_ENABLED
688   const uint32_t numDisabledBleScans = EventLoopManagerSingleton::get()
689                                            ->getBleRequestManager()
690                                            .disableActiveScan(nanoapp.get());
691   logDanglingResources("BLE scan", numDisabledBleScans);
692 #endif  // CHRE_BLE_SUPPORT_ENABLED
693 
694   const uint32_t numCancelledTimers =
695       getTimerPool().cancelAllNanoappTimers(nanoapp.get());
696   logDanglingResources("timers", numCancelledTimers);
697 
698   const uint32_t numFreedBlocks =
699       EventLoopManagerSingleton::get()->getMemoryManager().nanoappFreeAll(
700           nanoapp.get());
701   logDanglingResources("heap blocks", numFreedBlocks);
702 
703   // Destroy the Nanoapp instance
704   mNanoapps.erase(index);
705 
706   mCurrentApp = nullptr;
707 }
708 
handleNanoappWakeupBuckets()709 void EventLoop::handleNanoappWakeupBuckets() {
710   Nanoseconds now = SystemTime::getMonotonicTime();
711   Nanoseconds duration = now - mTimeLastWakeupBucketCycled;
712   if (duration > kIntervalWakeupBucket) {
713     mTimeLastWakeupBucketCycled = now;
714     for (auto &nanoapp : mNanoapps) {
715       nanoapp->cycleWakeupBuckets(now);
716     }
717   }
718 }
719 
logDanglingResources(const char * name,uint32_t count)720 void EventLoop::logDanglingResources(const char *name, uint32_t count) {
721   if (count > 0) {
722     LOGE("App 0x%016" PRIx64 " had %" PRIu32 " remaining %s at unload",
723          mCurrentApp->getAppId(), count, name);
724   }
725 }
726 
getEndpointInfoFromNanoappLocked(const Nanoapp & nanoapp)727 EndpointInfo EventLoop::getEndpointInfoFromNanoappLocked(
728     const Nanoapp &nanoapp) {
729   return EndpointInfo(
730       /* id= */ nanoapp.getAppId(),
731       /* name= */ nanoapp.getAppName(),
732       /* version= */ nanoapp.getAppVersion(),
733       /* type= */ EndpointType::NANOAPP,
734       /* requiredPermissions= */ nanoapp.getAppPermissions());
735 }
736 
737 }  // namespace chre
738