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