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