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