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