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