Merge changes from topics "FrameInfo", "_advanceFrame"

* changes:
  AImageDecoder: Add APIs for FrameInfo
  Add AImageDecoder _advanceFrame and _rewind
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index afa0b4d..c215c95 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -227,7 +227,6 @@
 static const std::string DUMP_HALS_TASK = "DUMP HALS";
 static const std::string DUMP_BOARD_TASK = "dumpstate_board()";
 static const std::string DUMP_CHECKINS_TASK = "DUMP CHECKINS";
-static const std::string DUMP_APP_INFOS_TASK = "DUMP APP INFOS";
 
 namespace android {
 namespace os {
@@ -1577,7 +1576,6 @@
         ds.dump_pool_->enqueueTask(DUMP_INCIDENT_REPORT_TASK, &DumpIncidentReport);
         ds.dump_pool_->enqueueTaskWithFd(DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
         ds.dump_pool_->enqueueTaskWithFd(DUMP_CHECKINS_TASK, &DumpCheckins, _1);
-        ds.dump_pool_->enqueueTaskWithFd(DUMP_APP_INFOS_TASK, &DumpAppInfos, _1);
     }
 
     // Dump various things. Note that anything that takes "long" (i.e. several seconds) should
@@ -1730,11 +1728,7 @@
         RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_CHECKINS_TASK, DumpCheckins);
     }
 
-    if (ds.dump_pool_) {
-        WAIT_TASK_WITH_CONSENT_CHECK(DUMP_APP_INFOS_TASK, ds.dump_pool_);
-    } else {
-        RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_APP_INFOS_TASK, DumpAppInfos);
-    }
+    RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpAppInfos);
 
     printf("========================================================\n");
     printf("== Dropbox crashes\n");
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index 1327cfd..a017246 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -427,7 +427,7 @@
                  << strerror(errno) << std::endl;
             status = -errno;
             break;
-        } else if (rc == 0) {
+        } else if (rc == 0 || time_left_ms() == 0) {
             status = TIMED_OUT;
             break;
         }
diff --git a/include/android/thermal.h b/include/android/thermal.h
index 83582d6..eb81534 100644
--- a/include/android/thermal.h
+++ b/include/android/thermal.h
@@ -53,7 +53,7 @@
 #include <sys/types.h>
 
 #if !defined(__INTRODUCED_IN)
-#define __INTRODUCED_IN(30) /* Introduced in API level 30 */
+#define __INTRODUCED_IN(__api_level) /* nothing */
 #endif
 
 #ifdef __cplusplus
@@ -181,6 +181,51 @@
 
 #endif  //  __ANDROID_API__ >= 30
 
+#if __ANDROID_API__ >= 31
+
+/**
+ * Provides an estimate of how much thermal headroom the device currently has before
+ * hitting severe throttling.
+ *
+ * Note that this only attempts to track the headroom of slow-moving sensors, such as
+ * the skin temperature sensor. This means that there is no benefit to calling this function
+ * more frequently than about once per second, and attempted to call significantly
+ * more frequently may result in the function returning {@code NaN}.
+ *
+ * In addition, in order to be able to provide an accurate forecast, the system does
+ * not attempt to forecast until it has multiple temperature samples from which to
+ * extrapolate. This should only take a few seconds from the time of the first call,
+ * but during this time, no forecasting will occur, and the current headroom will be
+ * returned regardless of the value of {@code forecastSeconds}.
+ *
+ * The value returned is a non-negative float that represents how much of the thermal envelope
+ * is in use (or is forecasted to be in use). A value of 1.0 indicates that the device is
+ * (or will be) throttled at {@link #THERMAL_STATUS_SEVERE}. Such throttling can affect the
+ * CPU, GPU, and other subsystems. Values may exceed 1.0, but there is no implied mapping
+ * to specific thermal levels beyond that point. This means that values greater than 1.0
+ * may correspond to {@link #THERMAL_STATUS_SEVERE}, but may also represent heavier throttling.
+ *
+ * A value of 0.0 corresponds to a fixed distance from 1.0, but does not correspond to any
+ * particular thermal status or temperature. Values on (0.0, 1.0] may be expected to scale
+ * linearly with temperature, though temperature changes over time are typically not linear.
+ * Negative values will be clamped to 0.0 before returning.
+ *
+ * Available since API level 31.
+ *
+ * @param manager The manager instance to use.
+ *                Acquired via {@link AThermal_acquireManager}.
+ * @param forecastSeconds how many seconds into the future to forecast. Given that device
+ *                        conditions may change at any time, forecasts from further in the
+ *                        future will likely be less accurate than forecasts in the near future.
+ * @return a value greater than equal to 0.0, where 1.0 indicates the SEVERE throttling threshold,
+ *         as described above. Returns NaN if the device does not support this functionality or
+ *         if this function is called significantly faster than once per second.
+  */
+float AThermal_getThermalHeadroom(AThermalManager *manager,
+        int forecastSeconds) __INTRODUCED_IN(31);
+
+#endif  //  __ANDROID_API__ >= 31
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/audiomanager/AudioManager.h b/include/audiomanager/AudioManager.h
index 639df7a..4aa2f60 100644
--- a/include/audiomanager/AudioManager.h
+++ b/include/audiomanager/AudioManager.h
@@ -37,6 +37,7 @@
     PLAYER_STATE_STARTED  = 2,
     PLAYER_STATE_PAUSED   = 3,
     PLAYER_STATE_STOPPED  = 4,
+    PLAYER_UPDATE_DEVICE_ID = 5,
 } player_state_t;
 
 // must be kept in sync with definitions in AudioManager.java
diff --git a/include/audiomanager/IAudioManager.h b/include/audiomanager/IAudioManager.h
index 2f5ccb8..7d1f38f 100644
--- a/include/audiomanager/IAudioManager.h
+++ b/include/audiomanager/IAudioManager.h
@@ -49,7 +49,8 @@
                 audio_content_type_t content, const sp<IBinder>& player) = 0;
     /*oneway*/ virtual status_t playerAttributes(audio_unique_id_t piid, audio_usage_t usage,
                 audio_content_type_t content)= 0;
-    /*oneway*/ virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event) = 0;
+    /*oneway*/ virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event,
+                audio_port_handle_t deviceId) = 0;
     /*oneway*/ virtual status_t releasePlayer(audio_unique_id_t piid) = 0;
     virtual audio_unique_id_t trackRecorder(const sp<IBinder>& recorder) = 0;
     /*oneway*/ virtual status_t recorderEvent(audio_unique_id_t riid, recorder_state_t event) = 0;
diff --git a/libs/adbd_auth/adbd_auth.cpp b/libs/adbd_auth/adbd_auth.cpp
index dae6eeb..15bd5c3 100644
--- a/libs/adbd_auth/adbd_auth.cpp
+++ b/libs/adbd_auth/adbd_auth.cpp
@@ -282,9 +282,8 @@
             LOG(FATAL) << "adbd_auth: unhandled packet type?";
         }
 
-        output_queue_.pop_front();
-
         ssize_t rc = writev(framework_fd_.get(), iovs, iovcnt);
+        output_queue_.pop_front();
         if (rc == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
             PLOG(ERROR) << "adbd_auth: failed to write to framework fd";
             ReplaceFrameworkFd(unique_fd());
diff --git a/libs/binder/include/binder/ParcelableHolder.h b/libs/binder/include/binder/ParcelableHolder.h
index 7024a4b..ff0a686 100644
--- a/libs/binder/include/binder/ParcelableHolder.h
+++ b/libs/binder/include/binder/ParcelableHolder.h
@@ -52,53 +52,59 @@
     }
 
     template <typename T>
-    bool setParcelable(T&& p) {
+    status_t setParcelable(T&& p) {
         using Tt = typename std::decay<T>::type;
         return setParcelable<Tt>(std::make_shared<Tt>(std::forward<T>(p)));
     }
 
     template <typename T>
-    bool setParcelable(std::shared_ptr<T> p) {
+    status_t setParcelable(std::shared_ptr<T> p) {
         static_assert(std::is_base_of<Parcelable, T>::value, "T must be derived from Parcelable");
         if (p && this->getStability() > p->getStability()) {
-            return false;
+            return android::BAD_VALUE;
         }
         this->mParcelable = p;
         this->mParcelableName = T::getParcelableDescriptor();
         this->mParcelPtr = nullptr;
-        return true;
+        return android::OK;
     }
 
     template <typename T>
-    std::shared_ptr<T> getParcelable() const {
+    status_t getParcelable(std::shared_ptr<T>* ret) const {
         static_assert(std::is_base_of<Parcelable, T>::value, "T must be derived from Parcelable");
         const std::string& parcelableDesc = T::getParcelableDescriptor();
         if (!this->mParcelPtr) {
             if (!this->mParcelable || !this->mParcelableName) {
                 ALOGD("empty ParcelableHolder");
-                return nullptr;
+                *ret = nullptr;
+                return android::OK;
             } else if (parcelableDesc != *mParcelableName) {
                 ALOGD("extension class name mismatch expected:%s actual:%s",
                       mParcelableName->c_str(), parcelableDesc.c_str());
-                return nullptr;
+                *ret = nullptr;
+                return android::BAD_VALUE;
             }
-            return std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+            *ret = std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+            return android::OK;
         }
         this->mParcelPtr->setDataPosition(0);
         status_t status = this->mParcelPtr->readUtf8FromUtf16(&this->mParcelableName);
         if (status != android::OK || parcelableDesc != this->mParcelableName) {
             this->mParcelableName = std::nullopt;
-            return nullptr;
+            *ret = nullptr;
+            return status;
         }
         this->mParcelable = std::make_shared<T>();
         status = mParcelable.get()->readFromParcel(this->mParcelPtr.get());
         if (status != android::OK) {
             this->mParcelableName = std::nullopt;
             this->mParcelable = nullptr;
-            return nullptr;
+            *ret = nullptr;
+            return status;
         }
         this->mParcelPtr = nullptr;
-        return std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+        *ret = std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
+        return android::OK;
     }
 
     Stability getStability() const override { return mStability; }
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
index e1d6c34..6636a41 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -82,34 +82,37 @@
     }
 
     template <typename T>
-    bool setParcelable(const T& p) {
+    binder_status_t setParcelable(const T& p) {
         if (this->mStability > T::_aidl_stability) {
-            return false;
+            return STATUS_BAD_VALUE;
         }
         AParcel_reset(mParcel.get());
         AParcel_writeString(mParcel.get(), T::descriptor, strlen(T::descriptor));
         p.writeToParcel(mParcel.get());
-        return true;
+        return STATUS_OK;
     }
 
     template <typename T>
-    std::unique_ptr<T> getParcelable() const {
+    binder_status_t getParcelable(std::optional<T>* ret) const {
         const std::string parcelableDesc(T::descriptor);
         AParcel_setDataPosition(mParcel.get(), 0);
         if (AParcel_getDataSize(mParcel.get()) == 0) {
-            return nullptr;
+            *ret = std::nullopt;
+            return STATUS_OK;
         }
         std::string parcelableDescInParcel;
         binder_status_t status = AParcel_readString(mParcel.get(), &parcelableDescInParcel);
         if (status != STATUS_OK || parcelableDesc != parcelableDescInParcel) {
-            return nullptr;
+            *ret = std::nullopt;
+            return status;
         }
-        std::unique_ptr<T> ret = std::make_unique<T>();
-        status = ret->readFromParcel(this->mParcel.get());
+        *ret = std::make_optional<T>();
+        status = (*ret)->readFromParcel(this->mParcel.get());
         if (status != STATUS_OK) {
-            return nullptr;
+            *ret = std::nullopt;
+            return status;
         }
-        return std::move(ret);
+        return STATUS_OK;
     }
 
     void reset() { AParcel_reset(mParcel.get()); }
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index af9ef06..7dd584d 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -38,9 +38,10 @@
 
 cc_library_shared {
     name: "libgui",
-    vendor_available: false,
+    vendor_available: true,
     vndk: {
         enabled: true,
+        private: true,
     },
     double_loadable: true,
 
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index ee5552f..eaa47f9 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -371,7 +371,7 @@
                                mPendingTransactions.end());
 
     if (applyTransaction) {
-        t->apply();
+        t->setApplyToken(mApplyToken).apply();
     }
 
     BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64
@@ -600,6 +600,14 @@
         return BufferQueueProducer::connect(new AsyncProducerListener(listener), api,
                                             producerControlledByApp, output);
     }
+
+    int query(int what, int* value) override {
+        if (what == NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER) {
+            *value = 1;
+            return NO_ERROR;
+        }
+        return BufferQueueProducer::query(what, value);
+    }
 };
 
 // Similar to BufferQueue::createBufferQueue but creates an adapter specific bufferqueue producer.
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 94390aa..1bba5e4 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -985,6 +985,10 @@
                 }
                 break;
             case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: {
+                status_t err = mGraphicBufferProducer->query(what, value);
+                if (err == NO_ERROR) {
+                    return NO_ERROR;
+                }
                 if (composerService()->authenticateSurfaceTexture(
                         mGraphicBufferProducer)) {
                     *value = 1;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 5570d99..97c2693 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -396,7 +396,8 @@
         mContainsBuffer(other.mContainsBuffer),
         mDesiredPresentTime(other.mDesiredPresentTime),
         mIsAutoTimestamp(other.mIsAutoTimestamp),
-        mFrameTimelineVsyncId(other.mFrameTimelineVsyncId) {
+        mFrameTimelineVsyncId(other.mFrameTimelineVsyncId),
+        mApplyToken(other.mApplyToken) {
     mDisplayStates = other.mDisplayStates;
     mComposerStates = other.mComposerStates;
     mInputWindowCommands = other.mInputWindowCommands;
@@ -427,7 +428,8 @@
     const int64_t desiredPresentTime = parcel->readInt64();
     const bool isAutoTimestamp = parcel->readBool();
     const int64_t frameTimelineVsyncId = parcel->readInt64();
-
+    sp<IBinder> applyToken;
+    parcel->readNullableStrongBinder(&applyToken);
     size_t count = static_cast<size_t>(parcel->readUint32());
     if (count > parcel->dataSize()) {
         return BAD_VALUE;
@@ -505,6 +507,7 @@
     mListenerCallbacks = listenerCallbacks;
     mComposerStates = composerStates;
     mInputWindowCommands = inputWindowCommands;
+    mApplyToken = applyToken;
     return NO_ERROR;
 }
 
@@ -532,6 +535,7 @@
     parcel->writeInt64(mDesiredPresentTime);
     parcel->writeBool(mIsAutoTimestamp);
     parcel->writeInt64(mFrameTimelineVsyncId);
+    parcel->writeStrongBinder(mApplyToken);
     parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size()));
     for (auto const& displayState : mDisplayStates) {
         displayState.write(*parcel);
@@ -607,6 +611,7 @@
     mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup;
     mExplicitEarlyWakeupStart = mExplicitEarlyWakeupStart || other.mExplicitEarlyWakeupStart;
     mExplicitEarlyWakeupEnd = mExplicitEarlyWakeupEnd || other.mExplicitEarlyWakeupEnd;
+    mApplyToken = other.mApplyToken;
 
     // When merging vsync Ids we take the oldest one
     if (mFrameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID &&
@@ -635,6 +640,7 @@
     mDesiredPresentTime = 0;
     mIsAutoTimestamp = true;
     mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID;
+    mApplyToken = nullptr;
 }
 
 void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) {
@@ -763,7 +769,10 @@
         flags |= ISurfaceComposer::eExplicitEarlyWakeupEnd;
     }
 
-    sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
+    sp<IBinder> applyToken = mApplyToken
+            ? mApplyToken
+            : IInterface::asBinder(TransactionCompletedListener::getIInstance());
+
     sf->setTransactionState(mFrameTimelineVsyncId, composerStates, displayStates, flags, applyToken,
                             mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp,
                             {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,
@@ -1579,6 +1588,12 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setApplyToken(
+        const sp<IBinder>& applyToken) {
+    mApplyToken = applyToken;
+    return *this;
+}
+
 // ---------------------------------------------------------------------------
 
 DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index c4cdb65..1198135 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -165,6 +165,10 @@
 
     std::function<void(int64_t)> mTransactionCompleteCallback GUARDED_BY(mMutex) = nullptr;
     uint64_t mTransactionCompleteFrameNumber GUARDED_BY(mMutex){0};
+
+    // Queues up transactions using this token in SurfaceFlinger. This prevents queued up
+    // transactions from other parts of the client from blocking this transaction.
+    const sp<IBinder> mApplyToken = new BBinder();
 };
 
 } // namespace android
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 0abe72c..48bc5d5 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -388,6 +388,10 @@
         // The vsync Id provided by Choreographer.getVsyncId
         int64_t mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID;
 
+        // If not null, transactions will be queued up using this token otherwise a common token
+        // per process will be used.
+        sp<IBinder> mApplyToken = nullptr;
+
         InputWindowCommands mInputWindowCommands;
         int mStatus = NO_ERROR;
 
@@ -555,6 +559,11 @@
         // in shared buffer mode.
         Transaction& setAutoRefresh(const sp<SurfaceControl>& sc, bool autoRefresh);
 
+        // Queues up transactions using this token in SurfaceFlinger.  By default, all transactions
+        // from a client are placed on the same queue. This can be used to prevent multiple
+        // transactions from blocking each other.
+        Transaction& setApplyToken(const sp<IBinder>& token);
+
         status_t setDisplaySurface(const sp<IBinder>& token,
                 const sp<IGraphicBufferProducer>& bufferProducer);
 
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 17f8b97..d69b7c3 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -24,6 +24,7 @@
 #include <gui/FrameTimestamps.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/IProducerListener.h>
+#include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 #include <gui/SyncScreenCaptureListener.h>
 #include <private/gui/ComposerService.h>
@@ -220,6 +221,32 @@
         return captureResults.result;
     }
 
+    void queueBuffer(sp<IGraphicBufferProducer> igbp, uint8_t r, uint8_t g, uint8_t b,
+                     nsecs_t presentTimeDelay) {
+        int slot;
+        sp<Fence> fence;
+        sp<GraphicBuffer> buf;
+        auto ret = igbp->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight,
+                                       PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                       nullptr, nullptr);
+        ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret);
+        ASSERT_EQ(OK, igbp->requestBuffer(slot, &buf));
+
+        uint32_t* bufData;
+        buf->lock(static_cast<uint32_t>(GraphicBuffer::USAGE_SW_WRITE_OFTEN),
+                  reinterpret_cast<void**>(&bufData));
+        fillBuffer(bufData, Rect(buf->getWidth(), buf->getHeight() / 2), buf->getStride(), r, g, b);
+        buf->unlock();
+
+        IGraphicBufferProducer::QueueBufferOutput qbOutput;
+        nsecs_t timestampNanos = systemTime() + presentTimeDelay;
+        IGraphicBufferProducer::QueueBufferInput input(timestampNanos, false, HAL_DATASPACE_UNKNOWN,
+                                                       Rect(mDisplayWidth, mDisplayHeight / 2),
+                                                       NATIVE_WINDOW_SCALING_MODE_FREEZE, 0,
+                                                       Fence::NO_FENCE);
+        igbp->queueBuffer(slot, input, &qbOutput);
+    }
+
     sp<SurfaceComposerClient> mClient;
     sp<ISurfaceComposer> mComposer;
 
@@ -515,6 +542,53 @@
     adapter.waitForCallbacks();
 }
 
+TEST_F(BLASTBufferQueueTest, QueryNativeWindowQueuesToWindowComposer) {
+    BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+
+    sp<android::Surface> surface = new Surface(adapter.getIGraphicBufferProducer());
+    ANativeWindow* nativeWindow = (ANativeWindow*)(surface.get());
+    int queuesToNativeWindow = 0;
+    int err = nativeWindow->query(nativeWindow, NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
+                                  &queuesToNativeWindow);
+    ASSERT_EQ(NO_ERROR, err);
+    ASSERT_EQ(queuesToNativeWindow, 1);
+}
+
+TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) {
+    sp<SurfaceControl> bgSurface =
+            mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+                                   ISurfaceComposerClient::eFXSurfaceBufferState);
+    ASSERT_NE(nullptr, bgSurface.get());
+    Transaction t;
+    t.setLayerStack(bgSurface, 0)
+            .show(bgSurface)
+            .setDataspace(bgSurface, ui::Dataspace::V0_SRGB)
+            .setFrame(bgSurface, Rect(0, 0, mDisplayWidth, mDisplayHeight))
+            .setLayer(bgSurface, std::numeric_limits<int32_t>::max() - 1)
+            .apply();
+
+    BLASTBufferQueueHelper slowAdapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+    sp<IGraphicBufferProducer> slowIgbProducer;
+    setUpProducer(slowAdapter, slowIgbProducer);
+    nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count();
+    queueBuffer(slowIgbProducer, 0 /* r */, 0 /* g */, 0 /* b */, presentTimeDelay);
+
+    BLASTBufferQueueHelper fastAdapter(bgSurface, mDisplayWidth, mDisplayHeight);
+    sp<IGraphicBufferProducer> fastIgbProducer;
+    setUpProducer(fastAdapter, fastIgbProducer);
+    uint8_t r = 255;
+    uint8_t g = 0;
+    uint8_t b = 0;
+    queueBuffer(fastIgbProducer, r, g, b, 0 /* presentTimeDelay */);
+    fastAdapter.waitForCallbacks();
+
+    // capture screen and verify that it is red
+    ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+
+    ASSERT_NO_FATAL_FAILURE(
+            checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
+}
+
 class BLASTBufferQueueTransformTest : public BLASTBufferQueueTest {
 public:
     void test(uint32_t tr) {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 3d6b7af..7567f05 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -418,6 +418,32 @@
     mProtectedTextureCache.erase(bufferId);
 }
 
+sk_sp<SkShader> SkiaGLRenderEngine::createRuntimeEffectShader(sk_sp<SkShader> shader,
+                                                              const LayerSettings* layer,
+                                                              const DisplaySettings& display,
+                                                              bool undoPremultipliedAlpha) {
+    if (mUseColorManagement &&
+        needsLinearEffect(layer->colorTransform, layer->sourceDataspace, display.outputDataspace)) {
+        LinearEffect effect = LinearEffect{.inputDataspace = layer->sourceDataspace,
+                                           .outputDataspace = display.outputDataspace,
+                                           .undoPremultipliedAlpha = undoPremultipliedAlpha};
+
+        auto effectIter = mRuntimeEffects.find(effect);
+        sk_sp<SkRuntimeEffect> runtimeEffect = nullptr;
+        if (effectIter == mRuntimeEffects.end()) {
+            runtimeEffect = buildRuntimeEffect(effect);
+            mRuntimeEffects.insert({effect, runtimeEffect});
+        } else {
+            runtimeEffect = effectIter->second;
+        }
+        return createLinearEffectShader(shader, effect, runtimeEffect, layer->colorTransform,
+                                        display.maxLuminance,
+                                        layer->source.buffer.maxMasteringLuminance,
+                                        layer->source.buffer.maxContentLuminance);
+    }
+    return shader;
+}
+
 status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
                                         const std::vector<const LayerSettings*>& layers,
                                         const sp<GraphicBuffer>& buffer,
@@ -624,41 +650,22 @@
                 shader = image->makeShader(SkSamplingOptions(), matrix);
             }
 
-            if (mUseColorManagement &&
-                needsLinearEffect(layer->colorTransform, layer->sourceDataspace,
-                                  display.outputDataspace)) {
-                LinearEffect effect = LinearEffect{.inputDataspace = layer->sourceDataspace,
-                                                   .outputDataspace = display.outputDataspace,
-                                                   .undoPremultipliedAlpha = !item.isOpaque &&
-                                                           item.usePremultipliedAlpha};
+            paint.setShader(
+                    createRuntimeEffectShader(shader, layer, display,
+                                              !item.isOpaque && item.usePremultipliedAlpha));
 
-                auto effectIter = mRuntimeEffects.find(effect);
-                sk_sp<SkRuntimeEffect> runtimeEffect = nullptr;
-                if (effectIter == mRuntimeEffects.end()) {
-                    runtimeEffect = buildRuntimeEffect(effect);
-                    mRuntimeEffects.insert({effect, runtimeEffect});
-                } else {
-                    runtimeEffect = effectIter->second;
-                }
-
-                paint.setShader(createLinearEffectShader(shader, effect, runtimeEffect,
-                                                         layer->colorTransform,
-                                                         display.maxLuminance,
-                                                         layer->source.buffer.maxMasteringLuminance,
-                                                         layer->source.buffer.maxContentLuminance));
-            } else {
-                paint.setShader(shader);
-            }
             // Make sure to take into the account the alpha set on the layer.
             paint.setAlphaf(layer->alpha);
         } else {
             ATRACE_NAME("DrawColor");
             const auto color = layer->source.solidColor;
-            paint.setShader(SkShaders::Color(SkColor4f{.fR = color.r,
-                                                       .fG = color.g,
-                                                       .fB = color.b,
-                                                       layer->alpha},
-                                             nullptr));
+            sk_sp<SkShader> shader = SkShaders::Color(SkColor4f{.fR = color.r,
+                                                                .fG = color.g,
+                                                                .fB = color.b,
+                                                                layer->alpha},
+                                                      nullptr);
+            paint.setShader(createRuntimeEffectShader(shader, layer, display,
+                                                      /* undoPremultipliedAlpha */ false));
         }
 
         paint.setColorFilter(SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform)));
@@ -672,13 +679,17 @@
                     ? getSkRect(layer->geometry.roundedCornersCrop)
                     : dest;
             drawShadow(canvas, rect, layer->geometry.roundedCornersRadius, layer->shadow);
+        } else {
+            // Shadows are assumed to live only on their own layer - it's not valid
+            // to draw the boundary retangles when there is already a caster shadow
+            // TODO(b/175915334): consider relaxing this restriction to enable more flexible
+            // composition - using a well-defined invalid color is long-term less error-prone.
+            // Push the clipRRect onto the clip stack. Draw the image. Pop the clip.
+            if (layer->geometry.roundedCornersRadius > 0) {
+                canvas->clipRRect(getRoundedRect(layer), true);
+            }
+            canvas->drawRect(dest, paint);
         }
-
-        // Push the clipRRect onto the clip stack. Draw the image. Pop the clip.
-        if (layer->geometry.roundedCornersRadius > 0) {
-            canvas->clipRRect(getRoundedRect(layer), true);
-        }
-        canvas->drawRect(dest, paint);
         canvas->restore();
     }
     canvas->restore();
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 3d8c693..5384ec8 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -91,6 +91,11 @@
     void drawBlurRegion(SkCanvas* canvas, const BlurRegion& blurRegion, const SkRect& layerRect,
                         sk_sp<SkSurface> blurredSurface);
     SkMatrix getBlurShaderTransform(const SkCanvas* canvas, const SkRect& layerRect);
+    // If mUseColorManagement is correct and layer needsLinearEffect, it returns a linear runtime
+    // shader. Otherwise it returns the input shader.
+    sk_sp<SkShader> createRuntimeEffectShader(sk_sp<SkShader> shader, const LayerSettings* layer,
+                                              const DisplaySettings& display,
+                                              bool undoPremultipliedAlpha);
 
     EGLDisplay mEGLDisplay;
     EGLContext mEGLContext;
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 47b8cad..15fb1b8 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -306,6 +306,26 @@
                           backgroundColor.a);
     }
 
+    void expectShadowColorWithoutCaster(const FloatRect& casterBounds,
+                                        const renderengine::ShadowSettings& shadow,
+                                        const ubyte4& backgroundColor) {
+        const float shadowInset = shadow.length * -1.0f;
+        const Rect casterRect(casterBounds);
+        const Rect shadowRect =
+                Rect(casterRect).inset(shadowInset, shadowInset, shadowInset, shadowInset);
+
+        const Region backgroundRegion =
+                Region(fullscreenRect()).subtractSelf(casterRect).subtractSelf(shadowRect);
+
+        expectAlpha(shadowRect, 255);
+        // (0, 0, 0) fill on the bounds of the layer should be ignored.
+        expectBufferColor(casterRect, 255, 255, 255, 255, 254);
+
+        // verify background
+        expectBufferColor(backgroundRegion, backgroundColor.r, backgroundColor.g, backgroundColor.b,
+                          backgroundColor.a);
+    }
+
     static renderengine::ShadowSettings getShadowSettings(const vec2& casterPos, float shadowLength,
                                                           bool casterIsTranslucent) {
         renderengine::ShadowSettings shadow;
@@ -447,6 +467,10 @@
                     const renderengine::ShadowSettings& shadow, const ubyte4& casterColor,
                     const ubyte4& backgroundColor);
 
+    void drawShadowWithoutCaster(const FloatRect& castingBounds,
+                                 const renderengine::ShadowSettings& shadow,
+                                 const ubyte4& backgroundColor);
+
     std::unique_ptr<renderengine::gl::GLESRenderEngine> mRE;
 
     // Dumb hack to avoid NPE in the EGL driver: the GraphicBuffer needs to
@@ -1119,6 +1143,37 @@
     invokeDraw(settings, layers, mBuffer);
 }
 
+void RenderEngineTest::drawShadowWithoutCaster(const FloatRect& castingBounds,
+                                               const renderengine::ShadowSettings& shadow,
+                                               const ubyte4& backgroundColor) {
+    renderengine::DisplaySettings settings;
+    settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+    settings.physicalDisplay = fullscreenRect();
+    settings.clip = fullscreenRect();
+
+    std::vector<const renderengine::LayerSettings*> layers;
+
+    // add background layer
+    renderengine::LayerSettings bgLayer;
+    bgLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+    bgLayer.geometry.boundaries = fullscreenRect().toFloatRect();
+    ColorSourceVariant::fillColor(bgLayer, backgroundColor.r / 255.0f, backgroundColor.g / 255.0f,
+                                  backgroundColor.b / 255.0f, this);
+    bgLayer.alpha = backgroundColor.a / 255.0f;
+    layers.push_back(&bgLayer);
+
+    // add shadow layer
+    renderengine::LayerSettings shadowLayer;
+    shadowLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+    shadowLayer.geometry.boundaries = castingBounds;
+    shadowLayer.alpha = 1.0f;
+    ColorSourceVariant::fillColor(shadowLayer, 0, 0, 0, this);
+    shadowLayer.shadow = shadow;
+    layers.push_back(&shadowLayer);
+
+    invokeDraw(settings, layers, mBuffer);
+}
+
 INSTANTIATE_TEST_SUITE_P(PerRenderEngineType, RenderEngineTest,
                          testing::Values(std::make_shared<GLESRenderEngineFactory>(),
                                          std::make_shared<GLESCMRenderEngineFactory>(),
@@ -1609,6 +1664,22 @@
     EXPECT_FALSE(mRE->isImageCachedForTesting(bufferId));
 }
 
+TEST_P(RenderEngineTest, drawLayers_fillShadow_castsWithoutCasterLayer) {
+    const auto& renderEngineFactory = GetParam();
+    mRE = renderEngineFactory->createRenderEngine();
+
+    const ubyte4 backgroundColor(255, 255, 255, 255);
+    const float shadowLength = 5.0f;
+    Rect casterBounds(DEFAULT_DISPLAY_WIDTH / 3.0f, DEFAULT_DISPLAY_HEIGHT / 3.0f);
+    casterBounds.offsetBy(shadowLength + 1, shadowLength + 1);
+    renderengine::ShadowSettings settings =
+            getShadowSettings(vec2(casterBounds.left, casterBounds.top), shadowLength,
+                              false /* casterIsTranslucent */);
+
+    drawShadowWithoutCaster(casterBounds.toFloatRect(), settings, backgroundColor);
+    expectShadowColorWithoutCaster(casterBounds.toFloatRect(), settings, backgroundColor);
+}
+
 TEST_P(RenderEngineTest, drawLayers_fillShadow_casterLayerMinSize) {
     const auto& renderEngineFactory = GetParam();
     mRE = renderEngineFactory->createRenderEngine();
diff --git a/opengl/Android.bp b/opengl/Android.bp
index 48abdce..8b94f61 100644
--- a/opengl/Android.bp
+++ b/opengl/Android.bp
@@ -54,6 +54,7 @@
 
 cc_library_headers {
     name: "gl_headers",
+    host_supported: true,
     vendor_available: true,
     export_include_dirs: ["include"],
 }
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index 398efc0..f576660 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -128,6 +128,7 @@
         "EGL_KHR_stream_producer_eglsurface "
         "EGL_KHR_surfaceless_context "
         "EGL_KHR_wait_sync "                    // strongly recommended
+        "EGL_NV_context_priority_realtime "
         "EGL_NV_system_time "
         ;
 
diff --git a/services/audiomanager/IAudioManager.cpp b/services/audiomanager/IAudioManager.cpp
index 6235f06..0d17265 100644
--- a/services/audiomanager/IAudioManager.cpp
+++ b/services/audiomanager/IAudioManager.cpp
@@ -84,11 +84,13 @@
         return remote()->transact(PLAYER_ATTRIBUTES, data, &reply, IBinder::FLAG_ONEWAY);
     }
 
-    virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event) {
+    virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event,
+            audio_port_handle_t deviceId) {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
         data.writeInt32((int32_t) piid);
         data.writeInt32((int32_t) event);
+        data.writeInt32((int32_t) deviceId);
         return remote()->transact(PLAYER_EVENT, data, &reply, IBinder::FLAG_ONEWAY);
     }
 
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index ac72ac4..3e6910d 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -54,10 +54,11 @@
     if (!hasEventHubDevices()) {
         return false;
     }
-    // devices are either all enabled or all disabled, so we only need to check the first
-    auto& devicePair = mDevices.begin()->second;
-    auto& contextPtr = devicePair.first;
-    return contextPtr->isDeviceEnabled();
+    // An input device composed of sub devices can be individually enabled or disabled.
+    // If any of the sub device is enabled then the input device is considered as enabled.
+    bool enabled = false;
+    for_each_subdevice([&enabled](auto& context) { enabled |= context.isDeviceEnabled(); });
+    return enabled;
 }
 
 void InputDevice::setEnabled(bool enabled, nsecs_t when) {
@@ -504,8 +505,7 @@
 }
 
 void InputDevice::notifyReset(nsecs_t when) {
-    NotifyDeviceResetArgs args(mContext->getNextId(), when, mId);
-    mContext->getListener()->notifyDeviceReset(&args);
+    mContext->notifyDeviceReset(when, mId);
 }
 
 std::optional<int32_t> InputDevice::getAssociatedDisplayId() {
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index be21ace..7c448e4 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -222,7 +222,9 @@
     }
 
     // Sensor input device is noisy, to save power disable it by default.
-    if (device->getClasses().test(InputDeviceClass::SENSOR)) {
+    // Input device is classified as SENSOR when any sub device is a SENSOR device, check Eventhub
+    // device class to disable SENSOR sub device only.
+    if (mEventHub->getDeviceClasses(eventHubId).test(InputDeviceClass::SENSOR)) {
         mEventHub->disableDevice(eventHubId);
     }
 }
@@ -337,8 +339,7 @@
     updateGlobalMetaStateLocked();
 
     // Enqueue configuration changed.
-    NotifyConfigurationChangedArgs args(mContext.getNextId(), when);
-    mQueuedListener->notifyConfigurationChanged(&args);
+    mContext.notifyConfigurationChanged(when);
 }
 
 void InputReader::refreshConfigurationLocked(uint32_t changes) {
@@ -365,9 +366,7 @@
     }
 
     if (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE) {
-        const NotifyPointerCaptureChangedArgs args(mContext.getNextId(), now,
-                                                   mConfig.pointerCapture);
-        mQueuedListener->notifyPointerCaptureChanged(&args);
+        mContext.notifyPointerCaptureChanged(now, mConfig.pointerCapture);
     }
 }
 
@@ -866,16 +865,64 @@
     return mReader->mPolicy.get();
 }
 
-InputListenerInterface* InputReader::ContextImpl::getListener() {
-    return mReader->mQueuedListener.get();
-}
-
 EventHubInterface* InputReader::ContextImpl::getEventHub() {
     return mReader->mEventHub.get();
 }
 
-int32_t InputReader::ContextImpl::getNextId() {
-    return mIdGenerator.nextId();
+void InputReader::ContextImpl::notifyConfigurationChanged(nsecs_t when) {
+    NotifyConfigurationChangedArgs args(mIdGenerator.nextId(), when);
+    mReader->mQueuedListener->notifyConfigurationChanged(&args);
+}
+
+void InputReader::ContextImpl::notifyKey(nsecs_t eventTime, int32_t deviceId, uint32_t source,
+                                         int32_t displayId, uint32_t policyFlags, int32_t action,
+                                         int32_t flags, int32_t keyCode, int32_t scanCode,
+                                         int32_t metaState, nsecs_t downTime) {
+    NotifyKeyArgs args(mIdGenerator.nextId(), eventTime, deviceId, source, displayId, policyFlags,
+                       action, flags, keyCode, scanCode, metaState, downTime);
+    mReader->mQueuedListener->notifyKey(&args);
+}
+void InputReader::ContextImpl::notifyMotion(
+        nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId,
+        uint32_t policyFlags, int32_t action, int32_t actionButton, int32_t flags,
+        int32_t metaState, int32_t buttonState, MotionClassification classification,
+        int32_t edgeFlags, uint32_t pointerCount, const PointerProperties* pointerProperties,
+        const PointerCoords* pointerCoords, float xPrecision, float yPrecision,
+        float xCursorPosition, float yCursorPosition, nsecs_t downTime,
+        const std::vector<TouchVideoFrame>& videoFrames) {
+    NotifyMotionArgs args(mIdGenerator.nextId(), eventTime, deviceId, source, displayId,
+                          policyFlags, action, actionButton, flags, metaState, buttonState,
+                          classification, edgeFlags, pointerCount, pointerProperties, pointerCoords,
+                          xPrecision, yPrecision, xCursorPosition, yCursorPosition, downTime,
+                          videoFrames);
+    mReader->mQueuedListener->notifyMotion(&args);
+}
+
+void InputReader::ContextImpl::notifySensor(nsecs_t when, int32_t deviceId,
+                                            InputDeviceSensorType sensorType,
+                                            InputDeviceSensorAccuracy accuracy,
+                                            bool accuracyChanged, nsecs_t timestamp,
+                                            std::vector<float> values) {
+    NotifySensorArgs args(mIdGenerator.nextId(), when, deviceId, AINPUT_SOURCE_SENSOR, sensorType,
+                          accuracy, accuracyChanged, timestamp, std::move(values));
+    mReader->mQueuedListener->notifySensor(&args);
+}
+
+void InputReader::ContextImpl::notifySwitch(nsecs_t eventTime, uint32_t switchValues,
+                                            uint32_t switchMask) {
+    NotifySwitchArgs args(mIdGenerator.nextId(), eventTime, 0 /*policyFlags*/, switchValues,
+                          switchMask);
+    mReader->mQueuedListener->notifySwitch(&args);
+}
+
+void InputReader::ContextImpl::notifyDeviceReset(nsecs_t when, int32_t deviceId) {
+    NotifyDeviceResetArgs args(mIdGenerator.nextId(), when, deviceId);
+    mReader->mQueuedListener->notifyDeviceReset(&args);
+}
+
+void InputReader::ContextImpl::notifyPointerCaptureChanged(nsecs_t when, bool hasCapture) {
+    const NotifyPointerCaptureChangedArgs args(mIdGenerator.nextId(), when, hasCapture);
+    mReader->mQueuedListener->notifyPointerCaptureChanged(&args);
 }
 
 } // namespace android
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 48d4596..7be932a 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -127,11 +127,30 @@
         void dispatchExternalStylusState(const StylusState& outState)
                 NO_THREAD_SAFETY_ANALYSIS override;
         InputReaderPolicyInterface* getPolicy() NO_THREAD_SAFETY_ANALYSIS override;
-        InputListenerInterface* getListener() NO_THREAD_SAFETY_ANALYSIS override;
         EventHubInterface* getEventHub() NO_THREAD_SAFETY_ANALYSIS override;
-        int32_t getNextId() NO_THREAD_SAFETY_ANALYSIS override;
         void updateLedMetaState(int32_t metaState) NO_THREAD_SAFETY_ANALYSIS override;
         int32_t getLedMetaState() NO_THREAD_SAFETY_ANALYSIS override;
+
+        // Send events to InputListener interface
+        void notifyConfigurationChanged(nsecs_t when) override;
+        void notifyKey(nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId,
+                       uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
+                       int32_t scanCode, int32_t metaState, nsecs_t downTime) override;
+        void notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId,
+                          uint32_t policyFlags, int32_t action, int32_t actionButton, int32_t flags,
+                          int32_t metaState, int32_t buttonState,
+                          MotionClassification classification, int32_t edgeFlags,
+                          uint32_t pointerCount, const PointerProperties* pointerProperties,
+                          const PointerCoords* pointerCoords, float xPrecision, float yPrecision,
+                          float xCursorPosition, float yCursorPosition, nsecs_t downTime,
+                          const std::vector<TouchVideoFrame>& videoFrames) override;
+        void notifySwitch(nsecs_t eventTime, uint32_t switchValues, uint32_t switchMask) override;
+        void notifySensor(nsecs_t when, int32_t deviceId, InputDeviceSensorType sensorType,
+                          InputDeviceSensorAccuracy accuracy, bool accuracyChanged,
+                          nsecs_t timestamp, std::vector<float> values) override;
+        void notifyDeviceReset(nsecs_t when, int32_t deviceId) override;
+        void notifyPointerCaptureChanged(nsecs_t when, bool hasCapture) override;
+
     } mContext;
 
     friend class ContextImpl;
diff --git a/services/inputflinger/reader/include/InputReaderContext.h b/services/inputflinger/reader/include/InputReaderContext.h
index dc807f7..edab312 100644
--- a/services/inputflinger/reader/include/InputReaderContext.h
+++ b/services/inputflinger/reader/include/InputReaderContext.h
@@ -55,13 +55,33 @@
     virtual void dispatchExternalStylusState(const StylusState& outState) = 0;
 
     virtual InputReaderPolicyInterface* getPolicy() = 0;
-    virtual InputListenerInterface* getListener() = 0;
     virtual EventHubInterface* getEventHub() = 0;
 
-    virtual int32_t getNextId() = 0;
-
     virtual void updateLedMetaState(int32_t metaState) = 0;
     virtual int32_t getLedMetaState() = 0;
+
+    // Send events to InputListener interface
+
+    virtual void notifyConfigurationChanged(nsecs_t when) = 0;
+    virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId,
+                           uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
+                           int32_t scanCode, int32_t metaState, nsecs_t downTime) = 0;
+    virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t source,
+                              int32_t displayId, uint32_t policyFlags, int32_t action,
+                              int32_t actionButton, int32_t flags, int32_t metaState,
+                              int32_t buttonState, MotionClassification classification,
+                              int32_t edgeFlags, uint32_t pointerCount,
+                              const PointerProperties* pointerProperties,
+                              const PointerCoords* pointerCoords, float xPrecision,
+                              float yPrecision, float xCursorPosition, float yCursorPosition,
+                              nsecs_t downTime,
+                              const std::vector<TouchVideoFrame>& videoFrames) = 0;
+    virtual void notifySwitch(nsecs_t eventTime, uint32_t switchValues, uint32_t switchMask) = 0;
+    virtual void notifySensor(nsecs_t when, int32_t deviceId, InputDeviceSensorType sensorType,
+                              InputDeviceSensorAccuracy accuracy, bool accuracyChanged,
+                              nsecs_t timestamp, std::vector<float> values) = 0;
+    virtual void notifyDeviceReset(nsecs_t when, int32_t deviceId) = 0;
+    virtual void notifyPointerCaptureChanged(nsecs_t when, bool hasCapture) = 0;
 };
 
 } // namespace android
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index 254b64b..7f7b33c 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -175,8 +175,7 @@
         }
         bumpGeneration();
         if (changes) {
-            NotifyDeviceResetArgs args(getContext()->getNextId(), when, getDeviceId());
-            getListener()->notifyDeviceReset(&args);
+            getContext()->notifyDeviceReset(when, getDeviceId());
         }
     }
 
@@ -383,40 +382,35 @@
             while (!released.isEmpty()) {
                 int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit());
                 buttonState &= ~actionButton;
-                NotifyMotionArgs releaseArgs(getContext()->getNextId(), when, getDeviceId(),
-                                             mSource, displayId, policyFlags,
-                                             AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
-                                             metaState, buttonState, MotionClassification::NONE,
-                                             AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
-                                             &pointerCoords, mXPrecision, mYPrecision,
-                                             xCursorPosition, yCursorPosition, downTime,
-                                             /* videoFrames */ {});
-                getListener()->notifyMotion(&releaseArgs);
+                getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
+                                           AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
+                                           metaState, buttonState, MotionClassification::NONE,
+                                           AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
+                                           &pointerCoords, mXPrecision, mYPrecision,
+                                           xCursorPosition, yCursorPosition, downTime,
+                                           /* videoFrames */ {});
             }
         }
 
-        NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
-                              policyFlags, motionEventAction, 0, 0, metaState, currentButtonState,
-                              MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
-                              &pointerProperties, &pointerCoords, mXPrecision, mYPrecision,
-                              xCursorPosition, yCursorPosition, downTime,
-                              /* videoFrames */ {});
-        getListener()->notifyMotion(&args);
+        getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
+                                   motionEventAction, 0, 0, metaState, currentButtonState,
+                                   MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+                                   &pointerProperties, &pointerCoords, mXPrecision, mYPrecision,
+                                   xCursorPosition, yCursorPosition, downTime,
+                                   /* videoFrames */ {});
 
         if (buttonsPressed) {
             BitSet32 pressed(buttonsPressed);
             while (!pressed.isEmpty()) {
                 int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit());
                 buttonState |= actionButton;
-                NotifyMotionArgs pressArgs(getContext()->getNextId(), when, getDeviceId(), mSource,
-                                           displayId, policyFlags,
+                getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
                                            AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
                                            metaState, buttonState, MotionClassification::NONE,
                                            AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
                                            &pointerCoords, mXPrecision, mYPrecision,
                                            xCursorPosition, yCursorPosition, downTime,
                                            /* videoFrames */ {});
-                getListener()->notifyMotion(&pressArgs);
             }
         }
 
@@ -424,13 +418,12 @@
 
         // Send hover move after UP to tell the application that the mouse is hovering now.
         if (motionEventAction == AMOTION_EVENT_ACTION_UP && (mSource == AINPUT_SOURCE_MOUSE)) {
-            NotifyMotionArgs hoverArgs(getContext()->getNextId(), when, getDeviceId(), mSource,
-                                       displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
-                                       0, metaState, currentButtonState, MotionClassification::NONE,
+            getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
+                                       AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
+                                       currentButtonState, MotionClassification::NONE,
                                        AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
                                        &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
                                        yCursorPosition, downTime, /* videoFrames */ {});
-            getListener()->notifyMotion(&hoverArgs);
         }
 
         // Send scroll events.
@@ -438,13 +431,12 @@
             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
 
-            NotifyMotionArgs scrollArgs(getContext()->getNextId(), when, getDeviceId(), mSource,
-                                        displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0,
-                                        metaState, currentButtonState, MotionClassification::NONE,
-                                        AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
-                                        &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
-                                        yCursorPosition, downTime, /* videoFrames */ {});
-            getListener()->notifyMotion(&scrollArgs);
+            getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
+                                       AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
+                                       currentButtonState, MotionClassification::NONE,
+                                       AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
+                                       &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
+                                       yCursorPosition, downTime, /* videoFrames */ {});
         }
     }
 
diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h
index bd64d8d..6ca6ec9 100644
--- a/services/inputflinger/reader/mapper/InputMapper.h
+++ b/services/inputflinger/reader/mapper/InputMapper.h
@@ -19,7 +19,6 @@
 
 #include "EventHub.h"
 #include "InputDevice.h"
-#include "InputListener.h"
 #include "InputReaderContext.h"
 #include "StylusState.h"
 #include "VibrationElement.h"
@@ -48,7 +47,6 @@
     inline const std::string getDeviceName() { return mDeviceContext.getName(); }
     inline InputReaderContext* getContext() { return mDeviceContext.getContext(); }
     inline InputReaderPolicyInterface* getPolicy() { return getContext()->getPolicy(); }
-    inline InputListenerInterface* getListener() { return getContext()->getListener(); }
 
     virtual uint32_t getSources() = 0;
     virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
index abd8aa9..ac4669c 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
@@ -337,13 +337,12 @@
     // TODO: Use the input device configuration to control this behavior more finely.
     uint32_t policyFlags = 0;
 
-    NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), AINPUT_SOURCE_JOYSTICK,
-                          ADISPLAY_ID_NONE, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
-                          buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
-                          &pointerProperties, &pointerCoords, 0, 0,
-                          AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                          AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
-    getListener()->notifyMotion(&args);
+    getContext()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE,
+                               policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,
+                               MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+                               &pointerProperties, &pointerCoords, 0, 0,
+                               AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                               AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
 }
 
 void JoystickInputMapper::setPointerCoordsAxisValue(PointerCoords* pointerCoords, int32_t axis,
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 8b9f235..03d7405 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -350,10 +350,9 @@
         policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
     }
 
-    NotifyKeyArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, getDisplayId(),
-                       policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
-                       AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
-    getListener()->notifyKey(&args);
+    getContext()->notifyKey(when, getDeviceId(), mSource, getDisplayId(), policyFlags,
+                            down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
+                            AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
 }
 
 ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) {
diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
index 594ff42..3f8a364 100644
--- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
@@ -121,13 +121,12 @@
         int32_t metaState = getContext()->getGlobalMetaState();
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SCROLL, scroll * mScalingFactor);
 
-        NotifyMotionArgs scrollArgs(getContext()->getNextId(), when, getDeviceId(), mSource,
-                                    displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0,
-                                    metaState, /* buttonState */ 0, MotionClassification::NONE,
-                                    AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
-                                    &pointerCoords, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                                    AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
-        getListener()->notifyMotion(&scrollArgs);
+        getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
+                                   AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
+                                   /* buttonState */ 0, MotionClassification::NONE,
+                                   AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
+                                   &pointerCoords, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                                   AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
     }
 
     mRotaryEncoderScrollAccumulator.finishSync();
diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.cpp b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
index 7ac2dec..68c1e40 100644
--- a/services/inputflinger/reader/mapper/SensorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
@@ -405,13 +405,10 @@
             // Convert to Android unit
             convertFromLinuxToAndroid(values, sensorType);
             // Notify dispatcher for sensor event
-            NotifySensorArgs args(getContext()->getNextId(), when, getDeviceId(),
-                                  AINPUT_SOURCE_SENSOR, sensorType, sensor.sensorInfo.accuracy,
-                                  sensor.accuracy !=
-                                          sensor.sensorInfo.accuracy /* accuracyChanged */,
-                                  timestamp /* hwTimestamp */, values);
-
-            getListener()->notifySensor(&args);
+            getContext()->notifySensor(when, getDeviceId(), sensorType, sensor.sensorInfo.accuracy,
+                                       sensor.accuracy !=
+                                               sensor.sensorInfo.accuracy /* accuracyChanged */,
+                                       timestamp /* hwTimestamp */, std::move(values));
             sensor.lastSampleTimeNs = timestamp;
             sensor.accuracy = sensor.sensorInfo.accuracy;
         }
diff --git a/services/inputflinger/reader/mapper/SwitchInputMapper.cpp b/services/inputflinger/reader/mapper/SwitchInputMapper.cpp
index 4f73681..07de244 100644
--- a/services/inputflinger/reader/mapper/SwitchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/SwitchInputMapper.cpp
@@ -56,10 +56,7 @@
 void SwitchInputMapper::sync(nsecs_t when) {
     if (mUpdatedSwitchMask) {
         uint32_t updatedSwitchValues = mSwitchValues & mUpdatedSwitchMask;
-        NotifySwitchArgs args(getContext()->getNextId(), when, 0 /*policyFlags*/,
-                              updatedSwitchValues, mUpdatedSwitchMask);
-        getListener()->notifySwitch(&args);
-
+        getContext()->notifySwitch(when, updatedSwitchValues, mUpdatedSwitchMask);
         mUpdatedSwitchMask = 0;
     }
 }
diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
index a86443d..ff6341f 100644
--- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
+++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
@@ -66,9 +66,8 @@
          (currentButtonState & buttonState)) ||
         (action == AKEY_EVENT_ACTION_UP && (lastButtonState & buttonState) &&
          !(currentButtonState & buttonState))) {
-        NotifyKeyArgs args(context->getNextId(), when, deviceId, source, displayId, policyFlags,
-                           action, 0, keyCode, 0, context->getGlobalMetaState(), when);
-        context->getListener()->notifyKey(&args);
+        context->notifyKey(when, deviceId, source, displayId, policyFlags, action, 0 /*flags*/,
+                           keyCode, 0 /*scanCode*/, context->getGlobalMetaState(), when);
     }
 }
 
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index ce12c27..fb30b88 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -397,8 +397,7 @@
     if (changes && resetNeeded) {
         // Send reset, unless this is the first time the device has been configured,
         // in which case the reader will call reset itself after all mappers are ready.
-        NotifyDeviceResetArgs args(getContext()->getNextId(), when, getDeviceId());
-        getListener()->notifyDeviceReset(&args);
+        getContext()->notifyDeviceReset(when, getDeviceId());
     }
 }
 
@@ -1829,10 +1828,9 @@
     int32_t metaState = getContext()->getGlobalMetaState();
     policyFlags |= POLICY_FLAG_VIRTUAL;
 
-    NotifyKeyArgs args(getContext()->getNextId(), when, getDeviceId(), AINPUT_SOURCE_KEYBOARD,
-                       mViewport.displayId, policyFlags, keyEventAction, keyEventFlags, keyCode,
-                       scanCode, metaState, downTime);
-    getListener()->notifyKey(&args);
+    getContext()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, mViewport.displayId,
+                            policyFlags, keyEventAction, keyEventFlags, keyCode, scanCode,
+                            metaState, downTime);
 }
 
 void TouchInputMapper::abortTouches(nsecs_t when, uint32_t policyFlags) {
@@ -2508,12 +2506,11 @@
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
 
         const int32_t displayId = mPointerController->getDisplayId();
-        NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
-                              policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
-                              buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
-                              1, &pointerProperties, &pointerCoords, 0, 0, x, y,
-                              mPointerGesture.downTime, /* videoFrames */ {});
-        getListener()->notifyMotion(&args);
+        getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
+                                   AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, buttonState,
+                                   MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+                                   &pointerProperties, &pointerCoords, 0, 0, x, y,
+                                   mPointerGesture.downTime, /* videoFrames */ {});
     }
 
     // Update state.
@@ -3428,28 +3425,28 @@
         mPointerSimple.down = false;
 
         // Send up.
-        NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
-                              policyFlags, AMOTION_EVENT_ACTION_UP, 0, 0, metaState,
-                              mLastRawState.buttonState, MotionClassification::NONE,
-                              AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
-                              &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision,
-                              xCursorPosition, yCursorPosition, mPointerSimple.downTime,
-                              /* videoFrames */ {});
-        getListener()->notifyMotion(&args);
+        getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
+                                   AMOTION_EVENT_ACTION_UP, 0, 0, metaState,
+                                   mLastRawState.buttonState, MotionClassification::NONE,
+                                   AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
+                                   &mPointerSimple.lastCoords, mOrientedXPrecision,
+                                   mOrientedYPrecision, xCursorPosition, yCursorPosition,
+                                   mPointerSimple.downTime,
+                                   /* videoFrames */ {});
     }
 
     if (mPointerSimple.hovering && !hovering) {
         mPointerSimple.hovering = false;
 
         // Send hover exit.
-        NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
-                              policyFlags, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState,
-                              mLastRawState.buttonState, MotionClassification::NONE,
-                              AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
-                              &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision,
-                              xCursorPosition, yCursorPosition, mPointerSimple.downTime,
-                              /* videoFrames */ {});
-        getListener()->notifyMotion(&args);
+        getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
+                                   AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState,
+                                   mLastRawState.buttonState, MotionClassification::NONE,
+                                   AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
+                                   &mPointerSimple.lastCoords, mOrientedXPrecision,
+                                   mOrientedYPrecision, xCursorPosition, yCursorPosition,
+                                   mPointerSimple.downTime,
+                                   /* videoFrames */ {});
     }
 
     if (down) {
@@ -3458,25 +3455,24 @@
             mPointerSimple.downTime = when;
 
             // Send down.
-            NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource,
-                                  displayId, policyFlags, AMOTION_EVENT_ACTION_DOWN, 0, 0,
-                                  metaState, mCurrentRawState.buttonState,
-                                  MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
-                                  &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
-                                  mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
-                                  yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
-            getListener()->notifyMotion(&args);
+            getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
+                                       AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState,
+                                       mCurrentRawState.buttonState, MotionClassification::NONE,
+                                       AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+                                       &mPointerSimple.currentProperties,
+                                       &mPointerSimple.currentCoords, mOrientedXPrecision,
+                                       mOrientedYPrecision, xCursorPosition, yCursorPosition,
+                                       mPointerSimple.downTime, /* videoFrames */ {});
         }
 
         // Send move.
-        NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
-                              policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
-                              mCurrentRawState.buttonState, MotionClassification::NONE,
-                              AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
-                              &mPointerSimple.currentCoords, mOrientedXPrecision,
-                              mOrientedYPrecision, xCursorPosition, yCursorPosition,
-                              mPointerSimple.downTime, /* videoFrames */ {});
-        getListener()->notifyMotion(&args);
+        getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
+                                   AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
+                                   mCurrentRawState.buttonState, MotionClassification::NONE,
+                                   AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+                                   &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
+                                   mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
+                                   yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
     }
 
     if (hovering) {
@@ -3484,25 +3480,24 @@
             mPointerSimple.hovering = true;
 
             // Send hover enter.
-            NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource,
-                                  displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0,
-                                  metaState, mCurrentRawState.buttonState,
-                                  MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
-                                  &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
-                                  mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
-                                  yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
-            getListener()->notifyMotion(&args);
+            getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
+                                       AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
+                                       mCurrentRawState.buttonState, MotionClassification::NONE,
+                                       AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+                                       &mPointerSimple.currentProperties,
+                                       &mPointerSimple.currentCoords, mOrientedXPrecision,
+                                       mOrientedYPrecision, xCursorPosition, yCursorPosition,
+                                       mPointerSimple.downTime, /* videoFrames */ {});
         }
 
         // Send hover move.
-        NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
-                              policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
-                              mCurrentRawState.buttonState, MotionClassification::NONE,
-                              AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
-                              &mPointerSimple.currentCoords, mOrientedXPrecision,
-                              mOrientedYPrecision, xCursorPosition, yCursorPosition,
-                              mPointerSimple.downTime, /* videoFrames */ {});
-        getListener()->notifyMotion(&args);
+        getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
+                                   AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
+                                   mCurrentRawState.buttonState, MotionClassification::NONE,
+                                   AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+                                   &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
+                                   mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
+                                   yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
     }
 
     if (mCurrentRawState.rawVScroll || mCurrentRawState.rawHScroll) {
@@ -3517,14 +3512,14 @@
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
 
-        NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,
-                              policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
-                              mCurrentRawState.buttonState, MotionClassification::NONE,
-                              AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
-                              &pointerCoords, mOrientedXPrecision, mOrientedYPrecision,
-                              xCursorPosition, yCursorPosition, mPointerSimple.downTime,
-                              /* videoFrames */ {});
-        getListener()->notifyMotion(&args);
+        getContext()->notifyMotion(when, getDeviceId(), mSource, displayId, policyFlags,
+                                   AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
+                                   mCurrentRawState.buttonState, MotionClassification::NONE,
+                                   AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+                                   &mPointerSimple.currentProperties, &pointerCoords,
+                                   mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
+                                   yCursorPosition, mPointerSimple.downTime,
+                                   /* videoFrames */ {});
     }
 
     // Save state.
@@ -3595,12 +3590,11 @@
     std::vector<TouchVideoFrame> frames = getDeviceContext().getVideoFrames();
     std::for_each(frames.begin(), frames.end(),
                   [this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); });
-    NotifyMotionArgs args(getContext()->getNextId(), when, deviceId, source, displayId, policyFlags,
-                          action, actionButton, flags, metaState, buttonState,
-                          MotionClassification::NONE, edgeFlags, pointerCount, pointerProperties,
-                          pointerCoords, xPrecision, yPrecision, xCursorPosition, yCursorPosition,
-                          downTime, std::move(frames));
-    getListener()->notifyMotion(&args);
+    getContext()->notifyMotion(when, deviceId, source, displayId, policyFlags, action, actionButton,
+                               flags, metaState, buttonState, MotionClassification::NONE, edgeFlags,
+                               pointerCount, pointerProperties, pointerCoords, xPrecision,
+                               yPrecision, xCursorPosition, yCursorPosition, downTime,
+                               std::move(frames));
 }
 
 bool TouchInputMapper::updateMovedPointers(const PointerProperties* inProperties,
@@ -3644,6 +3638,9 @@
     const float xScaled = float(x - mRawPointerAxes.x.minValue) * mXScale;
     const float yScaled = float(y - mRawPointerAxes.y.minValue) * mYScale;
 
+    const float xScaledMax = float(mRawPointerAxes.x.maxValue - x) * mXScale;
+    const float yScaledMax = float(mRawPointerAxes.y.maxValue - y) * mYScale;
+
     // Rotate to surface coordinate.
     // 0 - no swap and reverse.
     // 90 - swap x/y and reverse y.
@@ -3655,16 +3652,16 @@
             y = yScaled + mYTranslate;
             break;
         case DISPLAY_ORIENTATION_90:
-            y = mSurfaceRight - xScaled;
+            y = xScaledMax - (mRawSurfaceWidth - mSurfaceRight);
             x = yScaled + mYTranslate;
             break;
         case DISPLAY_ORIENTATION_180:
-            x = mSurfaceRight - xScaled;
-            y = mSurfaceBottom - yScaled;
+            x = xScaledMax - (mRawSurfaceWidth - mSurfaceRight);
+            y = yScaledMax - (mRawSurfaceHeight - mSurfaceBottom);
             break;
         case DISPLAY_ORIENTATION_270:
             y = xScaled + mXTranslate;
-            x = mSurfaceBottom - yScaled;
+            x = yScaledMax - (mRawSurfaceHeight - mSurfaceBottom);
             break;
         default:
             assert(false);
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 23f3026..91d5864 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -1481,6 +1481,32 @@
     ASSERT_EQ(1U, mReader->getInputDevices().size());
 }
 
+TEST_F(InputReaderTest, GetMergedInputDevicesEnabled) {
+    constexpr int32_t deviceId = END_RESERVED_ID + 1000;
+    constexpr int32_t eventHubIds[2] = {END_RESERVED_ID, END_RESERVED_ID + 1};
+    // Add two subdevices to device
+    std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake");
+    // Must add at least one mapper or the device will be ignored!
+    device->addMapper<FakeInputMapper>(eventHubIds[0], AINPUT_SOURCE_KEYBOARD);
+    device->addMapper<FakeInputMapper>(eventHubIds[1], AINPUT_SOURCE_KEYBOARD);
+
+    // Push same device instance for next device to be added, so they'll have same identifier.
+    mReader->pushNextDevice(device);
+    mReader->pushNextDevice(device);
+    // Sensor device is initially disabled
+    ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[0], "fake1",
+                                      InputDeviceClass::KEYBOARD | InputDeviceClass::SENSOR,
+                                      nullptr));
+    // Device is disabled because the only sub device is a sensor device and disabled initially.
+    ASSERT_FALSE(mFakeEventHub->isDeviceEnabled(eventHubIds[0]));
+    ASSERT_FALSE(device->isEnabled());
+    ASSERT_NO_FATAL_FAILURE(
+            addDevice(eventHubIds[1], "fake2", InputDeviceClass::KEYBOARD, nullptr));
+    // The merged device is enabled if any sub device is enabled
+    ASSERT_TRUE(mFakeEventHub->isDeviceEnabled(eventHubIds[1]));
+    ASSERT_TRUE(device->isEnabled());
+}
+
 TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) {
     constexpr int32_t deviceId = END_RESERVED_ID + 1000;
     constexpr Flags<InputDeviceClass> deviceClass(InputDeviceClass::KEYBOARD);
@@ -2721,6 +2747,7 @@
     ASSERT_TRUE(mapper.enableSensor(InputDeviceSensorType::ACCELEROMETER,
                                     std::chrono::microseconds(10000),
                                     std::chrono::microseconds(0)));
+    ASSERT_TRUE(mFakeEventHub->isDeviceEnabled(EVENTHUB_ID));
     process(mapper, ARBITRARY_TIME, EV_ABS, ABS_X, 20000);
     process(mapper, ARBITRARY_TIME, EV_ABS, ABS_Y, -20000);
     process(mapper, ARBITRARY_TIME, EV_ABS, ABS_Z, 40000);
@@ -2750,6 +2777,7 @@
     ASSERT_TRUE(mapper.enableSensor(InputDeviceSensorType::GYROSCOPE,
                                     std::chrono::microseconds(10000),
                                     std::chrono::microseconds(0)));
+    ASSERT_TRUE(mFakeEventHub->isDeviceEnabled(EVENTHUB_ID));
     process(mapper, ARBITRARY_TIME, EV_ABS, ABS_RX, 20000);
     process(mapper, ARBITRARY_TIME, EV_ABS, ABS_RY, -20000);
     process(mapper, ARBITRARY_TIME, EV_ABS, ABS_RZ, 40000);
@@ -8017,6 +8045,34 @@
     processPositionAndVerify(mapper, x - 1, y, x + 1, y, xExpected, yExpected);
 }
 
+TEST_F(MultiTouchInputMapperTest_SurfaceRange, Viewports_SurfaceRange_Corner) {
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+    prepareAxes(POSITION);
+    MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+    const int32_t x = 0;
+    const int32_t y = 0;
+
+    const int32_t xExpected = x;
+    const int32_t yExpected = y;
+    processPositionAndVerify(mapper, x - 1, y, x, y, xExpected, yExpected);
+
+    clearViewports();
+    prepareDisplay(DISPLAY_ORIENTATION_90);
+    // expect x/y = swap x/y then reverse y.
+    const int32_t xExpected90 = y;
+    const int32_t yExpected90 = DISPLAY_WIDTH - 1;
+    processPositionAndVerify(mapper, x - 1, y, x, y, xExpected90, yExpected90);
+
+    clearViewports();
+    prepareDisplay(DISPLAY_ORIENTATION_270);
+    // expect x/y = swap x/y then reverse x.
+    const int32_t xExpected270 = DISPLAY_HEIGHT - 1;
+    const int32_t yExpected270 = x;
+    processPositionAndVerify(mapper, x - 1, y, x, y, xExpected270, yExpected270);
+}
+
 TEST_F(MultiTouchInputMapperTest, Process_TouchpadCapture) {
     // we need a pointer controller for mouse mode of touchpad (start pointer at 0,0)
     std::shared_ptr<FakePointerController> fakePointerController =
diff --git a/services/powermanager/PowerHalWrapper.cpp b/services/powermanager/PowerHalWrapper.cpp
index 4a711ca..2f32827 100644
--- a/services/powermanager/PowerHalWrapper.cpp
+++ b/services/powermanager/PowerHalWrapper.cpp
@@ -114,14 +114,15 @@
 
 HalResult AidlHalWrapper::setBoost(Boost boost, int32_t durationMs) {
     std::unique_lock<std::mutex> lock(mBoostMutex);
+    size_t idx = static_cast<size_t>(boost);
+
     // Quick return if boost is not supported by HAL
-    if (boost > Boost::DISPLAY_UPDATE_IMMINENT ||
-        mBoostSupportedArray[static_cast<int32_t>(boost)] == HalSupport::OFF) {
+    if (idx >= mBoostSupportedArray.size() || mBoostSupportedArray[idx] == HalSupport::OFF) {
         ALOGV("Skipped setBoost %s because Power HAL doesn't support it", toString(boost).c_str());
         return HalResult::UNSUPPORTED;
     }
 
-    if (mBoostSupportedArray[static_cast<int32_t>(boost)] == HalSupport::UNKNOWN) {
+    if (mBoostSupportedArray[idx] == HalSupport::UNKNOWN) {
         bool isSupported = false;
         auto isSupportedRet = mHandle->isBoostSupported(boost, &isSupported);
         if (!isSupportedRet.isOk()) {
@@ -130,8 +131,7 @@
             return HalResult::FAILED;
         }
 
-        mBoostSupportedArray[static_cast<int32_t>(boost)] =
-                isSupported ? HalSupport::ON : HalSupport::OFF;
+        mBoostSupportedArray[idx] = isSupported ? HalSupport::ON : HalSupport::OFF;
         if (!isSupported) {
             ALOGV("Skipped setBoost %s because Power HAL doesn't support it",
                   toString(boost).c_str());
@@ -145,14 +145,15 @@
 
 HalResult AidlHalWrapper::setMode(Mode mode, bool enabled) {
     std::unique_lock<std::mutex> lock(mModeMutex);
+    size_t idx = static_cast<size_t>(mode);
+
     // Quick return if mode is not supported by HAL
-    if (mode > Mode::DISPLAY_INACTIVE ||
-        mModeSupportedArray[static_cast<int32_t>(mode)] == HalSupport::OFF) {
+    if (idx >= mModeSupportedArray.size() || mModeSupportedArray[idx] == HalSupport::OFF) {
         ALOGV("Skipped setMode %s because Power HAL doesn't support it", toString(mode).c_str());
         return HalResult::UNSUPPORTED;
     }
 
-    if (mModeSupportedArray[static_cast<int32_t>(mode)] == HalSupport::UNKNOWN) {
+    if (mModeSupportedArray[idx] == HalSupport::UNKNOWN) {
         bool isSupported = false;
         auto isSupportedRet = mHandle->isModeSupported(mode, &isSupported);
         if (!isSupportedRet.isOk()) {
@@ -161,8 +162,7 @@
             return HalResult::FAILED;
         }
 
-        mModeSupportedArray[static_cast<int32_t>(mode)] =
-                isSupported ? HalSupport::ON : HalSupport::OFF;
+        mModeSupportedArray[idx] = isSupported ? HalSupport::ON : HalSupport::OFF;
         if (!isSupported) {
             ALOGV("Skipped setMode %s because Power HAL doesn't support it",
                   toString(mode).c_str());
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 6561707..424a8b3 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -389,33 +389,58 @@
     mBufferInfo.mFrameLatencyNeeded = true;
 }
 
+bool BufferLayer::shouldPresentNow(nsecs_t expectedPresentTime) const {
+    // If this is not a valid vsync for the layer's uid, return and try again later
+    const bool isVsyncValidForUid =
+            mFlinger->mScheduler->isVsyncValid(expectedPresentTime, mOwnerUid);
+    if (!isVsyncValidForUid) {
+        ATRACE_NAME("!isVsyncValidForUid");
+        return false;
+    }
+
+    // AutoRefresh layers and sideband streams should always be presented
+    if (getSidebandStreamChanged() || getAutoRefresh()) {
+        return true;
+    }
+
+    // If the next planned present time is not current, return and try again later
+    if (frameIsEarly(expectedPresentTime)) {
+        ATRACE_NAME("frameIsEarly()");
+        return false;
+    }
+
+    // If this layer doesn't have a frame is shouldn't be presented
+    if (!hasFrameUpdate()) {
+        return false;
+    }
+
+    // Defer to the derived class to decide whether the next buffer is due for
+    // presentation.
+    return isBufferDue(expectedPresentTime);
+}
+
 bool BufferLayer::frameIsEarly(nsecs_t expectedPresentTime) const {
     // TODO(b/169901895): kEarlyLatchVsyncThreshold should be based on the
     // vsync period. We can do this change as soon as ag/13100772 is merged.
     constexpr static std::chrono::nanoseconds kEarlyLatchVsyncThreshold = 5ms;
 
     const auto presentTime = nextPredictedPresentTime();
-    if (std::abs(presentTime - expectedPresentTime) >= kEarlyLatchMaxThreshold.count()) {
+    if (!presentTime.has_value()) {
         return false;
     }
 
-    return presentTime >= expectedPresentTime &&
-            presentTime - expectedPresentTime >= kEarlyLatchVsyncThreshold.count();
+    if (std::abs(*presentTime - expectedPresentTime) >= kEarlyLatchMaxThreshold.count()) {
+        return false;
+    }
+
+    return *presentTime >= expectedPresentTime &&
+            *presentTime - expectedPresentTime >= kEarlyLatchVsyncThreshold.count();
 }
 
 bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
                               nsecs_t expectedPresentTime) {
     ATRACE_CALL();
 
-    // If this is not a valid vsync for the layer's uid, return and try again later
-    const bool isVsyncValidForUid =
-            mFlinger->mScheduler->isVsyncValid(expectedPresentTime, mOwnerUid);
-    if (!isVsyncValidForUid) {
-        ATRACE_NAME("!isVsyncValidForUid");
-        mFlinger->setTransactionFlags(eTraversalNeeded);
-        return false;
-    }
-
     bool refreshRequired = latchSidebandStream(recomputeVisibleRegions);
 
     if (refreshRequired) {
@@ -435,12 +460,6 @@
         return false;
     }
 
-    if (frameIsEarly(expectedPresentTime)) {
-        ATRACE_NAME("frameIsEarly()");
-        mFlinger->signalLayerUpdate();
-        return false;
-    }
-
     // If the head buffer's acquire fence hasn't signaled yet, return and
     // try again later
     if (!fenceHasSignaled()) {
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 5cd9a7c..2118f4a 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -175,12 +175,24 @@
     void setTransformHint(ui::Transform::RotationFlags displayTransformHint) override;
 
     // Transform hint provided to the producer. This must be accessed holding
-    /// the mStateLock.
+    // the mStateLock.
     ui::Transform::RotationFlags mTransformHint = ui::Transform::ROT_0;
 
     bool getAutoRefresh() const { return mAutoRefresh; }
     bool getSidebandStreamChanged() const { return mSidebandStreamChanged; }
 
+    // Returns true if the next buffer should be presented at the expected present time
+    bool shouldPresentNow(nsecs_t expectedPresentTime) const final;
+
+    // Returns true if the next buffer should be presented at the expected present time,
+    // overridden by BufferStateLayer and BufferQueueLayer for implementation
+    // specific logic
+    virtual bool isBufferDue(nsecs_t /*expectedPresentTime*/) const = 0;
+
+    // Returns true if the next frame is considered too early to present
+    // at the given expectedPresentTime
+    bool frameIsEarly(nsecs_t expectedPresentTime) const;
+
     std::atomic<bool> mAutoRefresh{false};
     std::atomic<bool> mSidebandStreamChanged{false};
 
@@ -225,13 +237,8 @@
 
     FloatRect computeSourceBounds(const FloatRect& parentBounds) const override;
 
-    // Returns true if the next frame is considered too early to present
-    // at the given expectedPresentTime
-    bool frameIsEarly(nsecs_t expectedPresentTime) const;
-
-    // Returns the predicted present time of the next frame if available or
-    // 0 otherwise.
-    virtual nsecs_t nextPredictedPresentTime() const = 0;
+    // Returns the predicted present time of the next frame if available
+    virtual std::optional<nsecs_t> nextPredictedPresentTime() const = 0;
 
     // The amount of time SF can delay a frame if it is considered early based
     // on the VsyncModulator::VsyncConfig::appWorkDuration
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 04cec4f..32e6b10 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -100,15 +100,7 @@
     return mQueuedFrames;
 }
 
-bool BufferQueueLayer::shouldPresentNow(nsecs_t expectedPresentTime) const {
-    if (getSidebandStreamChanged() || getAutoRefresh()) {
-        return true;
-    }
-
-    if (!hasFrameUpdate()) {
-        return false;
-    }
-
+bool BufferQueueLayer::isBufferDue(nsecs_t expectedPresentTime) const {
     Mutex::Autolock lock(mQueueItemLock);
 
     const int64_t addedTime = mQueueItems[0].item.mTimestamp;
@@ -223,16 +215,16 @@
     return mQueuedFrames > 0;
 }
 
-nsecs_t BufferQueueLayer::nextPredictedPresentTime() const {
+std::optional<nsecs_t> BufferQueueLayer::nextPredictedPresentTime() const {
     Mutex::Autolock lock(mQueueItemLock);
     if (mQueueItems.empty()) {
-        return 0;
+        return std::nullopt;
     }
 
     const auto& bufferData = mQueueItems[0];
 
     if (!bufferData.item.mIsAutoTimestamp || !bufferData.surfaceFrame) {
-        return 0;
+        return std::nullopt;
     }
 
     return bufferData.surfaceFrame->getPredictions().presentTime;
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 2347d8c..0e8fdbe 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -53,7 +53,8 @@
 
     int32_t getQueuedFrameCount() const override;
 
-    bool shouldPresentNow(nsecs_t expectedPresentTime) const override;
+    // Returns true if the next buffer should be presented at the expected present time
+    bool isBufferDue(nsecs_t expectedPresentTime) const override;
 
     // Implements BufferLayer.
     bool fenceHasSignaled() const override;
@@ -116,7 +117,7 @@
     // Temporary - Used only for LEGACY camera mode.
     uint32_t getProducerStickyTransform() const;
 
-    nsecs_t nextPredictedPresentTime() const override;
+    std::optional<nsecs_t> nextPredictedPresentTime() const override;
 
     sp<BufferLayerConsumer> mConsumer;
     sp<IGraphicBufferProducer> mProducer;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index bca1c69..ad08f82 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -212,14 +212,6 @@
     }
 }
 
-bool BufferStateLayer::shouldPresentNow(nsecs_t /*expectedPresentTime*/) const {
-    if (getSidebandStreamChanged() || getAutoRefresh()) {
-        return true;
-    }
-
-    return hasFrameUpdate();
-}
-
 bool BufferStateLayer::willPresentCurrentTransaction() const {
     // Returns true if the most recent Transaction applied to CurrentState will be presented.
     return (getSidebandStreamChanged() || getAutoRefresh() ||
@@ -602,9 +594,9 @@
     return mCurrentStateModified && (c.buffer != nullptr || c.bgColorLayer != nullptr);
 }
 
-nsecs_t BufferStateLayer::nextPredictedPresentTime() const {
+std::optional<nsecs_t> BufferStateLayer::nextPredictedPresentTime() const {
     if (!getDrawingState().isAutoTimestamp || !mSurfaceFrame) {
-        return 0;
+        return std::nullopt;
     }
 
     return mSurfaceFrame->getPredictions().presentTime;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 6414e6b..bc508e3 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -45,7 +45,7 @@
     void finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence,
                                    const CompositorTiming& compositorTiming) override;
 
-    bool shouldPresentNow(nsecs_t expectedPresentTime) const override;
+    bool isBufferDue(nsecs_t /*expectedPresentTime*/) const override { return true; }
 
     uint32_t doTransactionResize(uint32_t flags, Layer::State* /*stateToCommit*/) override {
         return flags;
@@ -152,7 +152,7 @@
 
     bool bufferNeedsFiltering() const override;
 
-    nsecs_t nextPredictedPresentTime() const override;
+    std::optional<nsecs_t> nextPredictedPresentTime() const override;
 
     static const std::array<float, 16> IDENTITY_MATRIX;
 
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 4731f50..a545d18 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -688,6 +688,7 @@
     shadowLayer.source.buffer.fence = nullptr;
     shadowLayer.frameNumber = 0;
     shadowLayer.bufferId = 0;
+    shadowLayer.name = getName();
 
     if (shadowLayer.shadow.ambientColor.a <= 0.f && shadowLayer.shadow.spotColor.a <= 0.f) {
         return {};
@@ -723,6 +724,7 @@
 
     // If layer is blacked out, force alpha to 1 so that we draw a black color layer.
     layerSettings.alpha = blackout ? 1.0f : 0.0f;
+    layerSettings.name = getName();
 }
 
 std::vector<compositionengine::LayerFE::LayerSettings> Layer::prepareClientCompositionList(
diff --git a/services/surfaceflinger/StartPropertySetThread.cpp b/services/surfaceflinger/StartPropertySetThread.cpp
index db82772..f42cd53 100644
--- a/services/surfaceflinger/StartPropertySetThread.cpp
+++ b/services/surfaceflinger/StartPropertySetThread.cpp
@@ -31,6 +31,7 @@
     property_set(kTimestampProperty, mTimestampPropertyValue ? "1" : "0");
     // Clear BootAnimation exit flag
     property_set("service.bootanim.exit", "0");
+    property_set("service.bootanim.progress", "0");
     // Start BootAnimation if not started
     property_set("ctl.start", "bootanim");
     // Exit immediately
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 6967f69..63201b0 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1994,11 +1994,6 @@
 
     mScheduler->onDisplayRefreshed(presentTime);
 
-    // Set presentation information before calling postComposition, such that jank information from
-    // this' frame classification is already available when sending jank info to clients.
-    mFrameTimeline->setSfPresent(systemTime(),
-                                 std::make_shared<FenceTime>(mPreviousPresentFences[0]));
-
     postFrame();
     postComposition();
 
@@ -2120,11 +2115,6 @@
     ATRACE_CALL();
     ALOGV("postComposition");
 
-    nsecs_t dequeueReadyTime = systemTime();
-    for (const auto& layer : mLayersWithQueuedFrames) {
-        layer->releasePendingBuffer(dequeueReadyTime);
-    }
-
     const auto* display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()).get();
 
     getBE().mGlCompositionDoneTimeline.updateSignalTimes();
@@ -2146,6 +2136,17 @@
     auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFences[0]);
     getBE().mDisplayTimeline.push(presentFenceTime);
 
+    // Set presentation information before calling Layer::releasePendingBuffer, such that jank
+    // information from previous' frame classification is already available when sending jank info
+    // to clients, so they get jank classification as early as possible.
+    mFrameTimeline->setSfPresent(systemTime(),
+                                 std::make_shared<FenceTime>(mPreviousPresentFences[0]));
+
+    nsecs_t dequeueReadyTime = systemTime();
+    for (const auto& layer : mLayersWithQueuedFrames) {
+        layer->releasePendingBuffer(dequeueReadyTime);
+    }
+
     const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(systemTime());
 
     // We use the CompositionEngine::getLastFrameRefreshTimestamp() which might