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