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). A senderInstanceId cannot
143    * be provided to this method because it should only be used to post events
144    * sent by the system. If the event fails to post, this is considered a fatal
145    * error.
146    *
147    * @see postLowPriorityEventOrFree
148    */
149   bool postEventOrDie(uint16_t eventType, void *eventData,
150                       chreEventCompleteFunction *freeCallback,
151                       uint32_t targetInstanceId = kBroadcastInstanceId);
152 
153   /**
154    * Posts an event to a nanoapp that is currently running (or all nanoapps if
155    * the target instance ID is kBroadcastInstanceId). If the event fails to
156    * post, it is freed with freeCallback.
157    *
158    * This function is safe to call from any thread.
159    *
160    * @param eventType The type of data being posted.
161    * @param eventData The data being posted.
162    * @param freeCallback The callback to invoke when the event is no longer
163    *        needed.
164    * @param senderInstanceId The instance ID of the sender of this event.
165    * @param targetInstanceId The instance ID of the destination of this event.
166    *
167    * @return true if the event was successfully added to the queue.
168    *
169    * @see chreSendEvent
170    */
171   bool postLowPriorityEventOrFree(
172       uint16_t eventType, void *eventData,
173       chreEventCompleteFunction *freeCallback,
174       uint32_t senderInstanceId = kSystemInstanceId,
175       uint32_t targetInstanceId = kBroadcastInstanceId);
176 
177   /**
178    * Returns a pointer to the currently executing Nanoapp, or nullptr if none is
179    * currently executing. Must only be called from within the thread context
180    * associated with this EventLoop.
181    *
182    * @return the currently executing nanoapp, or nullptr
183    */
getCurrentNanoapp()184   Nanoapp *getCurrentNanoapp() const {
185     return mCurrentApp;
186   }
187 
188   /**
189    * Gets the number of nanoapps currently associated with this event loop. Must
190    * only be called within the context of this EventLoop.
191    *
192    * @return The number of nanoapps managed by this event loop
193    */
getNanoappCount()194   size_t getNanoappCount() const {
195     return mNanoapps.size();
196   }
197 
198   /**
199    * Obtains the TimerPool associated with this event loop.
200    *
201    * @return The timer pool owned by this event loop.
202    */
getTimerPool()203   TimerPool& getTimerPool() {
204     return mTimerPool;
205   }
206 
207   /**
208    * Searches the set of nanoapps managed by this EventLoop for one with the
209    * given instance ID.
210    *
211    * This function is safe to call from any thread.
212    *
213    * @param instanceId The nanoapp instance ID to search for.
214    * @return a pointer to the found nanoapp or nullptr if no match was found.
215    */
216   Nanoapp *findNanoappByInstanceId(uint32_t instanceId) const;
217 
218   /**
219    * Looks for an app with the given ID and if found, populates info with its
220    * metadata. Safe to call from any thread.
221    *
222    * @see chreGetNanoappInfoByAppId
223    */
224   bool populateNanoappInfoForAppId(uint64_t appId,
225                                    struct chreNanoappInfo *info) const;
226 
227   /**
228    * Looks for an app with the given instance ID and if found, populates info
229    * with its metadata. Safe to call from any thread.
230    *
231    * @see chreGetNanoappInfoByInstanceId
232    */
233   bool populateNanoappInfoForInstanceId(uint32_t instanceId,
234                                         struct chreNanoappInfo *info) const;
235 
236   /**
237    * @return true if the current Nanoapp (or entire CHRE) is being unloaded, and
238    *         therefore it should not be allowed to send events or messages, etc.
239    */
240   bool currentNanoappIsStopping() const;
241 
242   /**
243    * Prints state in a string buffer. Must only be called from the context of
244    * the main CHRE thread.
245    *
246    * @param buffer Pointer to the start of the buffer.
247    * @param bufferPos Pointer to buffer position to start the print (in-out).
248    * @param size Size of the buffer in bytes.
249    */
250   void logStateToBuffer(char *buffer, size_t *bufferPos,
251                         size_t bufferSize) const;
252 
253 
254   /**
255    * Returns a reference to the power control manager. This allows power
256    * controls from subsystems outside the event loops.
257    */
getPowerControlManager()258   PowerControlManager& getPowerControlManager() {
259     return mPowerControlManager;
260   }
261 
262  private:
263   //! The maximum number of events that can be active in the system.
264   static constexpr size_t kMaxEventCount = CHRE_MAX_EVENT_COUNT;
265 
266   //! The minimum number of events to reserve in the event pool for high
267   //! priority events.
268   static constexpr size_t kMinReservedHighPriorityEventCount = 16;
269 
270   //! The maximum number of events that are awaiting to be scheduled. These
271   //! events are in a queue to be distributed to apps.
272   static constexpr size_t kMaxUnscheduledEventCount =
273       CHRE_MAX_UNSCHEDULED_EVENT_COUNT;
274 
275   //! The memory pool to allocate incoming events from.
276   SynchronizedMemoryPool<Event, kMaxEventCount> mEventPool;
277 
278   //! The timer used schedule timed events for tasks running in this event loop.
279   TimerPool mTimerPool;
280 
281   //! The list of nanoapps managed by this event loop.
282   DynamicVector<UniquePtr<Nanoapp>> mNanoapps;
283 
284   //! This lock *must* be held whenever we:
285   //!   (1) make changes to the mNanoapps vector, or
286   //!   (2) read the mNanoapps vector from a thread other than the one
287   //!       associated with this EventLoop
288   //! It is not necessary to acquire the lock when reading mNanoapps from within
289   //! the thread context of this EventLoop.
290   mutable Mutex mNanoappsLock;
291 
292   //! The blocking queue of incoming events from the system that have not been
293   //! distributed out to apps yet.
294   FixedSizeBlockingQueue<Event *, kMaxUnscheduledEventCount> mEvents;
295 
296   //! Indicates whether the event loop is running.
297   AtomicBool mRunning;
298 
299   //! The nanoapp that is currently executing - must be set any time we call
300   //! into the nanoapp's entry points or callbacks
301   Nanoapp *mCurrentApp = nullptr;
302 
303   //! Set to the nanoapp we are in the process of unloading in unloadNanoapp()
304   Nanoapp *mStoppingNanoapp = nullptr;
305 
306   //! The object which manages power related controls.
307   PowerControlManager mPowerControlManager;
308 
309   //! The maximum number of events ever waiting in the event pool.
310   size_t mMaxEventPoolUsage = 0;
311 
312   /**
313    * Modifies the run loop state so it no longer iterates on new events. This
314    * should only be invoked by the event loop when it is ready to stop
315    * processing new events.
316    */
317   void onStopComplete();
318 
319   /**
320    * Allocates an event from the event pool and post it.
321    *
322    * @return true if the event has been successfully allocated and posted.
323    *
324    * @see postEventOrDie and postLowPriorityEventOrFree
325    */
326   bool allocateAndPostEvent(uint16_t eventType, void *eventData,
327     chreEventCompleteFunction *freeCallback, uint32_t senderInstanceId,
328     uint32_t targetInstanceId);
329 
330   /**
331    * Do one round of Nanoapp event delivery, only considering events in
332    * Nanoapps' own queues (not mEvents).
333    *
334    * @return true if there are more events pending in Nanoapps' own queues
335    */
336   bool deliverEvents();
337 
338   /**
339    * Delivers the next event pending in the Nanoapp's queue, and takes care of
340    * freeing events once they have been delivered to all nanoapps. Must only be
341    * called after confirming that the app has at least 1 pending event.
342    *
343    * @return true if the nanoapp has another event pending in its queue
344    */
345   bool deliverNextEvent(const UniquePtr<Nanoapp>& app);
346 
347   /**
348    * Given an event pulled from the main incoming event queue (mEvents), deliver
349    * it to all Nanoapps that should receive the event, or free the event if
350    * there are no valid recipients.
351    *
352    * @param event The Event to distribute to Nanoapps
353    */
354   void distributeEvent(Event *event);
355 
356   /**
357    * Distribute all events pending in the inbound event queue. Note that this
358    * function only guarantees that any events in the inbound queue at the time
359    * it is called will be distributed to Nanoapp event queues - new events may
360    * still be posted during or after this function call from other threads as
361    * long as postEvent() will accept them.
362    */
363   void flushInboundEventQueue();
364 
365   /**
366    * Delivers events pending in Nanoapps' own queues until they are all empty.
367    */
368   void flushNanoappEventQueues();
369 
370   /**
371    * Call after when an Event has been delivered to all intended recipients.
372    * Invokes the event's free callback (if given) and releases resources.
373    *
374    * @param event The event to be freed
375    */
376   void freeEvent(Event *event);
377 
378   /**
379    * Finds a Nanoapp with the given 64-bit appId.
380    *
381    * Only safe to call within this EventLoop's thread, or if mNanoappsLock is
382    * held.
383    *
384    * @param appId Nanoapp ID
385    * @return Pointer to Nanoapp instance in this EventLoop with the given app
386    *         ID, or nullptr if not found
387    */
388   Nanoapp *lookupAppByAppId(uint64_t appId) const;
389 
390   /**
391    * Finds a Nanoapp with the given instanceId.
392    *
393    * Only safe to call within this EventLoop's thread, or if mNanoappsLock is
394    * held.
395    *
396    * @param instanceId Nanoapp instance identifier
397    * @return Nanoapp with the given instanceId, or nullptr if not found
398    */
399   Nanoapp *lookupAppByInstanceId(uint32_t instanceId) const;
400 
401   /**
402    * Sends an event with payload struct chreNanoappInfo populated from the given
403    * Nanoapp instance to inform other nanoapps about it starting/stopping.
404    *
405    * @param eventType Should be one of CHRE_EVENT_NANOAPP_{STARTED, STOPPED}
406    * @param nanoapp The nanoapp instance whose status has changed
407    */
408   void notifyAppStatusChange(uint16_t eventType, const Nanoapp& nanoapp);
409 
410   /**
411    * Stops and unloads the Nanoapp at the given index in mNanoapps.
412    *
413    * IMPORTANT: prior to calling this function, the event queues must be in a
414    * safe condition for removal of this nanoapp. This means that there must not
415    * be any pending events in this nanoapp's queue, and there must not be any
416    * outstanding events sent by this nanoapp, as they may reference the
417    * nanoapp's own memory (even if there is no free callback).
418    */
419   void unloadNanoappAtIndex(size_t index);
420 };
421 
422 }  // namespace chre
423 
424 #endif  // CHRE_CORE_EVENT_LOOP_H_
425