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