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