Support targeting events to specific groups of apps

Up until this point, events could only be targeted to a single nanoapp
or all nanoapps that are registered for a given event type. With this
CL, events can now be targeted to a subset of nanoapps registered for a
given event type. This can be used to allow events that cause different
power usages depending on the receipient nanoapp to be further targeted
to only a subset of nanoapps that need to actually consume that event
type at that moment. As a concrete example, this can be used to replace
big-image sensor types in SLPI and the same sensor type can be reused
for (e.g. accel), but under the hood, the sensor driver can split
requests for accel between big-image and micro-image and deliver accel
data events to the right subset of nanoapps.

Bug: 177324066
Test: Load CHRE and verify apps continue to work with noone using the
new targeting yet

Change-Id: I4ee3801ea04d0840f8208aa49e9a113d88fcf552
diff --git a/core/event_loop.cc b/core/event_loop.cc
index 1c1d7ec..ed592c7 100644
--- a/core/event_loop.cc
+++ b/core/event_loop.cc
@@ -251,10 +251,12 @@
 
 void EventLoop::postEventOrDie(uint16_t eventType, void *eventData,
                                chreEventCompleteFunction *freeCallback,
-                               uint32_t targetInstanceId) {
+                               uint32_t targetInstanceId,
+                               uint16_t targetGroupMask) {
   if (mRunning) {
     if (!allocateAndPostEvent(eventType, eventData, freeCallback,
-                              kSystemInstanceId, targetInstanceId)) {
+                              kSystemInstanceId, targetInstanceId,
+                              targetGroupMask)) {
       FATAL_ERROR("Failed to post critical system event 0x%" PRIx16, eventType);
     }
   } else if (freeCallback != nullptr) {
@@ -280,13 +282,14 @@
 bool EventLoop::postLowPriorityEventOrFree(
     uint16_t eventType, void *eventData,
     chreEventCompleteFunction *freeCallback, uint32_t senderInstanceId,
-    uint32_t targetInstanceId) {
+    uint32_t targetInstanceId, uint16_t targetGroupMask) {
   bool eventPosted = false;
 
   if (mRunning) {
     if (mEventPool.getFreeBlockCount() > kMinReservedHighPriorityEventCount) {
       eventPosted = allocateAndPostEvent(eventType, eventData, freeCallback,
-                                         senderInstanceId, targetInstanceId);
+                                         senderInstanceId, targetInstanceId,
+                                         targetGroupMask);
       if (!eventPosted) {
         LOGE("Failed to allocate event 0x%" PRIx16 " to instanceId %" PRIu32,
              eventType, targetInstanceId);
@@ -363,11 +366,13 @@
 bool EventLoop::allocateAndPostEvent(uint16_t eventType, void *eventData,
                                      chreEventCompleteFunction *freeCallback,
                                      uint32_t senderInstanceId,
-                                     uint32_t targetInstanceId) {
+                                     uint32_t targetInstanceId,
+                                     uint16_t targetGroupMask) {
   bool success = false;
 
-  Event *event = mEventPool.allocate(eventType, eventData, freeCallback,
-                                     senderInstanceId, targetInstanceId);
+  Event *event =
+      mEventPool.allocate(eventType, eventData, freeCallback, senderInstanceId,
+                          targetInstanceId, targetGroupMask);
   if (event != nullptr) {
     success = mEvents.push(event);
   }
@@ -405,7 +410,8 @@
 void EventLoop::distributeEvent(Event *event) {
   for (const UniquePtr<Nanoapp> &app : mNanoapps) {
     if ((event->targetInstanceId == chre::kBroadcastInstanceId &&
-         app->isRegisteredForBroadcastEvent(event->eventType)) ||
+         app->isRegisteredForBroadcastEvent(event->eventType,
+                                            event->targetAppGroupMask)) ||
         event->targetInstanceId == app->getInstanceId()) {
       app->postEvent(event);
     }
diff --git a/core/include/chre/core/event.h b/core/include/chre/core/event.h
index e652185..e5e46a2 100644
--- a/core/include/chre/core/event.h
+++ b/core/include/chre/core/event.h
@@ -37,6 +37,10 @@
 //! ID is invalid/not assigned yet
 constexpr uint32_t kInvalidInstanceId = kBroadcastInstanceId;
 
+//! Default target group mask that results in the event being sent to any app
+//! registered for it.
+constexpr uint16_t kDefaultTargetGroupMask = UINT16_MAX;
+
 class Event : public NonCopyable {
  public:
   Event() = delete;
@@ -45,15 +49,18 @@
   Event(uint16_t eventType_, void *eventData_,
         chreEventCompleteFunction *freeCallback_,
         uint32_t senderInstanceId_ = kSystemInstanceId,
-        uint32_t targetInstanceId_ = kBroadcastInstanceId)
+        uint32_t targetInstanceId_ = kBroadcastInstanceId,
+        uint16_t targetAppGroupMask_ = kDefaultTargetGroupMask)
       : eventType(eventType_),
         receivedTimeMillis(getTimeMillis()),
         eventData(eventData_),
         freeCallback(freeCallback_),
         senderInstanceId(senderInstanceId_),
-        targetInstanceId(targetInstanceId_) {
+        targetInstanceId(targetInstanceId_),
+        targetAppGroupMask(targetAppGroupMask_) {
     // Sending events to the system must only be done via the other constructor
     CHRE_ASSERT(targetInstanceId_ != kSystemInstanceId);
+    CHRE_ASSERT(targetAppGroupMask_ > 0);
   }
 
   // Alternative constructor used for system-internal events (e.g. deferred
@@ -65,7 +72,8 @@
         eventData(eventData_),
         systemEventCallback(systemEventCallback_),
         extraData(extraData_),
-        targetInstanceId(kSystemInstanceId) {
+        targetInstanceId(kSystemInstanceId),
+        targetAppGroupMask(kDefaultTargetGroupMask) {
     // Posting events to the system must always have a corresponding callback
     CHRE_ASSERT(systemEventCallback_ != nullptr);
   }
@@ -128,8 +136,15 @@
   };
   const uint32_t targetInstanceId;
 
+  // Bitmask that's used to limit the event delivery to some subset of listeners
+  // registered for this type of event (useful when waking up listeners that can
+  // have different power considerations). When left as the default value
+  // (kDefaultTargetGroupMask), this has the same behavior as broadcasting to
+  // all registered listeners.
+  const uint16_t targetAppGroupMask;
+
  private:
-  size_t mRefCount = 0;
+  uint16_t mRefCount = 0;
 
   //! @return Monotonic time reference for initializing receivedTimeMillis
   static uint16_t getTimeMillis();
diff --git a/core/include/chre/core/event_loop.h b/core/include/chre/core/event_loop.h
index 009e4bb..0c70b77 100644
--- a/core/include/chre/core/event_loop.h
+++ b/core/include/chre/core/event_loop.h
@@ -159,15 +159,21 @@
    *
    * Safe to call from any thread.
    *
+   * @param eventType Event type identifier, which implies the type of eventData
+   * @param eventData The data being posted
    * @param freeCallback Function to invoke to when the event has been processed
    *        by all recipients; this must be safe to call immediately, to handle
    *        the case where CHRE is shutting down
+   * @param targetInstanceId The instance ID of the destination of this event
+   * @param targetGroupMask Mask used to limit the recipients that are
+   *        registered to receive this event
    *
    * @see postLowPriorityEventOrFree
    */
   void postEventOrDie(uint16_t eventType, void *eventData,
                       chreEventCompleteFunction *freeCallback,
-                      uint32_t targetInstanceId = kBroadcastInstanceId);
+                      uint32_t targetInstanceId = kBroadcastInstanceId,
+                      uint16_t targetGroupMask = kDefaultTargetGroupMask);
 
   /**
    * Posts an event to a nanoapp that is currently running (or all nanoapps if
@@ -178,10 +184,13 @@
    *
    * @param eventType Event type identifier, which implies the type of eventData
    * @param eventData The data being posted
-   * @param freeCallback The callback to invoke when the event is no longer
-   *        needed
+   * @param freeCallback Function to invoke to when the event has been processed
+   *        by all recipients; this must be safe to call immediately, to handle
+   *        the case where CHRE is shutting down
    * @param senderInstanceId The instance ID of the sender of this event
    * @param targetInstanceId The instance ID of the destination of this event
+   * @param targetGroupMask Mask used to limit the recipients that are
+   *        registered to receive this event
    *
    * @return true if the event was successfully added to the queue.
    *
@@ -191,7 +200,8 @@
       uint16_t eventType, void *eventData,
       chreEventCompleteFunction *freeCallback,
       uint32_t senderInstanceId = kSystemInstanceId,
-      uint32_t targetInstanceId = kBroadcastInstanceId);
+      uint32_t targetInstanceId = kBroadcastInstanceId,
+      uint16_t targetGroupMask = kDefaultTargetGroupMask);
 
   /**
    * Posts an event for processing by the system from within the context of the
@@ -375,7 +385,8 @@
   bool allocateAndPostEvent(uint16_t eventType, void *eventData,
                             chreEventCompleteFunction *freeCallback,
                             uint32_t senderInstanceId,
-                            uint32_t targetInstanceId);
+                            uint32_t targetInstanceId,
+                            uint16_t targetGroupMask);
 
   /**
    * Do one round of Nanoapp event delivery, only considering events in
diff --git a/core/include/chre/core/nanoapp.h b/core/include/chre/core/nanoapp.h
index 8dbdcaf..0900b94 100644
--- a/core/include/chre/core/nanoapp.h
+++ b/core/include/chre/core/nanoapp.h
@@ -91,23 +91,32 @@
    * @return true if the nanoapp should receive broadcast events with the given
    *         type
    */
-  bool isRegisteredForBroadcastEvent(uint16_t eventType) const;
+  bool isRegisteredForBroadcastEvent(uint16_t eventType,
+                                     uint16_t targetGroupIdMask) const;
 
   /**
    * Updates the Nanoapp's registration so that it will receive broadcast events
-   * with the given event ID.
+   * with the given event type.
    *
-   * @return true if the event is newly registered
+   * @param eventType The event type that the nanoapp will now be registered to
+   *     receive
+   * @param groupIdMask A mask of group IDs to register the nanoapp for. If an
+   *     event is sent that targets any of the group IDs in the mask, it will
+   *     be delivered to the nanoapp.
    */
-  bool registerForBroadcastEvent(uint16_t eventId);
+  void registerForBroadcastEvent(
+      uint16_t eventType, uint16_t groupIdMask = kDefaultTargetGroupMask);
 
   /**
    * Updates the Nanoapp's registration so that it will not receive broadcast
-   * events with the given event ID.
+   * events with the given event type.
    *
-   * @return true if the event was previously registered
+   * @param eventType The event type that the nanoapp will be unregistered from
+   *    assuming the group ID also matches a valid entry.
+   * @param groupIdMask The mask of group IDs that will be unregistered from.
    */
-  bool unregisterForBroadcastEvent(uint16_t eventId);
+  void unregisterForBroadcastEvent(
+      uint16_t eventType, uint16_t groupIdMask = kDefaultTargetGroupMask);
 
   /**
    * Adds an event to this nanoapp's queue of pending events.
@@ -214,13 +223,27 @@
   //! wakeups over time intervals.
   FixedSizeVector<uint16_t, kMaxSizeWakeupBuckets> mWakeupBuckets;
 
+  //! Metadata needed for keeping track of the registered events for this
+  //! nanoapp.
+  struct EventRegistration {
+    EventRegistration(uint16_t eventType_, uint16_t groupIdMask_)
+        : eventType(eventType_), groupIdMask(groupIdMask_) {}
+
+    uint16_t eventType;
+    uint16_t groupIdMask;
+  };
+
   //! The set of broadcast events that this app is registered for.
   // TODO: Implement a set container and replace DynamicVector here. There may
   // also be a better way of handling this (perhaps we map event type to apps
   // who care about them).
-  DynamicVector<uint16_t> mRegisteredEvents;
+  DynamicVector<EventRegistration> mRegisteredEvents;
 
   EventRefQueue mEventQueue;
+
+  //! @return index of event registration if found. mRegisteredEvents.size() if
+  //!     not.
+  size_t registrationIndex(uint16_t eventType) const;
 };
 
 }  // namespace chre
diff --git a/core/nanoapp.cc b/core/nanoapp.cc
index ceadb4a..6c3a89e 100644
--- a/core/nanoapp.cc
+++ b/core/nanoapp.cc
@@ -44,30 +44,40 @@
   }
 }
 
-bool Nanoapp::isRegisteredForBroadcastEvent(uint16_t eventType) const {
-  return (mRegisteredEvents.find(eventType) != mRegisteredEvents.size());
+bool Nanoapp::isRegisteredForBroadcastEvent(uint16_t eventType,
+                                            uint16_t targetGroupIdMask) const {
+  bool registered = false;
+  size_t foundIndex = registrationIndex(eventType);
+  if (foundIndex < mRegisteredEvents.size()) {
+    const EventRegistration &reg = mRegisteredEvents[foundIndex];
+    if (targetGroupIdMask & reg.groupIdMask) {
+      registered = true;
+    }
+  }
+  return registered;
 }
 
-bool Nanoapp::registerForBroadcastEvent(uint16_t eventId) {
-  if (isRegisteredForBroadcastEvent(eventId)) {
-    return false;
-  }
-
-  if (!mRegisteredEvents.push_back(eventId)) {
+void Nanoapp::registerForBroadcastEvent(uint16_t eventType,
+                                        uint16_t groupIdMask) {
+  size_t foundIndex = registrationIndex(eventType);
+  if (foundIndex < mRegisteredEvents.size()) {
+    mRegisteredEvents[foundIndex].groupIdMask |= groupIdMask;
+  } else if (!mRegisteredEvents.push_back(
+                 EventRegistration(eventType, groupIdMask))) {
     FATAL_ERROR_OOM();
   }
-
-  return true;
 }
 
-bool Nanoapp::unregisterForBroadcastEvent(uint16_t eventId) {
-  size_t registeredEventIndex = mRegisteredEvents.find(eventId);
-  if (registeredEventIndex == mRegisteredEvents.size()) {
-    return false;
+void Nanoapp::unregisterForBroadcastEvent(uint16_t eventType,
+                                          uint16_t groupIdMask) {
+  size_t foundIndex = registrationIndex(eventType);
+  if (foundIndex < mRegisteredEvents.size()) {
+    EventRegistration &reg = mRegisteredEvents[foundIndex];
+    reg.groupIdMask &= ~groupIdMask;
+    if (reg.groupIdMask == 0) {
+      mRegisteredEvents.erase(foundIndex);
+    }
   }
-
-  mRegisteredEvents.erase(registeredEventIndex);
-  return true;
 }
 
 void Nanoapp::configureNanoappInfoEvents(bool enable) {
@@ -158,4 +168,15 @@
          ((getAppPermissions() & permission) == permission);
 }
 
+size_t Nanoapp::registrationIndex(uint16_t eventType) const {
+  size_t foundIndex = 0;
+  for (; foundIndex < mRegisteredEvents.size(); ++foundIndex) {
+    const EventRegistration &reg = mRegisteredEvents[foundIndex];
+    if (reg.eventType == eventType) {
+      break;
+    }
+  }
+  return foundIndex;
+}
+
 }  // namespace chre