Home | History | Annotate | Download | only in core
      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 namespace 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  */
     40 class 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