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