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