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/util/dynamic_vector.h"
26 #include "chre/util/fixed_size_blocking_queue.h"
27 #include "chre/util/non_copyable.h"
28 #include "chre/util/synchronized_memory_pool.h"
29 #include "chre/util/unique_ptr.h"
30 
31 namespace chre {
32 
33 /**
34  * The EventLoop represents a single thread of execution that is shared among
35  * zero or more nanoapps. As the name implies, the EventLoop is built around a
36  * loop that delivers events to the nanoapps managed within for processing.
37  */
38 class EventLoop : public NonCopyable {
39  public:
40   /**
41    * Setup the event loop.
42    */
43   EventLoop();
44 
45   /**
46    * Synchronous callback used with forEachNanoapp
47    */
48   typedef void (NanoappCallbackFunction)(const Nanoapp *nanoapp, void *data);
49 
50   /**
51    * Searches the set of nanoapps managed by this EventLoop for one with the
52    * given app ID. If found, provides its instance ID, which can be used to send
53    * events to the app.
54    *
55    * This function is safe to call from any thread.
56    *
57    * @param appId The nanoapp identifier to search for.
58    * @param instanceId If this function returns true, will be populated with the
59    *        instanceId associated with the given appId; otherwise unmodified.
60    *        Must not be null.
61    * @return true if the given app ID was found and instanceId was populated
62    */
63   bool findNanoappInstanceIdByAppId(uint64_t appId, uint32_t *instanceId);
64 
65   /**
66    * Iterates over the list of Nanoapps managed by this EventLoop, and invokes
67    * the supplied callback for each one. This holds a lock if necessary, so it
68    * is safe to call from any thread.
69    *
70    * @param callback Function to invoke on each Nanoapp (synchronously)
71    * @param data Arbitrary data to pass to the callback
72    */
73   void forEachNanoapp(NanoappCallbackFunction *callback, void *data);
74 
75   /**
76    * Invokes the Nanoapp's start callback, and if successful, adds it to the
77    * set of Nanoapps managed by this EventLoop. This function must only be
78    * called from the context of the thread that runs this event loop (i.e. from
79    * the same thread that will call run() or from a callback invoked within
80    * run()).
81    *
82    * @param nanoapp The nanoapp that will be started. Upon success, this
83    *        UniquePtr will become invalid, as the underlying Nanoapp instance
84    *        will have been transferred to be managed by this EventLoop.
85    * @return true if the app was started successfully
86    */
87   bool startNanoapp(UniquePtr<Nanoapp>& nanoapp);
88 
89   /**
90    * Stops a nanoapp by invoking the stop entry point. The nanoapp passed in
91    * must have been previously started by the startNanoapp method. After this
92    * function returns, all references to the Nanoapp are invalid.
93    *
94    * @param nanoapp A pointer to the nanoapp to stop.
95    */
96   void stopNanoapp(Nanoapp *nanoapp);
97 
98   /**
99    * Executes the loop that blocks on the event queue and delivers received
100    * events to nanoapps. Only returns after stop() is called (from another
101    * context).
102    */
103   void run();
104 
105   /**
106    * Signals the event loop currently executing in run() to exit gracefully at
107    * the next available opportunity. This function is thread-safe.
108    */
109   void stop();
110 
111   /**
112    * Posts an event to a nanoapp that is currently running (or all nanoapps if
113    * the target instance ID is kBroadcastInstanceId).
114    *
115    * This function is safe to call from any thread.
116    *
117    * @param eventType The type of data being posted.
118    * @param eventData The data being posted.
119    * @param freeCallback The callback to invoke when the event is no longer
120    *        needed.
121    * @param senderInstanceId The instance ID of the sender of this event.
122    * @param targetInstanceId The instance ID of the destination of this event.
123    *
124    * @return true if the event was successfully added to the queue
125    *
126    * @see chreSendEvent
127    */
128   bool postEvent(uint16_t eventType, void *eventData,
129                  chreEventCompleteFunction *freeCallback,
130                  uint32_t senderInstanceId = kSystemInstanceId,
131                  uint32_t targetInstanceId = kBroadcastInstanceId);
132 
133   /**
134    * Returns a pointer to the currently executing Nanoapp, or nullptr if none is
135    * currently executing. Must only be called from within the thread context
136    * associated with this EventLoop.
137    *
138    * @return the currently executing nanoapp, or nullptr
139    */
140   Nanoapp *getCurrentNanoapp() const;
141 
142   /**
143    * Gets the number of nanoapps currently associated with this event loop. Must
144    * only be called within the context of this EventLoop.
145    *
146    * @return The number of nanoapps managed by this event loop
147    */
148   size_t getNanoappCount() const;
149 
150   /**
151    * Obtains the TimerPool associated with this event loop.
152    *
153    * @return The timer pool owned by this event loop.
154    */
155   TimerPool& getTimerPool();
156 
157   /**
158    * Searches the set of nanoapps managed by this EventLoop for one with the
159    * given instance ID.
160    *
161    * This function is safe to call from any thread.
162    *
163    * @param instanceId The nanoapp instance ID to search for.
164    * @return a pointer to the found nanoapp or nullptr if no match was found.
165    */
166   Nanoapp *findNanoappByInstanceId(uint32_t instanceId);
167 
168  private:
169   //! The maximum number of events that can be active in the system.
170   static constexpr size_t kMaxEventCount = 1024;
171 
172   //! The maximum number of events that are awaiting to be scheduled. These
173   //! events are in a queue to be distributed to apps.
174   static constexpr size_t kMaxUnscheduledEventCount = 1024;
175 
176   //! The memory pool to allocate incoming events from.
177   SynchronizedMemoryPool<Event, kMaxEventCount> mEventPool;
178 
179   //! The timer used schedule timed events for tasks running in this event loop.
180   TimerPool mTimerPool;
181 
182   //! The list of nanoapps managed by this event loop.
183   DynamicVector<UniquePtr<Nanoapp>> mNanoapps;
184 
185   //! This lock *must* be held whenever we:
186   //!   (1) make changes to the mNanoapps vector, or
187   //!   (2) read the mNanoapps vector from a thread other than the one
188   //!       associated with this EventLoop
189   //! It is not necessary to acquire the lock when reading mNanoapps from within
190   //! the thread context of this EventLoop.
191   Mutex mNanoappsLock;
192 
193   //! The blocking queue of incoming events from the system that have not been
194   //!  distributed out to apps yet.
195   FixedSizeBlockingQueue<Event *, kMaxUnscheduledEventCount> mEvents;
196 
197   // TODO: should probably be atomic to be fully correct
198   volatile bool mRunning = false;
199 
200   Nanoapp *mCurrentApp = nullptr;
201 
202   /**
203    * Delivers the next event pending in the Nanoapp's queue, and takes care of
204    * freeing events once they have been delivered to all nanoapps. Must only be
205    * called after confirming that the app has at least 1 pending event.
206    *
207    * @return true if the nanoapp has another event pending in its queue
208    */
209   bool deliverNextEvent(const UniquePtr<Nanoapp>& app);
210 
211   /**
212    * Call after when an Event has been delivered to all intended recipients.
213    * Invokes the event's free callback (if given) and releases resources.
214    *
215    * @param event The event to be freed
216    */
217   void freeEvent(Event *event);
218 
219   /**
220    * Finds a Nanoapp with the given instanceId.
221    *
222    * Only safe to call within this EventLoop's thread.
223    *
224    * @param instanceId Nanoapp instance identifier
225    * @return Nanoapp with the given instanceId, or nullptr if not found
226    */
227   Nanoapp *lookupAppByInstanceId(uint32_t instanceId);
228 
229   /**
230    * Stops the Nanoapp at the given index in mNanoapps
231    */
232   void stopNanoapp(size_t index);
233 };
234 
235 }  // namespace chre
236 
237 #endif  // CHRE_CORE_EVENT_LOOP_H_
238