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 #ifndef CHRE_CORE_EVENT_LOOP_H_ 18 #define CHRE_CORE_EVENT_LOOP_H_ 19 20 #include <pw_function/function.h> 21 #include <stddef.h> 22 #include <optional> 23 24 #include "chre/core/event.h" 25 #include "chre/core/nanoapp.h" 26 #include "chre/core/timer_pool.h" 27 #include "chre/platform/atomic.h" 28 #include "chre/platform/mutex.h" 29 #include "chre/platform/power_control_manager.h" 30 #include "chre/platform/system_time.h" 31 #include "chre/util/dynamic_vector.h" 32 #include "chre/util/non_copyable.h" 33 #include "chre/util/system/debug_dump.h" 34 #include "chre/util/system/message_common.h" 35 #include "chre/util/system/stats_container.h" 36 #include "chre/util/unique_ptr.h" 37 #include "chre_api/chre/event.h" 38 39 #ifdef CHRE_STATIC_EVENT_LOOP 40 #include "chre/util/system/fixed_size_blocking_queue.h" 41 #include "chre/util/system/synchronized_memory_pool.h" 42 43 // These default values can be overridden in the variant-specific makefile. 44 #ifndef CHRE_MAX_EVENT_COUNT 45 #define CHRE_MAX_EVENT_COUNT 96 46 #endif 47 48 #ifndef CHRE_MAX_UNSCHEDULED_EVENT_COUNT 49 #define CHRE_MAX_UNSCHEDULED_EVENT_COUNT 96 50 #endif 51 #else 52 #include "chre/util/blocking_segmented_queue.h" 53 #include "chre/util/system/synchronized_expandable_memory_pool.h" 54 55 // These default values can be overridden in the variant-specific makefile. 56 #ifndef CHRE_EVENT_PER_BLOCK 57 #define CHRE_EVENT_PER_BLOCK 24 58 #endif 59 60 #ifndef CHRE_MAX_EVENT_BLOCKS 61 #define CHRE_MAX_EVENT_BLOCKS 4 62 #endif 63 64 #endif 65 66 namespace chre { 67 68 /** 69 * The EventLoop represents a single thread of execution that is shared among 70 * zero or more nanoapps. As the name implies, the EventLoop is built around a 71 * loop that delivers events to the nanoapps managed within for processing. 72 */ 73 class EventLoop : public NonCopyable { 74 public: 75 /** 76 * Synchronous callback used with forEachNanoapp 77 */ 78 typedef void(NanoappCallbackFunction)(const Nanoapp *nanoapp, void *data); 79 EventLoop()80 EventLoop() 81 : 82 #ifndef CHRE_STATIC_EVENT_LOOP 83 mEvents(kMaxEventBlock), 84 #endif 85 mTimeLastWakeupBucketCycled(SystemTime::getMonotonicTime()), 86 mRunning(true) { 87 } 88 89 /** 90 * Searches the set of nanoapps managed by this EventLoop for one with the 91 * given app ID. If found, provides its instance ID, which can be used to send 92 * events to the app. 93 * 94 * This function is safe to call from any thread. 95 * 96 * @param appId The nanoapp identifier to search for. 97 * @param instanceId If this function returns true, will be populated with the 98 * instanceId associated with the given appId; otherwise unmodified. 99 * Must not be null. 100 * @return true if the given app ID was found and instanceId was populated 101 */ 102 bool findNanoappInstanceIdByAppId(uint64_t appId, uint16_t *instanceId) const; 103 104 /* 105 * Checks if the new wakeup buckets need to be pushed to nanoapps because the 106 * wakeup bucket interval has been surpassed since we pushed and pushes to the 107 * apps. 108 */ 109 void handleNanoappWakeupBuckets(); 110 111 /** 112 * Iterates over the list of Nanoapps managed by this EventLoop, and invokes 113 * the supplied callback for each one. This holds a lock if necessary, so it 114 * is safe to call from any thread. 115 * 116 * @param callback Function to invoke on each Nanoapp (synchronously) 117 * @param data Arbitrary data to pass to the callback 118 */ 119 void forEachNanoapp(NanoappCallbackFunction *callback, void *data); 120 121 /** 122 * Invokes a message to host free callback supplied by the given nanoapp 123 * (identified by app ID). Ensures that the calling context is updated 124 * appropriately. 125 * 126 * @param appId Identifies the nanoapp that sent this message and supplied the 127 * free callback 128 * @param freeFunction The non-null message free callback given by the nanoapp 129 * @param message Pointer to the message data 130 * @param messageSize Size of the message 131 */ 132 void invokeMessageFreeFunction(uint64_t appId, 133 chreMessageFreeFunction *freeFunction, 134 void *message, size_t messageSize); 135 136 /** 137 * Invokes the Nanoapp's start callback, and if successful, adds it to the 138 * set of Nanoapps managed by this EventLoop. This function must only be 139 * called from the context of the thread that runs this event loop (i.e. from 140 * the same thread that will call run() or from a callback invoked within 141 * run()). 142 * 143 * @param nanoapp The nanoapp that will be started. Upon success, this 144 * UniquePtr will become invalid, as the underlying Nanoapp instance 145 * will have been transferred to be managed by this EventLoop. 146 * @return true if the app was started successfully 147 */ 148 bool startNanoapp(UniquePtr<Nanoapp> &nanoapp); 149 150 /** 151 * Stops and unloads a nanoapp identified by its instance ID. The end entry 152 * point will be invoked, and the chre::Nanoapp instance will be destroyed. 153 * After this function returns, all references to the Nanoapp instance are 154 * invalidated. 155 * 156 * @param instanceId The nanoapp's unique instance identifier 157 * @param allowSystemNanoappUnload If false, this function will reject 158 * attempts to unload a system nanoapp 159 * @param nanoappStarted Indicates whether the nanoapp successfully started 160 * 161 * @return true if the nanoapp with the given instance ID was found & unloaded 162 */ 163 bool unloadNanoapp(uint16_t instanceId, bool allowSystemNanoappUnload, 164 bool nanoappStarted = true); 165 166 /** 167 * Executes the loop that blocks on the event queue and delivers received 168 * events to nanoapps. Only returns after stop() is called (from another 169 * context). 170 */ 171 void run(); 172 173 /** 174 * Signals the event loop currently executing in run() to exit gracefully at 175 * the next available opportunity. This function is thread-safe. 176 */ 177 void stop(); 178 179 /** 180 * Synchronously distributes an event to all nanoapps that should receive it. 181 * The event is sent from the system to a specific nanoapp if targetInstanceId 182 * matches the nanoappId, or to all registered nanoapps if targetInstanceId 183 * is set to kBroadcastInstanceId 184 * 185 * This is intended to be used by the function provided to 186 * EventLoopManager::deferCallback in cases where pre- and post-processing are 187 * required around event delivery. This closes the gaps around event delivery 188 * and can remove the need for posting multiple events. 189 * 190 * This must only be used from the EventLoop thread, and must only be used in 191 * rare circumstances where one of the postEvent functions cannot be used. In 192 * particular, misuse of this API can break explicit and implicit event 193 * ordering guarantees and trigger subtle bugs in nanoapps, so use with 194 * caution. 195 * 196 * No freeCallback is provided. The caller is expected to manage the memory 197 * for eventData, and handle any cleanup. 198 * 199 * @param eventType Event type identifier, which implies the type of eventData 200 * @param eventData The data being posted 201 * @param targetInstanceId The instance ID of the destination of this event 202 * @param targetGroupMask Mask used to limit the recipients that are 203 * registered to receive this event 204 */ 205 bool distributeEventSync(uint16_t eventType, void *eventData, 206 uint16_t targetInstanceId = kBroadcastInstanceId, 207 uint16_t targetGroupMask = kDefaultTargetGroupMask); 208 209 /** 210 * Posts an event to a nanoapp that is currently running (or all nanoapps if 211 * the target instance ID is kBroadcastInstanceId). A senderInstanceId cannot 212 * be provided to this method because it must only be used to post events 213 * sent by the system. If the event fails to post and the event loop thread is 214 * running, this is considered a fatal error. If the thread is not running 215 * (e.g. CHRE is shutting down), the event is silently dropped and the free 216 * callback is invoked prior to returning (if not null). 217 * 218 * Safe to call from any thread. 219 * 220 * @param eventType Event type identifier, which implies the type of eventData 221 * @param eventData The data being posted 222 * @param freeCallback Function to invoke to when the event has been processed 223 * by all recipients; this must be safe to call immediately, to handle 224 * the case where CHRE is shutting down 225 * @param targetInstanceId The instance ID of the destination of this event 226 * @param targetGroupMask Mask used to limit the recipients that are 227 * registered to receive this event 228 * 229 * @see postLowPriorityEventOrFree 230 */ 231 void postEventOrDie(uint16_t eventType, void *eventData, 232 chreEventCompleteFunction *freeCallback, 233 uint16_t targetInstanceId = kBroadcastInstanceId, 234 uint16_t targetGroupMask = kDefaultTargetGroupMask); 235 236 /** 237 * Posts an event to a nanoapp that is currently running (or all nanoapps if 238 * the target instance ID is kBroadcastInstanceId). If the event fails to 239 * post, freeCallback is invoked prior to returning (if not null). 240 * 241 * Safe to call from any thread. 242 * 243 * @param eventType Event type identifier, which implies the type of eventData 244 * @param eventData The data being posted 245 * @param freeCallback Function to invoke to when the event has been processed 246 * by all recipients; this must be safe to call immediately, to handle 247 * the case where CHRE is shutting down 248 * @param senderInstanceId The instance ID of the sender of this event 249 * @param targetInstanceId The instance ID of the destination of this event 250 * @param targetGroupMask Mask used to limit the recipients that are 251 * registered to receive this event 252 * 253 * @return true if the event was successfully added to the queue. 254 * 255 * @see chreSendEvent 256 */ 257 bool postLowPriorityEventOrFree( 258 uint16_t eventType, void *eventData, 259 chreEventCompleteFunction *freeCallback, 260 uint16_t senderInstanceId = kSystemInstanceId, 261 uint16_t targetInstanceId = kBroadcastInstanceId, 262 uint16_t targetGroupMask = kDefaultTargetGroupMask); 263 264 /** 265 * Posts an event for processing by the system from within the context of the 266 * CHRE thread. Uses the same underlying event queue as is used for nanoapp 267 * events, but gives the ability to provide an additional data pointer. If the 268 * event loop is running and the system event can't be posted (i.e. queue is 269 * full), then a fatal error is raised. 270 * 271 * Safe to call from any thread. 272 * 273 * @param eventType Event type identifier, which is forwarded to the callback 274 * @param eventData Arbitrary data to pass to the callback 275 * @param callback Function to invoke from the context of the CHRE thread 276 * @param extraData Additional arbitrary data to provide to the callback 277 * 278 * @return true if successfully posted; false ONLY IF the CHRE event loop is 279 * shutting down and not accepting any new events - in this case, 280 * the callback will not be invoked and any allocated memory must be 281 * cleaned up 282 * 283 * @see postEventOrDie 284 * @see EventLoopManager::deferCallback 285 */ 286 bool postSystemEvent(uint16_t eventType, void *eventData, 287 SystemEventCallbackFunction *callback, void *extraData); 288 289 /** 290 * Returns a pointer to the currently executing Nanoapp, or nullptr if none is 291 * currently executing. Must only be called from within the thread context 292 * associated with this EventLoop. 293 * 294 * @return the currently executing nanoapp, or nullptr 295 */ getCurrentNanoapp()296 Nanoapp *getCurrentNanoapp() const { 297 return mCurrentApp; 298 } 299 300 /** 301 * Gets the number of nanoapps currently associated with this event loop. Must 302 * only be called within the context of this EventLoop. 303 * 304 * @return The number of nanoapps managed by this event loop 305 */ getNanoappCount()306 size_t getNanoappCount() const { 307 return mNanoapps.size(); 308 } 309 310 /** 311 * Obtains the TimerPool associated with this event loop. 312 * 313 * @return The timer pool owned by this event loop. 314 */ getTimerPool()315 TimerPool &getTimerPool() { 316 return mTimerPool; 317 } 318 319 /** 320 * Searches the set of nanoapps managed by this EventLoop for one with the 321 * given instance ID. 322 * 323 * This function is safe to call from any thread. 324 * 325 * @param instanceId The nanoapp instance ID to search for. 326 * @return a pointer to the found nanoapp or nullptr if no match was found. 327 */ 328 Nanoapp *findNanoappByInstanceId(uint16_t instanceId) const; 329 330 /** 331 * Searches the set of nanoapps managed by this EventLoop for one with the 332 * given nanoapp ID. 333 * 334 * This function is safe to call from any thread. 335 * 336 * @param appId The nanoapp ID to search for. 337 * @return a pointer to the found nanoapp or nullptr if no match was found. 338 */ 339 Nanoapp *findNanoappByAppId(uint64_t appId) const; 340 341 /** 342 * Looks for an app with the given ID and if found, populates info with its 343 * metadata. Safe to call from any thread. 344 * 345 * @see chreGetNanoappInfoByAppId 346 */ 347 bool populateNanoappInfoForAppId(uint64_t appId, 348 struct chreNanoappInfo *info) const; 349 350 /** 351 * Looks for an app with the given instance ID and if found, populates info 352 * with its metadata. Safe to call from any thread. 353 * 354 * @see chreGetNanoappInfoByInstanceId 355 */ 356 bool populateNanoappInfoForInstanceId(uint16_t instanceId, 357 struct chreNanoappInfo *info) const; 358 359 /** 360 * @return true if the current Nanoapp (or entire CHRE) is being unloaded, and 361 * therefore it should not be allowed to send events or messages, etc. 362 */ 363 bool currentNanoappIsStopping() const; 364 365 /** 366 * Prints state in a string buffer. Must only be called from the context of 367 * the main CHRE thread. 368 * 369 * @param debugDump The debug dump wrapper where a string can be printed 370 * into one of the buffers. 371 */ 372 void logStateToBuffer(DebugDumpWrapper &debugDump) const; 373 374 /** 375 * Executes function for each nanoapp in the event loop. If function 376 * returns true, the iteration will stop. 377 * 378 * This function is safe to call from any thread. 379 * 380 * @param function The function to execute for each nanoapp. 381 */ 382 void onMatchingNanoappEndpoint( 383 const pw::Function<bool(const message::EndpointInfo &)> &function); 384 385 /** 386 * Returns the EndpointInfo for the given nanoapp. 387 * 388 * This function is safe to call from any thread. 389 * 390 * @param appId The nanoapp ID to search for. 391 * @return The EndpointInfo for the given nanoapp, or std::nullopt if not 392 * found. 393 */ 394 std::optional<message::EndpointInfo> getEndpointInfo(uint64_t appId); 395 396 /** 397 * Returns a reference to the power control manager. This allows power 398 * controls from subsystems outside the event loops. 399 */ getPowerControlManager()400 PowerControlManager &getPowerControlManager() { 401 return mPowerControlManager; 402 } 403 getMaxEventQueueSize()404 inline uint32_t getMaxEventQueueSize() const { 405 return mEventPoolUsage.getMax(); 406 } 407 getNumEventsDropped()408 inline uint32_t getNumEventsDropped() const { 409 return mNumDroppedLowPriEvents; 410 } 411 412 private: 413 #ifdef CHRE_STATIC_EVENT_LOOP 414 //! The maximum number of events that can be active in the system. 415 static constexpr size_t kMaxEventCount = CHRE_MAX_EVENT_COUNT; 416 417 //! The maximum number of events that are awaiting to be scheduled. These 418 //! events are in a queue to be distributed to apps. 419 static constexpr size_t kMaxUnscheduledEventCount = 420 CHRE_MAX_UNSCHEDULED_EVENT_COUNT; 421 422 //! The memory pool to allocate incoming events from. 423 SynchronizedMemoryPool<Event, kMaxEventCount> mEventPool; 424 425 //! The blocking queue of incoming events from the system that have not been 426 //! distributed out to apps yet. 427 FixedSizeBlockingQueue<Event *, kMaxUnscheduledEventCount> mEvents; 428 429 #else 430 //! The maximum number of event that can be stored in a block in mEventPool. 431 static constexpr size_t kEventPerBlock = CHRE_EVENT_PER_BLOCK; 432 433 //! The maximum number of event blocks that mEventPool can hold. 434 static constexpr size_t kMaxEventBlock = CHRE_MAX_EVENT_BLOCKS; 435 436 static constexpr size_t kMaxEventCount = 437 CHRE_EVENT_PER_BLOCK * CHRE_MAX_EVENT_BLOCKS; 438 439 //! The memory pool to allocate incoming events from. 440 SynchronizedExpandableMemoryPool<Event, kEventPerBlock, kMaxEventBlock> 441 mEventPool; 442 443 //! The blocking queue of incoming events from the system that have not been 444 //! distributed out to apps yet. 445 BlockingSegmentedQueue<Event *, kEventPerBlock> mEvents; 446 #endif 447 //! The time interval of nanoapp wakeup buckets, adjust in conjunction with 448 //! Nanoapp::kMaxSizeWakeupBuckets. 449 static constexpr Nanoseconds kIntervalWakeupBucket = 450 Nanoseconds(180 * kOneMinuteInNanoseconds); 451 452 //! The last time wakeup buckets were pushed onto the nanoapps. 453 Nanoseconds mTimeLastWakeupBucketCycled; 454 455 //! The timer used schedule timed events for tasks running in this event loop. 456 TimerPool mTimerPool; 457 458 //! The list of nanoapps managed by this event loop. 459 DynamicVector<UniquePtr<Nanoapp>> mNanoapps; 460 461 //! This lock *must* be held whenever we: 462 //! (1) make changes to the mNanoapps vector, or 463 //! (2) read the mNanoapps vector from a thread other than the one 464 //! associated with this EventLoop 465 //! It is not necessary to acquire the lock when reading mNanoapps from within 466 //! the thread context of this EventLoop. 467 mutable Mutex mNanoappsLock; 468 469 //! Indicates whether the event loop is running. 470 AtomicBool mRunning; 471 472 //! The nanoapp that is currently executing - must be set any time we call 473 //! into the nanoapp's entry points or callbacks 474 Nanoapp *mCurrentApp = nullptr; 475 476 //! Set to the nanoapp we are in the process of unloading in unloadNanoapp() 477 Nanoapp *mStoppingNanoapp = nullptr; 478 479 //! The object which manages power related controls. 480 PowerControlManager mPowerControlManager; 481 482 //! The stats collection used to collect event pool usage 483 StatsContainer<uint32_t> mEventPoolUsage; 484 485 //! The number of events dropped due to capacity limits 486 uint32_t mNumDroppedLowPriEvents = 0; 487 488 /** 489 * Modifies the run loop state so it no longer iterates on new events. This 490 * should only be invoked by the event loop when it is ready to stop 491 * processing new events. 492 */ 493 void onStopComplete(); 494 495 /** 496 * Allocates an event from the event pool and post it. 497 * 498 * @return true if the event has been successfully allocated and posted. 499 * 500 * @see postEventOrDie and postLowPriorityEventOrFree 501 */ 502 bool allocateAndPostEvent(uint16_t eventType, void *eventData, 503 chreEventCompleteFunction *freeCallback, 504 bool isLowPriority, uint16_t senderInstanceId, 505 uint16_t targetInstanceId, 506 uint16_t targetGroupMask); 507 /** 508 * Remove some non nanoapp and low priority events from back of the queue. 509 * 510 * @param removeNum Number of low priority events to be removed. 511 * @return False if cannot remove any low priority event. 512 */ 513 bool removeNonNanoappLowPriorityEventsFromBack(size_t removeNum); 514 515 /** 516 * Determine if there are space for high priority event. 517 * During the processing of determining the vacant space, it might 518 * remove low priority events to make space for high priority event. 519 * 520 * @return true if there are no space for a new high priority event. 521 */ 522 bool hasNoSpaceForHighPriorityEvent(); 523 524 /** 525 * Delivers the next event pending to the Nanoapp. 526 */ 527 void deliverNextEvent(const UniquePtr<Nanoapp> &app, Event *event); 528 529 /** 530 * Given an event pulled from the main incoming event queue (mEvents), deliver 531 * it to all Nanoapps that should receive the event, or free the event if 532 * there are no valid recipients. 533 * 534 * @param event The Event to distribute to Nanoapps 535 */ 536 void distributeEvent(Event *event); 537 538 /** 539 * Shared functionality to distributeEvent and distributeEventSync. Should 540 * only be called by those functions. Hnadles event distribution and logging 541 * without any pre- or post-processing. 542 * 543 * @param event The Event to distribute to Nanoapps 544 * @return True if the event was delivered to any nanoapps, otherwise false 545 */ 546 bool distributeEventCommon(Event *event); 547 548 /** 549 * Distribute all events pending in the inbound event queue. Note that this 550 * function only guarantees that any events in the inbound queue at the time 551 * it is called will be distributed to Nanoapp event queues - new events may 552 * still be posted during or after this function call from other threads as 553 * long as postEvent() will accept them. 554 */ 555 void flushInboundEventQueue(); 556 557 /** 558 * Call after when an Event has been delivered to all intended recipients. 559 * Invokes the event's free callback (if given) and releases resources. 560 * 561 * @param event The event to be freed 562 */ 563 void freeEvent(Event *event); 564 565 /** 566 * Finds a Nanoapp with the given 64-bit appId. 567 * 568 * Only safe to call within this EventLoop's thread, or if mNanoappsLock is 569 * held. 570 * 571 * @param appId Nanoapp ID 572 * @return Pointer to Nanoapp instance in this EventLoop with the given app 573 * ID, or nullptr if not found 574 */ 575 Nanoapp *lookupAppByAppId(uint64_t appId) const; 576 577 /** 578 * Finds a Nanoapp with the given instanceId. 579 * 580 * Only safe to call within this EventLoop's thread, or if mNanoappsLock is 581 * held. 582 * 583 * @param instanceId Nanoapp instance identifier 584 * @return Nanoapp with the given instanceId, or nullptr if not found 585 */ 586 Nanoapp *lookupAppByInstanceId(uint16_t instanceId) const; 587 588 /** 589 * Sends an event with payload struct chreNanoappInfo populated from the given 590 * Nanoapp instance to inform other nanoapps about it starting/stopping. 591 * 592 * @param eventType Should be one of CHRE_EVENT_NANOAPP_{STARTED, STOPPED} 593 * @param nanoapp The nanoapp instance whose status has changed 594 */ 595 void notifyAppStatusChange(uint16_t eventType, const Nanoapp &nanoapp); 596 597 /** 598 * Stops and unloads the Nanoapp at the given index in mNanoapps. 599 * 600 * IMPORTANT: prior to calling this function, the event queues must be in a 601 * safe condition for removal of this nanoapp. This means that there must not 602 * be any pending events in this nanoapp's queue, and there must not be any 603 * outstanding events sent by this nanoapp, as they may reference the 604 * nanoapp's own memory (even if there is no free callback). 605 * 606 * @param index Index of the nanoapp in the list of nanoapps managed by event 607 * loop. 608 * @param nanoappStarted Indicates whether the nanoapp successfully started 609 */ 610 void unloadNanoappAtIndex(size_t index, bool nanoappStarted = true); 611 612 /** 613 * Logs dangling resources when a nanoapp is unloaded. 614 * 615 * @param name The name of the resource. 616 * @param count The number of dangling resources. 617 */ 618 void logDanglingResources(const char *name, uint32_t count); 619 620 /** 621 * Returns the EndpointInfo for the given nanoapp. 622 * 623 * Only safe to call within this EventLoop's thread, or if mNanoappsLock is 624 * held. 625 * 626 * @param nanoapp The nanoapp to get the EndpointInfo for. 627 * @return The EndpointInfo for the given nanoapp 628 */ 629 message::EndpointInfo getEndpointInfoFromNanoappLocked( 630 const Nanoapp &nanoapp); 631 }; 632 633 } // namespace chre 634 635 #endif // CHRE_CORE_EVENT_LOOP_H_ 636