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