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