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