Merge "Fix SkSurface cache."
diff --git a/include/android/input.h b/include/android/input.h
index b04775b..38af89a 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -163,6 +163,9 @@
 
     /** Focus event */
     AINPUT_EVENT_TYPE_FOCUS = 3,
+
+    /** Capture event */
+    AINPUT_EVENT_TYPE_CAPTURE = 4,
 };
 
 /**
diff --git a/include/input/Input.h b/include/input/Input.h
index 3facfa5..aa42db8 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -773,6 +773,25 @@
     bool mInTouchMode;
 };
 
+/*
+ * Capture events.
+ */
+class CaptureEvent : public InputEvent {
+public:
+    virtual ~CaptureEvent() {}
+
+    virtual int32_t getType() const override { return AINPUT_EVENT_TYPE_CAPTURE; }
+
+    inline bool getPointerCaptureEnabled() const { return mPointerCaptureEnabled; }
+
+    void initialize(int32_t id, bool pointerCaptureEnabled);
+
+    void initialize(const CaptureEvent& from);
+
+protected:
+    bool mPointerCaptureEnabled;
+};
+
 /**
  * Base class for verified events.
  * Do not create a VerifiedInputEvent explicitly.
@@ -835,6 +854,7 @@
     virtual KeyEvent* createKeyEvent() = 0;
     virtual MotionEvent* createMotionEvent() = 0;
     virtual FocusEvent* createFocusEvent() = 0;
+    virtual CaptureEvent* createCaptureEvent() = 0;
 };
 
 /*
@@ -849,11 +869,13 @@
     virtual KeyEvent* createKeyEvent() override { return &mKeyEvent; }
     virtual MotionEvent* createMotionEvent() override { return &mMotionEvent; }
     virtual FocusEvent* createFocusEvent() override { return &mFocusEvent; }
+    virtual CaptureEvent* createCaptureEvent() override { return &mCaptureEvent; }
 
 private:
     KeyEvent mKeyEvent;
     MotionEvent mMotionEvent;
     FocusEvent mFocusEvent;
+    CaptureEvent mCaptureEvent;
 };
 
 /*
@@ -867,6 +889,7 @@
     virtual KeyEvent* createKeyEvent() override;
     virtual MotionEvent* createMotionEvent() override;
     virtual FocusEvent* createFocusEvent() override;
+    virtual CaptureEvent* createCaptureEvent() override;
 
     void recycle(InputEvent* event);
 
@@ -876,6 +899,7 @@
     std::queue<std::unique_ptr<KeyEvent>> mKeyEventPool;
     std::queue<std::unique_ptr<MotionEvent>> mMotionEventPool;
     std::queue<std::unique_ptr<FocusEvent>> mFocusEventPool;
+    std::queue<std::unique_ptr<CaptureEvent>> mCaptureEventPool;
 };
 
 } // namespace android
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index ad0a14e..8744ef7 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -67,6 +67,7 @@
         MOTION,
         FINISHED,
         FOCUS,
+        CAPTURE,
     };
 
     struct Header {
@@ -166,6 +167,13 @@
 
             inline size_t size() const { return sizeof(Focus); }
         } focus;
+
+        struct Capture {
+            int32_t eventId;
+            uint32_t pointerCaptureEnabled; // actually a bool, but we maintain 8-byte alignment
+
+            inline size_t size() const { return sizeof(Capture); }
+        } capture;
     } __attribute__((aligned(8))) body;
 
     bool isValid(size_t actualSize) const;
@@ -182,6 +190,8 @@
                 return "FINISHED";
             case Type::FOCUS:
                 return "FOCUS";
+            case Type::CAPTURE:
+                return "CAPTURE";
         }
     }
 };
@@ -341,6 +351,15 @@
      */
     status_t publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus, bool inTouchMode);
 
+    /* Publishes a capture event to the input channel.
+     *
+     * Returns OK on success.
+     * Returns WOULD_BLOCK if the channel is full.
+     * Returns DEAD_OBJECT if the channel's peer has been closed.
+     * Other errors probably indicate that the channel is broken.
+     */
+    status_t publishCaptureEvent(uint32_t seq, int32_t eventId, bool pointerCaptureEnabled);
+
     /* Receives the finished signal from the consumer in reply to the original dispatch signal.
      * If a signal was received, returns the message sequence number,
      * and whether the consumer handled the message.
@@ -576,6 +595,7 @@
     static void initializeKeyEvent(KeyEvent* event, const InputMessage* msg);
     static void initializeMotionEvent(MotionEvent* event, const InputMessage* msg);
     static void initializeFocusEvent(FocusEvent* event, const InputMessage* msg);
+    static void initializeCaptureEvent(CaptureEvent* event, const InputMessage* msg);
     static void addSample(MotionEvent* event, const InputMessage* msg);
     static bool canAddSample(const Batch& batch, const InputMessage* msg);
     static ssize_t findSampleNoLaterThan(const Batch& batch, nsecs_t time);
diff --git a/libs/binder/ActivityManager.cpp b/libs/binder/ActivityManager.cpp
index 727ea60..e45a656 100644
--- a/libs/binder/ActivityManager.cpp
+++ b/libs/binder/ActivityManager.cpp
@@ -62,23 +62,27 @@
     return service != nullptr ? service->openContentUri(stringUri) : -1;
 }
 
-void ActivityManager::registerUidObserver(const sp<IUidObserver>& observer,
+status_t ActivityManager::registerUidObserver(const sp<IUidObserver>& observer,
                                           const int32_t event,
                                           const int32_t cutpoint,
                                           const String16& callingPackage)
 {
     sp<IActivityManager> service = getService();
     if (service != nullptr) {
-        service->registerUidObserver(observer, event, cutpoint, callingPackage);
+        return service->registerUidObserver(observer, event, cutpoint, callingPackage);
     }
+    // ActivityManagerService appears dead. Return usual error code for dead service.
+    return DEAD_OBJECT;
 }
 
-void ActivityManager::unregisterUidObserver(const sp<IUidObserver>& observer)
+status_t ActivityManager::unregisterUidObserver(const sp<IUidObserver>& observer)
 {
     sp<IActivityManager> service = getService();
     if (service != nullptr) {
-        service->unregisterUidObserver(observer);
+        return service->unregisterUidObserver(observer);
     }
+    // ActivityManagerService appears dead. Return usual error code for dead service.
+    return DEAD_OBJECT;
 }
 
 bool ActivityManager::isUidActive(const uid_t uid, const String16& callingPackage)
diff --git a/libs/binder/Debug.cpp b/libs/binder/Debug.cpp
index da342ff..3a62059 100644
--- a/libs/binder/Debug.cpp
+++ b/libs/binder/Debug.cpp
@@ -208,7 +208,7 @@
     }
 
     for (offset = 0; ; offset += bytesPerLine, pos += bytesPerLine) {
-        size_t remain = length;
+        ssize_t remain = length;
 
         char* c = buffer;
         if (!oneLine && !cStyle) {
diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp
index e9f5aae..cf9bb46 100644
--- a/libs/binder/IActivityManager.cpp
+++ b/libs/binder/IActivityManager.cpp
@@ -59,7 +59,7 @@
         return fd;
     }
 
-    virtual void registerUidObserver(const sp<IUidObserver>& observer,
+    virtual status_t registerUidObserver(const sp<IUidObserver>& observer,
                                      const int32_t event,
                                      const int32_t cutpoint,
                                      const String16& callingPackage)
@@ -70,15 +70,23 @@
          data.writeInt32(event);
          data.writeInt32(cutpoint);
          data.writeString16(callingPackage);
-         remote()->transact(REGISTER_UID_OBSERVER_TRANSACTION, data, &reply);
+         status_t err = remote()->transact(REGISTER_UID_OBSERVER_TRANSACTION, data, &reply);
+         if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) {
+             return err;
+         }
+         return OK;
     }
 
-    virtual void unregisterUidObserver(const sp<IUidObserver>& observer)
+    virtual status_t unregisterUidObserver(const sp<IUidObserver>& observer)
     {
          Parcel data, reply;
          data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor());
          data.writeStrongBinder(IInterface::asBinder(observer));
-         remote()->transact(UNREGISTER_UID_OBSERVER_TRANSACTION, data, &reply);
+         status_t err = remote()->transact(UNREGISTER_UID_OBSERVER_TRANSACTION, data, &reply);
+         if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) {
+             return err;
+         }
+         return OK;
     }
 
     virtual bool isUidActive(const uid_t uid, const String16& callingPackage)
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index b1b2aa0..0377075 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -2056,7 +2056,7 @@
     if (size >= 0 && size < INT32_MAX) {
         *outLen = size;
         const char* str = (const char*)readInplace(size+1);
-        if (str != nullptr) {
+        if (str != nullptr && str[size] == '\0') {
             return str;
         }
     }
@@ -2139,7 +2139,7 @@
     if (size >= 0 && size < INT32_MAX) {
         *outLen = size;
         const char16_t* str = (const char16_t*)readInplace((size+1)*sizeof(char16_t));
-        if (str != nullptr) {
+        if (str != nullptr && str[size] == u'\0') {
             return str;
         }
     }
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 61a611d..dafc879 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -50,6 +50,14 @@
           "exclude-filter": "android.os.cts.StrictModeTest#testNonSdkApiUsage"
         }
       ]
+    },
+    {
+      "name": "libbinder_rs-internal_test"
+    }
+  ],
+  "postsubmit": [
+    {
+      "name": "rustBinderTest"
     }
   ]
 }
diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h
index 0240858..830971b 100644
--- a/libs/binder/include/binder/ActivityManager.h
+++ b/libs/binder/include/binder/ActivityManager.h
@@ -74,11 +74,11 @@
     ActivityManager();
 
     int openContentUri(const String16& stringUri);
-    void registerUidObserver(const sp<IUidObserver>& observer,
+    status_t registerUidObserver(const sp<IUidObserver>& observer,
                              const int32_t event,
                              const int32_t cutpoint,
                              const String16& callingPackage);
-    void unregisterUidObserver(const sp<IUidObserver>& observer);
+    status_t unregisterUidObserver(const sp<IUidObserver>& observer);
     bool isUidActive(const uid_t uid, const String16& callingPackage);
     int getUidProcessState(const uid_t uid, const String16& callingPackage);
     status_t checkPermission(const String16& permission, const pid_t pid, const uid_t uid, int32_t* outResult);
diff --git a/libs/binder/include/binder/IActivityManager.h b/libs/binder/include/binder/IActivityManager.h
index e2081ff..2d58c46 100644
--- a/libs/binder/include/binder/IActivityManager.h
+++ b/libs/binder/include/binder/IActivityManager.h
@@ -31,11 +31,11 @@
     DECLARE_META_INTERFACE(ActivityManager)
 
     virtual int openContentUri(const String16& stringUri) = 0;
-    virtual void registerUidObserver(const sp<IUidObserver>& observer,
+    virtual status_t registerUidObserver(const sp<IUidObserver>& observer,
                                      const int32_t event,
                                      const int32_t cutpoint,
                                      const String16& callingPackage) = 0;
-    virtual void unregisterUidObserver(const sp<IUidObserver>& observer) = 0;
+    virtual status_t unregisterUidObserver(const sp<IUidObserver>& observer) = 0;
     virtual bool isUidActive(const uid_t uid, const String16& callingPackage) = 0;
     virtual int32_t getUidProcessState(const uid_t uid, const String16& callingPackage) = 0;
     virtual status_t checkPermission(const String16& permission,
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index ece25a0..4b2d50d 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -210,6 +210,8 @@
     template<typename T>
     status_t            writeParcelableVector(const std::shared_ptr<std::vector<std::unique_ptr<T>>>& val);
     template<typename T>
+    status_t            writeParcelableVector(const std::shared_ptr<std::vector<std::optional<T>>>& val);
+    template<typename T>
     status_t            writeParcelableVector(const std::vector<T>& val);
 
     template<typename T>
@@ -1229,6 +1231,16 @@
     return unsafeWriteTypedVector<NullableT, const NullableT&>(*val, &Parcel::writeNullableParcelable);
 }
 
+template<typename T>
+status_t Parcel::writeParcelableVector(const std::shared_ptr<std::vector<std::optional<T>>>& val) {
+    if (val.get() == nullptr) {
+        return this->writeInt32(-1);
+    }
+
+    using NullableT = std::optional<T>;
+    return unsafeWriteTypedVector<NullableT, const NullableT&>(*val, &Parcel::writeNullableParcelable);
+}
+
 template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool>>
 status_t Parcel::writeEnum(const T& val) {
     return writeInt32(static_cast<int32_t>(val));
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index 3e3eda1..ec7c7d8 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -261,7 +261,7 @@
 }
 
 binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd) {
-    std::unique_ptr<ParcelFileDescriptor> parcelFd;
+    std::optional<ParcelFileDescriptor> parcelFd;
 
     status_t status = parcel->get()->readParcelable(&parcelFd);
     if (status != STATUS_OK) return PruneStatusT(status);
diff --git a/libs/binder/parcel_fuzzer/binder.cpp b/libs/binder/parcel_fuzzer/binder.cpp
index a94f06f..96cd215 100644
--- a/libs/binder/parcel_fuzzer/binder.cpp
+++ b/libs/binder/parcel_fuzzer/binder.cpp
@@ -143,6 +143,13 @@
         FUZZ_LOG() << "read c-str: " << (str ? str : "<empty string>");
     },
     PARCEL_READ_OPT_STATUS(android::String8, readString8),
+    [] (const ::android::Parcel& p, uint8_t /*data*/) {
+        FUZZ_LOG() << "about to readString8Inplace";
+        size_t outLen = 0;
+        const char* str = p.readString8Inplace(&outLen);
+        std::string bytes = hexString(str, sizeof(char) * (outLen + 1));
+        FUZZ_LOG() << "readString8Inplace: " << bytes << " size: " << outLen;
+    },
     PARCEL_READ_OPT_STATUS(android::String16, readString16),
     PARCEL_READ_WITH_STATUS(std::unique_ptr<android::String16>, readString16),
     PARCEL_READ_WITH_STATUS(std::optional<android::String16>, readString16),
@@ -150,8 +157,8 @@
         FUZZ_LOG() << "about to readString16Inplace";
         size_t outLen = 0;
         const char16_t* str = p.readString16Inplace(&outLen);
-        FUZZ_LOG() << "readString16Inplace: " << hexString(str, sizeof(char16_t) * outLen)
-                   << " size: " << outLen;
+        std::string bytes = hexString(str, sizeof(char16_t) * (outLen + 1));
+        FUZZ_LOG() << "readString16Inplace: " << bytes << " size: " << outLen;
     },
     PARCEL_READ_WITH_STATUS(android::sp<android::IBinder>, readStrongBinder),
     PARCEL_READ_WITH_STATUS(android::sp<android::IBinder>, readNullableStrongBinder),
diff --git a/libs/binder/rust/TEST_MAPPING b/libs/binder/rust/TEST_MAPPING
deleted file mode 100644
index 50c474c..0000000
--- a/libs/binder/rust/TEST_MAPPING
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-  "presubmit": [
-    {
-      "name": "libbinder_rs-internal_test"
-    }
-  ],
-  "postsubmit": [
-    {
-      "name": "rustBinderTest"
-    }
-  ]
-}
diff --git a/libs/binder/tests/binderParcelTest.cpp b/libs/binder/tests/binderParcelTest.cpp
index 1764228..841d47b 100644
--- a/libs/binder/tests/binderParcelTest.cpp
+++ b/libs/binder/tests/binderParcelTest.cpp
@@ -25,6 +25,40 @@
 using android::String8;
 using android::status_t;
 
+TEST(Parcel, NonNullTerminatedString8) {
+    String8 kTestString = String8("test-is-good");
+
+    // write non-null terminated string
+    Parcel p;
+    p.writeString8(kTestString);
+    p.setDataPosition(0);
+    // BAD! assumption of wire format for test
+    // write over length of string
+    p.writeInt32(kTestString.size() - 2);
+
+    p.setDataPosition(0);
+    String8 output;
+    EXPECT_NE(OK, p.readString8(&output));
+    EXPECT_EQ(output.size(), 0);
+}
+
+TEST(Parcel, NonNullTerminatedString16) {
+    String16 kTestString = String16("test-is-good");
+
+    // write non-null terminated string
+    Parcel p;
+    p.writeString16(kTestString);
+    p.setDataPosition(0);
+    // BAD! assumption of wire format for test
+    // write over length of string
+    p.writeInt32(kTestString.size() - 2);
+
+    p.setDataPosition(0);
+    String16 output;
+    EXPECT_NE(OK, p.readString16(&output));
+    EXPECT_EQ(output.size(), 0);
+}
+
 // Tests a second operation results in a parcel at the same location as it
 // started.
 void parcelOpSameLength(const std::function<void(Parcel*)>& a, const std::function<void(Parcel*)>& b) {
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index ac1c736..e6aa02a 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -111,8 +111,8 @@
                                    int width, int height, bool enableTripleBuffering)
       : mName(name),
         mSurfaceControl(surface),
-        mWidth(width),
-        mHeight(height),
+        mSize(width, height),
+        mRequestedSize(mSize),
         mNextTransaction(nullptr) {
     BufferQueue::createBufferQueue(&mProducer, &mConsumer);
     // since the adapter is in the client process, set dequeue timeout
@@ -130,7 +130,7 @@
     mBufferItemConsumer->setName(String8(consumerName.c_str()));
     mBufferItemConsumer->setFrameAvailableListener(this);
     mBufferItemConsumer->setBufferFreedListener(this);
-    mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
+    mBufferItemConsumer->setDefaultBufferSize(mSize.width, mSize.height);
     mBufferItemConsumer->setDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888);
 
     mTransformHint = mSurfaceControl->getTransformHint();
@@ -146,10 +146,10 @@
     std::unique_lock _lock{mMutex};
     mSurfaceControl = surface;
 
-    if (mWidth != width || mHeight != height) {
-        mWidth = width;
-        mHeight = height;
-        mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
+    ui::Size newSize(width, height);
+    if (mRequestedSize != newSize) {
+        mRequestedSize.set(newSize);
+        mBufferItemConsumer->setDefaultBufferSize(mRequestedSize.width, mRequestedSize.height);
     }
 }
 
@@ -218,6 +218,7 @@
     // number of buffers.
     if (mNumFrameAvailable == 0 || maxBuffersAcquired()) {
         BQA_LOGV("processNextBufferLocked waiting for frame available or callback");
+        mCallbackCV.notify_all();
         return;
     }
 
@@ -252,10 +253,13 @@
     }
 
     if (rejectBuffer(bufferItem)) {
-        BQA_LOGE("rejecting buffer:configured size=%dx%d, buffer{size=%dx%d transform=%d}", mWidth,
-                 mHeight, buffer->getWidth(), buffer->getHeight(), bufferItem.mTransform);
-        // TODO(b/168917217) temporarily don't reject buffers until we can synchronize buffer size
-        // changes from ViewRootImpl.
+        BQA_LOGE("rejecting buffer:active_size=%dx%d, requested_size=%dx%d"
+                 "buffer{size=%dx%d transform=%d}",
+                 mSize.width, mSize.height, mRequestedSize.width, mRequestedSize.height,
+                 buffer->getWidth(), buffer->getHeight(), bufferItem.mTransform);
+        mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE);
+        processNextBufferLocked(useNextTransaction);
+        return;
     }
 
     mNumAcquired++;
@@ -278,26 +282,31 @@
     t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this));
 
     t->setFrame(mSurfaceControl,
-                {0, 0, static_cast<int32_t>(mWidth), static_cast<int32_t>(mHeight)});
+                {0, 0, static_cast<int32_t>(mSize.width), static_cast<int32_t>(mSize.height)});
     t->setCrop(mSurfaceControl, computeCrop(bufferItem));
     t->setTransform(mSurfaceControl, bufferItem.mTransform);
     t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse);
     t->setDesiredPresentTime(bufferItem.mTimestamp);
     t->setFrameNumber(mSurfaceControl, bufferItem.mFrameNumber);
 
+    if (mAutoRefresh != bufferItem.mAutoRefresh) {
+        t->setAutoRefresh(mSurfaceControl, bufferItem.mAutoRefresh);
+        mAutoRefresh = bufferItem.mAutoRefresh;
+    }
+
     if (applyTransaction) {
         t->apply();
     }
 
     BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64
              " applyTransaction=%s mTimestamp=%" PRId64,
-             mWidth, mHeight, bufferItem.mFrameNumber, toString(applyTransaction),
+             mSize.width, mSize.height, bufferItem.mFrameNumber, toString(applyTransaction),
              bufferItem.mTimestamp);
 }
 
 Rect BLASTBufferQueue::computeCrop(const BufferItem& item) {
     if (item.mScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
-        return GLConsumer::scaleDownCrop(item.mCrop, mWidth, mHeight);
+        return GLConsumer::scaleDownCrop(item.mCrop, mSize.width, mSize.height);
     }
     return item.mCrop;
 }
@@ -332,8 +341,9 @@
     mNextTransaction = t;
 }
 
-bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) const {
+bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) {
     if (item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) {
+        mSize = mRequestedSize;
         // Only reject buffers if scaling mode is freeze.
         return false;
     }
@@ -345,9 +355,14 @@
     if (item.mTransform & ui::Transform::ROT_90) {
         std::swap(bufWidth, bufHeight);
     }
+    ui::Size bufferSize(bufWidth, bufHeight);
+    if (mRequestedSize != mSize && mRequestedSize == bufferSize) {
+        mSize = mRequestedSize;
+        return false;
+    }
 
     // reject buffers if the buffer size doesn't match.
-    return bufWidth != mWidth || bufHeight != mHeight;
+    return mSize != bufferSize;
 }
 
 // Check if we have acquired the maximum number of buffers.
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 90999fa..7d2c7b8 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -61,7 +61,9 @@
         frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT),
         shouldBeSeamless(true),
         fixedTransformHint(ui::Transform::ROT_INVALID),
-        frameNumber(0) {
+        frameNumber(0),
+        frameTimelineVsyncId(ISurfaceComposer::INVALID_VSYNC_ID),
+        autoRefresh(false) {
     matrix.dsdx = matrix.dtdy = 1.0f;
     matrix.dsdy = matrix.dtdx = 0.0f;
     hdrMetadata.validTypes = 0;
@@ -149,6 +151,7 @@
     SAFE_PARCEL(output.writeUint32, fixedTransformHint);
     SAFE_PARCEL(output.writeUint64, frameNumber);
     SAFE_PARCEL(output.writeInt64, frameTimelineVsyncId);
+    SAFE_PARCEL(output.writeBool, autoRefresh);
 
     SAFE_PARCEL(output.writeUint32, blurRegions.size());
     for (auto region : blurRegions) {
@@ -269,6 +272,7 @@
     fixedTransformHint = static_cast<ui::Transform::RotationFlags>(tmpUint32);
     SAFE_PARCEL(input.readUint64, &frameNumber);
     SAFE_PARCEL(input.readInt64, &frameTimelineVsyncId);
+    SAFE_PARCEL(input.readBool, &autoRefresh);
 
     uint32_t numRegions = 0;
     SAFE_PARCEL(input.readUint32, &numRegions);
@@ -534,6 +538,20 @@
         what |= eFrameNumberChanged;
         frameNumber = other.frameNumber;
     }
+    if (other.what & eFrameTimelineVsyncChanged) {
+        // When merging vsync Ids we take the oldest valid one
+        if (frameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID &&
+            other.frameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID) {
+            frameTimelineVsyncId = std::max(frameTimelineVsyncId, other.frameTimelineVsyncId);
+        } else if (frameTimelineVsyncId == ISurfaceComposer::INVALID_VSYNC_ID) {
+            frameTimelineVsyncId = other.frameTimelineVsyncId;
+        }
+        what |= eFrameTimelineVsyncChanged;
+    }
+    if (other.what & eAutoRefreshChanged) {
+        what |= eAutoRefreshChanged;
+        autoRefresh = other.autoRefresh;
+    }
     if ((other.what & what) != other.what) {
         ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
               "other.what=0x%" PRIu64 " what=0x%" PRIu64,
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index a822598..47a08ab 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1527,6 +1527,19 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAutoRefresh(
+        const sp<SurfaceControl>& sc, bool autoRefresh) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+
+    s->what |= layer_state_t::eAutoRefreshChanged;
+    s->autoRefresh = autoRefresh;
+    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 7741d8c..9fb7d6f 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -100,7 +100,7 @@
     void processNextBufferLocked(bool useNextTransaction) REQUIRES(mMutex);
     Rect computeCrop(const BufferItem& item) REQUIRES(mMutex);
     // Return true if we need to reject the buffer based on the scaling mode and the buffer size.
-    bool rejectBuffer(const BufferItem& item) const REQUIRES(mMutex);
+    bool rejectBuffer(const BufferItem& item) REQUIRES(mMutex);
     bool maxBuffersAcquired() const REQUIRES(mMutex);
 
     std::string mName;
@@ -126,8 +126,8 @@
     // is ready to be presented.
     PendingReleaseItem mPendingReleaseItem GUARDED_BY(mMutex);
 
-    uint32_t mWidth GUARDED_BY(mMutex);
-    uint32_t mHeight GUARDED_BY(mMutex);
+    ui::Size mSize GUARDED_BY(mMutex);
+    ui::Size mRequestedSize GUARDED_BY(mMutex);
 
     uint32_t mTransformHint GUARDED_BY(mMutex);
 
@@ -139,6 +139,10 @@
     // If set to true, the next queue buffer will wait until the shadow queue has been processed by
     // the adapter.
     bool mFlushShadowQueue = false;
+    // Last requested auto refresh state set by the producer. The state indicates that the consumer
+    // should acquire the next frame as soon as it can and not wait for a frame to become available.
+    // This is only relevant for shared buffer mode.
+    bool mAutoRefresh GUARDED_BY(mMutex) = false;
 };
 
 } // namespace android
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index d9f2806..f1c5d67 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -130,6 +130,7 @@
         eFrameNumberChanged = 0x400'00000000,
         eFrameTimelineVsyncChanged = 0x800'00000000,
         eBlurRegionsChanged = 0x1000'00000000,
+        eAutoRefreshChanged = 0x2000'00000000,
     };
 
     layer_state_t();
@@ -234,6 +235,11 @@
     uint64_t frameNumber;
 
     int64_t frameTimelineVsyncId;
+
+    // Indicates that the consumer should acquire the next frame as soon as it
+    // can and not wait for a frame to become available. This is only relevant
+    // in shared buffer mode.
+    bool autoRefresh;
 };
 
 struct ComposerState {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 6289c6a..2eb97f2 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -541,6 +541,11 @@
         Transaction& setFrameTimelineVsync(const sp<SurfaceControl>& sc,
                 int64_t frameTimelineVsyncId);
 
+        // Indicates that the consumer should acquire the next frame as soon as it
+        // can and not wait for a frame to become available. This is only relevant
+        // in shared buffer mode.
+        Transaction& setAutoRefresh(const sp<SurfaceControl>& sc, bool autoRefresh);
+
         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 f3559fa..4282ef9 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -55,9 +55,9 @@
         mBlastBufferQueueAdapter->setNextTransaction(next);
     }
 
-    int getWidth() { return mBlastBufferQueueAdapter->mWidth; }
+    int getWidth() { return mBlastBufferQueueAdapter->mSize.width; }
 
-    int getHeight() { return mBlastBufferQueueAdapter->mHeight; }
+    int getHeight() { return mBlastBufferQueueAdapter->mSize.height; }
 
     Transaction* getNextTransaction() { return mBlastBufferQueueAdapter->mNextTransaction; }
 
@@ -250,8 +250,15 @@
                                    PIXEL_FORMAT_RGBA_8888);
     adapter.update(updateSurface, mDisplayWidth / 2, mDisplayHeight / 2);
     ASSERT_EQ(updateSurface, adapter.getSurfaceControl());
-    ASSERT_EQ(mDisplayWidth / 2, adapter.getWidth());
-    ASSERT_EQ(mDisplayHeight / 2, adapter.getHeight());
+    sp<IGraphicBufferProducer> igbProducer;
+    setUpProducer(adapter, igbProducer);
+
+    int32_t width;
+    igbProducer->query(NATIVE_WINDOW_WIDTH, &width);
+    ASSERT_EQ(mDisplayWidth / 2, width);
+    int32_t height;
+    igbProducer->query(NATIVE_WINDOW_HEIGHT, &height);
+    ASSERT_EQ(mDisplayHeight / 2, height);
 }
 
 TEST_F(BLASTBufferQueueTest, SetNextTransaction) {
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 0ea3889..0a00d68 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -89,6 +89,9 @@
         case AINPUT_EVENT_TYPE_FOCUS: {
             return "FOCUS";
         }
+        case AINPUT_EVENT_TYPE_CAPTURE: {
+            return "CAPTURE";
+        }
     }
     return "UNKNOWN";
 }
@@ -754,6 +757,19 @@
     mInTouchMode = from.mInTouchMode;
 }
 
+// --- CaptureEvent ---
+
+void CaptureEvent::initialize(int32_t id, bool pointerCaptureEnabled) {
+    InputEvent::initialize(id, ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID, AINPUT_SOURCE_UNKNOWN,
+                           ADISPLAY_ID_NONE, INVALID_HMAC);
+    mPointerCaptureEnabled = pointerCaptureEnabled;
+}
+
+void CaptureEvent::initialize(const CaptureEvent& from) {
+    InputEvent::initialize(from);
+    mPointerCaptureEnabled = from.mPointerCaptureEnabled;
+}
+
 // --- PooledInputEventFactory ---
 
 PooledInputEventFactory::PooledInputEventFactory(size_t maxPoolSize) :
@@ -790,6 +806,15 @@
     return event;
 }
 
+CaptureEvent* PooledInputEventFactory::createCaptureEvent() {
+    if (mCaptureEventPool.empty()) {
+        return new CaptureEvent();
+    }
+    CaptureEvent* event = mCaptureEventPool.front().release();
+    mCaptureEventPool.pop();
+    return event;
+}
+
 void PooledInputEventFactory::recycle(InputEvent* event) {
     switch (event->getType()) {
     case AINPUT_EVENT_TYPE_KEY:
@@ -810,6 +835,13 @@
             return;
         }
         break;
+    case AINPUT_EVENT_TYPE_CAPTURE:
+        if (mCaptureEventPool.size() < mMaxPoolSize) {
+            mCaptureEventPool.push(
+                    std::unique_ptr<CaptureEvent>(static_cast<CaptureEvent*>(event)));
+            return;
+        }
+        break;
     }
     delete event;
 }
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 85df405..acea473 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -105,6 +105,8 @@
                 return true;
             case Type::FOCUS:
                 return true;
+            case Type::CAPTURE:
+                return true;
         }
     }
     return false;
@@ -120,6 +122,8 @@
             return sizeof(Header) + body.finished.size();
         case Type::FOCUS:
             return sizeof(Header) + body.focus.size();
+        case Type::CAPTURE:
+            return sizeof(Header) + body.capture.size();
     }
     return sizeof(Header);
 }
@@ -238,6 +242,11 @@
             msg->body.focus.inTouchMode = body.focus.inTouchMode;
             break;
         }
+        case InputMessage::Type::CAPTURE: {
+            msg->body.capture.eventId = body.capture.eventId;
+            msg->body.capture.pointerCaptureEnabled = body.capture.pointerCaptureEnabled;
+            break;
+        }
     }
 }
 
@@ -571,6 +580,23 @@
     return mChannel->sendMessage(&msg);
 }
 
+status_t InputPublisher::publishCaptureEvent(uint32_t seq, int32_t eventId,
+                                             bool pointerCaptureEnabled) {
+    if (ATRACE_ENABLED()) {
+        std::string message =
+                StringPrintf("publishCaptureEvent(inputChannel=%s, pointerCaptureEnabled=%s)",
+                             mChannel->getName().c_str(), toString(pointerCaptureEnabled));
+        ATRACE_NAME(message.c_str());
+    }
+
+    InputMessage msg;
+    msg.header.type = InputMessage::Type::CAPTURE;
+    msg.header.seq = seq;
+    msg.body.capture.eventId = eventId;
+    msg.body.capture.pointerCaptureEnabled = pointerCaptureEnabled ? 1 : 0;
+    return mChannel->sendMessage(&msg);
+}
+
 status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {
     if (DEBUG_TRANSPORT_ACTIONS) {
         ALOGD("channel '%s' publisher ~ receiveFinishedSignal", mChannel->getName().c_str());
@@ -739,6 +765,16 @@
                 *outEvent = focusEvent;
                 break;
             }
+
+            case InputMessage::Type::CAPTURE: {
+                CaptureEvent* captureEvent = factory->createCaptureEvent();
+                if (!captureEvent) return NO_MEMORY;
+
+                initializeCaptureEvent(captureEvent, &mMsg);
+                *outSeq = mMsg.header.seq;
+                *outEvent = captureEvent;
+                break;
+            }
         }
     }
     return OK;
@@ -1171,6 +1207,10 @@
                       msg->body.focus.inTouchMode == 1);
 }
 
+void InputConsumer::initializeCaptureEvent(CaptureEvent* event, const InputMessage* msg) {
+    event->initialize(msg->body.capture.eventId, msg->body.capture.pointerCaptureEnabled == 1);
+}
+
 void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) {
     uint32_t pointerCount = msg->body.motion.pointerCount;
     PointerProperties pointerProperties[pointerCount];
@@ -1274,6 +1314,12 @@
                                                        toString(msg.body.focus.inTouchMode));
                     break;
                 }
+                case InputMessage::Type::CAPTURE: {
+                    out += android::base::StringPrintf("hasCapture=%s",
+                                                       toString(msg.body.capture
+                                                                        .pointerCaptureEnabled));
+                    break;
+                }
             }
             out += "\n";
         }
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 4f53dc9..9da7b69 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -51,6 +51,7 @@
     void PublishAndConsumeKeyEvent();
     void PublishAndConsumeMotionEvent();
     void PublishAndConsumeFocusEvent();
+    void PublishAndConsumeCaptureEvent();
 };
 
 TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) {
@@ -309,6 +310,43 @@
             << "publisher receiveFinishedSignal should have set handled to consumer's reply";
 }
 
+void InputPublisherAndConsumerTest::PublishAndConsumeCaptureEvent() {
+    status_t status;
+
+    constexpr uint32_t seq = 42;
+    int32_t eventId = InputEvent::nextId();
+    constexpr bool captureEnabled = true;
+
+    status = mPublisher->publishCaptureEvent(seq, eventId, captureEnabled);
+    ASSERT_EQ(OK, status) << "publisher publishKeyEvent should return OK";
+
+    uint32_t consumeSeq;
+    InputEvent* event;
+    status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
+    ASSERT_EQ(OK, status) << "consumer consume should return OK";
+
+    ASSERT_TRUE(event != nullptr) << "consumer should have returned non-NULL event";
+    ASSERT_EQ(AINPUT_EVENT_TYPE_CAPTURE, event->getType())
+            << "consumer should have returned a capture event";
+
+    const CaptureEvent* captureEvent = static_cast<CaptureEvent*>(event);
+    EXPECT_EQ(seq, consumeSeq);
+    EXPECT_EQ(eventId, captureEvent->getId());
+    EXPECT_EQ(captureEnabled, captureEvent->getPointerCaptureEnabled());
+
+    status = mConsumer->sendFinishedSignal(seq, true);
+    ASSERT_EQ(OK, status) << "consumer sendFinishedSignal should return OK";
+
+    uint32_t finishedSeq = 0;
+    bool handled = false;
+    status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);
+    ASSERT_EQ(OK, status) << "publisher receiveFinishedSignal should return OK";
+    ASSERT_EQ(seq, finishedSeq)
+            << "publisher receiveFinishedSignal should have returned the original sequence number";
+    ASSERT_TRUE(handled)
+            << "publisher receiveFinishedSignal should have set handled to consumer's reply";
+}
+
 TEST_F(InputPublisherAndConsumerTest, PublishKeyEvent_EndToEnd) {
     ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
 }
@@ -321,6 +359,10 @@
     ASSERT_NO_FATAL_FAILURE(PublishAndConsumeFocusEvent());
 }
 
+TEST_F(InputPublisherAndConsumerTest, PublishCaptureEvent_EndToEnd) {
+    ASSERT_NO_FATAL_FAILURE(PublishAndConsumeCaptureEvent());
+}
+
 TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenSequenceNumberIsZero_ReturnsError) {
     status_t status;
     const size_t pointerCount = 1;
@@ -385,6 +427,9 @@
     ASSERT_NO_FATAL_FAILURE(PublishAndConsumeFocusEvent());
     ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
     ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
+    ASSERT_NO_FATAL_FAILURE(PublishAndConsumeCaptureEvent());
+    ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
+    ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
 }
 
 } // namespace android
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 3c5fb22..4107d61 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -79,6 +79,9 @@
   CHECK_OFFSET(InputMessage::Body::Focus, hasFocus, 4);
   CHECK_OFFSET(InputMessage::Body::Focus, inTouchMode, 6);
 
+  CHECK_OFFSET(InputMessage::Body::Capture, eventId, 0);
+  CHECK_OFFSET(InputMessage::Body::Capture, pointerCaptureEnabled, 4);
+
   CHECK_OFFSET(InputMessage::Body::Finished, handled, 4);
 }
 
@@ -99,6 +102,7 @@
                           sizeof(InputMessage::Body::Motion::Pointer) * MAX_POINTERS);
     static_assert(sizeof(InputMessage::Body::Finished) == 8);
     static_assert(sizeof(InputMessage::Body::Focus) == 8);
+    static_assert(sizeof(InputMessage::Body::Capture) == 8);
 }
 
 // --- VerifiedInputEvent ---
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 1ec73ce..a375d43 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -397,6 +397,16 @@
     return 0;
 }
 
+int AHardwareBuffer_getId(const AHardwareBuffer* buffer, uint64_t* outId) {
+    if (!buffer || !outId) return BAD_VALUE;
+
+    const GraphicBuffer* gb = AHardwareBuffer_to_GraphicBuffer(buffer);
+    if (!gb) return BAD_VALUE;
+
+    *outId = gb->getId();
+
+    return OK;
+}
 
 // ----------------------------------------------------------------------------
 // VNDK functions
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index ae5e47b..4fcca9e 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -45,14 +45,14 @@
 #ifndef ANDROID_HARDWARE_BUFFER_H
 #define ANDROID_HARDWARE_BUFFER_H
 
+#include <android/rect.h>
 #include <inttypes.h>
-
 #include <sys/cdefs.h>
 
-#include <android/rect.h>
-
 __BEGIN_DECLS
 
+// clang-format off
+
 /**
  * Buffer pixel formats.
  */
@@ -201,9 +201,9 @@
     AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK        = 0xFUL << 4,
 
     /// The buffer will be read from by the GPU as a texture.
-    AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE      = 1UL << 8,
+    AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE     = 1UL << 8,
     /// The buffer will be written to by the GPU as a framebuffer attachment.
-    AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER        = 1UL << 9,
+    AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER       = 1UL << 9,
     /**
      * The buffer will be written to by the GPU as a framebuffer
      * attachment.
@@ -214,7 +214,7 @@
      * attachment should also have this flag. Use the equivalent flag
      * AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER to avoid this confusion.
      */
-    AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT       = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER,
+    AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT      = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER,
     /**
      * The buffer will be used as a composer HAL overlay layer.
      *
@@ -225,7 +225,7 @@
      * directly through AHardwareBuffer_allocate instead of buffers allocated
      * by the framework.
      */
-    AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY       = 1ULL << 11,
+    AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY      = 1ULL << 11,
     /**
      * The buffer is protected from direct CPU access or being read by
      * non-secure hardware, such as video encoders.
@@ -236,19 +236,19 @@
      * GL_EXT_protected_textures for more information on how these
      * buffers are expected to behave.
      */
-    AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT      = 1UL << 14,
+    AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT     = 1UL << 14,
     /// The buffer will be read by a hardware video encoder.
-    AHARDWAREBUFFER_USAGE_VIDEO_ENCODE           = 1UL << 16,
+    AHARDWAREBUFFER_USAGE_VIDEO_ENCODE          = 1UL << 16,
     /**
      * The buffer will be used for direct writes from sensors.
      * When this flag is present, the format must be AHARDWAREBUFFER_FORMAT_BLOB.
      */
-    AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA     = 1UL << 23,
+    AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA    = 1UL << 23,
     /**
      * The buffer will be used as a shader storage or uniform buffer object.
      * When this flag is present, the format must be AHARDWAREBUFFER_FORMAT_BLOB.
      */
-    AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER        = 1UL << 24,
+    AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER       = 1UL << 24,
     /**
      * The buffer will be used as a cube map texture.
      * When this flag is present, the buffer must have a layer count
@@ -256,13 +256,13 @@
      * bound to OpenGL textures using the extension
      * GL_EXT_EGL_image_storage instead of GL_KHR_EGL_image.
      */
-    AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP               = 1UL << 25,
+    AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP          = 1UL << 25,
     /**
      * The buffer contains a complete mipmap hierarchy.
      * Note that buffers with this flag must be bound to OpenGL textures using
      * the extension GL_EXT_EGL_image_storage instead of GL_KHR_EGL_image.
      */
-    AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE        = 1UL << 26,
+    AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE   = 1UL << 26,
 
     AHARDWAREBUFFER_USAGE_VENDOR_0  = 1ULL << 28,
     AHARDWAREBUFFER_USAGE_VENDOR_1  = 1ULL << 29,
@@ -291,8 +291,8 @@
  * parameters of existing ones.
  */
 typedef struct AHardwareBuffer_Desc {
-    uint32_t    width;      ///< Width in pixels.
-    uint32_t    height;     ///< Height in pixels.
+    uint32_t width;  ///< Width in pixels.
+    uint32_t height; ///< Height in pixels.
     /**
      * Number of images in an image array. AHardwareBuffers with one
      * layer correspond to regular 2D textures. AHardwareBuffers with
@@ -301,21 +301,21 @@
      * AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP is present, the buffer is
      * a cube map or a cube map array.
      */
-    uint32_t    layers;
-    uint32_t    format;     ///< One of AHardwareBuffer_Format.
-    uint64_t    usage;      ///< Combination of AHardwareBuffer_UsageFlags.
-    uint32_t    stride;     ///< Row stride in pixels, ignored for AHardwareBuffer_allocate()
-    uint32_t    rfu0;       ///< Initialize to zero, reserved for future use.
-    uint64_t    rfu1;       ///< Initialize to zero, reserved for future use.
+    uint32_t layers;
+    uint32_t format; ///< One of AHardwareBuffer_Format.
+    uint64_t usage;  ///< Combination of AHardwareBuffer_UsageFlags.
+    uint32_t stride; ///< Row stride in pixels, ignored for AHardwareBuffer_allocate()
+    uint32_t rfu0;   ///< Initialize to zero, reserved for future use.
+    uint64_t rfu1;   ///< Initialize to zero, reserved for future use.
 } AHardwareBuffer_Desc;
 
 /**
  * Holds data for a single image plane.
  */
 typedef struct AHardwareBuffer_Plane {
-    void*       data;        ///< Points to first byte in plane
-    uint32_t    pixelStride; ///< Distance in bytes from the color channel of one pixel to the next
-    uint32_t    rowStride;   ///< Distance in bytes from the first value of one row of the image to
+    void*    _Nullable data; ///< Points to first byte in plane
+    uint32_t pixelStride;    ///< Distance in bytes from the color channel of one pixel to the next
+    uint32_t rowStride;      ///< Distance in bytes from the first value of one row of the image to
                              ///  the first value of the next row.
 } AHardwareBuffer_Plane;
 
@@ -323,8 +323,8 @@
  * Holds all image planes that contain the pixel data.
  */
 typedef struct AHardwareBuffer_Planes {
-    uint32_t               planeCount; ///< Number of distinct planes
-    AHardwareBuffer_Plane  planes[4];     ///< Array of image planes
+    uint32_t              planeCount; ///< Number of distinct planes
+    AHardwareBuffer_Plane planes[4];  ///< Array of image planes
 } AHardwareBuffer_Planes;
 
 /**
@@ -332,6 +332,8 @@
  */
 typedef struct AHardwareBuffer AHardwareBuffer;
 
+// clang-format on
+
 #if __ANDROID_API__ >= 26
 
 /**
@@ -347,8 +349,8 @@
  * \return 0 on success, or an error number of the allocation fails for
  * any reason. The returned buffer has a reference count of 1.
  */
-int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc,
-        AHardwareBuffer** outBuffer) __INTRODUCED_IN(26);
+int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* _Nonnull desc,
+                             AHardwareBuffer* _Nullable* _Nonnull outBuffer) __INTRODUCED_IN(26);
 /**
  * Acquire a reference on the given AHardwareBuffer object.
  *
@@ -357,7 +359,7 @@
  *
  * Available since API level 26.
  */
-void AHardwareBuffer_acquire(AHardwareBuffer* buffer) __INTRODUCED_IN(26);
+void AHardwareBuffer_acquire(AHardwareBuffer* _Nonnull buffer) __INTRODUCED_IN(26);
 
 /**
  * Remove a reference that was previously acquired with
@@ -365,7 +367,7 @@
  *
  * Available since API level 26.
  */
-void AHardwareBuffer_release(AHardwareBuffer* buffer) __INTRODUCED_IN(26);
+void AHardwareBuffer_release(AHardwareBuffer* _Nonnull buffer) __INTRODUCED_IN(26);
 
 /**
  * Return a description of the AHardwareBuffer in the passed
@@ -373,8 +375,8 @@
  *
  * Available since API level 26.
  */
-void AHardwareBuffer_describe(const AHardwareBuffer* buffer,
-        AHardwareBuffer_Desc* outDesc) __INTRODUCED_IN(26);
+void AHardwareBuffer_describe(const AHardwareBuffer* _Nonnull buffer,
+                              AHardwareBuffer_Desc* _Nonnull outDesc) __INTRODUCED_IN(26);
 
 /**
  * Lock the AHardwareBuffer for direct CPU access.
@@ -428,8 +430,57 @@
  * has more than one layer. Error number if the lock fails for any other
  * reason.
  */
-int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage,
-        int32_t fence, const ARect* rect, void** outVirtualAddress) __INTRODUCED_IN(26);
+int AHardwareBuffer_lock(AHardwareBuffer* _Nonnull buffer, uint64_t usage, int32_t fence,
+                         const ARect* _Nullable rect, void* _Nullable* _Nonnull outVirtualAddress)
+        __INTRODUCED_IN(26);
+
+/**
+ * Unlock the AHardwareBuffer from direct CPU access.
+ *
+ * Must be called after all changes to the buffer are completed by the
+ * caller.  If \a fence is NULL, the function will block until all work
+ * is completed.  Otherwise, \a fence will be set either to a valid file
+ * descriptor or to -1.  The file descriptor will become signaled once
+ * the unlocking is complete and buffer contents are updated.
+ * The caller is responsible for closing the file descriptor once it's
+ * no longer needed.  The value -1 indicates that unlocking has already
+ * completed before the function returned and no further operations are
+ * necessary.
+ *
+ * Available since API level 26.
+ *
+ * \return 0 on success. -EINVAL if \a buffer is NULL. Error number if
+ * the unlock fails for any reason.
+ */
+int AHardwareBuffer_unlock(AHardwareBuffer* _Nonnull buffer, int32_t* _Nullable fence)
+        __INTRODUCED_IN(26);
+
+/**
+ * Send the AHardwareBuffer to an AF_UNIX socket.
+ *
+ * Available since API level 26.
+ *
+ * \return 0 on success, -EINVAL if \a buffer is NULL, or an error
+ * number if the operation fails for any reason.
+ */
+int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* _Nonnull buffer, int socketFd)
+        __INTRODUCED_IN(26);
+
+/**
+ * Receive an AHardwareBuffer from an AF_UNIX socket.
+ *
+ * Available since API level 26.
+ *
+ * \return 0 on success, -EINVAL if \a outBuffer is NULL, or an error
+ * number if the operation fails for any reason.
+ */
+int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd,
+                                             AHardwareBuffer* _Nullable* _Nonnull outBuffer)
+        __INTRODUCED_IN(26);
+
+#endif // __ANDROID_API__ >= 26
+
+#if __ANDROID_API__ >= 29
 
 /**
  * Lock a potentially multi-planar AHardwareBuffer for direct CPU access.
@@ -458,52 +509,9 @@
  * has more than one layer. Error number if the lock fails for any other
  * reason.
  */
-int AHardwareBuffer_lockPlanes(AHardwareBuffer* buffer, uint64_t usage,
-        int32_t fence, const ARect* rect, AHardwareBuffer_Planes* outPlanes) __INTRODUCED_IN(29);
-
-/**
- * Unlock the AHardwareBuffer from direct CPU access.
- *
- * Must be called after all changes to the buffer are completed by the
- * caller.  If \a fence is NULL, the function will block until all work
- * is completed.  Otherwise, \a fence will be set either to a valid file
- * descriptor or to -1.  The file descriptor will become signaled once
- * the unlocking is complete and buffer contents are updated.
- * The caller is responsible for closing the file descriptor once it's
- * no longer needed.  The value -1 indicates that unlocking has already
- * completed before the function returned and no further operations are
- * necessary.
- *
- * Available since API level 26.
- *
- * \return 0 on success. -EINVAL if \a buffer is NULL. Error number if
- * the unlock fails for any reason.
- */
-int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) __INTRODUCED_IN(26);
-
-/**
- * Send the AHardwareBuffer to an AF_UNIX socket.
- *
- * Available since API level 26.
- *
- * \return 0 on success, -EINVAL if \a buffer is NULL, or an error
- * number if the operation fails for any reason.
- */
-int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int socketFd) __INTRODUCED_IN(26);
-
-/**
- * Receive an AHardwareBuffer from an AF_UNIX socket.
- *
- * Available since API level 26.
- *
- * \return 0 on success, -EINVAL if \a outBuffer is NULL, or an error
- * number if the operation fails for any reason.
- */
-int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** outBuffer) __INTRODUCED_IN(26);
-
-#endif // __ANDROID_API__ >= 26
-
-#if __ANDROID_API__ >= 29
+int AHardwareBuffer_lockPlanes(AHardwareBuffer* _Nonnull buffer, uint64_t usage, int32_t fence,
+                               const ARect* _Nullable rect,
+                               AHardwareBuffer_Planes* _Nonnull outPlanes) __INTRODUCED_IN(29);
 
 /**
  * Test whether the given format and usage flag combination is
@@ -524,7 +532,7 @@
  * \return 1 if the format and usage flag combination is allocatable,
  *     0 otherwise.
  */
-int AHardwareBuffer_isSupported(const AHardwareBuffer_Desc* desc) __INTRODUCED_IN(29);
+int AHardwareBuffer_isSupported(const AHardwareBuffer_Desc* _Nonnull desc) __INTRODUCED_IN(29);
 
 /**
  * Lock an AHardwareBuffer for direct CPU access.
@@ -537,11 +545,29 @@
  *
  * Available since API level 29.
  */
-int AHardwareBuffer_lockAndGetInfo(AHardwareBuffer* buffer, uint64_t usage,
-        int32_t fence, const ARect* rect, void** outVirtualAddress,
-        int32_t* outBytesPerPixel, int32_t* outBytesPerStride) __INTRODUCED_IN(29);
+int AHardwareBuffer_lockAndGetInfo(AHardwareBuffer* _Nonnull buffer, uint64_t usage, int32_t fence,
+                                   const ARect* _Nullable rect,
+                                   void* _Nullable* _Nonnull outVirtualAddress,
+                                   int32_t* _Nonnull outBytesPerPixel,
+                                   int32_t* _Nonnull outBytesPerStride) __INTRODUCED_IN(29);
+
 #endif // __ANDROID_API__ >= 29
 
+#if __ANDROID_API__ >= 31
+
+/**
+ * Get the system wide unique id for an AHardwareBuffer.
+ *
+ * Available since API level 31.
+ *
+ * \return 0 on success, -EINVAL if \a buffer or \a outId is NULL, or an error number if the
+ * operation fails for any reason.
+ */
+int AHardwareBuffer_getId(const AHardwareBuffer* _Nonnull buffer, uint64_t* _Nonnull outId)
+        __INTRODUCED_IN(31);
+
+#endif // __ANDROID_API__ >= 31
+
 __END_DECLS
 
 #endif // ANDROID_HARDWARE_BUFFER_H
diff --git a/libs/nativewindow/include/vndk/hardware_buffer.h b/libs/nativewindow/include/vndk/hardware_buffer.h
index 3392d7f..50fe0b7 100644
--- a/libs/nativewindow/include/vndk/hardware_buffer.h
+++ b/libs/nativewindow/include/vndk/hardware_buffer.h
@@ -24,7 +24,14 @@
 
 __BEGIN_DECLS
 
-const native_handle_t* AHardwareBuffer_getNativeHandle(const AHardwareBuffer* buffer);
+/**
+ * Get the native handle from an AHardwareBuffer.
+ *
+ * \return a non-NULL native handle on success, NULL if \a buffer is nullptr or the operation fails
+ * for any reason.
+ */
+const native_handle_t* _Nullable AHardwareBuffer_getNativeHandle(
+        const AHardwareBuffer* _Nonnull buffer);
 
 enum CreateFromHandleMethod {
     // enum values chosen to match internal GraphicBuffer::HandleWrapMethod
@@ -33,9 +40,9 @@
 };
 
 /**
- * Create a AHardwareBuffer from a native handle.
+ * Create an AHardwareBuffer from a native handle.
  *
- * This function wraps a native handle in a AHardwareBuffer suitable for use by applications or
+ * This function wraps a native handle in an AHardwareBuffer suitable for use by applications or
  * other parts of the system. The contents of desc will be returned by AHardwareBuffer_describe().
  *
  * If method is AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_REGISTER, the handle is assumed to be
@@ -44,10 +51,13 @@
  *
  * If method is AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE, the handle will be cloned and the
  * clone registered. The AHardwareBuffer will own the cloned handle but not the original.
+ *
+ * \return 0 on success, -EINVAL if \a desc or \a handle or outBuffer is NULL, or an error number if
+ * the operation fails for any reason.
  */
-int AHardwareBuffer_createFromHandle(const AHardwareBuffer_Desc* desc,
-                                     const native_handle_t* handle, int32_t method,
-                                     AHardwareBuffer** outBuffer);
+int AHardwareBuffer_createFromHandle(const AHardwareBuffer_Desc* _Nonnull desc,
+                                     const native_handle_t* _Nonnull handle, int32_t method,
+                                     AHardwareBuffer* _Nullable* _Nonnull outBuffer);
 
 /**
  * Buffer pixel formats.
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index de48ec2..24d0e3b 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -4,6 +4,7 @@
     AHardwareBuffer_allocate;
     AHardwareBuffer_createFromHandle; # llndk # apex
     AHardwareBuffer_describe;
+    AHardwareBuffer_getId; # introduced=31
     AHardwareBuffer_getNativeHandle; # llndk # apex
     AHardwareBuffer_isSupported; # introduced=29
     AHardwareBuffer_lock;
diff --git a/libs/nativewindow/tests/AHardwareBufferTest.cpp b/libs/nativewindow/tests/AHardwareBufferTest.cpp
index 71b1f9f..ef863b6 100644
--- a/libs/nativewindow/tests/AHardwareBufferTest.cpp
+++ b/libs/nativewindow/tests/AHardwareBufferTest.cpp
@@ -17,12 +17,11 @@
 #define LOG_TAG "AHardwareBuffer_test"
 //#define LOG_NDEBUG 0
 
-#include <android/hardware_buffer.h>
-#include <private/android/AHardwareBufferHelpers.h>
 #include <android/hardware/graphics/common/1.0/types.h>
-#include <vndk/hardware_buffer.h>
-
 #include <gtest/gtest.h>
+#include <private/android/AHardwareBufferHelpers.h>
+#include <ui/GraphicBuffer.h>
+#include <vndk/hardware_buffer.h>
 
 using namespace android;
 using android::hardware::graphics::common::V1_0::BufferUsage;
@@ -131,3 +130,43 @@
     AHardwareBuffer_release(buffer);
     AHardwareBuffer_release(otherBuffer);
 }
+
+TEST(AHardwareBufferTest, GetIdTest) {
+    const uint32_t testWidth = 4;
+    const uint32_t testHeight = 4;
+    const uint32_t testLayers = 1;
+
+    AHardwareBuffer* ahb1 = nullptr;
+    uint64_t id1 = 0;
+    const AHardwareBuffer_Desc desc = {
+            .width = testWidth,
+            .height = testHeight,
+            .layers = testLayers,
+            .format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+            .usage = AHARDWAREBUFFER_USAGE_CPU_READ_RARELY,
+    };
+    int res = AHardwareBuffer_allocate(&desc, &ahb1);
+    EXPECT_EQ(NO_ERROR, res);
+    EXPECT_NE(nullptr, ahb1);
+    EXPECT_EQ(0, AHardwareBuffer_getId(ahb1, &id1));
+    const GraphicBuffer* gb1 = AHardwareBuffer_to_GraphicBuffer(ahb1);
+    EXPECT_NE(nullptr, gb1);
+    EXPECT_EQ(id1, gb1->getId());
+    EXPECT_NE(id1, 0);
+
+    sp<GraphicBuffer> gb2(new GraphicBuffer(testWidth,
+                                            testHeight,
+                                            PIXEL_FORMAT_RGBA_8888,
+                                            testLayers,
+                                            GraphicBuffer::USAGE_SW_READ_RARELY,
+                                            std::string("test")));
+    EXPECT_NE(nullptr, gb2.get());
+    const AHardwareBuffer* ahb2 = AHardwareBuffer_from_GraphicBuffer(gb2.get());
+    EXPECT_NE(nullptr, ahb2);
+    uint64_t id2 = 0;
+    EXPECT_EQ(0, AHardwareBuffer_getId(ahb2, &id2));
+    EXPECT_EQ(id2, gb2->getId());
+    EXPECT_NE(id2, 0);
+
+    EXPECT_NE(id1, id2);
+}
diff --git a/libs/nativewindow/tests/Android.bp b/libs/nativewindow/tests/Android.bp
index cdb3d20..2e4bd99 100644
--- a/libs/nativewindow/tests/Android.bp
+++ b/libs/nativewindow/tests/Android.bp
@@ -24,6 +24,7 @@
         "liblog",
         "libnativewindow",
         "libsync",
+        "libui",
         "libutils",
         "android.hardware.graphics.common@1.0",
     ],
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index 340d7bf..d5a19d3 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -80,6 +80,7 @@
 
 cc_library_shared {
     name: "libdvr.google",
+    system_ext_specific: true,
     owner: "google",
     cflags: cflags,
     header_libs: ["libdvr_headers"],
diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp
index 1ce9c99..b3534de 100644
--- a/libs/vr/libpdx_default_transport/Android.bp
+++ b/libs/vr/libpdx_default_transport/Android.bp
@@ -45,6 +45,7 @@
 
 cc_binary {
     name: "pdx_tool",
+    system_ext_specific: true,
     defaults: ["pdx_default_transport_compiler_defaults"],
     srcs: [
         "pdx_tool.cpp",
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index 77a0716..eafb5ab 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -405,6 +405,11 @@
     mListener->notifyDeviceReset(args);
 }
 
+void InputClassifier::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
+    // pass through
+    mListener->notifyPointerCaptureChanged(args);
+}
+
 void InputClassifier::setMotionClassifier(
         std::unique_ptr<MotionClassifierInterface> motionClassifier) {
     std::scoped_lock lock(mLock);
diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h
index 03510a6..6965940 100644
--- a/services/inputflinger/InputClassifier.h
+++ b/services/inputflinger/InputClassifier.h
@@ -230,6 +230,7 @@
     virtual void notifyMotion(const NotifyMotionArgs* args) override;
     virtual void notifySwitch(const NotifySwitchArgs* args) override;
     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
+    void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
 
     virtual void dump(std::string& dump) override;
 
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 84838ec..49a813e 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -48,7 +48,6 @@
     listener->notifyConfigurationChanged(this);
 }
 
-
 // --- NotifyKeyArgs ---
 
 NotifyKeyArgs::NotifyKeyArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source,
@@ -90,7 +89,6 @@
     listener->notifyKey(this);
 }
 
-
 // --- NotifyMotionArgs ---
 
 NotifyMotionArgs::NotifyMotionArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source,
@@ -189,7 +187,6 @@
     listener->notifyMotion(this);
 }
 
-
 // --- NotifySwitchArgs ---
 
 NotifySwitchArgs::NotifySwitchArgs(int32_t id, nsecs_t eventTime, uint32_t policyFlags,
@@ -214,7 +211,6 @@
     listener->notifySwitch(this);
 }
 
-
 // --- NotifyDeviceResetArgs ---
 
 NotifyDeviceResetArgs::NotifyDeviceResetArgs(int32_t id, nsecs_t eventTime, int32_t deviceId)
@@ -231,6 +227,23 @@
     listener->notifyDeviceReset(this);
 }
 
+// --- NotifyPointerCaptureChangedArgs ---
+
+NotifyPointerCaptureChangedArgs::NotifyPointerCaptureChangedArgs(int32_t id, nsecs_t eventTime,
+                                                                 bool enabled)
+      : NotifyArgs(id, eventTime), enabled(enabled) {}
+
+NotifyPointerCaptureChangedArgs::NotifyPointerCaptureChangedArgs(
+        const NotifyPointerCaptureChangedArgs& other)
+      : NotifyArgs(other.id, other.eventTime), enabled(other.enabled) {}
+
+bool NotifyPointerCaptureChangedArgs::operator==(const NotifyPointerCaptureChangedArgs& rhs) const {
+    return id == rhs.id && eventTime == rhs.eventTime && enabled == rhs.enabled;
+}
+
+void NotifyPointerCaptureChangedArgs::notify(const sp<InputListenerInterface>& listener) const {
+    listener->notifyPointerCaptureChanged(this);
+}
 
 // --- QueuedInputListener ---
 
@@ -278,6 +291,11 @@
     mArgsQueue.push_back(new NotifyDeviceResetArgs(*args));
 }
 
+void QueuedInputListener::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
+    traceEvent(__func__, args->id);
+    mArgsQueue.push_back(new NotifyPointerCaptureChangedArgs(*args));
+}
+
 void QueuedInputListener::flush() {
     size_t count = mArgsQueue.size();
     for (size_t i = 0; i < count; i++) {
@@ -288,5 +306,4 @@
     mArgsQueue.clear();
 }
 
-
 } // namespace android
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index b28bff2..91e9536 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -3542,6 +3542,15 @@
     }
 }
 
+void InputDispatcher::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
+#if DEBUG_INBOUND_EVENT_DETAILS
+    ALOGD("notifyPointerCaptureChanged - eventTime=%" PRId64 ", enabled=%s", args->eventTime,
+          args->enabled ? "true" : "false");
+#endif
+
+    // TODO(prabirmsp): Implement.
+}
+
 InputEventInjectionResult InputDispatcher::injectInputEvent(
         const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
         InputEventInjectionSync syncMode, std::chrono::milliseconds timeout, uint32_t policyFlags) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 5704a5a..9aaae74 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -94,6 +94,7 @@
     virtual void notifyMotion(const NotifyMotionArgs* args) override;
     virtual void notifySwitch(const NotifySwitchArgs* args) override;
     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
+    virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
 
     virtual android::os::InputEventInjectionResult injectInputEvent(
             const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h
index 8317b05..58eb915 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -181,6 +181,22 @@
     virtual void notify(const sp<InputListenerInterface>& listener) const;
 };
 
+/* Describes a change in the state of Pointer Capture. */
+struct NotifyPointerCaptureChangedArgs : public NotifyArgs {
+    bool enabled;
+
+    inline NotifyPointerCaptureChangedArgs() {}
+
+    NotifyPointerCaptureChangedArgs(int32_t id, nsecs_t eventTime, bool enabled);
+
+    NotifyPointerCaptureChangedArgs(const NotifyPointerCaptureChangedArgs& other);
+
+    bool operator==(const NotifyPointerCaptureChangedArgs& rhs) const;
+
+    virtual ~NotifyPointerCaptureChangedArgs() {}
+
+    virtual void notify(const sp<InputListenerInterface>& listener) const;
+};
 
 /*
  * The interface used by the InputReader to notify the InputListener about input events.
@@ -196,6 +212,7 @@
     virtual void notifyMotion(const NotifyMotionArgs* args) = 0;
     virtual void notifySwitch(const NotifySwitchArgs* args) = 0;
     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0;
+    virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) = 0;
 };
 
 
@@ -210,11 +227,12 @@
 public:
     explicit QueuedInputListener(const sp<InputListenerInterface>& innerListener);
 
-    virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
-    virtual void notifyKey(const NotifyKeyArgs* args);
-    virtual void notifyMotion(const NotifyMotionArgs* args);
-    virtual void notifySwitch(const NotifySwitchArgs* args);
-    virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
+    virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
+    virtual void notifyKey(const NotifyKeyArgs* args) override;
+    virtual void notifyMotion(const NotifyMotionArgs* args) override;
+    virtual void notifySwitch(const NotifySwitchArgs* args) override;
+    virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
+    void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
 
     void flush();
 
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 2028b91..e263f01 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -338,24 +338,30 @@
     mPolicy->getReaderConfiguration(&mConfig);
     mEventHub->setExcludedDevices(mConfig.excludedDeviceNames);
 
-    if (changes) {
-        ALOGI("Reconfiguring input devices, changes=%s",
-              InputReaderConfiguration::changesToString(changes).c_str());
-        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+    if (!changes) return;
 
-        if (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO) {
-            updatePointerDisplayLocked();
-        }
+    ALOGI("Reconfiguring input devices, changes=%s",
+          InputReaderConfiguration::changesToString(changes).c_str());
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
 
-        if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) {
-            mEventHub->requestReopenDevices();
-        } else {
-            for (auto& devicePair : mDevices) {
-                std::shared_ptr<InputDevice>& device = devicePair.second;
-                device->configure(now, &mConfig, changes);
-            }
+    if (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO) {
+        updatePointerDisplayLocked();
+    }
+
+    if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) {
+        mEventHub->requestReopenDevices();
+    } else {
+        for (auto& devicePair : mDevices) {
+            std::shared_ptr<InputDevice>& device = devicePair.second;
+            device->configure(now, &mConfig, changes);
         }
     }
+
+    if (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE) {
+        const NotifyPointerCaptureChangedArgs args(mContext.getNextId(), now,
+                                                   mConfig.pointerCapture);
+        mQueuedListener->notifyPointerCaptureChanged(&args);
+    }
 }
 
 void InputReader::updateGlobalMetaStateLocked() {
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index a72d5c3..99eaac6 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -1792,6 +1792,29 @@
               mReader->getKeyCodeState(deviceId, AINPUT_SOURCE_KEYBOARD, AKEYCODE_C));
 }
 
+TEST_F(InputReaderTest, ChangingPointerCaptureNotifiesInputListener) {
+    NotifyPointerCaptureChangedArgs args;
+
+    mFakePolicy->setPointerCapture(true);
+    mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+    mReader->loopOnce();
+    mFakeListener->assertNotifyCaptureWasCalled(&args);
+    ASSERT_TRUE(args.enabled) << "Pointer Capture should be enabled.";
+
+    mFakePolicy->setPointerCapture(false);
+    mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+    mReader->loopOnce();
+    mFakeListener->assertNotifyCaptureWasCalled(&args);
+    ASSERT_FALSE(args.enabled) << "Pointer Capture should be disabled.";
+
+    // Verify that the Pointer Capture state is re-configured correctly when the configuration value
+    // does not change.
+    mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+    mReader->loopOnce();
+    mFakeListener->assertNotifyCaptureWasCalled(&args);
+    ASSERT_FALSE(args.enabled) << "Pointer Capture should be disabled.";
+}
+
 // --- InputReaderIntegrationTest ---
 
 // These tests create and interact with the InputReader only through its interface.
diff --git a/services/inputflinger/tests/TestInputListener.cpp b/services/inputflinger/tests/TestInputListener.cpp
index 9bff166..352995c 100644
--- a/services/inputflinger/tests/TestInputListener.cpp
+++ b/services/inputflinger/tests/TestInputListener.cpp
@@ -82,6 +82,14 @@
                                            "Expected notifySwitch() to have been called."));
 }
 
+void TestInputListener::assertNotifyCaptureWasCalled(
+        NotifyPointerCaptureChangedArgs* outEventArgs) {
+    ASSERT_NO_FATAL_FAILURE(
+            assertCalled<NotifyPointerCaptureChangedArgs>(outEventArgs,
+                                                          "Expected notifyPointerCaptureChanged() "
+                                                          "to have been called."));
+}
+
 template <class NotifyArgsType>
 void TestInputListener::assertCalled(NotifyArgsType* outEventArgs, std::string message) {
     std::unique_lock<std::mutex> lock(mLock);
@@ -145,4 +153,8 @@
     notify<NotifySwitchArgs>(args);
 }
 
+void TestInputListener::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
+    notify<NotifyPointerCaptureChangedArgs>(args);
+}
+
 } // namespace android
diff --git a/services/inputflinger/tests/TestInputListener.h b/services/inputflinger/tests/TestInputListener.h
index d50c6bc..887d4ea 100644
--- a/services/inputflinger/tests/TestInputListener.h
+++ b/services/inputflinger/tests/TestInputListener.h
@@ -54,6 +54,8 @@
 
     void assertNotifySwitchWasCalled(NotifySwitchArgs* outEventArgs = nullptr);
 
+    void assertNotifyCaptureWasCalled(NotifyPointerCaptureChangedArgs* outEventArgs = nullptr);
+
 private:
     template <class NotifyArgsType>
     void assertCalled(NotifyArgsType* outEventArgs, std::string message);
@@ -74,16 +76,19 @@
 
     virtual void notifySwitch(const NotifySwitchArgs* args) override;
 
+    virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
+
     std::mutex mLock;
     std::condition_variable mCondition;
     const std::chrono::milliseconds mEventHappenedTimeout;
     const std::chrono::milliseconds mEventDidNotHappenTimeout;
 
-    std::tuple<std::vector<NotifyConfigurationChangedArgs>, //
-               std::vector<NotifyDeviceResetArgs>,          //
-               std::vector<NotifyKeyArgs>,                  //
-               std::vector<NotifyMotionArgs>,               //
-               std::vector<NotifySwitchArgs>>               //
+    std::tuple<std::vector<NotifyConfigurationChangedArgs>,  //
+               std::vector<NotifyDeviceResetArgs>,           //
+               std::vector<NotifyKeyArgs>,                   //
+               std::vector<NotifyMotionArgs>,                //
+               std::vector<NotifySwitchArgs>,                //
+               std::vector<NotifyPointerCaptureChangedArgs>> //
             mQueues GUARDED_BY(mLock);
 };
 
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index deaf846..63dfe5f 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -178,13 +178,17 @@
     /// the mStateLock.
     ui::Transform::RotationFlags mTransformHint = ui::Transform::ROT_0;
 
+    bool getAutoRefresh() const { return mAutoRefresh; }
+    bool getSidebandStreamChanged() const { return mSidebandStreamChanged; }
+
+    std::atomic<bool> mAutoRefresh{false};
+    std::atomic<bool> mSidebandStreamChanged{false};
+
 private:
     virtual bool fenceHasSignaled() const = 0;
     virtual bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const = 0;
     virtual uint64_t getFrameNumber(nsecs_t expectedPresentTime) const = 0;
 
-    virtual bool getAutoRefresh() const = 0;
-    virtual bool getSidebandStreamChanged() const = 0;
 
     // Latch sideband stream and returns true if the dirty region should be updated.
     virtual bool latchSidebandStream(bool& recomputeVisibleRegions) = 0;
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 71b05fd..dc99986 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -196,14 +196,6 @@
     return frameNumber;
 }
 
-bool BufferQueueLayer::getAutoRefresh() const {
-    return mAutoRefresh;
-}
-
-bool BufferQueueLayer::getSidebandStreamChanged() const {
-    return mSidebandStreamChanged;
-}
-
 bool BufferQueueLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
     // We need to update the sideband stream if the layer has both a buffer and a sideband stream.
     const bool updateSidebandStream = hasFrameUpdate() && mSidebandStream.get();
@@ -265,8 +257,10 @@
     const uint64_t maxFrameNumberToAcquire =
             std::min(mLastFrameNumberReceived.load(), lastSignaledFrameNumber);
 
-    status_t updateResult = mConsumer->updateTexImage(&r, expectedPresentTime, &mAutoRefresh,
+    bool autoRefresh;
+    status_t updateResult = mConsumer->updateTexImage(&r, expectedPresentTime, &autoRefresh,
                                                       &queuedBuffer, maxFrameNumberToAcquire);
+    mAutoRefresh = autoRefresh;
     if (updateResult == BufferQueue::PRESENT_LATER) {
         // Producer doesn't want buffer to be displayed yet.  Signal a
         // layer update so we check again at the next opportunity.
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index fb8a0c2..b45900e 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -90,9 +90,6 @@
 private:
     uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override;
 
-    bool getAutoRefresh() const override;
-    bool getSidebandStreamChanged() const override;
-
     bool latchSidebandStream(bool& recomputeVisibleRegions) override;
     void setTransformHint(ui::Transform::RotationFlags displayTransformHint) override;
 
@@ -140,11 +137,8 @@
     std::vector<BufferData> mQueueItems;
     std::atomic<uint64_t> mLastFrameNumberReceived{0};
 
-    bool mAutoRefresh{false};
-
     // thread-safe
     std::atomic<int32_t> mQueuedFrames{0};
-    std::atomic<bool> mSidebandStreamChanged{false};
 
     sp<ContentsChangedListener> mContentsChangedListener;
 
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index a64b243..963e541 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -482,13 +482,10 @@
     return mCurrentState.frameNumber;
 }
 
-bool BufferStateLayer::getAutoRefresh() const {
-    // TODO(marissaw): support shared buffer mode
-    return false;
-}
-
-bool BufferStateLayer::getSidebandStreamChanged() const {
-    return mSidebandStreamChanged.load();
+void BufferStateLayer::setAutoRefresh(bool autoRefresh) {
+    if (!mAutoRefresh.exchange(autoRefresh)) {
+        mFlinger->signalLayerUpdate();
+    }
 }
 
 bool BufferStateLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
@@ -526,37 +523,12 @@
         return NO_ERROR;
     }
 
-    const int32_t layerId = getSequence();
-
-    // Reject if the layer is invalid
-    uint32_t bufferWidth = s.buffer->width;
-    uint32_t bufferHeight = s.buffer->height;
-
-    if (s.transform & ui::Transform::ROT_90) {
-        std::swap(bufferWidth, bufferHeight);
-    }
-
-    if (s.transformToDisplayInverse) {
-        uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
-        if (invTransform & ui::Transform::ROT_90) {
-            std::swap(bufferWidth, bufferHeight);
-        }
-    }
-
-    if (getEffectiveScalingMode() == NATIVE_WINDOW_SCALING_MODE_FREEZE &&
-        (s.active.w != bufferWidth || s.active.h != bufferHeight)) {
-        ALOGE("[%s] rejecting buffer: "
-              "bufferWidth=%d, bufferHeight=%d, front.active.{w=%d, h=%d}",
-              getDebugName(), bufferWidth, bufferHeight, s.active.w, s.active.h);
-        mFlinger->mTimeStats->removeTimeRecord(layerId, mDrawingState.frameNumber);
-        return BAD_VALUE;
-    }
-
     for (auto& handle : mDrawingState.callbackHandles) {
         handle->latchTime = latchTime;
         handle->frameNumber = mDrawingState.frameNumber;
     }
 
+    const int32_t layerId = getSequence();
     mFlinger->mTimeStats->setAcquireFence(layerId, mDrawingState.frameNumber,
                                           std::make_shared<FenceTime>(mDrawingState.acquireFence));
     mFlinger->mTimeStats->setLatchTime(layerId, mDrawingState.frameNumber, latchTime);
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 104a13b..42be62a 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -100,6 +100,7 @@
     Rect getBufferSize(const State& s) const override;
     FloatRect computeSourceBounds(const FloatRect& parentBounds) const override;
     Layer::RoundedCornerState getRoundedCornerState() const override;
+    void setAutoRefresh(bool autoRefresh) override;
 
     // -----------------------------------------------------------------------
 
@@ -123,9 +124,6 @@
 
     uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override;
 
-    bool getAutoRefresh() const override;
-    bool getSidebandStreamChanged() const override;
-
     bool latchSidebandStream(bool& recomputeVisibleRegions) override;
 
     bool hasFrameUpdate() const override;
@@ -149,8 +147,6 @@
 
     std::unique_ptr<renderengine::Image> mTextureImage;
 
-    std::atomic<bool> mSidebandStreamChanged{false};
-
     mutable uint64_t mFrameNumber{0};
     uint64_t mFrameCounter{0};
 
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 4b4c050..901e19a 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -64,7 +64,7 @@
 PowerAdvisor::PowerAdvisor()
       : mUseUpdateImminentTimer(getUpdateTimeout() > 0),
         mUpdateImminentTimer(
-                OneShotTimer::Interval(getUpdateTimeout()),
+                "UpdateImminentTimer", OneShotTimer::Interval(getUpdateTimeout()),
                 /* resetCallback */ [this] { mSendUpdateImminent.store(false); },
                 /* timeoutCallback */ [this] { mSendUpdateImminent.store(true); }) {
     if (mUseUpdateImminentTimer) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 1a784aa..8d67ce5 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -444,6 +444,7 @@
     virtual bool setColorSpaceAgnostic(const bool agnostic);
     virtual bool setFrameRateSelectionPriority(int32_t priority);
     virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint);
+    virtual void setAutoRefresh(bool /* autoRefresh */) {}
     //  If the variable is not set on the layer, it traverses up the tree to inherit the frame
     //  rate priority from its parent.
     virtual int32_t getFrameRateSelectionPriority() const;
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index b7b7e46..2511eb3 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -175,6 +175,7 @@
         mScheduler(scheduler),
         mTunables(tunables),
         mIdleTimer(
+                "RegionSamplingIdleTimer",
                 std::chrono::duration_cast<std::chrono::milliseconds>(
                         mTunables.mSamplingTimerTimeout),
                 [] {}, [this] { checkForStaleLuma(); }),
diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.cpp b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
index 2783800..ce3b0c6 100644
--- a/services/surfaceflinger/Scheduler/OneShotTimer.cpp
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
@@ -16,6 +16,8 @@
 
 #include "OneShotTimer.h"
 
+#include <utils/Log.h>
+#include <utils/Timers.h>
 #include <chrono>
 #include <sstream>
 #include <thread>
@@ -29,25 +31,30 @@
 // (tv_sec) is the whole count of seconds. The second (tv_nsec) is the
 // nanosecond part of the count. This function takes care of translation.
 void calculateTimeoutTime(std::chrono::nanoseconds timestamp, timespec* spec) {
-    clock_gettime(CLOCK_MONOTONIC, spec);
-    spec->tv_sec += static_cast<__kernel_time_t>(timestamp.count() / kNsToSeconds);
-    spec->tv_nsec += timestamp.count() % kNsToSeconds;
+    const nsecs_t timeout = systemTime(CLOCK_MONOTONIC) + timestamp.count();
+    spec->tv_sec = static_cast<__kernel_time_t>(timeout / kNsToSeconds);
+    spec->tv_nsec = timeout % kNsToSeconds;
 }
 } // namespace
 
 namespace android {
 namespace scheduler {
 
-OneShotTimer::OneShotTimer(const Interval& interval, const ResetCallback& resetCallback,
+OneShotTimer::OneShotTimer(std::string name, const Interval& interval,
+                           const ResetCallback& resetCallback,
                            const TimeoutCallback& timeoutCallback)
-      : mInterval(interval), mResetCallback(resetCallback), mTimeoutCallback(timeoutCallback) {}
+      : mName(std::move(name)),
+        mInterval(interval),
+        mResetCallback(resetCallback),
+        mTimeoutCallback(timeoutCallback) {}
 
 OneShotTimer::~OneShotTimer() {
     stop();
 }
 
 void OneShotTimer::start() {
-    sem_init(&mSemaphore, 0, 0);
+    int result = sem_init(&mSemaphore, 0, 0);
+    LOG_ALWAYS_FATAL_IF(result, "sem_init failed");
 
     if (!mThread.joinable()) {
         // Only create thread if it has not been created.
@@ -57,15 +64,21 @@
 
 void OneShotTimer::stop() {
     mStopTriggered = true;
-    sem_post(&mSemaphore);
+    int result = sem_post(&mSemaphore);
+    LOG_ALWAYS_FATAL_IF(result, "sem_post failed");
 
     if (mThread.joinable()) {
         mThread.join();
-        sem_destroy(&mSemaphore);
+        result = sem_destroy(&mSemaphore);
+        LOG_ALWAYS_FATAL_IF(result, "sem_destroy failed");
     }
 }
 
 void OneShotTimer::loop() {
+    if (pthread_setname_np(pthread_self(), mName.c_str())) {
+        ALOGW("Failed to set thread name on dispatch thread");
+    }
+
     TimerState state = TimerState::RESET;
     while (true) {
         bool triggerReset = false;
@@ -77,7 +90,12 @@
         }
 
         if (state == TimerState::IDLE) {
-            sem_wait(&mSemaphore);
+            int result = sem_wait(&mSemaphore);
+            if (result && errno != EINTR) {
+                std::stringstream ss;
+                ss << "sem_wait failed (" << errno << ")";
+                LOG_ALWAYS_FATAL("%s", ss.str().c_str());
+            }
             continue;
         }
 
@@ -101,7 +119,12 @@
             // Wait for mInterval time for semaphore signal.
             struct timespec ts;
             calculateTimeoutTime(std::chrono::nanoseconds(mInterval), &ts);
-            sem_clockwait(&mSemaphore, CLOCK_MONOTONIC, &ts);
+            int result = sem_clockwait(&mSemaphore, CLOCK_MONOTONIC, &ts);
+            if (result && errno != ETIMEDOUT && errno != EINTR) {
+                std::stringstream ss;
+                ss << "sem_clockwait failed (" << errno << ")";
+                LOG_ALWAYS_FATAL("%s", ss.str().c_str());
+            }
 
             state = checkForResetAndStop(state);
             if (state == TimerState::RESET) {
@@ -135,7 +158,8 @@
 
 void OneShotTimer::reset() {
     mResetTriggered = true;
-    sem_post(&mSemaphore);
+    int result = sem_post(&mSemaphore);
+    LOG_ALWAYS_FATAL_IF(result, "sem_post failed");
 }
 
 std::string OneShotTimer::dump() const {
diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.h b/services/surfaceflinger/Scheduler/OneShotTimer.h
index 8bbd4f5..3690ce7 100644
--- a/services/surfaceflinger/Scheduler/OneShotTimer.h
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.h
@@ -36,7 +36,7 @@
     using ResetCallback = std::function<void()>;
     using TimeoutCallback = std::function<void()>;
 
-    OneShotTimer(const Interval& interval, const ResetCallback& resetCallback,
+    OneShotTimer(std::string name, const Interval& interval, const ResetCallback& resetCallback,
                  const TimeoutCallback& timeoutCallback);
     ~OneShotTimer();
 
@@ -81,6 +81,9 @@
     // Semaphore to keep mThread synchronized.
     sem_t mSemaphore;
 
+    // Timer's name.
+    std::string mName;
+
     // Interval after which timer expires.
     const Interval mInterval;
 
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index a14019e..3706631 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -135,7 +135,7 @@
         const auto callback = mOptions.supportKernelTimer ? &Scheduler::kernelIdleTimerCallback
                                                           : &Scheduler::idleTimerCallback;
         mIdleTimer.emplace(
-                std::chrono::milliseconds(millis),
+                "IdleTimer", std::chrono::milliseconds(millis),
                 [this, callback] { std::invoke(callback, this, TimerState::Reset); },
                 [this, callback] { std::invoke(callback, this, TimerState::Expired); });
         mIdleTimer->start();
@@ -144,7 +144,7 @@
     if (const int64_t millis = set_touch_timer_ms(0); millis > 0) {
         // Touch events are coming to SF every 100ms, so the timer needs to be higher than that
         mTouchTimer.emplace(
-                std::chrono::milliseconds(millis),
+                "TouchTimer", std::chrono::milliseconds(millis),
                 [this] { touchTimerCallback(TimerState::Reset); },
                 [this] { touchTimerCallback(TimerState::Expired); });
         mTouchTimer->start();
@@ -152,7 +152,7 @@
 
     if (const int64_t millis = set_display_power_timer_ms(0); millis > 0) {
         mDisplayPowerTimer.emplace(
-                std::chrono::milliseconds(millis),
+                "DisplayPowerTimer", std::chrono::milliseconds(millis),
                 [this] { displayPowerTimerCallback(TimerState::Reset); },
                 [this] { displayPowerTimerCallback(TimerState::Expired); });
         mDisplayPowerTimer->start();
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 75d1e6f..a28ed92 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -77,8 +77,12 @@
 
     if (!validate(timestamp)) {
         // VSR could elect to ignore the incongruent timestamp or resetModel(). If ts is ignored,
-        // don't insert this ts into mTimestamps ringbuffer.
-        if (!mTimestamps.empty()) {
+        // don't insert this ts into mTimestamps ringbuffer. If we are still
+        // in the learning phase we should just clear all timestamps and start
+        // over.
+        if (mTimestamps.size() < kMinimumSamplesForPrediction) {
+            clearTimestamps();
+        } else if (!mTimestamps.empty()) {
             mKnownTimestamp =
                     std::max(timestamp, *std::max_element(mTimestamps.begin(), mTimestamps.end()));
         } else {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 91f050c..604a83a 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -330,7 +330,7 @@
       : mFactory(factory),
         mInterceptor(mFactory.createSurfaceInterceptor()),
         mTimeStats(std::make_shared<impl::TimeStats>()),
-        mFrameTracer(std::make_unique<FrameTracer>()),
+        mFrameTracer(mFactory.createFrameTracer()),
         mFrameTimeline(std::make_unique<frametimeline::impl::FrameTimeline>(mTimeStats)),
         mEventQueue(mFactory.createMessageQueue()),
         mCompositionEngine(mFactory.createCompositionEngine()),
@@ -3796,6 +3796,9 @@
             flags |= eTraversalNeeded | eTransformHintUpdateNeeded;
         }
     }
+    if (what & layer_state_t::eAutoRefreshChanged) {
+        layer->setAutoRefresh(s.autoRefresh);
+    }
     // This has to happen after we reparent children because when we reparent to null we remove
     // child layers from current state and remove its relative z. If the children are reparented in
     // the same transaction, then we have to make sure we reparent the children first so we do not
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index 9a8deae..a93f5f6 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -28,6 +28,7 @@
 #include "ContainerLayer.h"
 #include "DisplayDevice.h"
 #include "EffectLayer.h"
+#include "FrameTracer/FrameTracer.h"
 #include "Layer.h"
 #include "MonitoredProducer.h"
 #include "NativeWindowSurface.h"
@@ -130,6 +131,9 @@
     return new EffectLayer(args);
 }
 
+std::unique_ptr<FrameTracer> DefaultFactory::createFrameTracer() {
+    return std::make_unique<FrameTracer>();
+}
 } // namespace android::surfaceflinger
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 40774ef..90032d4 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -54,6 +54,7 @@
     sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) override;
     sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) override;
     sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) override;
+    std::unique_ptr<FrameTracer> createFrameTracer() override;
 };
 
 } // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 2dd563b..69e9c3c 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -34,6 +34,7 @@
 class EffectLayer;
 class ContainerLayer;
 class DisplayDevice;
+class FrameTracer;
 class GraphicBuffer;
 class HWComposer;
 class IGraphicBufferConsumer;
@@ -100,6 +101,7 @@
     virtual sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) = 0;
     virtual sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) = 0;
     virtual sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) = 0;
+    virtual std::unique_ptr<FrameTracer> createFrameTracer() = 0;
 
 protected:
     ~Factory() = default;
diff --git a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
index 0208728..cfbb3f5 100644
--- a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
@@ -57,11 +57,12 @@
 namespace {
 TEST_F(OneShotTimerTest, createAndDestroyTest) {
     mIdleTimer = std::make_unique<scheduler::OneShotTimer>(
-            3ms, [] {}, [] {});
+            "TestTimer", 3ms, [] {}, [] {});
 }
 
 TEST_F(OneShotTimerTest, startStopTest) {
-    mIdleTimer = std::make_unique<scheduler::OneShotTimer>(30ms, mResetTimerCallback.getInvocable(),
+    mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 30ms,
+                                                           mResetTimerCallback.getInvocable(),
                                                            mExpiredTimerCallback.getInvocable());
     auto startTime = std::chrono::steady_clock::now();
     mIdleTimer->start();
@@ -81,7 +82,8 @@
 }
 
 TEST_F(OneShotTimerTest, resetTest) {
-    mIdleTimer = std::make_unique<scheduler::OneShotTimer>(20ms, mResetTimerCallback.getInvocable(),
+    mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 20ms,
+                                                           mResetTimerCallback.getInvocable(),
                                                            mExpiredTimerCallback.getInvocable());
     mIdleTimer->start();
     EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
@@ -106,7 +108,8 @@
 }
 
 TEST_F(OneShotTimerTest, resetBackToBackTest) {
-    mIdleTimer = std::make_unique<scheduler::OneShotTimer>(20ms, mResetTimerCallback.getInvocable(),
+    mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 20ms,
+                                                           mResetTimerCallback.getInvocable(),
                                                            mExpiredTimerCallback.getInvocable());
     mIdleTimer->start();
     EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
@@ -137,7 +140,8 @@
 }
 
 TEST_F(OneShotTimerTest, startNotCalledTest) {
-    mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+    mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms,
+                                                           mResetTimerCallback.getInvocable(),
                                                            mExpiredTimerCallback.getInvocable());
     // The start hasn't happened, so the callback does not happen.
     EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
@@ -149,7 +153,8 @@
 }
 
 TEST_F(OneShotTimerTest, idleTimerIdlesTest) {
-    mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+    mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms,
+                                                           mResetTimerCallback.getInvocable(),
                                                            mExpiredTimerCallback.getInvocable());
     mIdleTimer->start();
     EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
@@ -169,7 +174,8 @@
 }
 
 TEST_F(OneShotTimerTest, timeoutCallbackExecutionTest) {
-    mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+    mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms,
+                                                           mResetTimerCallback.getInvocable(),
                                                            mExpiredTimerCallback.getInvocable());
     mIdleTimer->start();
     EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
@@ -178,7 +184,8 @@
 }
 
 TEST_F(OneShotTimerTest, noCallbacksAfterStopAndResetTest) {
-    mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+    mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms,
+                                                           mResetTimerCallback.getInvocable(),
                                                            mExpiredTimerCallback.getInvocable());
     mIdleTimer->start();
     EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
@@ -192,7 +199,8 @@
 }
 
 TEST_F(OneShotTimerTest, noCallbacksAfterStopTest) {
-    mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+    mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms,
+                                                           mResetTimerCallback.getInvocable(),
                                                            mExpiredTimerCallback.getInvocable());
     mIdleTimer->start();
     EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index a9d9dc0..1b6e9ed 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -83,7 +83,7 @@
             mTouchTimer.reset();
         }
         mTouchTimer.emplace(
-                std::chrono::milliseconds(millis),
+                "Testable Touch timer", std::chrono::milliseconds(millis),
                 [this] { touchTimerCallback(TimerState::Reset); },
                 [this] { touchTimerCallback(TimerState::Expired); });
         mTouchTimer->start();
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 6ce738a..eba3f8e 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -30,6 +30,7 @@
 #include "DisplayDevice.h"
 #include "EffectLayer.h"
 #include "FakeVsyncConfiguration.h"
+#include "FrameTracer/FrameTracer.h"
 #include "Layer.h"
 #include "NativeWindowSurface.h"
 #include "Scheduler/MessageQueue.h"
@@ -41,6 +42,7 @@
 #include "TestableScheduler.h"
 #include "mock/DisplayHardware/MockDisplay.h"
 #include "mock/MockDisplayIdGenerator.h"
+#include "mock/MockFrameTracer.h"
 
 namespace android {
 
@@ -148,6 +150,10 @@
         return nullptr;
     }
 
+    std::unique_ptr<FrameTracer> createFrameTracer() override {
+        return std::make_unique<mock::FrameTracer>();
+    }
+
     using CreateBufferQueueFunction =
             std::function<void(sp<IGraphicBufferProducer>* /* outProducer */,
                                sp<IGraphicBufferConsumer>* /* outConsumer */,
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index 3d60479..a142022 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -475,6 +475,20 @@
     }
 }
 
+TEST_F(VSyncPredictorTest, InconsistentVsyncValueIsFlushedEventually) {
+    EXPECT_TRUE(tracker.addVsyncTimestamp(600));
+    EXPECT_TRUE(tracker.needsMoreSamples());
+
+    EXPECT_FALSE(tracker.addVsyncTimestamp(mNow += mPeriod));
+
+    for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
+        EXPECT_TRUE(tracker.needsMoreSamples());
+        EXPECT_TRUE(tracker.addVsyncTimestamp(mNow += mPeriod));
+    }
+
+    EXPECT_FALSE(tracker.needsMoreSamples());
+}
+
 } // namespace android::scheduler
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 4df7b7c..3728731 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -1,6 +1,8 @@
 cc_library_shared {
     name: "libvr_hwc-hal",
 
+    system_ext_specific: true,
+
     srcs: [
         "impl/vr_hwc.cpp",
         "impl/vr_composer_client.cpp",
@@ -97,6 +99,7 @@
 
 cc_binary {
     name: "vr_hwc",
+    system_ext_specific: true,
     vintf_fragments: ["manifest_vr_hwc.xml"],
     srcs: [
         "vr_hardware_composer_service.cpp",
diff --git a/services/vr/performanced/Android.bp b/services/vr/performanced/Android.bp
index 20301f6..0ef8cc4 100644
--- a/services/vr/performanced/Android.bp
+++ b/services/vr/performanced/Android.bp
@@ -30,6 +30,7 @@
 
 cc_binary {
     name: "performanced",
+    system_ext_specific: true,
     defaults: ["performanced_defaults"],
     srcs: [
         "cpu_set.cpp",