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