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