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 ® = 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 ® = 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 ® = mRegisteredEvents[foundIndex];
+ if (reg.eventType == eventType) {
+ break;
+ }
+ }
+ return foundIndex;
+}
+
} // namespace chre