Merge tag 'android-security-10.0.0_r53' into int/10/fp2

Android security 10.0.0 release 53

* tag 'android-security-10.0.0_r53':
  Revert "Add wakelocks to audio retries"

Change-Id: Id8c0113f178eb64d149e8e450e89dbb7acd8f046
diff --git a/Makefile b/Makefile
index 5943409..0675834 100644
--- a/Makefile
+++ b/Makefile
@@ -102,6 +102,8 @@
 include $(CHRE_PREFIX)/build/variant/google_hexagonv65_adsp-see-uimg.mk
 include $(CHRE_PREFIX)/build/variant/google_hexagonv65_slpi-see.mk
 include $(CHRE_PREFIX)/build/variant/google_hexagonv65_slpi-see-uimg.mk
+include $(CHRE_PREFIX)/build/variant/google_hexagonv66_adsp-see.mk
+include $(CHRE_PREFIX)/build/variant/google_hexagonv66_adsp-see-uimg.mk
 include $(CHRE_PREFIX)/build/variant/google_hexagonv66_slpi-see.mk
 include $(CHRE_PREFIX)/build/variant/google_hexagonv66_slpi-see-uimg.mk
 include $(CHRE_PREFIX)/build/variant/google_x86_linux.mk
diff --git a/build/nanoapp/app.mk b/build/nanoapp/app.mk
index 1452d7e..25f7791 100644
--- a/build/nanoapp/app.mk
+++ b/build/nanoapp/app.mk
@@ -107,6 +107,8 @@
 GOOGLE_HEXAGONV65_ADSP-SEE-UIMG_SRCS += $(DSO_SUPPORT_LIB_SRCS)
 GOOGLE_HEXAGONV65_SLPI-SEE_SRCS += $(DSO_SUPPORT_LIB_SRCS)
 GOOGLE_HEXAGONV65_SLPI-SEE-UIMG_SRCS += $(DSO_SUPPORT_LIB_SRCS)
+GOOGLE_HEXAGONV66_ADSP-SEE_SRCS += $(DSO_SUPPORT_LIB_SRCS)
+GOOGLE_HEXAGONV66_ADSP-SEE-UIMG_SRCS += $(DSO_SUPPORT_LIB_SRCS)
 GOOGLE_HEXAGONV66_SLPI-SEE_SRCS += $(DSO_SUPPORT_LIB_SRCS)
 GOOGLE_HEXAGONV66_SLPI-SEE-UIMG_SRCS += $(DSO_SUPPORT_LIB_SRCS)
 GOOGLE_ARM64_ANDROID_SRCS += $(DSO_SUPPORT_LIB_SRCS)
@@ -134,6 +136,8 @@
 include $(CHRE_PREFIX)/build/variant/google_hexagonv65_adsp-see-uimg.mk
 include $(CHRE_PREFIX)/build/variant/google_hexagonv65_slpi-see.mk
 include $(CHRE_PREFIX)/build/variant/google_hexagonv65_slpi-see-uimg.mk
+include $(CHRE_PREFIX)/build/variant/google_hexagonv66_adsp-see.mk
+include $(CHRE_PREFIX)/build/variant/google_hexagonv66_adsp-see-uimg.mk
 include $(CHRE_PREFIX)/build/variant/google_hexagonv66_slpi-see.mk
 include $(CHRE_PREFIX)/build/variant/google_hexagonv66_slpi-see-uimg.mk
 include $(CHRE_PREFIX)/build/variant/google_x86_linux.mk
diff --git a/build/variant/google_hexagonv66_adsp-see-uimg.mk b/build/variant/google_hexagonv66_adsp-see-uimg.mk
new file mode 100644
index 0000000..5777cb3
--- /dev/null
+++ b/build/variant/google_hexagonv66_adsp-see-uimg.mk
@@ -0,0 +1,42 @@
+#
+# Google CHRE Reference Implementation for Hexagon v66 Architecture on ADSP
+#
+
+include $(CHRE_PREFIX)/build/clean_build_template_args.mk
+
+TARGET_NAME = google_hexagonv66_adsp-see-uimg
+# Sized based on the buffer allocated in the host daemon (4096 bytes), minus
+# FlatBuffer overhead (max 80 bytes), minus some extra space to make a nice
+# round number and allow for addition of new fields to the FlatBuffer
+TARGET_CFLAGS = -DCHRE_MESSAGE_TO_HOST_MAX_SIZE=4000
+TARGET_CFLAGS += -DUIMG_DL_VER_MAJOR=2
+TARGET_CFLAGS += -DCHRE_SLPI_UIMG_ENABLED
+TARGET_CFLAGS += -DCHRE_THREAD_UTIL_ENABLED
+TARGET_CFLAGS += $(GOOGLE_HEXAGONV66_ADSP-SEE-UIMG_CFLAGS)
+TARGET_VARIANT_SRCS = $(GOOGLE_HEXAGONV66_ADSP-SEE-UIMG_SRCS)
+TARGET_SO_LATE_LIBS = $(GOOGLE_HEXAGONV66_ADSP-SEE-UIMG_LATE_LIBS)
+TARGET_PLATFORM_ID = 0x476f6f676c000007
+HEXAGON_ARCH = v66
+
+TARGET_CFLAGS += $(SLPI_CFLAGS)
+TARGET_VARIANT_SRCS += $(SLPI_SRCS)
+
+# Add SLPI/SEE-specific compiler flags and source files
+TARGET_CFLAGS += $(SLPI_SEE_CFLAGS)
+TARGET_CFLAGS += $(SLPI_SEE_QSK_CFLAGS)
+TARGET_VARIANT_SRCS += $(SLPI_SEE_SRCS)
+TARGET_VARIANT_SRCS += $(SLPI_SEE_QSK_SRCS)
+
+# Enable uImage support.
+TARGET_VARIANT_SRCS += $(SYS_SUPPORT_PATH)/qcom/uimg_dl_ver.c
+TARGET_SO_LDFLAGS += --script=$(SYS_SUPPORT_PATH)/qcom/uimage_v2.lcs
+
+ifneq ($(filter $(TARGET_NAME)% all, $(MAKECMDGOALS)),)
+ifneq ($(IS_NANOAPP_BUILD),)
+TARGET_SO_LATE_LIBS += $(CHRE_PREFIX)/build/app_support/google_slpi/libchre_slpi_skel.so
+include $(CHRE_PREFIX)/build/nanoapp/google_slpi.mk
+endif
+
+include $(CHRE_PREFIX)/build/arch/hexagon.mk
+include $(CHRE_PREFIX)/build/build_template.mk
+endif
diff --git a/build/variant/google_hexagonv66_adsp-see.mk b/build/variant/google_hexagonv66_adsp-see.mk
new file mode 100644
index 0000000..b1d0c6d
--- /dev/null
+++ b/build/variant/google_hexagonv66_adsp-see.mk
@@ -0,0 +1,36 @@
+#
+# Google CHRE Reference Implementation for Hexagon v66 Architecture on ADSP
+#
+
+include $(CHRE_PREFIX)/build/clean_build_template_args.mk
+
+TARGET_NAME = google_hexagonv66_adsp-see
+# Sized based on the buffer allocated in the host daemon (4096 bytes), minus
+# FlatBuffer overhead (max 80 bytes), minus some extra space to make a nice
+# round number and allow for addition of new fields to the FlatBuffer
+TARGET_CFLAGS = -DCHRE_MESSAGE_TO_HOST_MAX_SIZE=4000
+TARGET_CFLAGS += -DCHRE_THREAD_UTIL_ENABLED
+TARGET_CFLAGS += $(GOOGLE_HEXAGONV66_ADSP-SEE_CFLAGS)
+TARGET_VARIANT_SRCS = $(GOOGLE_HEXAGONV66_ADSP-SEE_SRCS)
+TARGET_SO_LATE_LIBS = $(GOOGLE_HEXAGONV66_ADSP-SEE_LATE_LIBS)
+TARGET_PLATFORM_ID = 0x476f6f676c000007
+HEXAGON_ARCH = v66
+
+TARGET_CFLAGS += $(SLPI_CFLAGS)
+TARGET_VARIANT_SRCS += $(SLPI_SRCS)
+
+# Add SLPI/SEE-specific compiler flags and source files
+TARGET_CFLAGS += $(SLPI_SEE_CFLAGS)
+TARGET_CFLAGS += $(SLPI_SEE_QMI_CFLAGS)
+TARGET_VARIANT_SRCS += $(SLPI_SEE_SRCS)
+TARGET_VARIANT_SRCS += $(SLPI_SEE_QMI_SRCS)
+
+ifneq ($(filter $(TARGET_NAME)% all, $(MAKECMDGOALS)),)
+ifneq ($(IS_NANOAPP_BUILD),)
+TARGET_SO_LATE_LIBS += $(CHRE_PREFIX)/build/app_support/google_slpi/libchre_slpi_skel.so
+include $(CHRE_PREFIX)/build/nanoapp/google_slpi.mk
+endif
+
+include $(CHRE_PREFIX)/build/arch/hexagon.mk
+include $(CHRE_PREFIX)/build/build_template.mk
+endif
diff --git a/chre_api/include/chre_api/chre/sensor.h b/chre_api/include/chre_api/chre/sensor.h
index 7985e9a..3a1f99e 100644
--- a/chre_api/include/chre_api/chre/sensor.h
+++ b/chre_api/include/chre_api/chre/sensor.h
@@ -972,6 +972,11 @@
  * CHRE_EVENT_SENSOR_FLUSH_COMPLETE events received must equal the number of
  * flush requests made.
  *
+ * If a sensor request is disabled after a flush request is made through this
+ * method but before the flush operation is completed, the nanoapp will receive
+ * a CHRE_EVENT_SENSOR_FLUSH_COMPLETE with the error code
+ * CHRE_ERROR_FUNCTION_DISABLED for any pending flush requests.
+ *
  * Starting with CHRE API v1.3, implementations must support this capability
  * across all exposed sensor types.
  *
diff --git a/core/audio_request_manager.cc b/core/audio_request_manager.cc
index a4a4f2e..7e162e7 100644
--- a/core/audio_request_manager.cc
+++ b/core/audio_request_manager.cc
@@ -66,6 +66,14 @@
 
 void AudioRequestManager::handleAudioDataEvent(
     const struct chreAudioDataEvent *audioDataEvent) {
+  uint32_t handle = audioDataEvent->handle;
+  if (handle >= mAudioRequestLists.size()) {
+    LOGE("Received audio event for unknown handle %" PRIu32, handle);
+  } else {
+    mAudioRequestLists[handle].lastEventTimestamp
+        = SystemTime::getMonotonicTime();
+  }
+
   auto callback = [](uint16_t /* eventType */, void *eventData) {
     auto *event = static_cast<struct chreAudioDataEvent *>(eventData);
     EventLoopManagerSingleton::get()->getAudioRequestManager()
@@ -112,13 +120,17 @@
     uint32_t handle = static_cast<uint32_t>(i);
     struct chreAudioSource source;
     mPlatformAudio.getAudioSource(handle, &source);
+
+    Nanoseconds timeSinceLastAudioEvent = SystemTime::getMonotonicTime()
+        - mAudioRequestLists[i].lastEventTimestamp;
     debugDumpPrint(buffer, bufferPos, bufferSize,
-        " handle=%" PRIu32 ", name=\"%s\", sampleRate=%" PRIu32
-        ", buffer(ms)=[%" PRIu64 ",%" PRIu64 "], format=%" PRIu8 "\n",
-        handle, source.name, source.sampleRate,
+        " handle=%" PRIu32 ", name=\"%s\", available=%d, sampleRate=%" PRIu32
+        ", buffer(ms)=[%" PRIu64 ",%" PRIu64 "], format=%" PRIu8
+        ", timeSinceLastAudioEvent(ms)=%" PRIu64 "\n",
+        handle, source.name, mAudioRequestLists[i].available, source.sampleRate,
         Milliseconds(Nanoseconds(source.minBufferDuration)).getMilliseconds(),
         Milliseconds(Nanoseconds(source.maxBufferDuration)).getMilliseconds(),
-        source.format);
+        source.format, Milliseconds(timeSinceLastAudioEvent).getMilliseconds());
 
     for (const auto& request : mAudioRequestLists[i].requests) {
       for (const auto& instanceId : request.instanceIds) {
@@ -380,9 +392,9 @@
   event->status.enabled = true;
   event->status.suspended = !available;
 
-  EventLoopManagerSingleton::get()->getEventLoop()
-      .postEvent(CHRE_EVENT_AUDIO_SAMPLING_CHANGE, event,
-                 freeEventDataCallback, kSystemInstanceId, instanceId);
+  EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
+      CHRE_EVENT_AUDIO_SAMPLING_CHANGE, event, freeEventDataCallback,
+      instanceId);
 }
 
 void AudioRequestManager::postAudioDataEventFatal(
@@ -392,11 +404,9 @@
     LOGW("Received audio data event for no clients");
     mPlatformAudio.releaseAudioDataEvent(event);
   } else {
-    for (const auto& instanceId : instanceIds) {
-      EventLoopManagerSingleton::get()->getEventLoop()
-          .postEvent(CHRE_EVENT_AUDIO_DATA, event,
-                     freeAudioDataEventCallback,
-                     kSystemInstanceId, instanceId);
+    for (const auto &instanceId : instanceIds) {
+      EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
+          CHRE_EVENT_AUDIO_DATA, event, freeAudioDataEventCallback, instanceId);
     }
 
     mAudioDataEventRefCounts.emplace_back(
diff --git a/core/event.cc b/core/event.cc
index ef87b66..298463b 100644
--- a/core/event.cc
+++ b/core/event.cc
@@ -19,10 +19,11 @@
 
 namespace chre {
 
-Event::Event(uint16_t eventType_, void *eventData_,
-             chreEventCompleteFunction *freeCallback_,
+Event::Event(uint16_t eventType_, uint16_t receivedTimeMillis_,
+             void *eventData_, chreEventCompleteFunction *freeCallback_,
              uint32_t senderInstanceId_, uint32_t targetInstanceId_)
-    : eventType(eventType_), eventData(eventData_), freeCallback(freeCallback_),
+    : eventType(eventType_), receivedTimeMillis(receivedTimeMillis_),
+      eventData(eventData_), freeCallback(freeCallback_),
       senderInstanceId(senderInstanceId_),
       targetInstanceId(targetInstanceId_) {}
 
diff --git a/core/event_loop.cc b/core/event_loop.cc
index a634298..5fdfd4b 100644
--- a/core/event_loop.cc
+++ b/core/event_loop.cc
@@ -22,9 +22,11 @@
 #include "chre/platform/context.h"
 #include "chre/platform/fatal_error.h"
 #include "chre/platform/log.h"
+#include "chre/platform/system_time.h"
 #include "chre/util/conditional_lock_guard.h"
 #include "chre/util/lock_guard.h"
 #include "chre/util/system/debug_dump.h"
+#include "chre/util/time.h"
 #include "chre_api/chre/version.h"
 
 namespace chre {
@@ -242,15 +244,14 @@
   return unloaded;
 }
 
-bool EventLoop::postEvent(uint16_t eventType, void *eventData,
-    chreEventCompleteFunction *freeCallback, uint32_t senderInstanceId,
-    uint32_t targetInstanceId) {
+bool EventLoop::postEventOrDie(uint16_t eventType, void *eventData,
+                               chreEventCompleteFunction *freeCallback,
+                               uint32_t targetInstanceId) {
   bool success = false;
 
-  if (mRunning && (senderInstanceId == kSystemInstanceId ||
-      mEventPool.getFreeBlockCount() > kMinReservedSystemEventCount)) {
+  if (mRunning) {
     success = allocateAndPostEvent(eventType, eventData, freeCallback,
-                                   senderInstanceId,targetInstanceId);
+                                   kSystemInstanceId, targetInstanceId);
     if (!success) {
       // This can only happen if the event is a system event type. This
       // postEvent method will fail if a non-system event is posted when the
@@ -262,16 +263,21 @@
   return success;
 }
 
-bool EventLoop::postEventOrFree(uint16_t eventType, void *eventData,
+bool EventLoop::postLowPriorityEventOrFree(
+    uint16_t eventType, void *eventData,
     chreEventCompleteFunction *freeCallback, uint32_t senderInstanceId,
     uint32_t targetInstanceId) {
   bool success = false;
 
   if (mRunning) {
-    success = allocateAndPostEvent(eventType, eventData, freeCallback,
-                                   senderInstanceId,targetInstanceId);
+    if (mEventPool.getFreeBlockCount() > kMinReservedHighPriorityEventCount) {
+      success = allocateAndPostEvent(eventType, eventData, freeCallback,
+                                     senderInstanceId, targetInstanceId);
+    }
     if (!success) {
-      freeCallback(eventType, eventData);
+      if (freeCallback != nullptr) {
+        freeCallback(eventType, eventData);
+      }
       LOGE("Failed to allocate event 0x%" PRIx16 " to instanceId %" PRIu32,
            eventType, targetInstanceId);
     }
@@ -286,7 +292,7 @@
   };
 
   // Stop accepting new events and tell the main loop to finish.
-  postEvent(0, nullptr, callback, kSystemInstanceId, kSystemInstanceId);
+  postEventOrDie(0, nullptr, callback, kSystemInstanceId);
 }
 
 void EventLoop::onStopComplete() {
@@ -334,8 +340,15 @@
     uint32_t targetInstanceId) {
   bool success = false;
 
-  Event *event = mEventPool.allocate(eventType, eventData, freeCallback,
-                                     senderInstanceId, targetInstanceId);
+  Milliseconds receivedTime = Nanoseconds(SystemTime::getMonotonicTime());
+  // The event loop should never contain more than 65 seconds worth of data
+  // unless something has gone terribly wrong so use uint16_t to save space.
+  uint16_t receivedTimeMillis = receivedTime.getMilliseconds();
+
+  Event *event = mEventPool.allocate(eventType, receivedTimeMillis, eventData,
+                                     freeCallback, senderInstanceId,
+                                     targetInstanceId);
+
   if (event != nullptr) {
     success = mEvents.push(event);
   }
@@ -444,7 +457,7 @@
     info->version    = nanoapp.getAppVersion();
     info->instanceId = nanoapp.getInstanceId();
 
-    postEvent(eventType, info, freeEventDataCallback);
+    postEventOrDie(eventType, info, freeEventDataCallback);
   }
 }
 
diff --git a/core/event_loop_manager.cc b/core/event_loop_manager.cc
index 76983e4..86b3e41 100644
--- a/core/event_loop_manager.cc
+++ b/core/event_loop_manager.cc
@@ -83,6 +83,8 @@
 }
 
 void EventLoopManager::lateInit() {
+  mSensorRequestManager.init();
+
 #ifdef CHRE_GNSS_SUPPORT_ENABLED
   mGnssManager.init();
 #endif  // CHRE_GNSS_SUPPORT_ENABLED
diff --git a/core/gnss_manager.cc b/core/gnss_manager.cc
index a04c657..b80a478 100644
--- a/core/gnss_manager.cc
+++ b/core/gnss_manager.cc
@@ -107,8 +107,8 @@
 }
 
 void GnssSession::handleReportEvent(void *event) {
-  EventLoopManagerSingleton::get()->getEventLoop()
-      .postEvent(mReportEventType, event, freeReportEventCallback);
+  EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
+      mReportEventType, event, freeReportEventCallback);
 }
 
 void GnssSession::logStateToBuffer(
@@ -293,9 +293,10 @@
       event->reserved = 0;
       event->cookie = cookie;
 
-      eventPosted = EventLoopManagerSingleton::get()->getEventLoop()
-          .postEvent(CHRE_EVENT_GNSS_ASYNC_RESULT, event, freeEventDataCallback,
-                     kSystemInstanceId, instanceId);
+      eventPosted =
+          EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
+              CHRE_EVENT_GNSS_ASYNC_RESULT, event, freeEventDataCallback,
+              instanceId);
 
       if (!eventPosted) {
         memoryFree(event);
diff --git a/core/host_comms_manager.cc b/core/host_comms_manager.cc
index 1019628..eb58af5 100644
--- a/core/host_comms_manager.cc
+++ b/core/host_comms_manager.cc
@@ -89,9 +89,9 @@
     msgFromHost->fromHostData.message = msgFromHost->message.data();
     msgFromHost->fromHostData.hostEndpoint = hostEndpoint;
 
-    success = EventLoopManagerSingleton::get()->getEventLoop().postEvent(
+    success = EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
         CHRE_EVENT_MESSAGE_FROM_HOST, &msgFromHost->fromHostData,
-        freeMessageFromHostCallback, kSystemInstanceId, targetInstanceId);
+        freeMessageFromHostCallback, targetInstanceId);
   }
 
   if (!success && msgFromHost != nullptr) {
diff --git a/core/include/chre/core/audio_request_manager.h b/core/include/chre/core/audio_request_manager.h
index 0732168..90f85f6 100644
--- a/core/include/chre/core/audio_request_manager.h
+++ b/core/include/chre/core/audio_request_manager.h
@@ -183,6 +183,9 @@
     //! Whether or not the source is available. It is unavailable by default.
     bool available = false;
 
+    //! The timestamp when the last audio data event was received.
+    Nanoseconds lastEventTimestamp;
+
     //! The request to post the next event to.
     AudioRequest *nextAudioRequest = nullptr;
 
diff --git a/core/include/chre/core/event.h b/core/include/chre/core/event.h
index cc35386..9a7dd39 100644
--- a/core/include/chre/core/event.h
+++ b/core/include/chre/core/event.h
@@ -38,8 +38,8 @@
 
 class Event : public NonCopyable {
  public:
-  Event(uint16_t eventType, void *eventData,
-        chreEventCompleteFunction *freeCallback,
+  Event(uint16_t eventType_, uint16_t receivedTimeMillis_, void *eventData_,
+        chreEventCompleteFunction *freeCallback_,
         uint32_t senderInstanceId = kSystemInstanceId,
         uint32_t targetInstanceId = kBroadcastInstanceId);
 
@@ -58,6 +58,9 @@
   }
 
   const uint16_t eventType;
+  //! This value can serve as a proxy for how fast CHRE is processing events
+  //! in its queue by substracting the newest event timestamp by the oldest one.
+  const uint16_t receivedTimeMillis;
   void * const eventData;
   chreEventCompleteFunction * const freeCallback;
   const uint32_t senderInstanceId;
diff --git a/core/include/chre/core/event_loop.h b/core/include/chre/core/event_loop.h
index aa27d00..3fd7e3b 100644
--- a/core/include/chre/core/event_loop.h
+++ b/core/include/chre/core/event_loop.h
@@ -139,10 +139,22 @@
 
   /**
    * Posts an event to a nanoapp that is currently running (or all nanoapps if
-   * the target instance ID is kBroadcastInstanceId). If the senderInstanceId is
-   * kSystemInstanceId and the event fails to post, this is considered a fatal
+   * the target instance ID is kBroadcastInstanceId). A senderInstanceId cannot
+   * be provided to this method because it should only be used to post events
+   * sent by the system. If the event fails to post, this is considered a fatal
    * error.
    *
+   * @see postLowPriorityEventOrFree
+   */
+  bool postEventOrDie(uint16_t eventType, void *eventData,
+                      chreEventCompleteFunction *freeCallback,
+                      uint32_t targetInstanceId = kBroadcastInstanceId);
+
+  /**
+   * Posts an event to a nanoapp that is currently running (or all nanoapps if
+   * the target instance ID is kBroadcastInstanceId). If the event fails to
+   * post, it is freed with freeCallback.
+   *
    * This function is safe to call from any thread.
    *
    * @param eventType The type of data being posted.
@@ -152,26 +164,15 @@
    * @param senderInstanceId The instance ID of the sender of this event.
    * @param targetInstanceId The instance ID of the destination of this event.
    *
-   * @return true if the event was successfully added to the queue. Note that
-   *         unlike chreSendEvent, this does *not* invoke the free callback if
-   *         it failed to post the event.
+   * @return true if the event was successfully added to the queue.
    *
    * @see chreSendEvent
    */
-  bool postEvent(uint16_t eventType, void *eventData,
-                 chreEventCompleteFunction *freeCallback,
-                 uint32_t senderInstanceId = kSystemInstanceId,
-                 uint32_t targetInstanceId = kBroadcastInstanceId);
-
-  /**
-   * Post an event to a nanoapp. If it fails, free the event with freeCallback.
-   *
-   * @see postEvent
-   */
-  bool postEventOrFree(uint16_t eventType, void *eventData,
-                       chreEventCompleteFunction *freeCallback,
-                       uint32_t senderInstanceId = kSystemInstanceId,
-                       uint32_t targetInstanceId = kBroadcastInstanceId);
+  bool postLowPriorityEventOrFree(
+      uint16_t eventType, void *eventData,
+      chreEventCompleteFunction *freeCallback,
+      uint32_t senderInstanceId = kSystemInstanceId,
+      uint32_t targetInstanceId = kBroadcastInstanceId);
 
   /**
    * Returns a pointer to the currently executing Nanoapp, or nullptr if none is
@@ -262,9 +263,9 @@
   //! The maximum number of events that can be active in the system.
   static constexpr size_t kMaxEventCount = CHRE_MAX_EVENT_COUNT;
 
-  //! The minimum number of events to reserve in the event pool for system
-  //! events.
-  static constexpr size_t kMinReservedSystemEventCount = 16;
+  //! The minimum number of events to reserve in the event pool for high
+  //! priority events.
+  static constexpr size_t kMinReservedHighPriorityEventCount = 16;
 
   //! The maximum number of events that are awaiting to be scheduled. These
   //! events are in a queue to be distributed to apps.
@@ -320,7 +321,7 @@
    *
    * @return true if the event has been successfully allocated and posted.
    *
-   * @see postEvent and postEventOrFree
+   * @see postEventOrDie and postLowPriorityEventOrFree
    */
   bool allocateAndPostEvent(uint16_t eventType, void *eventData,
     chreEventCompleteFunction *freeCallback, uint32_t senderInstanceId,
diff --git a/core/include/chre/core/event_loop_manager.h b/core/include/chre/core/event_loop_manager.h
index 4242d2d..fb72fbf 100644
--- a/core/include/chre/core/event_loop_manager.h
+++ b/core/include/chre/core/event_loop_manager.h
@@ -87,8 +87,8 @@
    */
   void deferCallback(SystemCallbackType type, void *data,
                      SystemCallbackFunction *callback) {
-    mEventLoop.postEvent(static_cast<uint16_t>(type), data, callback,
-                         kSystemInstanceId, kSystemInstanceId);
+    mEventLoop.postEventOrDie(static_cast<uint16_t>(type), data, callback,
+                              kSystemInstanceId);
   }
 
   /**
diff --git a/core/include/chre/core/sensor_request_manager.h b/core/include/chre/core/sensor_request_manager.h
index 1d36b61..2e48938 100644
--- a/core/include/chre/core/sensor_request_manager.h
+++ b/core/include/chre/core/sensor_request_manager.h
@@ -21,6 +21,7 @@
 #include "chre/core/sensor.h"
 #include "chre/core/sensor_request.h"
 #include "chre/core/timer_pool.h"
+#include "chre/platform/atomic.h"
 #include "chre/platform/system_time.h"
 #include "chre/platform/system_timer.h"
 #include "chre/util/fixed_size_vector.h"
@@ -44,6 +45,12 @@
   ~SensorRequestManager();
 
   /**
+   * Initializes the underlying platform-specific sensors. Must be called
+   * prior to invoking any other methods in this class.
+   */
+  void init();
+
+  /**
    * Determines whether the runtime is aware of a given sensor type. The
    * supplied sensorHandle is only populated if the sensor type is known.
    *
@@ -172,6 +179,16 @@
   void handleFlushCompleteEvent(uint8_t errorCode, SensorType sensorType);
 
   /**
+   * Invoked by the PlatformSensor when a sensor event is received for a given
+   * sensor. This method should be invoked from the same thread.
+   *
+   * @param sensorType the type of sensor the sensor data corresponds to
+   * @param event the event data formatted as one of the chreSensorXXXData
+   *     defined in the CHRE API, implicitly specified by sensorType.
+   */
+  void handleSensorEvent(SensorType sensorType, void *event);
+
+  /**
    * Prints state in a string buffer. Must only be called from the context of
    * the main CHRE thread.
    *
@@ -200,6 +217,8 @@
     //! The timestamp at which this request should complete.
     Nanoseconds deadlineTimestamp = SystemTime::getMonotonicTime() +
         Nanoseconds(CHRE_SENSOR_FLUSH_COMPLETE_TIMEOUT_NS);
+    //! True if this flush request is active and is pending completion.
+    bool isActive = false;
   };
 
   /**
@@ -208,6 +227,8 @@
    */
   class SensorRequests {
    public:
+    SensorRequests() : mFlushRequestPending(false) {}
+
      /**
       * Initializes the sensor object. This method must only be invoked once
       * when the SensorRequestManager initializes.
@@ -234,6 +255,13 @@
     }
 
     /**
+     * @return true if the sensor is currently enabled.
+     */
+    bool isSensorEnabled() const {
+      return !mMultiplexer.getRequests().empty();
+    }
+
+    /**
      * @return A constant reference to the sensor object. This method has an
      * undefined behavior if isSensorSupported() is false.
      */
@@ -347,12 +375,25 @@
      *
      * @return An error code from enum chreError
      */
-    uint8_t makeFlushRequest(const FlushRequest& request);
+    uint8_t makeFlushRequest(FlushRequest& request);
 
     /**
-     * Cancels a timeout timer for a pending flush request.
+     * Clears any states (e.g. timeout timer and relevant flags) associated
+     * with a pending flush request.
      */
-    void cancelFlushTimer();
+    void clearPendingFlushRequest();
+
+    /**
+     * Cancels the pending timeout timer associated with a flush request.
+     */
+    void cancelPendingFlushRequestTimer();
+
+    /**
+     * @return true if a flush through makeFlushRequest is pending.
+     */
+    inline bool isFlushRequestPending() const {
+      return mFlushRequestPending;
+    }
 
    private:
     //! The sensor associated with this request multiplexer. If this Optional
@@ -366,12 +407,15 @@
     //! The timeout timer handle for the current flush request.
     TimerHandle mFlushRequestTimerHandle = CHRE_TIMER_INVALID;
 
+    //! True if a flush request is pending for this sensor.
+    AtomicBool mFlushRequestPending;
+
     /**
-     * @return true if a flush through makeFlushRequest is pending.
+     * Make a flush request through PlatformSensor.
+     *
+     * @return true if the flush request was successfully made.
      */
-    inline bool isFlushRequestPending() const {
-      return mFlushRequestTimerHandle != CHRE_TIMER_INVALID;
-    }
+    bool doMakeFlushRequest();
   };
 
   //! The list of sensor requests.
@@ -400,13 +444,22 @@
     uint32_t sensorHandle, uint8_t errorCode, const FlushRequest& request);
 
   /**
+   * Completes a flush request at the specified index by posting a
+   * CHRE_EVENT_SENSOR_FLUSH_COMPLETE event with the specified errorCode,
+   * removing the request from the queue, cleaning up states as necessary.
+   *
+   * @param index The index of the flush request.
+   * @param errorCode The error code to send the completion event with.
+   */
+  void completeFlushRequestAtIndex(size_t index, uint8_t errorCode);
+
+  /**
    * Dispatches the next flush request for the given sensor. If there are no
    * more pending flush requests, this method does nothing.
    *
-   * @param sensorHandle The handle of the sensor to apply a request for.
    * @param sensorType The corresponding sensor type.
    */
-  void dispatchNextFlushRequest(uint32_t sensorHandle, SensorType sensorType);
+  void dispatchNextFlushRequest(SensorType sensorType);
 
   /**
    * Handles a complete event for a sensor flush requested through flushAsync.
@@ -417,6 +470,16 @@
    * @param sensorType The SensorType of sensor that has completed the flush.
    */
   void handleFlushCompleteEventSync(uint8_t errorCode, SensorType sensorType);
+
+  /**
+   * Cancels all pending flush requests for a given sensor and nanoapp.
+   *
+   * @param sensorType The type of sensor to cancel requests for.
+   * @param nanoappInstanceId The ID of the nanoapp to cancel requests for,
+   *     kSystemInstanceId to remove requests for all nanoapps.
+   */
+  void cancelFlushRequests(
+      SensorType sensorType, uint32_t nanoappInstanceId = kSystemInstanceId);
 };
 
 }  // namespace chre
diff --git a/core/include/chre/core/sensor_type.h b/core/include/chre/core/sensor_type.h
index 1fb0492..ebb5e52 100644
--- a/core/include/chre/core/sensor_type.h
+++ b/core/include/chre/core/sensor_type.h
@@ -326,6 +326,18 @@
  */
 SensorType toUncalibratedSensorType(SensorType sensorType);
 
+/**
+ * @param sensorType The sensor type.
+ *
+ * @return true if the sensor type is for a valid sensor.
+ */
+inline bool isValidSensorType(SensorType sensorType) {
+  // TODO: Consider asserting that sensorType < SensorType::SENSOR_TYPE_COUNT
+  //       once assertion can be enabled without costing extra memory overhead.
+  return sensorType > SensorType::Unknown
+      && sensorType < SensorType::SENSOR_TYPE_COUNT;
+}
+
 }  // namespace chre
 
 #endif  // CHRE_CORE_SENSOR_TYPE_H_
diff --git a/core/init.cc b/core/init.cc
index 401c95a..01991df 100644
--- a/core/init.cc
+++ b/core/init.cc
@@ -17,7 +17,6 @@
 #include "chre/core/init.h"
 
 #include "chre/core/event_loop_manager.h"
-#include "chre/platform/platform_sensor.h"
 #include "chre/platform/system_time.h"
 #include "chre/util/singleton.h"
 
@@ -35,15 +34,10 @@
   LOGI("CHRE init, version: %s", kChreVersionString);
 
   SystemTime::init();
-  PlatformSensor::init();
   EventLoopManagerSingleton::init();
 }
 
 void deinit() {
-  PlatformSensor::deinit();
-
-  // EventLoopManager has to be the last one to deinit to handle callback
-  // functions in PlatformSensor potentially from a different thread.
   EventLoopManagerSingleton::deinit();
 
   LOGD("CHRE deinit");
diff --git a/core/sensor_request_manager.cc b/core/sensor_request_manager.cc
index ca3730c..4053569 100644
--- a/core/sensor_request_manager.cc
+++ b/core/sensor_request_manager.cc
@@ -19,8 +19,14 @@
 #include "chre_api/chre/version.h"
 #include "chre/core/event_loop_manager.h"
 #include "chre/platform/fatal_error.h"
+#include "chre/platform/shared/platform_sensor_util.h"
+#include "chre/util/nested_data_ptr.h"
 #include "chre/util/system/debug_dump.h"
 
+#define LOG_INVALID_SENSOR(x) \
+    LOGE("Invalid sensor type %" PRIu8 ": line %d", \
+         static_cast<uint8_t>(x), __LINE__)
+
 namespace chre {
 namespace {
 
@@ -51,17 +57,27 @@
   return success;
 }
 
-void flushTimerCallback(uint16_t /* eventType */, void * /* data */) {
-  // TODO: Fatal error here since some platforms may not be able to handle
-  //       timeouts gracefully. Modify this implementation to drop flush
-  //       requests and handle stale responses in the future appropriately.
-  FATAL_ERROR("Flush request timed out");
-}
-
 }  // namespace
 
 SensorRequestManager::SensorRequestManager() {
   mSensorRequests.resize(mSensorRequests.capacity());
+}
+
+SensorRequestManager::~SensorRequestManager() {
+  for (size_t i = 0; i < mSensorRequests.size(); i++) {
+    // Disable sensors that have been enabled previously.
+    if (mSensorRequests[i].isSensorSupported()) {
+      mSensorRequests[i].removeAll();
+    }
+  }
+
+  PlatformSensor::deinit();
+}
+
+void SensorRequestManager::init() {
+  // The Platform sensor must be initialized prior to interacting with any
+  // sensors.
+  PlatformSensor::init();
 
   DynamicVector<Sensor> sensors;
   sensors.reserve(8);  // Avoid some initial reallocation churn
@@ -74,8 +90,8 @@
       SensorType sensorType = sensors[i].getSensorType();
       size_t sensorIndex = getSensorTypeArrayIndex(sensorType);
 
-      if (sensorType == SensorType::Unknown) {
-        LOGE("Invalid sensor type");
+      if (!isValidSensorType(sensorType)) {
+        LOG_INVALID_SENSOR(sensorType);
       } else if (sensors[i].getMinInterval() == 0) {
         LOGE("Invalid sensor minInterval: %s", getSensorTypeName(sensorType));
       } else {
@@ -86,22 +102,13 @@
   }
 }
 
-SensorRequestManager::~SensorRequestManager() {
-  for (size_t i = 0; i < mSensorRequests.size(); i++) {
-    // Disable sensors that have been enabled previously.
-    if (mSensorRequests[i].isSensorSupported()) {
-      mSensorRequests[i].removeAll();
-    }
-  }
-}
-
 bool SensorRequestManager::getSensorHandle(SensorType sensorType,
                                            uint32_t *sensorHandle) const {
   CHRE_ASSERT(sensorHandle);
 
   bool sensorHandleIsValid = false;
-  if (sensorType == SensorType::Unknown) {
-    LOGW("Querying for unknown sensor type");
+  if (!isValidSensorType(sensorType)) {
+    LOG_INVALID_SENSOR(sensorType);
   } else {
     size_t sensorIndex = getSensorTypeArrayIndex(sensorType);
     sensorHandleIsValid = mSensorRequests[sensorIndex].isSensorSupported();
@@ -119,8 +126,8 @@
 
   // Validate the input to ensure that a valid handle has been provided.
   SensorType sensorType = getSensorTypeFromSensorHandle(sensorHandle);
-  if (sensorType == SensorType::Unknown) {
-    LOGW("Attempting to configure an invalid sensor handle");
+  if (!isValidSensorType(sensorType)) {
+    LOG_INVALID_SENSOR(sensorType);
     return false;
   }
 
@@ -151,6 +158,8 @@
       // unregistered from events of this type if this request was successful.
       success = requests.remove(requestIndex, &requestChanged);
       if (success) {
+        cancelFlushRequests(sensorType, nanoapp->getInstanceId());
+
         nanoapp->unregisterForBroadcastEvent(eventType);
 
         uint16_t biasEventType;
@@ -185,12 +194,11 @@
       }
 
       // Deliver last valid event to new clients of on-change sensors
-      if (sensorTypeIsOnChange(sensor.getSensorType())
-          && sensor.getLastEvent() != nullptr) {
-        EventLoopManagerSingleton::get()->getEventLoop()
-            .postEvent(getSampleEventTypeForSensorType(sensorType),
-                       sensor.getLastEvent(), nullptr, kSystemInstanceId,
-                       nanoapp->getInstanceId());
+      if (sensorTypeIsOnChange(sensor.getSensorType()) &&
+          sensor.getLastEvent() != nullptr) {
+        EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
+            getSampleEventTypeForSensorType(sensorType), sensor.getLastEvent(),
+            nullptr, nanoapp->getInstanceId());
       }
     }
   } else {
@@ -215,9 +223,8 @@
 
   // Validate the input to ensure that a valid handle has been provided.
   SensorType sensorType = getSensorTypeFromSensorHandle(sensorHandle);
-  if (sensorType == SensorType::Unknown) {
-    LOGW("Attempting to access sensor with an invalid handle %" PRIu32,
-         sensorHandle);
+  if (!isValidSensorType(sensorType)) {
+    LOG_INVALID_SENSOR(sensorType);
   } else {
     size_t sensorIndex = getSensorTypeArrayIndex(sensorType);
     if (!mSensorRequests[sensorIndex].isSensorSupported()) {
@@ -250,8 +257,8 @@
 
 bool SensorRequestManager::removeAllRequests(SensorType sensorType) {
   bool success = false;
-  if (sensorType == SensorType::Unknown) {
-    LOGW("Attempting to remove all requests of an invalid sensor type");
+  if (!isValidSensorType(sensorType)) {
+    LOG_INVALID_SENSOR(sensorType);
   } else {
     size_t sensorIndex = getSensorTypeArrayIndex(sensorType);
     SensorRequests& requests = mSensorRequests[sensorIndex];
@@ -265,6 +272,7 @@
       }
     }
 
+    cancelFlushRequests(sensorType);
     success = requests.removeAll();
   }
   return success;
@@ -272,10 +280,8 @@
 
 Sensor *SensorRequestManager::getSensor(SensorType sensorType) {
   Sensor *sensorPtr = nullptr;
-  if (sensorType == SensorType::Unknown
-      || sensorType >= SensorType::SENSOR_TYPE_COUNT) {
-    LOGW("Attempting to get Sensor of an invalid SensorType %d",
-         static_cast<int>(sensorType));
+  if (!isValidSensorType(sensorType)) {
+    LOG_INVALID_SENSOR(sensorType);
   } else {
     size_t sensorIndex = getSensorTypeArrayIndex(sensorType);
     if (mSensorRequests[sensorIndex].isSensorSupported()) {
@@ -291,9 +297,8 @@
 
   bool success = false;
   SensorType sensorType = getSensorTypeFromSensorHandle(sensorHandle);
-  if (sensorType == SensorType::Unknown) {
-    LOGW("Attempting to access sensor with an invalid handle %" PRIu32,
-         sensorHandle);
+  if (!isValidSensorType(sensorType)) {
+    LOG_INVALID_SENSOR(sensorType);
   } else {
     size_t sensorIndex = getSensorTypeArrayIndex(sensorType);
     if (mSensorRequests[sensorIndex].isSensorSupported()) {
@@ -306,9 +311,8 @@
 const DynamicVector<SensorRequest>& SensorRequestManager::getRequests(
     SensorType sensorType) const {
   size_t sensorIndex = 0;
-  if (sensorType == SensorType::Unknown
-      || sensorType >= SensorType::SENSOR_TYPE_COUNT) {
-    LOGW("Attempting to get requests of an invalid SensorType");
+  if (!isValidSensorType(sensorType)) {
+    LOG_INVALID_SENSOR(sensorType);
   } else {
     sensorIndex = getSensorTypeArrayIndex(sensorType);
   }
@@ -340,9 +344,8 @@
   bool success = false;
   if (bias != nullptr) {
     SensorType sensorType = getSensorTypeFromSensorHandle(sensorHandle);
-    if (sensorType == SensorType::Unknown) {
-      LOGW("Attempting to access sensor with an invalid handle %" PRIu32,
-           sensorHandle);
+    if (!isValidSensorType(sensorType)) {
+      LOG_INVALID_SENSOR(sensorType);
     } else {
       size_t sensorIndex = getSensorTypeArrayIndex(sensorType);
       if (mSensorRequests[sensorIndex].isSensorSupported()) {
@@ -361,7 +364,7 @@
   uint32_t nanoappInstanceId = nanoapp->getInstanceId();
   SensorType sensorType = getSensorTypeFromSensorHandle(sensorHandle);
   // NOTE: One-shot sensors do not support flush per API
-  if (sensorType == SensorType::Unknown || sensorTypeIsOneShot(sensorType)) {
+  if (!isValidSensorType(sensorType) || sensorTypeIsOneShot(sensorType)) {
     LOGE("Cannot flush for sensor type %" PRIu32,
          static_cast<uint32_t>(sensorType));
   } else if (mFlushRequestQueue.full()) {
@@ -381,33 +384,49 @@
 
 void SensorRequestManager::handleFlushCompleteEvent(
     uint8_t errorCode, SensorType sensorType) {
-  struct CallbackState {
-    uint8_t errorCode;
-    SensorType sensorType;
-  };
+  size_t sensorIndex = getSensorTypeArrayIndex(sensorType);
+  if (isValidSensorType(sensorType)
+      && mSensorRequests[sensorIndex].isFlushRequestPending()) {
 
-  // Enables passing data through void pointer to avoid allocation.
-  union NestedCallbackState {
-    void *eventData;
-    CallbackState callbackState;
-  };
-  static_assert(sizeof(NestedCallbackState) == sizeof(void *),
-                "Size of NestedCallbackState must equal that of void *");
+    // Cancel flush request timer before posting to the event queue to ensure
+    // a timeout event isn't processed by CHRE now that the complete event
+    // has been received.
+    mSensorRequests[sensorIndex].cancelPendingFlushRequestTimer();
 
-  NestedCallbackState state = {};
-  state.callbackState.errorCode = errorCode;
-  state.callbackState.sensorType = sensorType;
+    struct CallbackState {
+      uint8_t errorCode;
+      SensorType sensorType;
+    };
 
-  auto callback = [](uint16_t /* eventType */, void *eventData) {
-    NestedCallbackState nestedState;
-    nestedState.eventData = eventData;
-    EventLoopManagerSingleton::get()->getSensorRequestManager()
-        .handleFlushCompleteEventSync(nestedState.callbackState.errorCode,
-                                      nestedState.callbackState.sensorType);
-  };
+    NestedDataPtr<CallbackState> state = {};
+    state.data.errorCode = errorCode;
+    state.data.sensorType = sensorType;
 
-  EventLoopManagerSingleton::get()->deferCallback(
-      SystemCallbackType::SensorFlushComplete, state.eventData, callback);
+    auto callback = [](uint16_t /* eventType */, void *eventData) {
+      NestedDataPtr<CallbackState> nestedState;
+      nestedState.dataPtr = eventData;
+      EventLoopManagerSingleton::get()->getSensorRequestManager()
+          .handleFlushCompleteEventSync(nestedState.data.errorCode,
+                                        nestedState.data.sensorType);
+    };
+
+    EventLoopManagerSingleton::get()->deferCallback(
+        SystemCallbackType::SensorFlushComplete, state.dataPtr, callback);
+  }
+}
+
+void SensorRequestManager::handleSensorEvent(SensorType sensorType,
+                                             void *event) {
+  uint16_t eventType = getSampleEventTypeForSensorType(sensorType);
+  // Only allow dropping continuous sensor events since losing one-shot or
+  // on-change events could result in nanoapps stuck in a bad state.
+  if (sensorTypeIsContinuous(sensorType)) {
+    EventLoopManagerSingleton::get()->getEventLoop().postLowPriorityEventOrFree(
+        eventType, event, sensorDataEventFree);
+  } else {
+    EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
+        eventType, event, sensorDataEventFree);
+  }
 }
 
 void SensorRequestManager::logStateToBuffer(char *buffer, size_t *bufferPos,
@@ -416,7 +435,7 @@
   for (uint8_t i = 0; i < static_cast<uint8_t>(SensorType::SENSOR_TYPE_COUNT);
        i++) {
     SensorType sensor = static_cast<SensorType>(i);
-    if (sensor != SensorType::Unknown) {
+    if (isValidSensorType(sensor)) {
       for (const auto& request : getRequests(sensor)) {
         debugDumpPrint(buffer, bufferPos, bufferSize, " %s: mode=%d"
                        " interval(ns)=%" PRIu64 " latency(ns)=%"
@@ -441,25 +460,41 @@
     event->cookie = request.cookie;
     memset(event->reserved, 0, sizeof(event->reserved));
 
-    EventLoopManagerSingleton::get()->getEventLoop().postEventOrFree(
+    EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
         CHRE_EVENT_SENSOR_FLUSH_COMPLETE, event, freeEventDataCallback,
-        kSystemInstanceId, request.nanoappInstanceId);
+        request.nanoappInstanceId);
   }
 }
 
-void SensorRequestManager::dispatchNextFlushRequest(
-    uint32_t sensorHandle, SensorType sensorType) {
+void SensorRequestManager::completeFlushRequestAtIndex(
+    size_t index, uint8_t errorCode) {
+  if (index < mFlushRequestQueue.size()) {
+    const FlushRequest& request = mFlushRequestQueue[index];
+    SensorType sensorType = request.sensorType;
+    if (request.isActive) {
+      SensorRequests& requests = getSensorRequests(sensorType);
+      requests.clearPendingFlushRequest();
+    }
+
+    uint32_t sensorHandle;
+    if (getSensorHandle(sensorType, &sensorHandle)) {
+      postFlushCompleteEvent(sensorHandle, errorCode, request);
+    }
+    mFlushRequestQueue.erase(index);
+  }
+}
+
+void SensorRequestManager::dispatchNextFlushRequest(SensorType sensorType) {
   SensorRequests& requests = getSensorRequests(sensorType);
 
   for (size_t i = 0; i < mFlushRequestQueue.size(); i++) {
-    const FlushRequest& request = mFlushRequestQueue[i];
+    FlushRequest& request = mFlushRequestQueue[i];
     if (request.sensorType == sensorType) {
       uint8_t newRequestErrorCode = requests.makeFlushRequest(request);
       if (newRequestErrorCode == CHRE_ERROR_NONE) {
         break;
       } else {
-        postFlushCompleteEvent(sensorHandle, newRequestErrorCode, request);
-        mFlushRequestQueue.erase(i);
+        completeFlushRequestAtIndex(i,  newRequestErrorCode);
         i--;
       }
     }
@@ -469,22 +504,33 @@
 void SensorRequestManager::handleFlushCompleteEventSync(
     uint8_t errorCode, SensorType sensorType) {
   for (size_t i = 0; i < mFlushRequestQueue.size(); i++) {
-    const FlushRequest& request = mFlushRequestQueue[i];
-    if (request.sensorType == sensorType) {
-      uint32_t sensorHandle;
-      if (getSensorHandle(sensorType, &sensorHandle)) {
-        SensorRequests& requests = getSensorRequests(sensorType);
-        requests.cancelFlushTimer();
-
-        postFlushCompleteEvent(sensorHandle, errorCode, request);
-        mFlushRequestQueue.erase(i);
-        dispatchNextFlushRequest(sensorHandle, sensorType);
-      }
+    if (mFlushRequestQueue[i].sensorType == sensorType) {
+      completeFlushRequestAtIndex(i, errorCode);
+      dispatchNextFlushRequest(sensorType);
       break;
     }
   }
 }
 
+void SensorRequestManager::cancelFlushRequests(
+    SensorType sensorType, uint32_t nanoappInstanceId) {
+  bool removeAll = (nanoappInstanceId == kSystemInstanceId);
+  for (size_t i = 0; i < mFlushRequestQueue.size(); i++) {
+    const FlushRequest& request = mFlushRequestQueue[i];
+    if (request.sensorType == sensorType &&
+        (request.nanoappInstanceId == nanoappInstanceId || removeAll)) {
+      completeFlushRequestAtIndex(
+          i, CHRE_ERROR_FUNCTION_DISABLED /* errorCode */);
+      i--;
+    }
+  }
+
+  SensorRequests& requests = getSensorRequests(sensorType);
+  if (!requests.isFlushRequestPending()) {
+    dispatchNextFlushRequest(sensorType);
+  }
+}
+
 const SensorRequest *SensorRequestManager::SensorRequests::find(
     uint32_t instanceId, size_t *index) const {
   CHRE_ASSERT(index);
@@ -607,7 +653,7 @@
 }
 
 uint8_t SensorRequestManager::SensorRequests::makeFlushRequest(
-    const FlushRequest& request) {
+    FlushRequest& request) {
   uint8_t errorCode = CHRE_ERROR;
   if (!isSensorSupported()) {
     LOGE("Cannot flush on unsupported sensor");
@@ -621,13 +667,33 @@
            ": deadline exceeded", static_cast<uint32_t>(request.sensorType),
            request.nanoappInstanceId);
       errorCode = CHRE_ERROR_TIMEOUT;
-    } else if (mSensor->flushAsync()) {
+    } else if (doMakeFlushRequest()) {
       errorCode = CHRE_ERROR_NONE;
       Nanoseconds delay = deadline - now;
+      request.isActive = true;
+
+      NestedDataPtr<SensorType> nestedType = {};
+      nestedType.data = request.sensorType;
+
+      auto callback = [](uint16_t /* eventType */, void * eventData) {
+        LOGE("Flush request timed out.");
+        NestedDataPtr<SensorType> nestedType;
+        nestedType.dataPtr = eventData;
+        // Send a complete event, thus closing out this flush request. If the
+        // request that has just timed out receives a response later, this may
+        // inadvertently close out a new request before it has actually
+        // completed.
+        // TODO: Attach an ID to all flush requests / responses so stale
+        // responses can be properly dropped.
+        EventLoopManagerSingleton::get()->getSensorRequestManager()
+            .handleFlushCompleteEventSync(CHRE_ERROR_TIMEOUT,
+                                          nestedType.data);
+      };
+
       mFlushRequestTimerHandle =
           EventLoopManagerSingleton::get()->setDelayedCallback(
-              SystemCallbackType::SensorFlushTimeout, nullptr /* data */,
-              flushTimerCallback, delay);
+              SystemCallbackType::SensorFlushTimeout, nestedType.dataPtr,
+              callback, delay);
     }
   } else {
     // Flush request will be made once the pending request is completed.
@@ -639,10 +705,25 @@
   return errorCode;
 }
 
-void SensorRequestManager::SensorRequests::cancelFlushTimer() {
-  EventLoopManagerSingleton::get()->cancelDelayedCallback(
-      mFlushRequestTimerHandle);
-  mFlushRequestTimerHandle = CHRE_TIMER_INVALID;
+void SensorRequestManager::SensorRequests::clearPendingFlushRequest() {
+  cancelPendingFlushRequestTimer();
+  mFlushRequestPending = false;
+}
+
+void SensorRequestManager::SensorRequests::cancelPendingFlushRequestTimer() {
+  if (mFlushRequestTimerHandle != CHRE_TIMER_INVALID) {
+    EventLoopManagerSingleton::get()->cancelDelayedCallback(
+        mFlushRequestTimerHandle);
+    mFlushRequestTimerHandle = CHRE_TIMER_INVALID;
+  }
+}
+
+bool SensorRequestManager::SensorRequests::doMakeFlushRequest() {
+  // Set to true before making the request since it's a synchronous request
+  // and we may get the complete event before it returns.
+  mFlushRequestPending = true;
+  mFlushRequestPending = mSensor->flushAsync();
+  return mFlushRequestPending;
 }
 
 }  // namespace chre
diff --git a/core/timer_pool.cc b/core/timer_pool.cc
index c910d80..87d0f31 100644
--- a/core/timer_pool.cc
+++ b/core/timer_pool.cc
@@ -223,11 +223,10 @@
     TimerRequest& currentTimerRequest = mTimerRequests.top();
     if (currentTime >= currentTimerRequest.expirationTime) {
       // Post an event for an expired timer.
-      success = EventLoopManagerSingleton::get()->getEventLoop().postEvent(
+      success = EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
           currentTimerRequest.eventType,
           const_cast<void *>(currentTimerRequest.cookie),
-          currentTimerRequest.callback, kSystemInstanceId,
-          currentTimerRequest.instanceId);
+          currentTimerRequest.callback, currentTimerRequest.instanceId);
 
       // Reschedule the timer if needed, and release the current request.
       if (!currentTimerRequest.isOneShot) {
diff --git a/core/wifi_request_manager.cc b/core/wifi_request_manager.cc
index 549c35d..51b3b25 100644
--- a/core/wifi_request_manager.cc
+++ b/core/wifi_request_manager.cc
@@ -380,9 +380,10 @@
       event->cookie = cookie;
 
       // Post the event.
-      eventPosted = EventLoopManagerSingleton::get()->getEventLoop()
-          .postEvent(CHRE_EVENT_WIFI_ASYNC_RESULT, event, freeEventDataCallback,
-                     kSystemInstanceId, nanoappInstanceId);
+      eventPosted =
+          EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
+              CHRE_EVENT_WIFI_ASYNC_RESULT, event, freeEventDataCallback,
+              nanoappInstanceId);
       if (!eventPosted) {
         memoryFree(event);
       }
@@ -416,9 +417,10 @@
     event->cookie = cookie;
 
     // Post the event.
-    eventPosted = EventLoopManagerSingleton::get()->getEventLoop()
-        .postEvent(CHRE_EVENT_WIFI_ASYNC_RESULT, event, freeEventDataCallback,
-                   kSystemInstanceId, nanoappInstanceId);
+    eventPosted =
+        EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
+            CHRE_EVENT_WIFI_ASYNC_RESULT, event, freeEventDataCallback,
+            nanoappInstanceId);
   }
 
   return eventPosted;
@@ -434,8 +436,8 @@
 }
 
 void WifiRequestManager::postScanEventFatal(chreWifiScanEvent *event) {
-  EventLoopManagerSingleton::get()->getEventLoop()
-      .postEvent(CHRE_EVENT_WIFI_SCAN_RESULT, event, freeWifiScanEventCallback);
+  EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
+      CHRE_EVENT_WIFI_SCAN_RESULT, event, freeWifiScanEventCallback);
 }
 
 void WifiRequestManager::handleScanMonitorStateChangeSync(bool enabled,
@@ -556,9 +558,10 @@
       event->reserved = 0;
       event->cookie = req.cookie;
 
-      eventPosted = EventLoopManagerSingleton::get()->getEventLoop().postEvent(
-          CHRE_EVENT_WIFI_ASYNC_RESULT, event, freeEventDataCallback,
-          kSystemInstanceId, req.nanoappInstanceId);
+      eventPosted =
+          EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
+              CHRE_EVENT_WIFI_ASYNC_RESULT, event, freeEventDataCallback,
+              req.nanoappInstanceId);
       if (!eventPosted) {
         memoryFree(event);
       }
@@ -593,9 +596,9 @@
     if (errorCode != CHRE_ERROR_NONE) {
       LOGW("RTT ranging failed with error %d", errorCode);
     } else {
-      EventLoopManagerSingleton::get()->getEventLoop().postEvent(
+      EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
           CHRE_EVENT_WIFI_RANGING_RESULT, event, freeWifiRangingEventCallback,
-          kSystemInstanceId, mPendingRangingRequests.front().nanoappInstanceId);
+          mPendingRangingRequests.front().nanoappInstanceId);
     }
     mPendingRangingRequests.pop();
   }
diff --git a/core/wwan_request_manager.cc b/core/wwan_request_manager.cc
index 3784566..4cf8243 100644
--- a/core/wwan_request_manager.cc
+++ b/core/wwan_request_manager.cc
@@ -65,10 +65,9 @@
     chreWwanCellInfoResult *result) {
   if (mCellInfoRequestingNanoappInstanceId.has_value()) {
     result->cookie = mCellInfoRequestingNanoappCookie;
-    EventLoopManagerSingleton::get()->getEventLoop()
-        .postEvent(CHRE_EVENT_WWAN_CELL_INFO_RESULT, result,
-                   freeCellInfoResultCallback, kSystemInstanceId,
-                   mCellInfoRequestingNanoappInstanceId.value());
+    EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
+        CHRE_EVENT_WWAN_CELL_INFO_RESULT, result, freeCellInfoResultCallback,
+        mCellInfoRequestingNanoappInstanceId.value());
   } else {
     LOGE("Cell info results received unexpectedly");
   }
diff --git a/host/msm/daemon/chre_daemon.cc b/host/msm/daemon/chre_daemon.cc
index 74e7113..e6b8bc5 100644
--- a/host/msm/daemon/chre_daemon.cc
+++ b/host/msm/daemon/chre_daemon.cc
@@ -81,6 +81,7 @@
 #include <hardware_legacy/power.h>
 
 using android::sp;
+using android::wp;
 using android::hardware::Return;
 using android::hardware::soundtrigger::V2_0::ISoundTriggerHw;
 using android::hardware::soundtrigger::V2_0::SoundModelHandle;
@@ -115,15 +116,32 @@
 //! The name of the wakelock to use for the CHRE daemon.
 static const char kWakeLockName[] = "chre_daemon";
 
+//! Forward declarations
+static void onStHalServiceDeath();
+
+//! Class to handle when a connected ST HAL service dies.
+class StHalDeathRecipient : public android::hardware::hidl_death_recipient {
+  virtual void serviceDied(
+      uint64_t /* cookie */,
+      const wp<::android::hidl::base::V1_0::IBase>& /* who */) override {
+    LOGE("ST HAL service died.");
+    onStHalServiceDeath();
+  }
+};
+
 struct LpmaEnableThreadData {
   pthread_t thread;
   pthread_mutex_t mutex;
   pthread_cond_t cond;
   bool currentLpmaEnabled;
   bool targetLpmaEnabled;
+  bool connectedToService;
+  sp<StHalDeathRecipient> deathRecipient = new StHalDeathRecipient();
+  sp<ISoundTriggerHw> stHalService;
 };
 
 static LpmaEnableThreadData lpmaEnableThread;
+
 #endif  // CHRE_DAEMON_LPMA_ENABLED
 
 //! The host ID to use when preloading nanoapps. This is used before the server
@@ -275,7 +293,13 @@
   return timeOffset;
 }
 
-static void sendTimeSyncMessage() {
+
+/**
+ * @param logOnError If true, logs an error message on failure.
+ *
+ * @return true if the time sync message was successfully sent to CHRE.
+ */
+static bool sendTimeSyncMessage(bool logOnError) {
   bool timeSyncSuccess = true;
   int64_t timeOffset = getTimeOffset(&timeSyncSuccess);
 
@@ -287,9 +311,36 @@
         static_cast<int>(builder.GetSize()));
 
     if (success != 0) {
-      LOGE("Failed to deliver timestamp message from host to CHRE: %d", success);
+      if (logOnError) {
+        LOGE("Failed to deliver time sync message from host to CHRE: %d",
+             success);
+      }
+      timeSyncSuccess = false;
     }
   }
+
+  return timeSyncSuccess;
+}
+
+/**
+ * Sends a time sync message to CHRE, retrying a specified time until success.
+ *
+ * @param maxNumRetries The number of times to retry sending the message
+ *
+ * @return true if the time sync message was successfully sent to CHRE.
+ */
+static bool sendTimeSyncMessageRetry(size_t maxNumRetries) {
+  size_t numRetries = 0;
+  useconds_t retryDelayUs = 50000; // 50 ms initially
+  bool success = sendTimeSyncMessage(numRetries == maxNumRetries);
+  while (!success && numRetries < maxNumRetries) {
+    usleep(retryDelayUs);
+    numRetries++;
+    retryDelayUs *= 2;
+    success = sendTimeSyncMessage(numRetries == maxNumRetries);
+  }
+
+  return success;
 }
 
 #ifdef CHRE_DAEMON_LPMA_ENABLED
@@ -326,6 +377,38 @@
   pthread_cond_signal(&lpmaEnableThread.cond);
 }
 
+static void onStHalServiceDeath() {
+  pthread_mutex_lock(&lpmaEnableThread.mutex);
+  lpmaEnableThread.connectedToService = false;
+  if (lpmaEnableThread.targetLpmaEnabled) {
+    // ST HAL has died, so assume that the sound model is no longer active,
+    // and trigger a reload of the sound model.
+    lpmaEnableThread.currentLpmaEnabled = false;
+    pthread_cond_signal(&lpmaEnableThread.cond);
+  }
+  pthread_mutex_unlock(&lpmaEnableThread.mutex);
+}
+
+/**
+ * Connects to the ST HAL service, if not already. This method should only
+ * be invoked after acquiring the lpmaEnableThread.mutex lock.
+ *
+ * @return true if successfully connected to the HAL.
+ */
+static bool connectToStHalServiceLocked() {
+  if (!lpmaEnableThread.connectedToService) {
+    lpmaEnableThread.stHalService = ISoundTriggerHw::getService();
+    if (lpmaEnableThread.stHalService != nullptr) {
+      LOGI("Connected to ST HAL service");
+      lpmaEnableThread.connectedToService = true;
+      lpmaEnableThread.stHalService->linkToDeath(
+          lpmaEnableThread.deathRecipient, 0 /* flags */);
+    }
+  }
+
+  return lpmaEnableThread.connectedToService;
+}
+
 /**
  * Loads the LPMA use case via the SoundTrigger HAL HIDL service.
  *
@@ -348,12 +431,12 @@
   soundModel.data.resize(1);  // Insert a dummy byte to bypass HAL NULL checks.
 
   bool loaded = false;
-  sp<ISoundTriggerHw> stHal = ISoundTriggerHw::getService();
-  if (stHal == nullptr) {
+  if (!connectToStHalServiceLocked()) {
     LOGE("Failed to get ST HAL service for LPMA load");
   } else {
     int32_t loadResult;
-    Return<void> hidlResult = stHal->loadSoundModel(soundModel, NULL, 0,
+    Return<void> hidlResult = lpmaEnableThread.stHalService->loadSoundModel(
+        soundModel, NULL /* callback */, 0 /* cookie */,
         [&](int32_t retval, SoundModelHandle handle) {
             loadResult = retval;
             *lpmaHandle = handle;
@@ -389,11 +472,11 @@
 static void unloadLpma(SoundModelHandle lpmaHandle) {
   LOGD("Unloading LPMA");
 
-  sp<ISoundTriggerHw> stHal = ISoundTriggerHw::getService();
-  if (stHal == nullptr) {
+  if (!connectToStHalServiceLocked()) {
     LOGE("Failed to get ST HAL service for LPMA unload");
   } else {
-    Return<int32_t> hidlResult = stHal->unloadSoundModel(lpmaHandle);
+    Return<int32_t> hidlResult =
+        lpmaEnableThread.stHalService->unloadSoundModel(lpmaHandle);
 
     if (hidlResult.isOk()) {
       if (hidlResult == 0) {
@@ -762,7 +845,7 @@
       if (messageType == fbs::ChreMessage::LogMessage) {
         parseAndEmitLogMessages(messageBuffer);
       } else if (messageType == fbs::ChreMessage::TimeSyncRequest) {
-        sendTimeSyncMessage();
+        sendTimeSyncMessage(true /* logOnError */);
 #ifdef CHRE_DAEMON_LPMA_ENABLED
       } else if (messageType == fbs::ChreMessage::LowPowerMicAccessRequest) {
         setLpmaState(true);
@@ -905,15 +988,19 @@
   }
 #endif  // ADSPRPC
 
-  if (!init_reverse_monitor(&reverse_monitor)) {
+  // Send time sync message before nanoapps start, retrying a few times
+  // in case the SLPI is not ready yet. This retry logic must be placed before
+  // any of the other FastRPC method invocations.
+  constexpr size_t kMaxNumRetries = 5;
+  if (!sendTimeSyncMessageRetry(kMaxNumRetries)) {
+    LOGE("Failed to send initial time sync message");
+  } else if (!init_reverse_monitor(&reverse_monitor)) {
     LOGE("Couldn't initialize reverse monitor");
 #ifdef CHRE_DAEMON_LPMA_ENABLED
   } else if (!initLpmaEnableThread(&lpmaEnableThread)) {
     LOGE("Couldn't initialize LPMA enable thread");
 #endif  // CHRE_DAEMON_LPMA_ENABLED
   } else {
-    // Send time offset message before nanoapps start
-    sendTimeSyncMessage();
     if ((ret = chre_slpi_start_thread()) != CHRE_FASTRPC_SUCCESS) {
       LOGE("Failed to start CHRE: %d", ret);
     } else {
diff --git a/platform/platform.mk b/platform/platform.mk
index 78a778b..2b0f74e 100644
--- a/platform/platform.mk
+++ b/platform/platform.mk
@@ -29,6 +29,7 @@
 SLPI_CFLAGS += -I$(SLPI_PREFIX)/core/api/systemdrivers
 SLPI_CFLAGS += -I$(SLPI_PREFIX)/platform/inc
 SLPI_CFLAGS += -I$(SLPI_PREFIX)/platform/inc/HAP
+SLPI_CFLAGS += -I$(SLPI_PREFIX)/platform/inc/a1std
 SLPI_CFLAGS += -I$(SLPI_PREFIX)/platform/inc/stddef
 SLPI_CFLAGS += -I$(SLPI_PREFIX)/platform/rtld/inc
 
diff --git a/platform/shared/chre_api_core.cc b/platform/shared/chre_api_core.cc
index fbf1e25..82f4ace 100644
--- a/platform/shared/chre_api_core.cc
+++ b/platform/shared/chre_api_core.cc
@@ -57,12 +57,9 @@
     LOGW("Rejecting event from app instance %" PRIu32 " because it's stopping",
          nanoapp->getInstanceId());
   } else {
-    success = eventLoop.postEvent(eventType, eventData, freeCallback,
-                                  nanoapp->getInstanceId(), targetInstanceId);
-  }
-
-  if (!success && freeCallback != nullptr) {
-    freeCallback(eventType, eventData);
+    success = eventLoop.postLowPriorityEventOrFree(
+        eventType, eventData, freeCallback, nanoapp->getInstanceId(),
+        targetInstanceId);
   }
   return success;
 }
diff --git a/platform/shared/include/chre/platform/shared/platform_sensor_util.h b/platform/shared/include/chre/platform/shared/platform_sensor_util.h
index 7bcb041..ad7ad8c 100644
--- a/platform/shared/include/chre/platform/shared/platform_sensor_util.h
+++ b/platform/shared/include/chre/platform/shared/platform_sensor_util.h
@@ -30,6 +30,20 @@
  */
 void updateLastEvent(SensorType sensorType, const void *eventData);
 
+/**
+ * A helper chreEventCompleteFunction that handles freeing sensor data and
+ * removing all requests associated with the sensor type if it represents a
+ * one-shot sensor.
+ *
+ * NOTE: This function assumes the eventData was allocated using the memoryAlloc
+ * platform function.
+ *
+ * @see postEvent
+ * @param eventType The type of sample event that eventData represents.
+ * @param eventData The sensor event data that should be freed.
+ */
+void sensorDataEventFree(uint16_t eventType, void *eventData);
+
 }  // namespace chre
 
 #endif  // CHRE_PLATFORM_SHARED_PLATFORM_SENSOR_UTIL_H_
diff --git a/platform/shared/platform_sensor_util.cc b/platform/shared/platform_sensor_util.cc
index 029c3b9..3aec295 100644
--- a/platform/shared/platform_sensor_util.cc
+++ b/platform/shared/platform_sensor_util.cc
@@ -67,4 +67,18 @@
   }
 }
 
+void sensorDataEventFree(uint16_t eventType, void *eventData) {
+  // TODO: Consider using a MemoryPool.
+  memoryFree(eventData);
+
+  // Remove all requests if it's a one-shot sensor and only after data has been
+  // delivered to all clients.
+  SensorType sensorType = getSensorTypeForSampleEventType(eventType);
+  if (sensorTypeIsOneShot(sensorType)) {
+    EventLoopManagerSingleton::get()
+        ->getSensorRequestManager()
+        .removeAllRequests(sensorType);
+  }
+}
+
 }  // namespace chre
diff --git a/platform/slpi/include/chre/platform/slpi/see/see_helper.h b/platform/slpi/include/chre/platform/slpi/see/see_helper.h
index 9d223a9..01bd5ee 100644
--- a/platform/slpi/include/chre/platform/slpi/see/see_helper.h
+++ b/platform/slpi/include/chre/platform/slpi/see/see_helper.h
@@ -81,7 +81,7 @@
 
 //! Default timeout for waitForService. Have a longer timeout since there may be
 //! external dependencies blocking SEE initialization.
-constexpr Nanoseconds kDefaultSeeWaitTimeout = Seconds(5);
+constexpr Nanoseconds kDefaultSeeWaitTimeout = Seconds(30);
 
 //! Default timeout for sendReq response
 constexpr Nanoseconds kDefaultSeeRespTimeout = Seconds(1);
diff --git a/platform/slpi/see/include/chre/target_platform/platform_sensor_base.h b/platform/slpi/see/include/chre/target_platform/platform_sensor_base.h
index 198e06d..47a5dbf 100644
--- a/platform/slpi/see/include/chre/target_platform/platform_sensor_base.h
+++ b/platform/slpi/see/include/chre/target_platform/platform_sensor_base.h
@@ -18,6 +18,7 @@
 #define CHRE_PLATFORM_SLPI_SEE_PLATFORM_SENSOR_BASE_H_
 
 #include "chre/core/sensor_request.h"
+#include "chre/platform/slpi/see/see_helper.h"
 
 namespace chre {
 
@@ -51,6 +52,10 @@
    */
   void setSamplingStatus(const struct chreSensorSamplingStatus& status);
 
+  //! Stores the last received sampling status from SEE for this sensor making
+  //! it easier to dedup updates that come in later from SEE.
+  SeeHelperCallbackInterface::SamplingStatusData mLastReceivedSamplingStatus {};
+
  protected:
   //! The sensor type of this sensor.
   SensorType mSensorType;
diff --git a/platform/slpi/see/platform_sensor.cc b/platform/slpi/see/platform_sensor.cc
index 16b6639..5d855e0 100644
--- a/platform/slpi/see/platform_sensor.cc
+++ b/platform/slpi/see/platform_sensor.cc
@@ -30,7 +30,6 @@
 #include "chre/platform/shared/platform_sensor_util.h"
 #include "chre/platform/slpi/power_control_util.h"
 #include "chre/platform/slpi/see/see_client.h"
-#include "chre/platform/slpi/see/see_helper.h"
 #include "chre/platform/system_time.h"
 
 #ifdef CHREX_SENSOR_SUPPORT
@@ -153,11 +152,12 @@
 void handleMissingSensor() {
   // Try rebooting if a sensor is missing, which might help recover from a
   // transient failure/race condition at startup. But to avoid endless crashes,
-  // only do this within the first 45 seconds after boot - we rely on knowledge
-  // that getMonotonicTime() maps into QTimer here, and QTimer only resets when
-  // the entire system is rebooted (it continues increasing after SLPI SSR).
+  // only do this within 15 seconds of the timeout on initializing SEE - we rely
+  // on knowledge that getMonotonicTime() maps into QTimer here, and QTimer only
+  // resets when the entire system is rebooted (it continues increasing after
+  // SLPI SSR).
 #ifndef CHRE_LOG_ONLY_NO_SENSOR
-  if (SystemTime::getMonotonicTime() < Seconds(45)) {
+  if (SystemTime::getMonotonicTime() < (kDefaultSeeWaitTimeout + Seconds(15))) {
     FATAL_ERROR("Missing required sensor(s)");
   } else
 #endif
@@ -212,18 +212,6 @@
   return sensorType;
 }
 
-void seeSensorDataEventFree(uint16_t eventType, void *eventData) {
-  memoryFree(eventData);
-
-  // Remove all requests if it's a one-shot sensor and only after data has been
-  // delivered to all clients.
-  SensorType sensorType = getSensorTypeForSampleEventType(eventType);
-  if (sensorTypeIsOneShot(sensorType)) {
-    EventLoopManagerSingleton::get()->getSensorRequestManager()
-        .removeAllRequests(sensorType);
-  }
-}
-
 /**
  * Posts a CHRE_EVENT_SENSOR_SAMPLING_CHANGE event to the specified Nanoapp.
  *
@@ -240,9 +228,9 @@
     event->sensorHandle = sensorHandle;
     event->status = status;
 
-    EventLoopManagerSingleton::get()->getEventLoop().postEventOrFree(
+    EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
         CHRE_EVENT_SENSOR_SAMPLING_CHANGE, event, freeEventDataCallback,
-        kSystemInstanceId, instanceId);
+        instanceId);
   }
 }
 
@@ -262,7 +250,7 @@
     } else {
       *event = bias;
       event->header.sensorHandle = getSensorHandleFromSensorType(sensorType);
-      EventLoopManagerSingleton::get()->getEventLoop().postEventOrFree(
+      EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
           eventType, event, freeEventDataCallback);
     }
   }
@@ -270,17 +258,19 @@
 
 /**
  * Updates the sampling status.
+ *
+ * This should only be called when the new SamplingStatusData is different
+ * from the most recently processed SamplingStatusData to avoid duplicate
+ * updates being posted to nanoapps.
  */
 void updateSamplingStatus(
     const SeeHelperCallbackInterface::SamplingStatusData& update) {
   Sensor *sensor = EventLoopManagerSingleton::get()->getSensorRequestManager()
       .getSensor(update.sensorType);
-  struct chreSensorSamplingStatus prevStatus;
+  struct chreSensorSamplingStatus newStatus;
 
   if (sensor != nullptr && !sensorTypeIsOneShot(update.sensorType)
-      && sensor->getSamplingStatus(&prevStatus)) {
-    struct chreSensorSamplingStatus newStatus = prevStatus;
-
+      && sensor->getSamplingStatus(&newStatus)) {
     if (update.enabledValid) {
       newStatus.enabled = update.status.enabled;
     }
@@ -291,35 +281,75 @@
       newStatus.latency = update.status.latency;
     }
 
-    if (newStatus.enabled != prevStatus.enabled ||
-        (newStatus.enabled && (newStatus.interval != prevStatus.interval
-                               || newStatus.latency != prevStatus.latency))) {
-      sensor->setSamplingStatus(newStatus);
+    sensor->setSamplingStatus(newStatus);
 
-      // Only post to Nanoapps with an open request.
-      uint32_t sensorHandle = getSensorHandleFromSensorType(update.sensorType);
-      const DynamicVector<SensorRequest>& requests =
-          EventLoopManagerSingleton::get()->getSensorRequestManager()
-          .getRequests(update.sensorType);
-      for (const auto& req : requests) {
-        postSamplingStatusEvent(req.getInstanceId(), sensorHandle, newStatus);
-      }
+    // Only post to Nanoapps with an open request.
+    uint32_t sensorHandle = getSensorHandleFromSensorType(update.sensorType);
+    const DynamicVector<SensorRequest>& requests =
+        EventLoopManagerSingleton::get()->getSensorRequestManager()
+        .getRequests(update.sensorType);
+    for (const auto& req : requests) {
+      postSamplingStatusEvent(req.getInstanceId(), sensorHandle, newStatus);
     }
   }
 }
 
+/**
+ * Compares the given status updates and returns true if they are the same.
+ *
+ * A simple memcmp cannot be done because if a given field is not valid, then
+ * the field may be different across updates, but doesn't indicate the update
+ * is different.
+ */
+bool isSameStatusUpdate(
+    const SeeHelperCallbackInterface::SamplingStatusData& status1,
+    const SeeHelperCallbackInterface::SamplingStatusData& status2) {
+  bool sameStatus = status1.enabledValid == status2.enabledValid;
+  if (sameStatus && status1.enabledValid) {
+    sameStatus &= status1.status.enabled == status2.status.enabled;
+  }
+
+  // Only check interval / latency fields if both status updates say the sensor
+  // is enabled since CHRE doesn't care what the fields are set to if the sensor
+  // is disabled.
+  if (sameStatus && status1.status.enabled) {
+    sameStatus &= status1.intervalValid == status2.intervalValid;
+    if (sameStatus && status1.intervalValid) {
+      sameStatus &= status1.status.interval == status2.status.interval;
+    }
+
+    sameStatus &= status1.latencyValid == status2.latencyValid;
+    if (sameStatus && status1.latencyValid) {
+      sameStatus &= status1.status.latency == status2.status.latency;
+    }
+  }
+
+  return sameStatus;
+}
+
 void SeeHelperCallback::onSamplingStatusUpdate(
     UniquePtr<SeeHelperCallbackInterface::SamplingStatusData>&& status) {
-  auto callback = [](uint16_t /* type */, void *data) {
-    auto cbData = UniquePtr<SeeHelperCallbackInterface::SamplingStatusData>(
-        static_cast<SeeHelperCallbackInterface::SamplingStatusData *>(data));
-    updateSamplingStatus(*cbData);
-  };
+  Sensor *sensor = EventLoopManagerSingleton::get()->getSensorRequestManager()
+      .getSensor(status->sensorType);
 
-  // Schedule a deferred callback to handle sensor status change in the main
-  // thread.
-  EventLoopManagerSingleton::get()->deferCallback(
-      SystemCallbackType::SensorStatusUpdate, status.release(), callback);
+  // TODO: Once the latency field is actually filled in by SEE, modify this
+  // logic to avoid reacting if the latency and interval of the sensor are
+  // updated separately, but contain the same info as before.
+  if (sensor != nullptr &&
+      !isSameStatusUpdate(sensor->mLastReceivedSamplingStatus, *status.get())) {
+    sensor->mLastReceivedSamplingStatus = *status.get();
+
+    auto callback = [](uint16_t /* type */, void *data) {
+      auto cbData = UniquePtr<SeeHelperCallbackInterface::SamplingStatusData>(
+          static_cast<SeeHelperCallbackInterface::SamplingStatusData *>(data));
+      updateSamplingStatus(*cbData);
+    };
+
+    // Schedule a deferred callback to handle sensor status change in the main
+    // thread.
+    EventLoopManagerSingleton::get()->deferCallback(
+        SystemCallbackType::SensorStatusUpdate, status.release(), callback);
+ }
 }
 
 void SeeHelperCallback::onSensorDataEvent(
@@ -330,9 +360,8 @@
     updateLastEvent(sensorType, eventData.get());
   }
 
-  uint16_t eventType = getSampleEventTypeForSensorType(sensorType);
-  EventLoopManagerSingleton::get()->getEventLoop().postEventOrFree(
-      eventType, eventData.get(), seeSensorDataEventFree);
+  EventLoopManagerSingleton::get()->getSensorRequestManager().handleSensorEvent(
+      sensorType, eventData.get());
   eventData.release();
 }
 
@@ -356,7 +385,7 @@
     // Posts a newly allocated event for the uncalibrated type
     postSensorBiasEvent(toUncalibratedSensorType(sensorType), *biasData.get());
 
-    EventLoopManagerSingleton::get()->getEventLoop().postEventOrFree(
+    EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
         eventType, biasData.release(), freeEventDataCallback);
   }
 }
diff --git a/platform/slpi/see/power_control_manager.cc b/platform/slpi/see/power_control_manager.cc
index a681a9c..8d2c97b 100644
--- a/platform/slpi/see/power_control_manager.cc
+++ b/platform/slpi/see/power_control_manager.cc
@@ -43,7 +43,7 @@
   if (mHostIsAwake != awake) {
     mHostIsAwake = awake;
 
-    EventLoopManagerSingleton::get()->getEventLoop().postEvent(
+    EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
         mHostIsAwake ? CHRE_EVENT_HOST_AWAKE : CHRE_EVENT_HOST_ASLEEP,
         nullptr /* eventData */, nullptr /* freeCallback */);
 
diff --git a/platform/slpi/smgr/platform_sensor.cc b/platform/slpi/smgr/platform_sensor.cc
index b8b90e9..3f7e609 100644
--- a/platform/slpi/smgr/platform_sensor.cc
+++ b/platform/slpi/smgr/platform_sensor.cc
@@ -532,21 +532,6 @@
   }
 }
 
-void smgrSensorDataEventFree(uint16_t eventType, void *eventData) {
-  // Events are allocated using the simple memoryAlloc/memoryFree platform
-  // functions.
-  // TODO: Consider using a MemoryPool.
-  memoryFree(eventData);
-
-  // Remove all requests if it's a one-shot sensor and only after data has been
-  // delivered to all clients.
-  SensorType sensorType = getSensorTypeForSampleEventType(eventType);
-  if (sensorTypeIsOneShot(sensorType)) {
-    EventLoopManagerSingleton::get()->getSensorRequestManager()
-        .removeAllRequests(sensorType);
-  }
-}
-
 /**
  * Handles sensor data provided by the SMGR framework.
  *
@@ -599,9 +584,9 @@
           updateLastEvent(sensorType, eventData);
         }
 
-        EventLoopManagerSingleton::get()->getEventLoop().postEventOrFree(
-            getSampleEventTypeForSensorType(sensorType), eventData,
-            smgrSensorDataEventFree);
+        EventLoopManagerSingleton::get()
+            ->getSensorRequestManager()
+            .handleSensorEvent(sensorType, eventData);
       }
     }
   }  // if (validReport)
@@ -871,9 +856,9 @@
     event->sensorHandle = sensorHandle;
     memcpy(&event->status, &status, sizeof(event->status));
 
-    EventLoopManagerSingleton::get()->getEventLoop().postEventOrFree(
+    EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
         CHRE_EVENT_SENSOR_SAMPLING_CHANGE, event, freeEventDataCallback,
-        kSystemInstanceId, instanceId);
+        instanceId);
   }
 }
 
@@ -933,7 +918,7 @@
   if (sensor == nullptr) {
     LOGE("Sensor ID: %" PRIu8 " in status update doesn't correspond to "
          "valid sensor.", sensorId);
-  // SMGR should send all callbacks back on the same thread which 
+  // SMGR should send all callbacks back on the same thread which
   // means the following code won't result in any timers overriding one
   // another.
   } else if (sensor->timerHandle.load() == CHRE_TIMER_INVALID) {
diff --git a/platform/slpi/smgr/power_control_manager.cc b/platform/slpi/smgr/power_control_manager.cc
index 5876268..c0e1f45 100644
--- a/platform/slpi/smgr/power_control_manager.cc
+++ b/platform/slpi/smgr/power_control_manager.cc
@@ -63,11 +63,11 @@
   EventLoopManagerSingleton::get()->getEventLoop()
       .getPowerControlManager().mHostIsAwake = !apSuspended;
   if (apSuspended) {
-    EventLoopManagerSingleton::get()->getEventLoop()
-        .postEvent(CHRE_EVENT_HOST_ASLEEP, nullptr, nullptr);
+    EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
+        CHRE_EVENT_HOST_ASLEEP, nullptr, nullptr);
   } else {
-    EventLoopManagerSingleton::get()->getEventLoop()
-        .postEvent(CHRE_EVENT_HOST_AWAKE, nullptr, nullptr);
+    EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
+        CHRE_EVENT_HOST_AWAKE, nullptr, nullptr);
   }
 }
 
diff --git a/util/include/chre/util/nested_data_ptr.h b/util/include/chre/util/nested_data_ptr.h
new file mode 100644
index 0000000..f4e4b2c
--- /dev/null
+++ b/util/include/chre/util/nested_data_ptr.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef UTIL_CHRE_NESTED_DATA_PTR_H_
+#define UTIL_CHRE_NESTED_DATA_PTR_H_
+
+namespace chre {
+
+/**
+ * A template that provides the ability to store data inside of a void pointer
+ * to avoid allocating space on the heap in the case where the data is smaller
+ * than the size of a void pointer.
+ */
+template<typename DataType>
+union NestedDataPtr {
+  NestedDataPtr() {
+    static_assert(sizeof(NestedDataPtr<DataType>) == sizeof(void *),
+                  "Size of NestedDataPtr must be equal to that of void *");
+  }
+  void *dataPtr;
+  DataType data;
+};
+
+}  // namespace chre
+
+#endif  // UTIL_CHRE_NESTED_DATA_PTR_H_
\ No newline at end of file