Merge "Add NDK async begin/end & counter"
diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h
index 8dd95cf..2b8cc57 100644
--- a/include/input/InputWindow.h
+++ b/include/input/InputWindow.h
@@ -225,6 +225,11 @@
     virtual bool updateInfo() = 0;
 
     /**
+     * Updates from another input window handle.
+     */
+    void updateFrom(const sp<InputWindowHandle> handle);
+
+    /**
      * Releases the channel used by the associated information when it is
      * no longer needed.
      */
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 127fcd6..d1c732b 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -31,7 +31,6 @@
         "-Werror",
     ],
     cppflags: [
-        "-std=c++1z",
         "-Weverything",
 
         // The static constructors and destructors in this library have not been noted to
@@ -123,6 +122,7 @@
 
     shared_libs: [
         "android.hardware.graphics.common@1.1",
+        "libbase",
         "libsync",
         "libbinder",
         "libbufferhub",
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
index 85ae433..96e9a85 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -18,10 +18,10 @@
 
 #define LOG_TAG "FrameEvents"
 
+#include <android-base/stringprintf.h>
 #include <cutils/compiler.h>  // For CC_[UN]LIKELY
 #include <inttypes.h>
 #include <utils/Log.h>
-#include <utils/String8.h>
 
 #include <algorithm>
 #include <limits>
@@ -29,6 +29,7 @@
 
 namespace android {
 
+using base::StringAppendF;
 
 // ============================================================================
 // FrameEvents
@@ -86,50 +87,49 @@
     releaseFence->getSignalTime();
 }
 
-static void dumpFenceTime(String8& outString, const char* name,
-        bool pending, const FenceTime& fenceTime) {
-    outString.appendFormat("--- %s", name);
+static void dumpFenceTime(std::string& outString, const char* name, bool pending,
+                          const FenceTime& fenceTime) {
+    StringAppendF(&outString, "--- %s", name);
     nsecs_t signalTime = fenceTime.getCachedSignalTime();
     if (Fence::isValidTimestamp(signalTime)) {
-        outString.appendFormat("%" PRId64 "\n", signalTime);
+        StringAppendF(&outString, "%" PRId64 "\n", signalTime);
     } else if (pending || signalTime == Fence::SIGNAL_TIME_PENDING) {
-        outString.appendFormat("Pending\n");
+        outString.append("Pending\n");
     } else if (&fenceTime == FenceTime::NO_FENCE.get()){
-        outString.appendFormat("N/A\n");
+        outString.append("N/A\n");
     } else {
-        outString.appendFormat("Error\n");
+        outString.append("Error\n");
     }
 }
 
-void FrameEvents::dump(String8& outString) const
-{
+void FrameEvents::dump(std::string& outString) const {
     if (!valid) {
         return;
     }
 
-    outString.appendFormat("-- Frame %" PRIu64 "\n", frameNumber);
-    outString.appendFormat("--- Posted      \t%" PRId64 "\n", postedTime);
-    outString.appendFormat("--- Req. Present\t%" PRId64 "\n", requestedPresentTime);
+    StringAppendF(&outString, "-- Frame %" PRIu64 "\n", frameNumber);
+    StringAppendF(&outString, "--- Posted      \t%" PRId64 "\n", postedTime);
+    StringAppendF(&outString, "--- Req. Present\t%" PRId64 "\n", requestedPresentTime);
 
-    outString.appendFormat("--- Latched     \t");
+    outString.append("--- Latched     \t");
     if (FrameEvents::isValidTimestamp(latchTime)) {
-        outString.appendFormat("%" PRId64 "\n", latchTime);
+        StringAppendF(&outString, "%" PRId64 "\n", latchTime);
     } else {
-        outString.appendFormat("Pending\n");
+        outString.append("Pending\n");
     }
 
-    outString.appendFormat("--- Refresh (First)\t");
+    outString.append("--- Refresh (First)\t");
     if (FrameEvents::isValidTimestamp(firstRefreshStartTime)) {
-        outString.appendFormat("%" PRId64 "\n", firstRefreshStartTime);
+        StringAppendF(&outString, "%" PRId64 "\n", firstRefreshStartTime);
     } else {
-        outString.appendFormat("Pending\n");
+        outString.append("Pending\n");
     }
 
-    outString.appendFormat("--- Refresh (Last)\t");
+    outString.append("--- Refresh (Last)\t");
     if (FrameEvents::isValidTimestamp(lastRefreshStartTime)) {
-        outString.appendFormat("%" PRId64 "\n", lastRefreshStartTime);
+        StringAppendF(&outString, "%" PRId64 "\n", lastRefreshStartTime);
     } else {
-        outString.appendFormat("Pending\n");
+        outString.append("Pending\n");
     }
 
     dumpFenceTime(outString, "Acquire           \t",
@@ -139,11 +139,11 @@
     dumpFenceTime(outString, "Display Present   \t",
             !addPostCompositeCalled, *displayPresentFence);
 
-    outString.appendFormat("--- DequeueReady  \t");
+    outString.append("--- DequeueReady  \t");
     if (FrameEvents::isValidTimestamp(dequeueReadyTime)) {
-        outString.appendFormat("%" PRId64 "\n", dequeueReadyTime);
+        StringAppendF(&outString, "%" PRId64 "\n", dequeueReadyTime);
     } else {
-        outString.appendFormat("Pending\n");
+        outString.append("Pending\n");
     }
 
     dumpFenceTime(outString, "Release           \t",
@@ -206,11 +206,11 @@
     return lhs.valid;
 }
 
-void FrameEventHistory::dump(String8& outString) const {
+void FrameEventHistory::dump(std::string& outString) const {
     auto earliestFrame = std::min_element(
             mFrames.begin(), mFrames.end(), &FrameNumberLessThan);
     if (!earliestFrame->valid) {
-        outString.appendFormat("-- N/A\n");
+        outString.append("-- N/A\n");
         return;
     }
     for (auto frame = earliestFrame; frame != mFrames.end(); ++frame) {
diff --git a/libs/gui/GuiConfig.cpp b/libs/gui/GuiConfig.cpp
index bc0c83c..3ec20ee 100644
--- a/libs/gui/GuiConfig.cpp
+++ b/libs/gui/GuiConfig.cpp
@@ -18,8 +18,7 @@
 
 namespace android {
 
-void appendGuiConfigString(String8& configStr)
-{
+void appendGuiConfigString(std::string& configStr) {
     static const char* config =
             " [libgui"
 #ifdef DONT_USE_FENCE_SYNC
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 80d435f..f1fefcc 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -636,6 +636,64 @@
         *outComponentMask = static_cast<uint8_t>(value);
         return error;
     }
+
+    virtual status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable,
+                                                      uint8_t componentMask,
+                                                      uint64_t maxFrames) const {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        data.writeStrongBinder(display);
+        data.writeBool(enable);
+        data.writeByte(static_cast<int8_t>(componentMask));
+        data.writeUint64(maxFrames);
+        status_t result =
+                remote()->transact(BnSurfaceComposer::SET_DISPLAY_CONTENT_SAMPLING_ENABLED, data,
+                                   &reply);
+        return result;
+    }
+
+    virtual status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
+                                               uint64_t timestamp,
+                                               DisplayedFrameStats* outStats) const {
+        if (!outStats) return BAD_VALUE;
+
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        data.writeStrongBinder(display);
+        data.writeUint64(maxFrames);
+        data.writeUint64(timestamp);
+
+        status_t result =
+                remote()->transact(BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLE, data, &reply);
+
+        if (result != NO_ERROR) {
+            return result;
+        }
+
+        result = reply.readUint64(&outStats->numFrames);
+        if (result != NO_ERROR) {
+            return result;
+        }
+
+        result = reply.readInt64Vector(
+                reinterpret_cast<std::vector<int64_t>*>(&outStats->component_0_sample));
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.readInt64Vector(
+                reinterpret_cast<std::vector<int64_t>*>(&outStats->component_1_sample));
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.readInt64Vector(
+                reinterpret_cast<std::vector<int64_t>*>(&outStats->component_2_sample));
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.readInt64Vector(
+                reinterpret_cast<std::vector<int64_t>*>(&outStats->component_3_sample));
+        return result;
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -1004,6 +1062,76 @@
             }
             return result;
         }
+        case SET_DISPLAY_CONTENT_SAMPLING_ENABLED: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+
+            sp<IBinder> display = nullptr;
+            bool enable = false;
+            int8_t componentMask = 0;
+            uint64_t maxFrames = 0;
+            status_t result = data.readStrongBinder(&display);
+            if (result != NO_ERROR) {
+                ALOGE("setDisplayContentSamplingEnabled failure in reading Display token: %d",
+                      result);
+                return result;
+            }
+
+            result = data.readBool(&enable);
+            if (result != NO_ERROR) {
+                ALOGE("setDisplayContentSamplingEnabled failure in reading enable: %d", result);
+                return result;
+            }
+
+            result = data.readByte(static_cast<int8_t*>(&componentMask));
+            if (result != NO_ERROR) {
+                ALOGE("setDisplayContentSamplingEnabled failure in reading component mask: %d",
+                      result);
+                return result;
+            }
+
+            result = data.readUint64(&maxFrames);
+            if (result != NO_ERROR) {
+                ALOGE("setDisplayContentSamplingEnabled failure in reading max frames: %d", result);
+                return result;
+            }
+
+            return setDisplayContentSamplingEnabled(display, enable,
+                                                    static_cast<uint8_t>(componentMask), maxFrames);
+        }
+        case GET_DISPLAYED_CONTENT_SAMPLE: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+
+            sp<IBinder> display = data.readStrongBinder();
+            uint64_t maxFrames = 0;
+            uint64_t timestamp = 0;
+
+            status_t result = data.readUint64(&maxFrames);
+            if (result != NO_ERROR) {
+                ALOGE("getDisplayedContentSample failure in reading max frames: %d", result);
+                return result;
+            }
+
+            result = data.readUint64(&timestamp);
+            if (result != NO_ERROR) {
+                ALOGE("getDisplayedContentSample failure in reading timestamp: %d", result);
+                return result;
+            }
+
+            DisplayedFrameStats stats;
+            result = getDisplayedContentSample(display, maxFrames, timestamp, &stats);
+            if (result == NO_ERROR) {
+                reply->writeUint64(stats.numFrames);
+                reply->writeInt64Vector(
+                        *reinterpret_cast<std::vector<int64_t>*>(&stats.component_0_sample));
+                reply->writeInt64Vector(
+                        *reinterpret_cast<std::vector<int64_t>*>(&stats.component_1_sample));
+                reply->writeInt64Vector(
+                        *reinterpret_cast<std::vector<int64_t>*>(&stats.component_2_sample));
+                reply->writeInt64Vector(
+                        *reinterpret_cast<std::vector<int64_t>*>(&stats.component_3_sample));
+            }
+            return result;
+        }
         default: {
             return BBinder::onTransact(code, data, reply, flags);
         }
diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp
index ccde9e0..cdde9a2 100644
--- a/libs/gui/LayerDebugInfo.cpp
+++ b/libs/gui/LayerDebugInfo.cpp
@@ -16,13 +16,14 @@
 
 #include <gui/LayerDebugInfo.h>
 
+#include <android-base/stringprintf.h>
+
 #include <ui/DebugUtils.h>
 
 #include <binder/Parcel.h>
 
-#include <utils/String8.h>
-
 using namespace android;
+using android::base::StringAppendF;
 
 #define RETURN_ON_ERROR(X) do {status_t res = (X); if (res != NO_ERROR) return res;} while(false)
 
@@ -108,38 +109,37 @@
 }
 
 std::string to_string(const LayerDebugInfo& info) {
-    String8 result;
+    std::string result;
 
-    result.appendFormat("+ %s (%s)\n", info.mType.c_str(), info.mName.c_str());
+    StringAppendF(&result, "+ %s (%s)\n", info.mType.c_str(), info.mName.c_str());
     info.mTransparentRegion.dump(result, "TransparentRegion");
     info.mVisibleRegion.dump(result, "VisibleRegion");
     info.mSurfaceDamageRegion.dump(result, "SurfaceDamageRegion");
 
-    result.appendFormat("      layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), ",
-            info.mLayerStack, info.mZ, static_cast<double>(info.mX), static_cast<double>(info.mY),
-            info.mWidth, info.mHeight);
+    StringAppendF(&result, "      layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), ",
+                  info.mLayerStack, info.mZ, static_cast<double>(info.mX),
+                  static_cast<double>(info.mY), info.mWidth, info.mHeight);
 
-    result.appendFormat("crop=%s, ", to_string(info.mCrop).c_str());
-    result.appendFormat("isOpaque=%1d, invalidate=%1d, ", info.mIsOpaque, info.mContentDirty);
-    result.appendFormat("dataspace=%s, ", dataspaceDetails(info.mDataSpace).c_str());
-    result.appendFormat("pixelformat=%s, ", decodePixelFormat(info.mPixelFormat).c_str());
-    result.appendFormat("color=(%.3f,%.3f,%.3f,%.3f), flags=0x%08x, ",
-            static_cast<double>(info.mColor.r), static_cast<double>(info.mColor.g),
-            static_cast<double>(info.mColor.b), static_cast<double>(info.mColor.a),
-            info.mFlags);
-    result.appendFormat("tr=[%.2f, %.2f][%.2f, %.2f]",
-            static_cast<double>(info.mMatrix[0][0]), static_cast<double>(info.mMatrix[0][1]),
-            static_cast<double>(info.mMatrix[1][0]), static_cast<double>(info.mMatrix[1][1]));
+    StringAppendF(&result, "crop=%s, ", to_string(info.mCrop).c_str());
+    StringAppendF(&result, "isOpaque=%1d, invalidate=%1d, ", info.mIsOpaque, info.mContentDirty);
+    StringAppendF(&result, "dataspace=%s, ", dataspaceDetails(info.mDataSpace).c_str());
+    StringAppendF(&result, "pixelformat=%s, ", decodePixelFormat(info.mPixelFormat).c_str());
+    StringAppendF(&result, "color=(%.3f,%.3f,%.3f,%.3f), flags=0x%08x, ",
+                  static_cast<double>(info.mColor.r), static_cast<double>(info.mColor.g),
+                  static_cast<double>(info.mColor.b), static_cast<double>(info.mColor.a),
+                  info.mFlags);
+    StringAppendF(&result, "tr=[%.2f, %.2f][%.2f, %.2f]", static_cast<double>(info.mMatrix[0][0]),
+                  static_cast<double>(info.mMatrix[0][1]), static_cast<double>(info.mMatrix[1][0]),
+                  static_cast<double>(info.mMatrix[1][1]));
     result.append("\n");
-    result.appendFormat("      parent=%s\n", info.mParentName.c_str());
-    result.appendFormat("      activeBuffer=[%4ux%4u:%4u,%s],",
-            info.mActiveBufferWidth, info.mActiveBufferHeight,
-            info.mActiveBufferStride,
-            decodePixelFormat(info.mActiveBufferFormat).c_str());
-    result.appendFormat(" queued-frames=%d, mRefreshPending=%d",
-            info.mNumQueuedFrames, info.mRefreshPending);
+    StringAppendF(&result, "      parent=%s\n", info.mParentName.c_str());
+    StringAppendF(&result, "      activeBuffer=[%4ux%4u:%4u,%s],", info.mActiveBufferWidth,
+                  info.mActiveBufferHeight, info.mActiveBufferStride,
+                  decodePixelFormat(info.mActiveBufferFormat).c_str());
+    StringAppendF(&result, " queued-frames=%d, mRefreshPending=%d", info.mNumQueuedFrames,
+                  info.mRefreshPending);
     result.append("\n");
-    return std::string(result.c_str());
+    return result;
 }
 
 } // android
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 407eecb..35ce6e3 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -16,6 +16,8 @@
 
 #define LOG_TAG "LayerState"
 
+#include <inttypes.h>
+
 #include <utils/Errors.h>
 #include <binder/Parcel.h>
 #include <gui/ISurfaceComposerClient.h>
@@ -27,7 +29,7 @@
 status_t layer_state_t::write(Parcel& output) const
 {
     output.writeStrongBinder(surface);
-    output.writeUint32(what);
+    output.writeUint64(what);
     output.writeFloat(x);
     output.writeFloat(y);
     output.writeInt32(z);
@@ -57,6 +59,7 @@
     output.writeUint32(transform);
     output.writeBool(transformToDisplayInverse);
     output.write(crop);
+    output.write(frame);
     if (buffer) {
         output.writeBool(true);
         output.write(*buffer);
@@ -97,7 +100,7 @@
 status_t layer_state_t::read(const Parcel& input)
 {
     surface = input.readStrongBinder();
-    what = input.readUint32();
+    what = input.readUint64();
     x = input.readFloat();
     y = input.readFloat();
     z = input.readInt32();
@@ -133,6 +136,7 @@
     transform = input.readUint32();
     transformToDisplayInverse = input.readBool();
     input.read(crop);
+    input.read(frame);
     buffer = new GraphicBuffer();
     if (input.readBool()) {
         input.read(*buffer);
@@ -320,6 +324,10 @@
         what |= eCropChanged;
         crop = other.crop;
     }
+    if (other.what & eFrameChanged) {
+        what |= eFrameChanged;
+        frame = other.frame;
+    }
     if (other.what & eBufferChanged) {
         what |= eBufferChanged;
         buffer = other.buffer;
@@ -366,7 +374,7 @@
 
     if ((other.what & what) != other.what) {
         ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
-              "other.what=0x%X what=0x%X",
+              "other.what=0x%" PRIu64 " what=0x%" PRIu64,
               other.what, what);
     }
 }
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 9dfccc7..9586219 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -609,6 +609,20 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame(
+        const sp<SurfaceControl>& sc, const Rect& frame) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eFrameChanged;
+    s->frame = frame;
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffer(
         const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer) {
     layer_state_t* s = getLayerState(sc);
@@ -1098,6 +1112,20 @@
                                                     outComponentMask);
 }
 
+status_t SurfaceComposerClient::setDisplayContentSamplingEnabled(const sp<IBinder>& display,
+                                                                 bool enable, uint8_t componentMask,
+                                                                 uint64_t maxFrames) {
+    return ComposerService::getComposerService()->setDisplayContentSamplingEnabled(display, enable,
+                                                                                   componentMask,
+                                                                                   maxFrames);
+}
+
+status_t SurfaceComposerClient::getDisplayedContentSample(const sp<IBinder>& display,
+                                                          uint64_t maxFrames, uint64_t timestamp,
+                                                          DisplayedFrameStats* outStats) {
+    return ComposerService::getComposerService()->getDisplayedContentSample(display, maxFrames,
+                                                                            timestamp, outStats);
+}
 // ----------------------------------------------------------------------------
 
 status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
diff --git a/libs/gui/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h
index e06e40f..df02494 100644
--- a/libs/gui/include/gui/FrameTimestamps.h
+++ b/libs/gui/include/gui/FrameTimestamps.h
@@ -30,7 +30,6 @@
 
 struct FrameEvents;
 class FrameEventHistoryDelta;
-class String8;
 
 
 // Identifiers for all the events that may be recorded or reported.
@@ -72,7 +71,7 @@
     bool hasDequeueReadyInfo() const;
 
     void checkFencesForCompletion();
-    void dump(String8& outString) const;
+    void dump(std::string& outString) const;
 
     bool valid{false};
     int connectId{0};
@@ -112,7 +111,7 @@
     FrameEvents* getFrame(uint64_t frameNumber);
     FrameEvents* getFrame(uint64_t frameNumber, size_t* iHint);
     void checkFencesForCompletion();
-    void dump(String8& outString) const;
+    void dump(std::string& outString) const;
 
     static constexpr size_t MAX_FRAME_HISTORY = 8;
 
diff --git a/libs/gui/include/gui/GuiConfig.h b/libs/gui/include/gui/GuiConfig.h
index b020ed9..7aa5432 100644
--- a/libs/gui/include/gui/GuiConfig.h
+++ b/libs/gui/include/gui/GuiConfig.h
@@ -17,12 +17,12 @@
 #ifndef ANDROID_GUI_CONFIG_H
 #define ANDROID_GUI_CONFIG_H
 
-#include <utils/String8.h>
+#include <string>
 
 namespace android {
 
 // Append the libgui configuration details to configStr.
-void appendGuiConfigString(String8& configStr);
+void appendGuiConfigString(std::string& configStr);
 
 }; // namespace android
 
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 3b6c6e4..3052c0b 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -27,10 +27,11 @@
 
 #include <binder/IInterface.h>
 
+#include <ui/DisplayedFrameStats.h>
 #include <ui/FrameStats.h>
-#include <ui/PixelFormat.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/GraphicTypes.h>
+#include <ui/PixelFormat.h>
 
 #include <vector>
 
@@ -300,6 +301,22 @@
                                                            ui::PixelFormat* outFormat,
                                                            ui::Dataspace* outDataspace,
                                                            uint8_t* outComponentMask) const = 0;
+
+    /* Turns on the color sampling engine on the display.
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    virtual status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable,
+                                                      uint8_t componentMask,
+                                                      uint64_t maxFrames) const = 0;
+
+    /* Returns statistics on the color profile of the last frame displayed for a given display
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    virtual status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
+                                               uint64_t timestamp,
+                                               DisplayedFrameStats* outStats) const = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -340,6 +357,8 @@
         GET_COMPOSITION_PREFERENCE,
         GET_COLOR_MANAGEMENT,
         GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES,
+        SET_DISPLAY_CONTENT_SAMPLING_ENABLED,
+        GET_DISPLAYED_CONTENT_SAMPLE,
     };
 
     virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 3cfee9e..02c6be2 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -83,6 +83,7 @@
         eListenerCallbacksChanged = 0x20000000,
         eInputInfoChanged = 0x40000000,
         eCornerRadiusChanged = 0x80000000,
+        eFrameChanged = 0x1'00000000,
     };
 
     layer_state_t()
@@ -104,6 +105,7 @@
             transform(0),
             transformToDisplayInverse(false),
             crop(Rect::INVALID_RECT),
+            frame(Rect::INVALID_RECT),
             dataspace(ui::Dataspace::UNKNOWN),
             surfaceDamageRegion(),
             api(-1),
@@ -124,7 +126,7 @@
         float dsdy{0};
     };
     sp<IBinder> surface;
-    uint32_t what;
+    uint64_t what;
     float x;
     float y;
     int32_t z;
@@ -157,6 +159,7 @@
     uint32_t transform;
     bool transformToDisplayInverse;
     Rect crop;
+    Rect frame;
     sp<GraphicBuffer> buffer;
     sp<Fence> acquireFence;
     ui::Dataspace dataspace;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 7d05512..8e3ba78 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -30,6 +30,7 @@
 #include <utils/SortedVector.h>
 #include <utils/threads.h>
 
+#include <ui/DisplayedFrameStats.h>
 #include <ui/FrameStats.h>
 #include <ui/GraphicTypes.h>
 #include <ui/PixelFormat.h>
@@ -295,6 +296,7 @@
         Transaction& setTransformToDisplayInverse(const sp<SurfaceControl>& sc,
                                                   bool transformToDisplayInverse);
         Transaction& setCrop(const sp<SurfaceControl>& sc, const Rect& crop);
+        Transaction& setFrame(const sp<SurfaceControl>& sc, const Rect& frame);
         Transaction& setBuffer(const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer);
         Transaction& setAcquireFence(const sp<SurfaceControl>& sc, const sp<Fence>& fence);
         Transaction& setDataspace(const sp<SurfaceControl>& sc, ui::Dataspace dataspace);
@@ -386,6 +388,11 @@
                                                           ui::PixelFormat* outFormat,
                                                           ui::Dataspace* outDataspace,
                                                           uint8_t* outComponentMask);
+    static status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable,
+                                                     uint8_t componentMask, uint64_t maxFrames);
+
+    static status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
+                                              uint64_t timestamp, DisplayedFrameStats* outStats);
 
 private:
     virtual void onFirstRef();
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 6de641d..f020a40 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -37,6 +37,7 @@
     shared_libs: [
         "android.hardware.configstore@1.0",
         "android.hardware.configstore-utils",
+        "libbase",
         "liblog",
         "libEGL",
         "libGLESv1_CM",
diff --git a/libs/gui/tests/DisplayedContentSampling_test.cpp b/libs/gui/tests/DisplayedContentSampling_test.cpp
index f2c0e0c..5443812 100644
--- a/libs/gui/tests/DisplayedContentSampling_test.cpp
+++ b/libs/gui/tests/DisplayedContentSampling_test.cpp
@@ -36,7 +36,12 @@
         ASSERT_TRUE(mDisplayToken);
     }
 
-    bool shouldSkipTest(status_t status) {
+    bool shouldSkipTest() {
+        ui::PixelFormat format;
+        ui::Dataspace dataspace;
+        status_t status =
+                mComposerClient->getDisplayedContentSamplingAttributes(mDisplayToken, &format,
+                                                                       &dataspace, &componentMask);
         if (status == PERMISSION_DENIED) {
             SUCCEED() << "permissions denial, skipping test";
             return true;
@@ -50,19 +55,68 @@
 
     sp<SurfaceComposerClient> mComposerClient;
     sp<IBinder> mDisplayToken;
+    uint8_t componentMask = 0;
 };
 
 TEST_F(DisplayedContentSamplingTest, GetDisplayedContentSamplingAttributesAreSane) {
+    // tradefed infrastructure does not support use of GTEST_SKIP
+    if (shouldSkipTest()) return;
+
     ui::PixelFormat format;
     ui::Dataspace dataspace;
-    uint8_t componentMask = 0;
     status_t status =
             mComposerClient->getDisplayedContentSamplingAttributes(mDisplayToken, &format,
                                                                    &dataspace, &componentMask);
-    if (shouldSkipTest(status)) {
-        return;
-    }
     EXPECT_EQ(OK, status);
     EXPECT_LE(componentMask, INVALID_MASK);
 }
+
+TEST_F(DisplayedContentSamplingTest, EnableWithInvalidMaskReturnsBadValue) {
+    if (shouldSkipTest()) return;
+
+    status_t status =
+            mComposerClient->setDisplayContentSamplingEnabled(mDisplayToken, true, INVALID_MASK, 0);
+    EXPECT_EQ(BAD_VALUE, status);
+}
+
+TEST_F(DisplayedContentSamplingTest, EnableAndDisableSucceed) {
+    if (shouldSkipTest()) return;
+
+    status_t status = mComposerClient->setDisplayContentSamplingEnabled(mDisplayToken, true,
+                                                                        componentMask, 10);
+    EXPECT_EQ(OK, status);
+
+    status = mComposerClient->setDisplayContentSamplingEnabled(mDisplayToken, false, componentMask,
+                                                               0);
+    EXPECT_EQ(OK, status);
+}
+
+TEST_F(DisplayedContentSamplingTest, SelectivelyDisableComponentOk) {
+    if (shouldSkipTest()) return;
+
+    status_t status = mComposerClient->setDisplayContentSamplingEnabled(mDisplayToken, true,
+                                                                        componentMask, 0);
+    EXPECT_EQ(OK, status);
+
+    // Clear the lowest bit.
+    componentMask &= (componentMask - 1);
+    status = mComposerClient->setDisplayContentSamplingEnabled(mDisplayToken, false, componentMask,
+                                                               0);
+    EXPECT_EQ(OK, status);
+}
+
+TEST_F(DisplayedContentSamplingTest, SampleCollectionCoherentWithSupportMask) {
+    if (shouldSkipTest()) return;
+
+    DisplayedFrameStats stats;
+    status_t status = mComposerClient->getDisplayedContentSample(mDisplayToken, 0, 0, &stats);
+    EXPECT_EQ(OK, status);
+    if (stats.numFrames <= 0) return;
+
+    if (componentMask & (0x1 << 0)) EXPECT_NE(0, stats.component_0_sample.size());
+    if (componentMask & (0x1 << 1)) EXPECT_NE(0, stats.component_1_sample.size());
+    if (componentMask & (0x1 << 2)) EXPECT_NE(0, stats.component_2_sample.size());
+    if (componentMask & (0x1 << 3)) EXPECT_NE(0, stats.component_3_sample.size());
+}
+
 } // namespace android
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 3950bb6..d37b810 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -647,6 +647,16 @@
                                                    uint8_t* /*outComponentMask*/) const override {
         return NO_ERROR;
     }
+    status_t setDisplayContentSamplingEnabled(const sp<IBinder>& /*display*/, bool /*enable*/,
+                                              uint8_t /*componentMask*/,
+                                              uint64_t /*maxFrames*/) const override {
+        return NO_ERROR;
+    }
+    status_t getDisplayedContentSample(const sp<IBinder>& /*display*/, uint64_t /*maxFrames*/,
+                                       uint64_t /*timestamp*/,
+                                       DisplayedFrameStats* /*outStats*/) const override {
+        return NO_ERROR;
+    }
 
     virtual status_t getColorManagement(bool* /*outGetColorManagement*/) const { return NO_ERROR; }
 
diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp
index 556a005..aa1371f 100644
--- a/libs/input/InputWindow.cpp
+++ b/libs/input/InputWindow.cpp
@@ -162,4 +162,8 @@
     return mInfo.token;
 }
 
+void InputWindowHandle::updateFrom(sp<InputWindowHandle> handle) {
+    mInfo = handle->mInfo;
+}
+
 } // namespace android
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index beaf9ee..d872f02 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -8,7 +8,6 @@
         "-Wunused",
         "-Wunreachable-code",
     ],
-    cppflags: ["-std=c++1z"],
 }
 
 cc_defaults {
@@ -19,6 +18,7 @@
         "-DEGL_EGLEXT_PROTOTYPES",
     ],
     shared_libs: [
+        "libbase",
         "libcutils",
         "libEGL",
         "libGLESv1_CM",
@@ -46,7 +46,7 @@
 filegroup {
     name: "librenderengine_gl_sources",
     srcs: [
-        "gl/GLES20RenderEngine.cpp",
+        "gl/GLESRenderEngine.cpp",
         "gl/GLExtensions.cpp",
         "gl/GLFramebuffer.cpp",
         "gl/GLImage.cpp",
diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
index 8be1c3c..6dd7283 100644
--- a/libs/renderengine/RenderEngine.cpp
+++ b/libs/renderengine/RenderEngine.cpp
@@ -19,7 +19,7 @@
 #include <cutils/properties.h>
 #include <log/log.h>
 #include <private/gui/SyncFeatures.h>
-#include "gl/GLES20RenderEngine.h"
+#include "gl/GLESRenderEngine.h"
 
 namespace android {
 namespace renderengine {
@@ -29,10 +29,10 @@
     property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, "gles");
     if (strcmp(prop, "gles") == 0) {
         ALOGD("RenderEngine GLES Backend");
-        return renderengine::gl::GLES20RenderEngine::create(hwcFormat, featureFlags);
+        return renderengine::gl::GLESRenderEngine::create(hwcFormat, featureFlags);
     }
     ALOGE("UNKNOWN BackendType: %s, create GLES RenderEngine.", prop);
-    return renderengine::gl::GLES20RenderEngine::create(hwcFormat, featureFlags);
+    return renderengine::gl::GLESRenderEngine::create(hwcFormat, featureFlags);
 }
 
 RenderEngine::~RenderEngine() = default;
diff --git a/libs/renderengine/gl/GLES20RenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
similarity index 84%
rename from libs/renderengine/gl/GLES20RenderEngine.cpp
rename to libs/renderengine/gl/GLESRenderEngine.cpp
index 7adda83..1395551 100644
--- a/libs/renderengine/gl/GLES20RenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -19,7 +19,7 @@
 #define LOG_TAG "RenderEngine"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
-#include "GLES20RenderEngine.h"
+#include "GLESRenderEngine.h"
 
 #include <math.h>
 #include <fstream>
@@ -27,6 +27,7 @@
 
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
+#include <android-base/stringprintf.h>
 #include <cutils/compiler.h>
 #include <renderengine/Mesh.h>
 #include <renderengine/Texture.h>
@@ -36,7 +37,6 @@
 #include <ui/Rect.h>
 #include <ui/Region.h>
 #include <utils/KeyedVector.h>
-#include <utils/String8.h>
 #include <utils/Trace.h>
 #include "GLExtensions.h"
 #include "GLFramebuffer.h"
@@ -109,6 +109,7 @@
 namespace renderengine {
 namespace gl {
 
+using base::StringAppendF;
 using ui::Dataspace;
 
 static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute,
@@ -221,8 +222,7 @@
     return err;
 }
 
-std::unique_ptr<GLES20RenderEngine> GLES20RenderEngine::create(int hwcFormat,
-                                                               uint32_t featureFlags) {
+std::unique_ptr<GLESRenderEngine> GLESRenderEngine::create(int hwcFormat, uint32_t featureFlags) {
     // initialize EGL for the default display
     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     if (!eglInitialize(display, nullptr, nullptr)) {
@@ -263,7 +263,7 @@
     GlesVersion version = parseGlesVersion(extensions.getVersion());
 
     // initialize the renderer while GL is current
-    std::unique_ptr<GLES20RenderEngine> engine;
+    std::unique_ptr<GLESRenderEngine> engine;
     switch (version) {
         case GLES_VERSION_1_0:
         case GLES_VERSION_1_1:
@@ -271,8 +271,7 @@
             break;
         case GLES_VERSION_2_0:
         case GLES_VERSION_3_0:
-            engine = std::make_unique<GLES20RenderEngine>(featureFlags, display, config, ctxt,
-                                                          dummy);
+            engine = std::make_unique<GLESRenderEngine>(featureFlags, display, config, ctxt, dummy);
             break;
     }
 
@@ -287,17 +286,17 @@
     return engine;
 }
 
-EGLConfig GLES20RenderEngine::chooseEglConfig(EGLDisplay display, int format, bool logConfig) {
+EGLConfig GLESRenderEngine::chooseEglConfig(EGLDisplay display, int format, bool logConfig) {
     status_t err;
     EGLConfig config;
 
-    // First try to get an ES2 config
-    err = selectEGLConfig(display, format, EGL_OPENGL_ES2_BIT, &config);
+    // First try to get an ES3 config
+    err = selectEGLConfig(display, format, EGL_OPENGL_ES3_BIT, &config);
     if (err != NO_ERROR) {
-        // If ES2 fails, try ES1
-        err = selectEGLConfig(display, format, EGL_OPENGL_ES_BIT, &config);
+        // If ES3 fails, try to get an ES2 config
+        err = selectEGLConfig(display, format, EGL_OPENGL_ES2_BIT, &config);
         if (err != NO_ERROR) {
-            // still didn't work, probably because we're on the emulator...
+            // If ES2 still doesn't work, probably because we're on the emulator.
             // try a simplified query
             ALOGW("no suitable EGLConfig found, trying a simpler query");
             err = selectEGLConfig(display, format, 0, &config);
@@ -326,8 +325,8 @@
     return config;
 }
 
-GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags, EGLDisplay display, EGLConfig config,
-                                       EGLContext ctxt, EGLSurface dummy)
+GLESRenderEngine::GLESRenderEngine(uint32_t featureFlags, EGLDisplay display, EGLConfig config,
+                                   EGLContext ctxt, EGLSurface dummy)
       : renderengine::impl::RenderEngine(featureFlags),
         mEGLDisplay(display),
         mEGLConfig(config),
@@ -382,28 +381,28 @@
     }
 }
 
-GLES20RenderEngine::~GLES20RenderEngine() {
+GLESRenderEngine::~GLESRenderEngine() {
     eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
     eglTerminate(mEGLDisplay);
 }
 
-std::unique_ptr<Framebuffer> GLES20RenderEngine::createFramebuffer() {
+std::unique_ptr<Framebuffer> GLESRenderEngine::createFramebuffer() {
     return std::make_unique<GLFramebuffer>(*this);
 }
 
-std::unique_ptr<Image> GLES20RenderEngine::createImage() {
+std::unique_ptr<Image> GLESRenderEngine::createImage() {
     return std::make_unique<GLImage>(*this);
 }
 
-void GLES20RenderEngine::primeCache() const {
+void GLESRenderEngine::primeCache() const {
     ProgramCache::getInstance().primeCache(mFeatureFlags & USE_COLOR_MANAGEMENT);
 }
 
-bool GLES20RenderEngine::isCurrent() const {
+bool GLESRenderEngine::isCurrent() const {
     return mEGLDisplay == eglGetCurrentDisplay() && mEGLContext == eglGetCurrentContext();
 }
 
-base::unique_fd GLES20RenderEngine::flush() {
+base::unique_fd GLESRenderEngine::flush() {
     if (!GLExtensions::getInstance().hasNativeFenceSync()) {
         return base::unique_fd();
     }
@@ -427,7 +426,7 @@
     return fenceFd;
 }
 
-bool GLES20RenderEngine::finish() {
+bool GLESRenderEngine::finish() {
     if (!GLExtensions::getInstance().hasFenceSync()) {
         ALOGW("no synchronization support");
         return false;
@@ -455,7 +454,7 @@
     return true;
 }
 
-bool GLES20RenderEngine::waitFence(base::unique_fd fenceFd) {
+bool GLESRenderEngine::waitFence(base::unique_fd fenceFd) {
     if (!GLExtensions::getInstance().hasNativeFenceSync() ||
         !GLExtensions::getInstance().hasWaitSync()) {
         return false;
@@ -485,13 +484,13 @@
     return true;
 }
 
-void GLES20RenderEngine::clearWithColor(float red, float green, float blue, float alpha) {
+void GLESRenderEngine::clearWithColor(float red, float green, float blue, float alpha) {
     glClearColor(red, green, blue, alpha);
     glClear(GL_COLOR_BUFFER_BIT);
 }
 
-void GLES20RenderEngine::fillRegionWithColor(const Region& region, float red, float green,
-                                             float blue, float alpha) {
+void GLESRenderEngine::fillRegionWithColor(const Region& region, float red, float green, float blue,
+                                           float alpha) {
     size_t c;
     Rect const* r = region.getArray(&c);
     Mesh mesh(Mesh::TRIANGLES, c * 6, 2);
@@ -514,7 +513,7 @@
     drawMesh(mesh);
 }
 
-void GLES20RenderEngine::setScissor(const Rect& region) {
+void GLESRenderEngine::setScissor(const Rect& region) {
     // Invert y-coordinate to map to GL-space.
     int32_t canvasHeight = mFboHeight;
     int32_t glBottom = canvasHeight - region.bottom;
@@ -523,19 +522,19 @@
     glEnable(GL_SCISSOR_TEST);
 }
 
-void GLES20RenderEngine::disableScissor() {
+void GLESRenderEngine::disableScissor() {
     glDisable(GL_SCISSOR_TEST);
 }
 
-void GLES20RenderEngine::genTextures(size_t count, uint32_t* names) {
+void GLESRenderEngine::genTextures(size_t count, uint32_t* names) {
     glGenTextures(count, names);
 }
 
-void GLES20RenderEngine::deleteTextures(size_t count, uint32_t const* names) {
+void GLESRenderEngine::deleteTextures(size_t count, uint32_t const* names) {
     glDeleteTextures(count, names);
 }
 
-void GLES20RenderEngine::bindExternalTextureImage(uint32_t texName, const Image& image) {
+void GLESRenderEngine::bindExternalTextureImage(uint32_t texName, const Image& image) {
     const GLImage& glImage = static_cast<const GLImage&>(image);
     const GLenum target = GL_TEXTURE_EXTERNAL_OES;
 
@@ -545,7 +544,7 @@
     }
 }
 
-status_t GLES20RenderEngine::bindFrameBuffer(Framebuffer* framebuffer) {
+status_t GLESRenderEngine::bindFrameBuffer(Framebuffer* framebuffer) {
     GLFramebuffer* glFramebuffer = static_cast<GLFramebuffer*>(framebuffer);
     EGLImageKHR eglImage = glFramebuffer->getEGLImage();
     uint32_t textureName = glFramebuffer->getTextureName();
@@ -569,14 +568,14 @@
     return glStatus == GL_FRAMEBUFFER_COMPLETE_OES ? NO_ERROR : BAD_VALUE;
 }
 
-void GLES20RenderEngine::unbindFrameBuffer(Framebuffer* /* framebuffer */) {
+void GLESRenderEngine::unbindFrameBuffer(Framebuffer* /* framebuffer */) {
     mFboHeight = 0;
 
     // back to main framebuffer
     glBindFramebuffer(GL_FRAMEBUFFER, 0);
 }
 
-void GLES20RenderEngine::checkErrors() const {
+void GLESRenderEngine::checkErrors() const {
     do {
         // there could be more than one error flag
         GLenum error = glGetError();
@@ -585,15 +584,15 @@
     } while (true);
 }
 
-status_t GLES20RenderEngine::drawLayers(const DisplaySettings& /*settings*/,
-                                        const std::vector<LayerSettings>& /*layers*/,
-                                        ANativeWindowBuffer* const /*buffer*/,
-                                        base::unique_fd* /*displayFence*/) const {
+status_t GLESRenderEngine::drawLayers(const DisplaySettings& /*settings*/,
+                                      const std::vector<LayerSettings>& /*layers*/,
+                                      ANativeWindowBuffer* const /*buffer*/,
+                                      base::unique_fd* /*displayFence*/) const {
     return NO_ERROR;
 }
 
-void GLES20RenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
-                                                  ui::Transform::orientation_flags rotation) {
+void GLESRenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
+                                                ui::Transform::orientation_flags rotation) {
     int32_t l = sourceCrop.left;
     int32_t r = sourceCrop.right;
     int32_t b = sourceCrop.bottom;
@@ -625,9 +624,8 @@
     mVpHeight = vph;
 }
 
-void GLES20RenderEngine::setupLayerBlending(bool premultipliedAlpha, bool opaque,
-                                            bool disableTexture, const half4& color,
-                                            float cornerRadius) {
+void GLESRenderEngine::setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
+                                          const half4& color, float cornerRadius) {
     mState.isPremultipliedAlpha = premultipliedAlpha;
     mState.isOpaque = opaque;
     mState.color = color;
@@ -645,23 +643,23 @@
     }
 }
 
-void GLES20RenderEngine::setSourceY410BT2020(bool enable) {
+void GLESRenderEngine::setSourceY410BT2020(bool enable) {
     mState.isY410BT2020 = enable;
 }
 
-void GLES20RenderEngine::setSourceDataSpace(Dataspace source) {
+void GLESRenderEngine::setSourceDataSpace(Dataspace source) {
     mDataSpace = source;
 }
 
-void GLES20RenderEngine::setOutputDataSpace(Dataspace dataspace) {
+void GLESRenderEngine::setOutputDataSpace(Dataspace dataspace) {
     mOutputDataSpace = dataspace;
 }
 
-void GLES20RenderEngine::setDisplayMaxLuminance(const float maxLuminance) {
+void GLESRenderEngine::setDisplayMaxLuminance(const float maxLuminance) {
     mState.displayMaxLuminance = maxLuminance;
 }
 
-void GLES20RenderEngine::setupLayerTexturing(const Texture& texture) {
+void GLESRenderEngine::setupLayerTexturing(const Texture& texture) {
     GLuint target = texture.getTextureTarget();
     glBindTexture(target, texture.getTextureName());
     GLenum filter = GL_NEAREST;
@@ -677,7 +675,7 @@
     mState.textureEnabled = true;
 }
 
-void GLES20RenderEngine::setupLayerBlackedOut() {
+void GLESRenderEngine::setupLayerBlackedOut() {
     glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
     Texture texture(Texture::TEXTURE_2D, mProtectedTexName);
     texture.setDimensions(1, 1); // FIXME: we should get that from somewhere
@@ -685,19 +683,19 @@
     mState.textureEnabled = true;
 }
 
-void GLES20RenderEngine::setColorTransform(const mat4& colorTransform) {
+void GLESRenderEngine::setColorTransform(const mat4& colorTransform) {
     mState.colorMatrix = colorTransform;
 }
 
-void GLES20RenderEngine::disableTexturing() {
+void GLESRenderEngine::disableTexturing() {
     mState.textureEnabled = false;
 }
 
-void GLES20RenderEngine::disableBlending() {
+void GLESRenderEngine::disableBlending() {
     glDisable(GL_BLEND);
 }
 
-void GLES20RenderEngine::setupFillWithColor(float r, float g, float b, float a) {
+void GLESRenderEngine::setupFillWithColor(float r, float g, float b, float a) {
     mState.isPremultipliedAlpha = true;
     mState.isOpaque = false;
     mState.color = half4(r, g, b, a);
@@ -705,11 +703,11 @@
     glDisable(GL_BLEND);
 }
 
-void GLES20RenderEngine::setupCornerRadiusCropSize(float width, float height) {
+void GLESRenderEngine::setupCornerRadiusCropSize(float width, float height) {
     mState.cropSize = half2(width, height);
 }
 
-void GLES20RenderEngine::drawMesh(const Mesh& mesh) {
+void GLESRenderEngine::drawMesh(const Mesh& mesh) {
     ATRACE_CALL();
     if (mesh.getTexCoordsSize()) {
         glEnableVertexAttribArray(Program::texCoords);
@@ -849,33 +847,33 @@
     }
 }
 
-size_t GLES20RenderEngine::getMaxTextureSize() const {
+size_t GLESRenderEngine::getMaxTextureSize() const {
     return mMaxTextureSize;
 }
 
-size_t GLES20RenderEngine::getMaxViewportDims() const {
+size_t GLESRenderEngine::getMaxViewportDims() const {
     return mMaxViewportDims[0] < mMaxViewportDims[1] ? mMaxViewportDims[0] : mMaxViewportDims[1];
 }
 
-void GLES20RenderEngine::dump(String8& result) {
+void GLESRenderEngine::dump(std::string& result) {
     const GLExtensions& extensions = GLExtensions::getInstance();
 
-    result.appendFormat("EGL implementation : %s\n", extensions.getEGLVersion());
-    result.appendFormat("%s\n", extensions.getEGLExtensions());
+    StringAppendF(&result, "EGL implementation : %s\n", extensions.getEGLVersion());
+    StringAppendF(&result, "%s\n", extensions.getEGLExtensions());
 
-    result.appendFormat("GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(),
-                        extensions.getVersion());
-    result.appendFormat("%s\n", extensions.getExtensions());
+    StringAppendF(&result, "GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(),
+                  extensions.getVersion());
+    StringAppendF(&result, "%s\n", extensions.getExtensions());
 
-    result.appendFormat("RenderEngine program cache size: %zu\n",
-                        ProgramCache::getInstance().getSize());
+    StringAppendF(&result, "RenderEngine program cache size: %zu\n",
+                  ProgramCache::getInstance().getSize());
 
-    result.appendFormat("RenderEngine last dataspace conversion: (%s) to (%s)\n",
-                        dataspaceDetails(static_cast<android_dataspace>(mDataSpace)).c_str(),
-                        dataspaceDetails(static_cast<android_dataspace>(mOutputDataSpace)).c_str());
+    StringAppendF(&result, "RenderEngine last dataspace conversion: (%s) to (%s)\n",
+                  dataspaceDetails(static_cast<android_dataspace>(mDataSpace)).c_str(),
+                  dataspaceDetails(static_cast<android_dataspace>(mOutputDataSpace)).c_str());
 }
 
-GLES20RenderEngine::GlesVersion GLES20RenderEngine::parseGlesVersion(const char* str) {
+GLESRenderEngine::GlesVersion GLESRenderEngine::parseGlesVersion(const char* str) {
     int major, minor;
     if (sscanf(str, "OpenGL ES-CM %d.%d", &major, &minor) != 2) {
         if (sscanf(str, "OpenGL ES %d.%d", &major, &minor) != 2) {
@@ -893,16 +891,18 @@
     return GLES_VERSION_1_0;
 }
 
-EGLContext GLES20RenderEngine::createEglContext(EGLDisplay display, EGLConfig config,
-                                                EGLContext shareContext, bool useContextPriority) {
+EGLContext GLESRenderEngine::createEglContext(EGLDisplay display, EGLConfig config,
+                                              EGLContext shareContext, bool useContextPriority) {
     EGLint renderableType = 0;
     if (config == EGL_NO_CONFIG) {
-        renderableType = EGL_OPENGL_ES2_BIT;
+        renderableType = EGL_OPENGL_ES3_BIT;
     } else if (!eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType)) {
         LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE");
     }
     EGLint contextClientVersion = 0;
-    if (renderableType & EGL_OPENGL_ES2_BIT) {
+    if (renderableType & EGL_OPENGL_ES3_BIT) {
+        contextClientVersion = 3;
+    } else if (renderableType & EGL_OPENGL_ES2_BIT) {
         contextClientVersion = 2;
     } else if (renderableType & EGL_OPENGL_ES_BIT) {
         contextClientVersion = 1;
@@ -920,11 +920,25 @@
     }
     contextAttributes.push_back(EGL_NONE);
 
-    return eglCreateContext(display, config, shareContext, contextAttributes.data());
+    EGLContext context = eglCreateContext(display, config, shareContext, contextAttributes.data());
+
+    if (contextClientVersion == 3 && context == EGL_NO_CONTEXT) {
+        // eglGetConfigAttrib indicated we can create GLES 3 context, but we failed, thus
+        // EGL_NO_CONTEXT so that we can abort.
+        if (config != EGL_NO_CONFIG) {
+            return context;
+        }
+        // If |config| is EGL_NO_CONFIG, we speculatively try to create GLES 3 context, so we should
+        // try to fall back to GLES 2.
+        contextAttributes[1] = 2;
+        context = eglCreateContext(display, config, shareContext, contextAttributes.data());
+    }
+
+    return context;
 }
 
-EGLSurface GLES20RenderEngine::createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config,
-                                                            int hwcFormat) {
+EGLSurface GLESRenderEngine::createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config,
+                                                          int hwcFormat) {
     EGLConfig dummyConfig = config;
     if (dummyConfig == EGL_NO_CONFIG) {
         dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
@@ -940,7 +954,7 @@
     return eglCreatePbufferSurface(display, dummyConfig, attributes.data());
 }
 
-bool GLES20RenderEngine::isHdrDataSpace(const Dataspace dataSpace) const {
+bool GLESRenderEngine::isHdrDataSpace(const Dataspace dataSpace) const {
     const Dataspace standard = static_cast<Dataspace>(dataSpace & Dataspace::STANDARD_MASK);
     const Dataspace transfer = static_cast<Dataspace>(dataSpace & Dataspace::TRANSFER_MASK);
     return standard == Dataspace::STANDARD_BT2020 &&
@@ -957,7 +971,7 @@
 // input data space or output data space is HDR data space, and the input transfer function
 // doesn't match the output transfer function, we would enable an intermediate transfrom to
 // XYZ color space.
-bool GLES20RenderEngine::needsXYZTransformMatrix() const {
+bool GLESRenderEngine::needsXYZTransformMatrix() const {
     const bool isInputHdrDataSpace = isHdrDataSpace(mDataSpace);
     const bool isOutputHdrDataSpace = isHdrDataSpace(mOutputDataSpace);
     const Dataspace inputTransfer = static_cast<Dataspace>(mDataSpace & Dataspace::TRANSFER_MASK);
diff --git a/libs/renderengine/gl/GLES20RenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
similarity index 91%
rename from libs/renderengine/gl/GLES20RenderEngine.h
rename to libs/renderengine/gl/GLESRenderEngine.h
index a9f8cad..21d5b81 100644
--- a/libs/renderengine/gl/GLES20RenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef SF_GLES20RENDERENGINE_H_
-#define SF_GLES20RENDERENGINE_H_
+#ifndef SF_GLESRENDERENGINE_H_
+#define SF_GLESRENDERENGINE_H_
 
 #include <stdint.h>
 #include <sys/types.h>
@@ -30,8 +30,6 @@
 
 namespace android {
 
-class String8;
-
 namespace renderengine {
 
 class Mesh;
@@ -41,14 +39,14 @@
 
 class GLImage;
 
-class GLES20RenderEngine : public impl::RenderEngine {
+class GLESRenderEngine : public impl::RenderEngine {
 public:
-    static std::unique_ptr<GLES20RenderEngine> create(int hwcFormat, uint32_t featureFlags);
+    static std::unique_ptr<GLESRenderEngine> create(int hwcFormat, uint32_t featureFlags);
     static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
 
-    GLES20RenderEngine(uint32_t featureFlags, // See RenderEngine::FeatureFlag
-                       EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy);
-    ~GLES20RenderEngine() override;
+    GLESRenderEngine(uint32_t featureFlags, // See RenderEngine::FeatureFlag
+                     EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy);
+    ~GLESRenderEngine() override;
 
     std::unique_ptr<Framebuffer> createFramebuffer() override;
     std::unique_ptr<Image> createImage() override;
@@ -79,7 +77,7 @@
     EGLConfig getEGLConfig() const { return mEGLConfig; }
 
 protected:
-    void dump(String8& result) override;
+    void dump(std::string& result) override;
     void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
                                   ui::Transform::orientation_flags rotation) override;
     void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
@@ -165,4 +163,4 @@
 } // namespace renderengine
 } // namespace android
 
-#endif /* SF_GLES20RENDERENGINE_H_ */
+#endif /* SF_GLESRENDERENGINE_H_ */
diff --git a/libs/renderengine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp
index 2bd4e7f..f4de91a 100644
--- a/libs/renderengine/gl/GLFramebuffer.cpp
+++ b/libs/renderengine/gl/GLFramebuffer.cpp
@@ -21,13 +21,13 @@
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 #include <nativebase/nativebase.h>
-#include "GLES20RenderEngine.h"
+#include "GLESRenderEngine.h"
 
 namespace android {
 namespace renderengine {
 namespace gl {
 
-GLFramebuffer::GLFramebuffer(const GLES20RenderEngine& engine)
+GLFramebuffer::GLFramebuffer(const GLESRenderEngine& engine)
       : mEGLDisplay(engine.getEGLDisplay()), mEGLImage(EGL_NO_IMAGE_KHR) {
     glGenTextures(1, &mTextureName);
     glGenFramebuffers(1, &mFramebufferName);
diff --git a/libs/renderengine/gl/GLFramebuffer.h b/libs/renderengine/gl/GLFramebuffer.h
index 90c6f4a..358ab47 100644
--- a/libs/renderengine/gl/GLFramebuffer.h
+++ b/libs/renderengine/gl/GLFramebuffer.h
@@ -28,11 +28,11 @@
 namespace renderengine {
 namespace gl {
 
-class GLES20RenderEngine;
+class GLESRenderEngine;
 
 class GLFramebuffer : public renderengine::Framebuffer {
 public:
-    explicit GLFramebuffer(const GLES20RenderEngine& engine);
+    explicit GLFramebuffer(const GLESRenderEngine& engine);
     ~GLFramebuffer() override;
 
     bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer) override;
diff --git a/libs/renderengine/gl/GLImage.cpp b/libs/renderengine/gl/GLImage.cpp
index 5a92093..a9529a7 100644
--- a/libs/renderengine/gl/GLImage.cpp
+++ b/libs/renderengine/gl/GLImage.cpp
@@ -19,7 +19,7 @@
 #include <vector>
 
 #include <log/log.h>
-#include "GLES20RenderEngine.h"
+#include "GLESRenderEngine.h"
 #include "GLExtensions.h"
 
 namespace android {
@@ -43,7 +43,7 @@
     return attrs;
 }
 
-GLImage::GLImage(const GLES20RenderEngine& engine) : mEGLDisplay(engine.getEGLDisplay()) {}
+GLImage::GLImage(const GLESRenderEngine& engine) : mEGLDisplay(engine.getEGLDisplay()) {}
 
 GLImage::~GLImage() {
     setNativeWindowBuffer(nullptr, false);
diff --git a/libs/renderengine/gl/GLImage.h b/libs/renderengine/gl/GLImage.h
index 0e451f8..c897d8e 100644
--- a/libs/renderengine/gl/GLImage.h
+++ b/libs/renderengine/gl/GLImage.h
@@ -29,11 +29,11 @@
 namespace renderengine {
 namespace gl {
 
-class GLES20RenderEngine;
+class GLESRenderEngine;
 
 class GLImage : public renderengine::Image {
 public:
-    explicit GLImage(const GLES20RenderEngine& engine);
+    explicit GLImage(const GLESRenderEngine& engine);
     ~GLImage() override;
 
     bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) override;
diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h
index 5941cdf..aa4e319 100644
--- a/libs/renderengine/include/renderengine/DisplaySettings.h
+++ b/libs/renderengine/include/renderengine/DisplaySettings.h
@@ -29,32 +29,32 @@
 struct DisplaySettings {
     // Rectangle describing the physical display. We will project from the
     // logical clip onto this rectangle.
-    Rect physicalDisplay;
+    Rect physicalDisplay = Rect::INVALID_RECT;
 
     // Rectangle bounded by the x,y- clipping planes in the logical display, so
     // that the orthographic projection matrix can be computed. When
     // constructing this matrix, z-coordinate bound are assumed to be at z=0 and
     // z=1.
-    Rect clip;
+    Rect clip = Rect::INVALID_RECT;
 
     // Global transform to apply to all layers.
-    mat4 globalTransform;
+    mat4 globalTransform = mat4();
 
     // Maximum luminance pulled from the display's HDR capabilities.
-    float maxLuminence;
+    float maxLuminence = 1.0f;
 
     // Output dataspace that will be populated if wide color gamut is used, or
     // DataSpace::UNKNOWN otherwise.
-    ui::Dataspace outputDataspace;
+    ui::Dataspace outputDataspace = ui::Dataspace::UNKNOWN;
 
     // Additional color transform to apply in linear space after transforming
     // to the output dataspace.
-    mat4 colorTransform;
+    mat4 colorTransform = mat4();
 
     // Region that will be cleared to (0, 0, 0, 0) prior to rendering.
     // clearRegion will first be transformed by globalTransform so that it will
     // be in the same coordinate space as the rendered layers.
-    Region clearRegion;
+    Region clearRegion = Region::INVALID_REGION;
 };
 
 } // namespace renderengine
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index facea21..38dee40 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -34,58 +34,58 @@
     // Buffer containing the image that we will render.
     // If buffer == nullptr, then the rest of the fields in this struct will be
     // ignored.
-    sp<GraphicBuffer> buffer;
+    sp<GraphicBuffer> buffer = nullptr;
 
     // Texture identifier to bind the external texture to.
     // TODO(alecmouri): This is GL-specific...make the type backend-agnostic.
-    uint32_t textureName;
+    uint32_t textureName = 0;
 
     // Whether to use filtering when rendering the texture.
-    bool useTextureFiltering;
+    bool useTextureFiltering = false;
 
     // Transform matrix to apply to texture coordinates.
-    mat4 textureTransform;
+    mat4 textureTransform = mat4();
 
     // Wheteher to use pre-multiplied alpha
-    bool usePremultipliedAlpha;
+    bool usePremultipliedAlpha = true;
 
     // HDR color-space setting for Y410.
-    bool isY410BT2020;
+    bool isY410BT2020 = false;
 };
 
 // Metadata describing the layer geometry.
 struct Geometry {
     // Boundaries of the layer.
-    FloatRect boundaries;
+    FloatRect boundaries = FloatRect();
 
     // Transform matrix to apply to mesh coordinates.
-    mat4 positionTransform;
+    mat4 positionTransform = mat4();
 };
 
 // Descriptor of the source pixels for this layer.
 struct PixelSource {
     // Source buffer
-    Buffer buffer;
+    Buffer buffer = Buffer();
 
     // The solid color with which to fill the layer.
     // This should only be populated if we don't render from an application
     // buffer.
-    half3 solidColor;
+    half3 solidColor = half3(0.0f, 0.0f, 0.0f);
 };
 
 // The settings that RenderEngine requires for correctly rendering a Layer.
 struct LayerSettings {
     // Geometry information
-    Geometry geometry;
+    Geometry geometry = Geometry();
 
     // Source pixels for this layer.
-    PixelSource source;
+    PixelSource source = PixelSource();
 
     // Alpha option to apply to the source pixels
-    half alpha;
+    half alpha = half(0.0);
 
     // Color space describing how the source pixels should be interpreted.
-    ui::Dataspace sourceDataspace;
+    ui::Dataspace sourceDataspace = ui::Dataspace::UNKNOWN;
 };
 
 } // namespace renderengine
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index bb7f4df..8eaa2d2 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -39,7 +39,6 @@
 
 namespace android {
 
-class String8;
 class Rect;
 class Region;
 
@@ -76,7 +75,7 @@
     virtual void primeCache() const = 0;
 
     // dump the extension strings. always call the base class.
-    virtual void dump(String8& result) = 0;
+    virtual void dump(std::string& result) = 0;
 
     virtual bool useNativeFenceSync() const = 0;
     virtual bool useWaitSync() const = 0;
diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp
index 65b7c82..051b8b6 100644
--- a/libs/renderengine/tests/Android.bp
+++ b/libs/renderengine/tests/Android.bp
@@ -24,6 +24,7 @@
         "librenderengine",
     ],
     shared_libs: [
+        "libbase",
         "libcutils",
         "libEGL",
         "libGLESv2",
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index f770975..956465c 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -26,7 +26,6 @@
         "-Werror",
     ],
     cppflags: [
-        "-std=c++1z",
         "-Weverything",
 
         // The static constructors and destructors in this library have not been noted to
@@ -55,6 +54,7 @@
     srcs: [
         "ColorSpace.cpp",
         "BufferHubBuffer.cpp",
+        "BufferHubEventFd.cpp",
         "BufferHubMetadata.cpp",
         "DebugUtils.cpp",
         "Fence.cpp",
@@ -112,6 +112,7 @@
             cflags: ["-DLIBUI_IN_VNDK"],
             exclude_srcs: [
                 "BufferHubBuffer.cpp",
+                "BufferHubEventFd.cpp",
                 "BufferHubMetadata.cpp",
             ],
             exclude_header_libs: [
diff --git a/libs/ui/BufferHubEventFd.cpp b/libs/ui/BufferHubEventFd.cpp
new file mode 100644
index 0000000..978b352
--- /dev/null
+++ b/libs/ui/BufferHubEventFd.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/eventfd.h>
+
+#include <log/log.h>
+#include <ui/BufferHubEventFd.h>
+
+namespace android {
+
+BufferHubEventFd::BufferHubEventFd() : mFd(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)) {}
+
+status_t BufferHubEventFd::signal() const {
+    if (!isValid()) {
+        ALOGE("%s: cannot signal an invalid eventfd.", __FUNCTION__);
+        return DEAD_OBJECT;
+    }
+
+    eventfd_write(mFd.get(), 1);
+    return OK;
+}
+
+status_t BufferHubEventFd::clear() const {
+    if (!isValid()) {
+        ALOGE("%s: cannot clear an invalid eventfd.", __FUNCTION__);
+        return DEAD_OBJECT;
+    }
+
+    eventfd_t value;
+    eventfd_read(mFd.get(), &value);
+    return OK;
+}
+
+} // namespace android
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index eaba1ed..a2f1783 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -24,9 +24,9 @@
 
 #include <grallocusage/GrallocUsageConversion.h>
 
+#include <android-base/stringprintf.h>
 #include <log/log.h>
 #include <utils/Singleton.h>
-#include <utils/String8.h>
 #include <utils/Trace.h>
 
 #include <ui/Gralloc2.h>
@@ -35,6 +35,8 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
+using base::StringAppendF;
+
 ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferAllocator )
 
 Mutex GraphicBufferAllocator::sLock;
@@ -50,46 +52,37 @@
 
 GraphicBufferAllocator::~GraphicBufferAllocator() {}
 
-void GraphicBufferAllocator::dump(String8& result) const
-{
+void GraphicBufferAllocator::dump(std::string& result) const {
     Mutex::Autolock _l(sLock);
     KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
     size_t total = 0;
-    const size_t SIZE = 4096;
-    char buffer[SIZE];
-    snprintf(buffer, SIZE, "Allocated buffers:\n");
-    result.append(buffer);
+    result.append("Allocated buffers:\n");
     const size_t c = list.size();
     for (size_t i=0 ; i<c ; i++) {
         const alloc_rec_t& rec(list.valueAt(i));
         if (rec.size) {
-            snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %4u | %8X | 0x%" PRIx64
-                    " | %s\n",
-                    list.keyAt(i), rec.size/1024.0,
-                    rec.width, rec.stride, rec.height, rec.layerCount, rec.format,
-                    rec.usage, rec.requestorName.c_str());
+            StringAppendF(&result,
+                          "%10p: %7.2f KiB | %4u (%4u) x %4u | %4u | %8X | 0x%" PRIx64 " | %s\n",
+                          list.keyAt(i), rec.size / 1024.0, rec.width, rec.stride, rec.height,
+                          rec.layerCount, rec.format, rec.usage, rec.requestorName.c_str());
         } else {
-            snprintf(buffer, SIZE, "%10p: unknown     | %4u (%4u) x %4u | %4u | %8X | 0x%" PRIx64
-                    " | %s\n",
-                    list.keyAt(i),
-                    rec.width, rec.stride, rec.height, rec.layerCount, rec.format,
-                    rec.usage, rec.requestorName.c_str());
+            StringAppendF(&result,
+                          "%10p: unknown     | %4u (%4u) x %4u | %4u | %8X | 0x%" PRIx64 " | %s\n",
+                          list.keyAt(i), rec.width, rec.stride, rec.height, rec.layerCount,
+                          rec.format, rec.usage, rec.requestorName.c_str());
         }
-        result.append(buffer);
         total += rec.size;
     }
-    snprintf(buffer, SIZE, "Total allocated (estimate): %.2f KB\n", total/1024.0);
-    result.append(buffer);
+    StringAppendF(&result, "Total allocated (estimate): %.2f KB\n", total / 1024.0);
 
-    std::string deviceDump = mAllocator->dumpDebugInfo();
-    result.append(deviceDump.c_str(), deviceDump.size());
+    result.append(mAllocator->dumpDebugInfo());
 }
 
 void GraphicBufferAllocator::dumpToSystemLog()
 {
-    String8 s;
+    std::string s;
     GraphicBufferAllocator::getInstance().dump(s);
-    ALOGD("%s", s.string());
+    ALOGD("%s", s.c_str());
 }
 
 status_t GraphicBufferAllocator::allocate(uint32_t width, uint32_t height,
diff --git a/libs/ui/Rect.cpp b/libs/ui/Rect.cpp
index d8702e5..13fed3a 100644
--- a/libs/ui/Rect.cpp
+++ b/libs/ui/Rect.cpp
@@ -72,6 +72,14 @@
     return *this;
 }
 
+Rect& Rect::inset(int32_t _left, int32_t _top, int32_t _right, int32_t _bottom) {
+    this->left += _left;
+    this->top += _top;
+    this->right -= _right;
+    this->bottom -= _bottom;
+    return *this;
+}
+
 const Rect Rect::operator +(const Point& rhs) const {
     const Rect result(left + rhs.x, top + rhs.y, right + rhs.x, bottom + rhs.y);
     return result;
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 618c7d6..3bd3748 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -19,8 +19,9 @@
 #include <inttypes.h>
 #include <limits.h>
 
+#include <android-base/stringprintf.h>
+
 #include <utils/Log.h>
-#include <utils/String8.h>
 #include <utils/CallStack.h>
 
 #include <ui/Rect.h>
@@ -41,6 +42,8 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
+using base::StringAppendF;
+
 enum {
     op_nand = region_operator<Rect>::op_nand,
     op_and  = region_operator<Rect>::op_and,
@@ -868,16 +871,14 @@
 
 // ----------------------------------------------------------------------------
 
-void Region::dump(String8& out, const char* what, uint32_t /* flags */) const
-{
+void Region::dump(std::string& out, const char* what, uint32_t /* flags */) const {
     const_iterator head = begin();
     const_iterator const tail = end();
 
-    out.appendFormat("  Region %s (this=%p, count=%" PRIdPTR ")\n",
-            what, this, tail - head);
+    StringAppendF(&out, "  Region %s (this=%p, count=%" PRIdPTR ")\n", what, this, tail - head);
     while (head != tail) {
-        out.appendFormat("    [%3d, %3d, %3d, %3d]\n", head->left, head->top,
-                head->right, head->bottom);
+        StringAppendF(&out, "    [%3d, %3d, %3d, %3d]\n", head->left, head->top, head->right,
+                      head->bottom);
         ++head;
     }
 }
diff --git a/libs/ui/UiConfig.cpp b/libs/ui/UiConfig.cpp
index 7730690..0ac863d 100644
--- a/libs/ui/UiConfig.cpp
+++ b/libs/ui/UiConfig.cpp
@@ -18,8 +18,7 @@
 
 namespace android {
 
-void appendUiConfigString(String8& configStr)
-{
+void appendUiConfigString(std::string& configStr) {
     static const char* config =
             " [libui]";
     configStr.append(config);
diff --git a/libs/ui/include/ui/BufferHubEventFd.h b/libs/ui/include/ui/BufferHubEventFd.h
new file mode 100644
index 0000000..0e856bd
--- /dev/null
+++ b/libs/ui/include/ui/BufferHubEventFd.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_BUFFER_HUB_EVENT_FD_H_
+#define ANDROID_BUFFER_HUB_EVENT_FD_H_
+
+#include <android-base/unique_fd.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+class BufferHubEventFd {
+public:
+    /**
+     * Constructs a valid event fd.
+     */
+    BufferHubEventFd();
+
+    /**
+     * Returns whether this BufferHubEventFd holds a valid event_fd.
+     */
+    bool isValid() const { return get() >= 0; }
+
+    /**
+     * Returns the fd number of the BufferHubEventFd object. Note that there is no ownership
+     * transfer.
+     */
+    int get() const { return mFd.get(); }
+
+    /**
+     * Signals the eventfd.
+     */
+    status_t signal() const;
+
+    /**
+     * Clears the signal from this eventfd if it is signaled.
+     */
+    status_t clear() const;
+
+private:
+    base::unique_fd mFd;
+};
+
+} // namespace android
+
+#endif // ANDROID_BUFFER_HUB_EVENT_FD_H_
diff --git a/libs/ui/include/ui/DisplayedFrameStats.h b/libs/ui/include/ui/DisplayedFrameStats.h
new file mode 100644
index 0000000..7a70ea1
--- /dev/null
+++ b/libs/ui/include/ui/DisplayedFrameStats.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <vector>
+
+namespace android {
+
+struct DisplayedFrameStats {
+    /* The number of frames represented by this sample. */
+    uint64_t numFrames = 0;
+    /* A histogram counting how many times a pixel of a given value was displayed onscreen for
+     * FORMAT_COMPONENT_0. The buckets of the histogram are evenly weighted, the number of buckets
+     * is device specific. eg, for RGBA_8888, if sampleComponent0 is {10, 6, 4, 1} this means that
+     * 10 red pixels were displayed onscreen in range 0x00->0x3F, 6 red pixels
+     * were displayed onscreen in range 0x40->0x7F, etc.
+     */
+    std::vector<uint64_t> component_0_sample = {};
+    /* The same sample definition as sampleComponent0, but for FORMAT_COMPONENT_1. */
+    std::vector<uint64_t> component_1_sample = {};
+    /* The same sample definition as sampleComponent0, but for FORMAT_COMPONENT_2. */
+    std::vector<uint64_t> component_2_sample = {};
+    /* The same sample definition as sampleComponent0, but for FORMAT_COMPONENT_3. */
+    std::vector<uint64_t> component_3_sample = {};
+};
+
+} // namespace android
diff --git a/libs/ui/include/ui/GraphicBufferAllocator.h b/libs/ui/include/ui/GraphicBufferAllocator.h
index 14a865e..7e2b230 100644
--- a/libs/ui/include/ui/GraphicBufferAllocator.h
+++ b/libs/ui/include/ui/GraphicBufferAllocator.h
@@ -39,7 +39,6 @@
 }
 
 class GraphicBufferMapper;
-class String8;
 
 class GraphicBufferAllocator : public Singleton<GraphicBufferAllocator>
 {
@@ -53,7 +52,7 @@
 
     status_t free(buffer_handle_t handle);
 
-    void dump(String8& res) const;
+    void dump(std::string& res) const;
     static void dumpToSystemLog();
 
 private:
diff --git a/libs/ui/include/ui/Rect.h b/libs/ui/include/ui/Rect.h
index 0bec0b7..e9da087 100644
--- a/libs/ui/include/ui/Rect.h
+++ b/libs/ui/include/ui/Rect.h
@@ -120,7 +120,7 @@
         right = rb.x;
         bottom = rb.y;
     }
-    
+
     // the following 4 functions return the 4 corners of the rect as Point
     Point leftTop() const {
         return Point(left, top);
@@ -175,6 +175,11 @@
     Rect& offsetTo(int32_t x, int32_t y);
     Rect& offsetBy(int32_t x, int32_t y);
 
+    /**
+     * Insets the rectangle on all sides specified by the insets.
+     */
+    Rect& inset(int32_t _left, int32_t _top, int32_t _right, int32_t _bottom);
+
     bool intersect(const Rect& with, Rect* result) const;
 
     // Create a new Rect by transforming this one using a graphics HAL
diff --git a/libs/ui/include/ui/Region.h b/libs/ui/include/ui/Region.h
index 0a09960..79642ae 100644
--- a/libs/ui/include/ui/Region.h
+++ b/libs/ui/include/ui/Region.h
@@ -27,12 +27,11 @@
 
 #include <android-base/macros.h>
 
+#include <string>
+
 namespace android {
 // ---------------------------------------------------------------------------
 
-class String8;
-
-// ---------------------------------------------------------------------------
 class Region : public LightFlattenable<Region>
 {
 public:
@@ -144,8 +143,8 @@
             status_t    flatten(void* buffer, size_t size) const;
             status_t    unflatten(void const* buffer, size_t size);
 
-    void        dump(String8& out, const char* what, uint32_t flags=0) const;
-    void        dump(const char* what, uint32_t flags=0) const;
+            void        dump(std::string& out, const char* what, uint32_t flags=0) const;
+            void        dump(const char* what, uint32_t flags=0) const;
 
 private:
     class rasterizer;
diff --git a/libs/ui/include/ui/UiConfig.h b/libs/ui/include/ui/UiConfig.h
index fcf8ed5..d1d6014 100644
--- a/libs/ui/include/ui/UiConfig.h
+++ b/libs/ui/include/ui/UiConfig.h
@@ -17,12 +17,12 @@
 #ifndef ANDROID_UI_CONFIG_H
 #define ANDROID_UI_CONFIG_H
 
-#include <utils/String8.h>
+#include <string>
 
 namespace android {
 
 // Append the libui configuration details to configStr.
-void appendUiConfigString(String8& configStr);
+void appendUiConfigString(std::string& configStr);
 
 }; // namespace android
 
diff --git a/libs/ui/include_vndk/ui/DisplayedFrameStats.h b/libs/ui/include_vndk/ui/DisplayedFrameStats.h
new file mode 120000
index 0000000..6014e19
--- /dev/null
+++ b/libs/ui/include_vndk/ui/DisplayedFrameStats.h
@@ -0,0 +1 @@
+../../include/ui/DisplayedFrameStats.h
\ No newline at end of file
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 00f30a6..fcc6d37 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -51,16 +51,23 @@
         "libdvr_headers",
         "libnativewindow_headers",
     ],
+    static_libs: [
+        "libgmock",
+    ],
     shared_libs: [
         "android.frameworks.bufferhub@1.0",
         "libcutils",
         "libhidlbase",
         "libhwbinder",
+        "liblog",
         "libpdx_default_transport",
         "libui",
         "libutils"
     ],
-    srcs: ["BufferHubBuffer_test.cpp"],
+    srcs: [
+        "BufferHubBuffer_test.cpp",
+        "BufferHubEventFd_test.cpp",
+    ],
     cflags: ["-Wall", "-Werror"],
 }
 
diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp
index 7c85e66..6c7d06b 100644
--- a/libs/ui/tests/BufferHubBuffer_test.cpp
+++ b/libs/ui/tests/BufferHubBuffer_test.cpp
@@ -127,7 +127,7 @@
     return;
 }
 
-TEST_F(BufferHubBufferTest, AllocateBuffer) {
+TEST_F(BufferHubBufferTest, AllocateAndFreeBuffer) {
     // TODO(b/116681016): directly test on BufferHubBuffer instead of the service.
     sp<IBufferHub> bufferHub = IBufferHub::getService();
     ASSERT_NE(nullptr, bufferHub.get());
@@ -138,11 +138,51 @@
     HardwareBufferDescription desc;
     memcpy(&desc, &aDesc, sizeof(HardwareBufferDescription));
 
-    IBufferHub::allocateBuffer_cb callback = [](const auto& client, const auto& status) {
-        EXPECT_EQ(status, BufferHubStatus::NO_ERROR);
-        EXPECT_NE(nullptr, client.get());
+    sp<IBufferClient> client;
+    BufferHubStatus ret;
+    IBufferHub::allocateBuffer_cb callback = [&](const auto& outClient, const auto& outStatus) {
+        client = outClient;
+        ret = outStatus;
     };
     EXPECT_TRUE(bufferHub->allocateBuffer(desc, kUserMetadataSize, callback).isOk());
+    EXPECT_EQ(ret, BufferHubStatus::NO_ERROR);
+    ASSERT_NE(nullptr, client.get());
+
+    EXPECT_EQ(BufferHubStatus::NO_ERROR, client->close());
+    EXPECT_EQ(BufferHubStatus::CLIENT_CLOSED, client->close());
+}
+
+TEST_F(BufferHubBufferTest, DuplicateFreedBuffer) {
+    // TODO(b/116681016): directly test on BufferHubBuffer instead of the service.
+    sp<IBufferHub> bufferHub = IBufferHub::getService();
+    ASSERT_NE(nullptr, bufferHub.get());
+
+    // Stride is an output, rfu0 and rfu1 are reserved data slot for future use.
+    AHardwareBuffer_Desc aDesc = {kWidth, kHeight,        kLayerCount,  kFormat,
+                                  kUsage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL};
+    HardwareBufferDescription desc;
+    memcpy(&desc, &aDesc, sizeof(HardwareBufferDescription));
+
+    sp<IBufferClient> client;
+    BufferHubStatus ret;
+    IBufferHub::allocateBuffer_cb callback = [&](const auto& outClient, const auto& outStatus) {
+        client = outClient;
+        ret = outStatus;
+    };
+    EXPECT_TRUE(bufferHub->allocateBuffer(desc, kUserMetadataSize, callback).isOk());
+    EXPECT_EQ(ret, BufferHubStatus::NO_ERROR);
+    ASSERT_NE(nullptr, client.get());
+
+    EXPECT_EQ(BufferHubStatus::NO_ERROR, client->close());
+
+    hidl_handle token;
+    IBufferClient::duplicate_cb dup_cb = [&](const auto& outToken, const auto& status) {
+        token = outToken;
+        ret = status;
+    };
+    EXPECT_TRUE(client->duplicate(dup_cb).isOk());
+    EXPECT_EQ(ret, BufferHubStatus::CLIENT_CLOSED);
+    EXPECT_EQ(token.getNativeHandle(), nullptr);
 }
 
 TEST_F(BufferHubBufferTest, DuplicateAndImportBuffer) {
@@ -230,5 +270,50 @@
     native_handle_delete(tokenHandle);
 }
 
+TEST_F(BufferHubBufferTest, ImportFreedBuffer) {
+    // TODO(b/116681016): directly test on BufferHubBuffer instead of the service.
+    sp<IBufferHub> bufferhub = IBufferHub::getService();
+    ASSERT_NE(nullptr, bufferhub.get());
+
+    // Stride is an output, rfu0 and rfu1 are reserved data slot for future use.
+    AHardwareBuffer_Desc aDesc = {kWidth, kHeight,        kLayerCount,  kFormat,
+                                  kUsage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL};
+    HardwareBufferDescription desc;
+    memcpy(&desc, &aDesc, sizeof(HardwareBufferDescription));
+
+    sp<IBufferClient> client;
+    BufferHubStatus ret;
+    IBufferHub::allocateBuffer_cb alloc_cb = [&](const auto& outClient, const auto& status) {
+        client = outClient;
+        ret = status;
+    };
+    ASSERT_TRUE(bufferhub->allocateBuffer(desc, kUserMetadataSize, alloc_cb).isOk());
+    EXPECT_EQ(ret, BufferHubStatus::NO_ERROR);
+    ASSERT_NE(nullptr, client.get());
+
+    hidl_handle token;
+    IBufferClient::duplicate_cb dup_cb = [&](const auto& outToken, const auto& status) {
+        token = outToken;
+        ret = status;
+    };
+    ASSERT_TRUE(client->duplicate(dup_cb).isOk());
+    EXPECT_EQ(ret, BufferHubStatus::NO_ERROR);
+    ASSERT_NE(token.getNativeHandle(), nullptr);
+    EXPECT_EQ(token->numInts, 1);
+    EXPECT_EQ(token->numFds, 0);
+
+    // Close the client. Now the token should be invalid.
+    client->close();
+
+    sp<IBufferClient> client2;
+    IBufferHub::importBuffer_cb import_cb = [&](const auto& outClient, const auto& status) {
+        client2 = outClient;
+        ret = status;
+    };
+    EXPECT_TRUE(bufferhub->importBuffer(token, import_cb).isOk());
+    EXPECT_EQ(ret, BufferHubStatus::INVALID_TOKEN);
+    EXPECT_EQ(nullptr, client2.get());
+}
+
 } // namespace
 } // namespace android
diff --git a/libs/ui/tests/BufferHubEventFd_test.cpp b/libs/ui/tests/BufferHubEventFd_test.cpp
new file mode 100644
index 0000000..92fb33f
--- /dev/null
+++ b/libs/ui/tests/BufferHubEventFd_test.cpp
@@ -0,0 +1,338 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BufferHubEventFdTest"
+
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+
+#include <array>
+#include <condition_variable>
+#include <mutex>
+#include <thread>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <ui/BufferHubEventFd.h>
+
+namespace android {
+
+namespace {
+
+const int kTimeout = 100;
+const std::chrono::milliseconds kTimeoutMs(kTimeout);
+
+using ::testing::Contains;
+using BufferHubEventFdTest = ::testing::Test;
+
+} // namespace
+
+TEST_F(BufferHubEventFdTest, EventFd_testSingleEpollFd) {
+    BufferHubEventFd eventFd;
+    ASSERT_TRUE(eventFd.isValid());
+
+    base::unique_fd epollFd(epoll_create(64));
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+
+    ASSERT_GE(epollFd.get(), 0);
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+    std::array<epoll_event, 1> events;
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+    eventFd.signal();
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+
+    // The epoll fd is edge triggered, so it only responds to the eventFd once.
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testClear) {
+    BufferHubEventFd eventFd;
+    ASSERT_TRUE(eventFd.isValid());
+
+    base::unique_fd epollFd(epoll_create(64));
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+
+    ASSERT_GE(epollFd.get(), 0);
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+    eventFd.signal();
+    eventFd.clear();
+
+    std::array<epoll_event, 1> events;
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testDupEventFd) {
+    BufferHubEventFd eventFd;
+    ASSERT_TRUE(eventFd.isValid());
+
+    base::unique_fd epollFd(epoll_create(64));
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+
+    ASSERT_GE(epollFd.get(), 0);
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+    // Technically, the dupliated eventFd and the original eventFd are pointing
+    // to the same kernel object. This test signals the duplicated eventFd but epolls the origianl
+    // eventFd.
+    base::unique_fd dupedEventFd(dup(eventFd.get()));
+    ASSERT_GE(dupedEventFd.get(), 0);
+
+    std::array<epoll_event, 1> events;
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+    eventfd_write(dupedEventFd.get(), 1);
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+
+    // The epoll fd is edge triggered, so it only responds to the eventFd once.
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+    eventfd_write(dupedEventFd.get(), 1);
+
+    eventfd_t value;
+    eventfd_read(dupedEventFd.get(), &value);
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testTwoEpollFds) {
+    BufferHubEventFd eventFd;
+    ASSERT_TRUE(eventFd.isValid());
+
+    base::unique_fd epollFd1(epoll_create(64));
+    base::unique_fd epollFd2(epoll_create(64));
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+
+    ASSERT_GE(epollFd1.get(), 0);
+    ASSERT_GE(epollFd2.get(), 0);
+
+    // Register the same eventFd to two EpollFds.
+    ASSERT_EQ(epoll_ctl(epollFd1.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+    ASSERT_EQ(epoll_ctl(epollFd2.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+    std::array<epoll_event, 1> events;
+    EXPECT_EQ(epoll_wait(epollFd1.get(), events.data(), events.size(), 0), 0);
+    EXPECT_EQ(epoll_wait(epollFd2.get(), events.data(), events.size(), 0), 0);
+
+    eventFd.signal();
+    EXPECT_EQ(epoll_wait(epollFd1.get(), events.data(), events.size(), 0), 1);
+    EXPECT_EQ(epoll_wait(epollFd2.get(), events.data(), events.size(), 0), 1);
+
+    // The epoll fd is edge triggered, so it only responds to the eventFd once.
+    EXPECT_EQ(epoll_wait(epollFd1.get(), events.data(), events.size(), 0), 0);
+    EXPECT_EQ(epoll_wait(epollFd2.get(), events.data(), events.size(), 0), 0);
+
+    eventFd.signal();
+    EXPECT_EQ(epoll_wait(epollFd1.get(), events.data(), events.size(), 0), 1);
+
+    eventFd.clear();
+    EXPECT_EQ(epoll_wait(epollFd1.get(), events.data(), events.size(), 0), 0);
+    EXPECT_EQ(epoll_wait(epollFd2.get(), events.data(), events.size(), 0), 0);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testTwoEventFds) {
+    BufferHubEventFd eventFd1;
+    BufferHubEventFd eventFd2;
+
+    ASSERT_TRUE(eventFd1.isValid());
+    ASSERT_TRUE(eventFd2.isValid());
+
+    base::unique_fd epollFd(epoll_create(64));
+    epoll_event e1 = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 1}};
+    epoll_event e2 = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 2}};
+
+    ASSERT_GE(epollFd.get(), 0);
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd1.get(), &e1), 0);
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd2.get(), &e2), 0);
+
+    std::array<epoll_event, 2> events;
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+    // Signal one by one.
+    eventFd1.signal();
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+    EXPECT_EQ(events[0].data.u32, e1.data.u32);
+
+    eventFd2.signal();
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+    EXPECT_EQ(events[0].data.u32, e2.data.u32);
+
+    // Signal both.
+    eventFd1.signal();
+    eventFd2.signal();
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 2);
+
+    uint32_t u32s[] = {events[0].data.u32, events[1].data.u32};
+    EXPECT_THAT(u32s, Contains(e1.data.u32));
+    EXPECT_THAT(u32s, Contains(e2.data.u32));
+
+    // The epoll fd is edge triggered, so it only responds to the eventFd once.
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+    eventFd1.signal();
+    eventFd2.signal();
+    eventFd2.clear();
+    EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testPollingThreadWithTwoEventFds) {
+    BufferHubEventFd eventFd1;
+    BufferHubEventFd eventFd2;
+
+    ASSERT_TRUE(eventFd1.isValid());
+    ASSERT_TRUE(eventFd2.isValid());
+
+    base::unique_fd epollFd(epoll_create(64));
+    epoll_event e1 = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 1}};
+    epoll_event e2 = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 2}};
+
+    ASSERT_GE(epollFd.get(), 0);
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd1.get(), &e1), 0);
+    ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd2.get(), &e2), 0);
+
+    int countEvent1 = 0;
+    int countEvent2 = 0;
+    std::atomic<bool> stop{false};
+    std::mutex mx;
+    std::condition_variable cv;
+
+    std::thread pollingThread([&] {
+        std::array<epoll_event, 2> events;
+        while (true) {
+            if (stop.load()) {
+                break;
+            }
+            int ret = epoll_wait(epollFd.get(), events.data(), events.size(), kTimeout);
+            ALOGE_IF(ret < 0 && errno != ETIMEDOUT, "Epoll failed.");
+
+            std::lock_guard<std::mutex> lock(mx);
+            for (int i = 0; i < ret; i++) {
+                if (events[i].data.u32 == e1.data.u32) {
+                    countEvent1++;
+                    cv.notify_one();
+                } else if (events[i].data.u32 == e2.data.u32) {
+                    countEvent2++;
+                    cv.notify_one();
+                }
+            }
+        }
+    });
+
+    {
+        std::unique_lock<std::mutex> lock(mx);
+
+        eventFd1.signal();
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent1 == 1; }));
+
+        eventFd1.signal();
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent1 == 2; }));
+
+        eventFd2.signal();
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent2 == 1; }));
+
+        eventFd1.clear();
+        eventFd2.clear();
+        EXPECT_EQ(countEvent1, 2);
+        EXPECT_EQ(countEvent2, 1);
+
+        eventFd1.signal();
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent1 == 3; }));
+
+        eventFd2.signal();
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent2 == 2; }));
+    }
+
+    stop.store(true);
+    pollingThread.join();
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testTwoPollingThreads) {
+    BufferHubEventFd eventFd;
+    ASSERT_TRUE(eventFd.isValid());
+
+    base::unique_fd epollFd1(epoll_create(64));
+    base::unique_fd epollFd2(epoll_create(64));
+    epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+
+    ASSERT_GE(epollFd1.get(), 0);
+    ASSERT_GE(epollFd2.get(), 0);
+
+    // Register the same eventFd to two EpollFds.
+    ASSERT_EQ(epoll_ctl(epollFd1.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+    ASSERT_EQ(epoll_ctl(epollFd2.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+    int countEpoll1 = 0;
+    int countEpoll2 = 0;
+    std::atomic<bool> stop{false};
+    std::mutex mx;
+    std::condition_variable cv;
+
+    std::thread pollingThread1([&] {
+        std::array<epoll_event, 1> events;
+        while (!stop.load()) {
+            int ret = epoll_wait(epollFd1.get(), events.data(), events.size(), kTimeout);
+            ALOGE_IF(ret < 0 && errno != ETIMEDOUT, "Epoll failed.");
+
+            if (ret > 0) {
+                std::lock_guard<std::mutex> lock(mx);
+                countEpoll1++;
+                cv.notify_one();
+            }
+        }
+    });
+
+    std::thread pollingThread2([&] {
+        std::array<epoll_event, 1> events;
+        while (!stop.load()) {
+            int ret = epoll_wait(epollFd2.get(), events.data(), events.size(), kTimeout);
+            ALOGE_IF(ret < 0 && errno != ETIMEDOUT, "Epoll failed.");
+
+            if (ret > 0) {
+                std::lock_guard<std::mutex> lock(mx);
+                countEpoll2++;
+                cv.notify_one();
+            }
+        }
+    });
+
+    {
+        std::unique_lock<std::mutex> lock(mx);
+
+        eventFd.signal();
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEpoll1 == 1; }));
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEpoll2 == 1; }));
+
+        eventFd.signal();
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEpoll1 == 2; }));
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEpoll2 == 2; }));
+
+        eventFd.clear();
+        EXPECT_EQ(countEpoll1, 2);
+        EXPECT_EQ(countEpoll2, 2);
+
+        eventFd.signal();
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEpoll1 == 3; }));
+        EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEpoll2 == 3; }));
+    }
+
+    stop.store(true);
+    pollingThread1.join();
+    pollingThread2.join();
+}
+
+} // namespace android
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index 43ac79e..fa92830 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -22,14 +22,12 @@
     "buffer_hub_base.cpp",
     "buffer_hub_rpc.cpp",
     "consumer_buffer.cpp",
-    "buffer_client_impl.cpp",
     "ion_buffer.cpp",
     "producer_buffer.cpp",
 ]
 
 sharedLibraries = [
     "libbase",
-    "libbinder",
     "libcutils",
     "libhardware",
     "liblog",
diff --git a/libs/vr/libbufferhub/buffer_client_impl.cpp b/libs/vr/libbufferhub/buffer_client_impl.cpp
deleted file mode 100644
index efa9c28..0000000
--- a/libs/vr/libbufferhub/buffer_client_impl.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-#include <log/log.h>
-#include <private/dvr/IBufferClient.h>
-
-namespace android {
-namespace dvr {
-
-class BpBufferClient : public BpInterface<IBufferClient> {
- public:
-  explicit BpBufferClient(const sp<IBinder>& impl)
-      : BpInterface<IBufferClient>(impl) {}
-
-  bool isValid() override;
-
-  status_t duplicate(uint64_t* outToken) override;
-};
-
-IMPLEMENT_META_INTERFACE(BufferClient, "android.dvr.IBufferClient");
-
-// Transaction code
-enum {
-  IS_VALID = IBinder::FIRST_CALL_TRANSACTION,
-  DUPLICATE,
-};
-
-bool BpBufferClient::isValid() {
-  Parcel data, reply;
-  status_t ret =
-      data.writeInterfaceToken(IBufferClient::getInterfaceDescriptor());
-  if (ret != OK) {
-    ALOGE("BpBufferClient::isValid: failed to write into parcel; errno=%d",
-          ret);
-    return false;
-  }
-
-  ret = remote()->transact(IS_VALID, data, &reply);
-  if (ret == OK) {
-    return reply.readBool();
-  } else {
-    ALOGE("BpBufferClient::isValid: failed to transact; errno=%d", ret);
-    return false;
-  }
-}
-
-status_t BpBufferClient::duplicate(uint64_t* outToken) {
-  Parcel data, reply;
-  status_t ret =
-      data.writeInterfaceToken(IBufferClient::getInterfaceDescriptor());
-  if (ret != OK) {
-    ALOGE("BpBufferClient::duplicate: failed to write into parcel; errno=%d",
-          ret);
-    return ret;
-  }
-
-  ret = remote()->transact(DUPLICATE, data, &reply);
-  if (ret == OK) {
-    *outToken = reply.readUint64();
-    return OK;
-  } else {
-    ALOGE("BpBufferClient::duplicate: failed to transact; errno=%d", ret);
-    return ret;
-  }
-}
-
-status_t BnBufferClient::onTransact(uint32_t code, const Parcel& data,
-                                    Parcel* reply, uint32_t flags) {
-  switch (code) {
-    case IS_VALID: {
-      CHECK_INTERFACE(IBufferClient, data, reply);
-      return reply->writeBool(isValid());
-    }
-    case DUPLICATE: {
-      CHECK_INTERFACE(IBufferClient, data, reply);
-      uint64_t token = 0;
-      status_t ret = duplicate(&token);
-      if (ret != OK) {
-        return ret;
-      }
-      return reply->writeUint64(token);
-    }
-    default:
-      // Should not reach except binder defined transactions such as dumpsys
-      return BBinder::onTransact(code, data, reply, flags);
-  }
-}
-
-}  // namespace dvr
-}  // namespace android
\ No newline at end of file
diff --git a/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h b/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h
deleted file mode 100644
index 31bf79d..0000000
--- a/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef ANDROID_DVR_IBUFFERCLIENT_H
-#define ANDROID_DVR_IBUFFERCLIENT_H
-
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-
-namespace android {
-namespace dvr {
-
-// Interface for acessing BufferHubBuffer remotely.
-class IBufferClient : public IInterface {
- public:
-  DECLARE_META_INTERFACE(BufferClient);
-
-  // Checks if the buffer node is valid.
-  virtual bool isValid() = 0;
-
-  // Duplicates the client. Token_out will be set to a new token when succeed,
-  // and not changed when failed.
-  virtual status_t duplicate(uint64_t* outToken) = 0;
-};
-
-// BnInterface for IBufferClient. Should only be created in bufferhub service.
-class BnBufferClient : public BnInterface<IBufferClient> {
- public:
-  virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
-                              uint32_t flags = 0);
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_IBUFFERCLIENT_H
\ No newline at end of file
diff --git a/libs/vr/libbufferhub/producer_buffer.cpp b/libs/vr/libbufferhub/producer_buffer.cpp
index c177970..de03fad 100644
--- a/libs/vr/libbufferhub/producer_buffer.cpp
+++ b/libs/vr/libbufferhub/producer_buffer.cpp
@@ -171,7 +171,7 @@
 
   if (BufferHubDefs::IsClientGained(current_buffer_state,
                                     client_state_mask())) {
-    ALOGI("%s: already gained id=%d.", __FUNCTION__, id());
+    ALOGV("%s: already gained id=%d.", __FUNCTION__, id());
     return 0;
   }
   if (BufferHubDefs::AnyClientAcquired(current_buffer_state) ||
diff --git a/libs/vr/libvrflinger/tests/Android.bp b/libs/vr/libvrflinger/tests/Android.bp
index 9a1d2e5..c884cb3 100644
--- a/libs/vr/libvrflinger/tests/Android.bp
+++ b/libs/vr/libvrflinger/tests/Android.bp
@@ -32,7 +32,6 @@
         "-Wall",
         "-Werror",
     ],
-    cppflags: ["-std=c++1z"],
     name: "vrflinger_test",
 
     // TODO(b/117568153): Temporarily opt out using libcrt.
diff --git a/services/bufferhub/Android.bp b/services/bufferhub/Android.bp
index b747dbc..f9aaa20 100644
--- a/services/bufferhub/Android.bp
+++ b/services/bufferhub/Android.bp
@@ -24,9 +24,9 @@
     ],
     srcs: [
         "BufferClient.cpp",
+        "BufferHubIdGenerator.cpp",
         "BufferHubService.cpp",
         "BufferNode.cpp",
-        "UniqueIdGenerator.cpp",
     ],
     header_libs: [
         "libbufferhub_headers",
diff --git a/services/bufferhub/BufferClient.cpp b/services/bufferhub/BufferClient.cpp
index 37fd75f..7459517 100644
--- a/services/bufferhub/BufferClient.cpp
+++ b/services/bufferhub/BufferClient.cpp
@@ -39,7 +39,29 @@
     return new BufferClient(service, node);
 }
 
+BufferClient::~BufferClient() {
+    close();
+}
+
+Return<BufferHubStatus> BufferClient::close() {
+    std::lock_guard<std::mutex> lock(mClosedMutex);
+    if (mClosed) {
+        return BufferHubStatus::CLIENT_CLOSED;
+    }
+
+    getService()->onClientClosed(this);
+    mBufferNode.reset();
+    mClosed = true;
+    return BufferHubStatus::NO_ERROR;
+}
+
 Return<void> BufferClient::duplicate(duplicate_cb _hidl_cb) {
+    std::lock_guard<std::mutex> lock(mClosedMutex);
+    if (mClosed) {
+        _hidl_cb(/*token=*/hidl_handle(), /*status=*/BufferHubStatus::CLIENT_CLOSED);
+        return Void();
+    }
+
     if (!mBufferNode) {
         // Should never happen
         ALOGE("%s: node is missing.", __FUNCTION__);
@@ -47,15 +69,19 @@
         return Void();
     }
 
+    const hidl_handle token = getService()->registerToken(this);
+    _hidl_cb(/*token=*/token, /*status=*/BufferHubStatus::NO_ERROR);
+    return Void();
+}
+
+sp<BufferHubService> BufferClient::getService() {
     sp<BufferHubService> service = mService.promote();
     if (service == nullptr) {
         // Should never happen. Kill the process.
         LOG_FATAL("%s: service died.", __FUNCTION__);
     }
 
-    const hidl_handle token = service->registerToken(this);
-    _hidl_cb(/*token=*/token, /*status=*/BufferHubStatus::NO_ERROR);
-    return Void();
+    return service;
 }
 
 } // namespace implementation
diff --git a/services/bufferhub/UniqueIdGenerator.cpp b/services/bufferhub/BufferHubIdGenerator.cpp
similarity index 81%
rename from services/bufferhub/UniqueIdGenerator.cpp
rename to services/bufferhub/BufferHubIdGenerator.cpp
index 362a026..6444a03 100644
--- a/services/bufferhub/UniqueIdGenerator.cpp
+++ b/services/bufferhub/BufferHubIdGenerator.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <bufferhub/UniqueIdGenerator.h>
+#include <bufferhub/BufferHubIdGenerator.h>
 
 namespace android {
 namespace frameworks {
@@ -22,9 +22,15 @@
 namespace V1_0 {
 namespace implementation {
 
-constexpr uint32_t UniqueIdGenerator::kInvalidId;
+constexpr uint32_t BufferHubIdGenerator::kInvalidId;
 
-uint32_t UniqueIdGenerator::getId() {
+BufferHubIdGenerator& BufferHubIdGenerator::getInstance() {
+    static BufferHubIdGenerator generator;
+
+    return generator;
+}
+
+uint32_t BufferHubIdGenerator::getId() {
     std::lock_guard<std::mutex> lock(mIdsInUseMutex);
 
     do {
@@ -37,7 +43,7 @@
     return mLastId;
 }
 
-bool UniqueIdGenerator::freeId(uint32_t id) {
+bool BufferHubIdGenerator::freeId(uint32_t id) {
     std::lock_guard<std::mutex> lock(mIdsInUseMutex);
     auto iter = mIdsInUse.find(id);
     if (iter != mIdsInUse.end()) {
diff --git a/services/bufferhub/BufferHubService.cpp b/services/bufferhub/BufferHubService.cpp
index 6f97f0d..b0869fe 100644
--- a/services/bufferhub/BufferHubService.cpp
+++ b/services/bufferhub/BufferHubService.cpp
@@ -35,7 +35,8 @@
 
     std::shared_ptr<BufferNode> node =
             std::make_shared<BufferNode>(desc.width, desc.height, desc.layers, desc.format,
-                                         desc.usage, userMetadataSize, nodeIdGenerator.getId());
+                                         desc.usage, userMetadataSize,
+                                         BufferHubIdGenerator::getInstance().getId());
     if (node == nullptr || !node->IsValid()) {
         ALOGE("%s: creating BufferNode failed.", __FUNCTION__);
         _hidl_cb(/*bufferClient=*/nullptr, /*status=*/BufferHubStatus::ALLOCATION_FAILED);
@@ -44,8 +45,8 @@
 
     sp<BufferClient> client = BufferClient::create(this, node);
     // Add it to list for bookkeeping and dumpsys.
-    std::lock_guard<std::mutex> lock(mClientListMutex);
-    mClientList.push_back(client);
+    std::lock_guard<std::mutex> lock(mClientSetMutex);
+    mClientSet.emplace(client);
 
     _hidl_cb(/*bufferClient=*/client, /*status=*/BufferHubStatus::NO_ERROR);
     return Void();
@@ -86,8 +87,8 @@
 
     sp<BufferClient> client = new BufferClient(*originClient);
 
-    std::lock_guard<std::mutex> lock(mClientListMutex);
-    mClientList.push_back(client);
+    std::lock_guard<std::mutex> lock(mClientSetMutex);
+    mClientSet.emplace(client);
     _hidl_cb(/*bufferClient=*/client, /*status=*/BufferHubStatus::NO_ERROR);
     return Void();
 }
@@ -111,6 +112,30 @@
     return returnToken;
 }
 
+void BufferHubService::onClientClosed(const BufferClient* client) {
+    removeTokenByClient(client);
+
+    std::lock_guard<std::mutex> lock(mClientSetMutex);
+    auto iter = std::find(mClientSet.begin(), mClientSet.end(), client);
+    if (iter != mClientSet.end()) {
+        mClientSet.erase(iter);
+    }
+}
+
+void BufferHubService::removeTokenByClient(const BufferClient* client) {
+    std::lock_guard<std::mutex> lock(mTokenMapMutex);
+    auto iter = mTokenMap.begin();
+    while (iter != mTokenMap.end()) {
+        if (iter->second == client) {
+            auto oldIter = iter;
+            ++iter;
+            mTokenMap.erase(oldIter);
+        } else {
+            ++iter;
+        }
+    }
+}
+
 } // namespace implementation
 } // namespace V1_0
 } // namespace bufferhub
diff --git a/services/bufferhub/BufferNode.cpp b/services/bufferhub/BufferNode.cpp
index 715d0a1..ec84849 100644
--- a/services/bufferhub/BufferNode.cpp
+++ b/services/bufferhub/BufferNode.cpp
@@ -66,8 +66,8 @@
     }
 
     // Free the id, if valid
-    if (id() != UniqueIdGenerator::kInvalidId) {
-        if (nodeIdGenerator.freeId(id())) {
+    if (id() != BufferHubIdGenerator::kInvalidId) {
+        if (BufferHubIdGenerator::getInstance().freeId(id())) {
             ALOGI("%s: id #%u is freed.", __FUNCTION__, id());
         } else {
             ALOGE("%s: Cannot free nonexistent id #%u", __FUNCTION__, id());
diff --git a/services/bufferhub/include/bufferhub/BufferClient.h b/services/bufferhub/include/bufferhub/BufferClient.h
index 769ec86..7f5d3a6 100644
--- a/services/bufferhub/include/bufferhub/BufferClient.h
+++ b/services/bufferhub/include/bufferhub/BufferClient.h
@@ -44,14 +44,22 @@
     // Creates a BufferClient from an existing BufferClient. Will share the same BufferNode.
     explicit BufferClient(const BufferClient& other)
           : mService(other.mService), mBufferNode(other.mBufferNode) {}
+    ~BufferClient();
 
+    Return<BufferHubStatus> close() override;
     Return<void> duplicate(duplicate_cb _hidl_cb) override;
 
 private:
     BufferClient(wp<BufferHubService> service, const std::shared_ptr<BufferNode>& node)
           : mService(service), mBufferNode(node) {}
 
+    sp<BufferHubService> getService();
+
     wp<BufferHubService> mService;
+
+    std::mutex mClosedMutex;
+    bool mClosed GUARDED_BY(mClosedMutex) = false;
+
     std::shared_ptr<BufferNode> mBufferNode;
 };
 
diff --git a/services/bufferhub/include/bufferhub/UniqueIdGenerator.h b/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h
similarity index 89%
rename from services/bufferhub/include/bufferhub/UniqueIdGenerator.h
rename to services/bufferhub/include/bufferhub/BufferHubIdGenerator.h
index d2e702f..c5b2cde 100644
--- a/services/bufferhub/include/bufferhub/UniqueIdGenerator.h
+++ b/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h
@@ -29,11 +29,14 @@
 namespace implementation {
 
 // A thread-safe incremental uint32_t id generator.
-class UniqueIdGenerator {
+class BufferHubIdGenerator {
 public:
     // 0 is considered invalid
     static constexpr uint32_t kInvalidId = 0UL;
 
+    // Get the singleton instance of this class
+    static BufferHubIdGenerator& getInstance();
+
     // Gets next available id. If next id is greater than std::numeric_limits<uint32_t>::max() (2 ^
     // 32 - 1), it will try to get an id start from 1 again.
     uint32_t getId();
@@ -42,6 +45,9 @@
     bool freeId(uint32_t id);
 
 private:
+    BufferHubIdGenerator() = default;
+    ~BufferHubIdGenerator() = default;
+
     std::mutex mIdsInUseMutex;
     // Start from kInvalidID to avoid generating it.
     uint32_t mLastId = kInvalidId;
diff --git a/services/bufferhub/include/bufferhub/BufferHubService.h b/services/bufferhub/include/bufferhub/BufferHubService.h
index 6535659..f2c8ef8 100644
--- a/services/bufferhub/include/bufferhub/BufferHubService.h
+++ b/services/bufferhub/include/bufferhub/BufferHubService.h
@@ -22,7 +22,7 @@
 
 #include <android/frameworks/bufferhub/1.0/IBufferHub.h>
 #include <bufferhub/BufferClient.h>
-#include <bufferhub/UniqueIdGenerator.h>
+#include <bufferhub/BufferHubIdGenerator.h>
 #include <utils/Mutex.h>
 
 namespace android {
@@ -35,8 +35,6 @@
 using hardware::Return;
 using hardware::graphics::common::V1_2::HardwareBufferDescription;
 
-static UniqueIdGenerator nodeIdGenerator;
-
 class BufferHubService : public IBufferHub {
 public:
     Return<void> allocateBuffer(const HardwareBufferDescription& description,
@@ -48,10 +46,15 @@
     // Internal help function for IBufferClient::duplicate.
     hidl_handle registerToken(const wp<BufferClient>& client);
 
+    void onClientClosed(const BufferClient* client);
+
 private:
+    // Helper function to remove all the token belongs to a specific client.
+    void removeTokenByClient(const BufferClient* client);
+
     // List of active BufferClient for bookkeeping.
-    std::mutex mClientListMutex;
-    std::vector<wp<BufferClient>> mClientList GUARDED_BY(mClientListMutex);
+    std::mutex mClientSetMutex;
+    std::set<wp<BufferClient>> mClientSet GUARDED_BY(mClientSetMutex);
 
     // TODO(b/118180214): use a more secure implementation
     std::mt19937 mTokenEngine;
diff --git a/services/bufferhub/include/bufferhub/BufferNode.h b/services/bufferhub/include/bufferhub/BufferNode.h
index c490e7c..94ef505 100644
--- a/services/bufferhub/include/bufferhub/BufferNode.h
+++ b/services/bufferhub/include/bufferhub/BufferNode.h
@@ -2,7 +2,7 @@
 #define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_NODE_H_
 
 #include <android/hardware_buffer.h>
-#include <bufferhub/UniqueIdGenerator.h>
+#include <bufferhub/BufferHubIdGenerator.h>
 #include <ui/BufferHubMetadata.h>
 
 namespace android {
@@ -16,7 +16,7 @@
     // Allocates a new BufferNode.
     BufferNode(uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
                uint64_t usage, size_t user_metadata_size,
-               uint32_t id = UniqueIdGenerator::kInvalidId);
+               uint32_t id = BufferHubIdGenerator::kInvalidId);
 
     ~BufferNode();
 
diff --git a/services/bufferhub/tests/Android.bp b/services/bufferhub/tests/Android.bp
index 8a30ef5..3967886 100644
--- a/services/bufferhub/tests/Android.bp
+++ b/services/bufferhub/tests/Android.bp
@@ -24,10 +24,10 @@
 }
 
 cc_test {
-    name: "UniqueIdGenerator_test",
-    srcs: ["UniqueIdGenerator_test.cpp"],
+    name: "BufferHubIdGenerator_test",
+    srcs: ["BufferHubIdGenerator_test.cpp"],
     cflags: [
-        "-DLOG_TAG=\"UniqueIdGenerator_test\"",
+        "-DLOG_TAG=\"BufferHubIdGenerator_test\"",
         "-DTRACE=0",
         "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
     ],
diff --git a/services/bufferhub/tests/BufferHubIdGenerator_test.cpp b/services/bufferhub/tests/BufferHubIdGenerator_test.cpp
new file mode 100644
index 0000000..4eddfe0
--- /dev/null
+++ b/services/bufferhub/tests/BufferHubIdGenerator_test.cpp
@@ -0,0 +1,45 @@
+#include <bufferhub/BufferHubIdGenerator.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+namespace {
+
+class BufferHubIdGeneratorTest : public testing::Test {
+protected:
+    BufferHubIdGenerator* mIdGenerator = &BufferHubIdGenerator::getInstance();
+};
+
+TEST_F(BufferHubIdGeneratorTest, TestGenerateAndFreeID) {
+    uint32_t id = mIdGenerator->getId();
+    EXPECT_NE(id, BufferHubIdGenerator::kInvalidId);
+
+    EXPECT_TRUE(mIdGenerator->freeId(id));
+    EXPECT_FALSE(mIdGenerator->freeId(id));
+}
+
+TEST_F(BufferHubIdGeneratorTest, TestGenerateUniqueIncrementalID) {
+    // 10 IDs should not overflow the UniqueIdGenerator to cause a roll back to start, so the
+    // resulting IDs should still keep incresing.
+    const size_t kTestSize = 10U;
+    uint32_t ids[kTestSize];
+    for (int i = 0; i < kTestSize; ++i) {
+        ids[i] = mIdGenerator->getId();
+        EXPECT_NE(ids[i], BufferHubIdGenerator::kInvalidId);
+        if (i >= 1) {
+            EXPECT_GT(ids[i], ids[i - 1]);
+        }
+    }
+}
+
+} // namespace
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
\ No newline at end of file
diff --git a/services/bufferhub/tests/UniqueIdGenerator_test.cpp b/services/bufferhub/tests/UniqueIdGenerator_test.cpp
deleted file mode 100644
index c4d83e0..0000000
--- a/services/bufferhub/tests/UniqueIdGenerator_test.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-#include <bufferhub/UniqueIdGenerator.h>
-#include <gtest/gtest.h>
-
-namespace android {
-namespace frameworks {
-namespace bufferhub {
-namespace V1_0 {
-namespace implementation {
-
-namespace {
-
-class UniqueIdGeneratorTest : public testing::Test {
-protected:
-    UniqueIdGenerator mIdGenerator;
-};
-
-TEST_F(UniqueIdGeneratorTest, TestGenerateAndFreeID) {
-    uint32_t id = mIdGenerator.getId();
-    EXPECT_NE(id, UniqueIdGenerator::kInvalidId);
-
-    EXPECT_TRUE(mIdGenerator.freeId(id));
-    EXPECT_FALSE(mIdGenerator.freeId(id));
-}
-
-TEST_F(UniqueIdGeneratorTest, TestGenerateUniqueIncrementalID) {
-    // 10 IDs should not overflow the UniqueIdGenerator to cause a roll back to start, so the
-    // resulting IDs should still keep incresing.
-    const size_t kTestSize = 10U;
-    uint32_t ids[kTestSize];
-    for (int i = 0; i < kTestSize; ++i) {
-        ids[i] = mIdGenerator.getId();
-        EXPECT_NE(ids[i], UniqueIdGenerator::kInvalidId);
-        if (i >= 1) {
-            EXPECT_GT(ids[i], ids[i - 1]);
-        }
-    }
-}
-
-} // namespace
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace bufferhub
-} // namespace frameworks
-} // namespace android
\ No newline at end of file
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 4a8b613..1fbc6bf 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -15,8 +15,6 @@
 cc_library_shared {
     name: "libinputflinger",
 
-    cpp_std: "c++17",
-
     srcs: [
         "InputDispatcher.cpp",
         "InputManager.cpp",
@@ -60,8 +58,6 @@
 cc_library_shared {
     name: "libinputreader",
 
-    cpp_std: "c++17",
-
     srcs: [
         "EventHub.cpp",
         "InputReader.cpp",
@@ -100,8 +96,6 @@
 cc_library_shared {
     name: "libinputflinger_base",
 
-    cpp_std: "c++17",
-
     srcs: [
         "InputListener.cpp",
         "InputReaderBase.cpp",
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 1dca1b6..885348e 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -3077,22 +3077,44 @@
             // Remove all handles on a display if there are no windows left.
             mWindowHandlesByDisplay.erase(displayId);
         } else {
-            size_t numWindows = inputWindowHandles.size();
+            // Since we compare the pointer of input window handles across window updates, we need
+            // to make sure the handle object for the same window stays unchanged across updates.
+            const Vector<sp<InputWindowHandle>>& oldHandles = mWindowHandlesByDisplay[displayId];
+            std::unordered_map<sp<IBinder>, sp<InputWindowHandle>, IBinderHash> oldHandlesByTokens;
+            for (size_t i = 0; i < oldHandles.size(); i++) {
+                const sp<InputWindowHandle>& handle = oldHandles.itemAt(i);
+                oldHandlesByTokens[handle->getToken()] = handle;
+            }
+
+            const size_t numWindows = inputWindowHandles.size();
+            Vector<sp<InputWindowHandle>> newHandles;
             for (size_t i = 0; i < numWindows; i++) {
-                const sp<InputWindowHandle>& windowHandle = inputWindowHandles.itemAt(i);
-                if (!windowHandle->updateInfo() || getInputChannelLocked(windowHandle->getToken()) == nullptr) {
+                const sp<InputWindowHandle>& handle = inputWindowHandles.itemAt(i);
+                if (!handle->updateInfo() || getInputChannelLocked(handle->getToken()) == nullptr) {
                     ALOGE("Window handle %s has no registered input channel",
-                            windowHandle->getName().c_str());
+                            handle->getName().c_str());
                     continue;
                 }
 
-                if (windowHandle->getInfo()->displayId != displayId) {
+                if (handle->getInfo()->displayId != displayId) {
                     ALOGE("Window %s updated by wrong display %d, should belong to display %d",
-                        windowHandle->getName().c_str(), displayId,
-                        windowHandle->getInfo()->displayId);
+                        handle->getName().c_str(), displayId,
+                        handle->getInfo()->displayId);
                     continue;
                 }
 
+                if (oldHandlesByTokens.find(handle->getToken()) != oldHandlesByTokens.end()) {
+                    const sp<InputWindowHandle> oldHandle =
+                            oldHandlesByTokens.at(handle->getToken());
+                    oldHandle->updateFrom(handle);
+                    newHandles.push_back(oldHandle);
+                } else {
+                    newHandles.push_back(handle);
+                }
+            }
+
+            for (size_t i = 0; i < newHandles.size(); i++) {
+                const sp<InputWindowHandle>& windowHandle = newHandles.itemAt(i);
                 if (windowHandle->getInfo()->hasFocus && windowHandle->getInfo()->visible) {
                     newFocusedWindowHandle = windowHandle;
                 }
@@ -3102,7 +3124,7 @@
             }
 
             // Insert or replace
-            mWindowHandlesByDisplay[displayId] = inputWindowHandles;
+            mWindowHandlesByDisplay[displayId] = newHandles;
         }
 
         if (!foundHoveredWindow) {
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 389a57c..5b275fb 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -2,7 +2,6 @@
 
 cc_test {
     name: "inputflinger_tests",
-    cpp_std: "c++17",
     srcs: [
         "InputReader_test.cpp",
         "InputDispatcher_test.cpp",
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 1f71a44..efc2c9f 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -97,10 +97,9 @@
     return stateUpdateAvailable;
 }
 
-Rect BufferStateLayer::getCrop(const Layer::State& s) const {
-    return (getEffectiveScalingMode() == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)
-            ? GLConsumer::scaleDownCrop(s.crop, s.active.w, s.active.h)
-            : s.crop;
+// Crop that applies to the window
+Rect BufferStateLayer::getCrop(const Layer::State& /*s*/) const {
+    return Rect::INVALID_RECT;
 }
 
 bool BufferStateLayer::setTransform(uint32_t transform) {
@@ -130,6 +129,30 @@
     return true;
 }
 
+bool BufferStateLayer::setFrame(const Rect& frame) {
+    int x = frame.left;
+    int y = frame.top;
+    int w = frame.getWidth();
+    int h = frame.getHeight();
+
+    if (mCurrentState.active.transform.tx() == x && mCurrentState.active.transform.ty() == y &&
+        mCurrentState.active.w == w && mCurrentState.active.h == h) {
+        return false;
+    }
+
+    if (!frame.isValid()) {
+        x = y = w = h = 0;
+    }
+    mCurrentState.active.transform.set(x, y);
+    mCurrentState.active.w = w;
+    mCurrentState.active.h = h;
+
+    mCurrentState.sequence++;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
 bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer) {
     if (mCurrentState.buffer) {
         mReleasePreviousBuffer = true;
@@ -239,27 +262,6 @@
     return willPresent;
 }
 
-bool BufferStateLayer::setSize(uint32_t w, uint32_t h) {
-    if (mCurrentState.active.w == w && mCurrentState.active.h == h) return false;
-    mCurrentState.active.w = w;
-    mCurrentState.active.h = h;
-    mCurrentState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
-bool BufferStateLayer::setPosition(float x, float y, bool /*immediate*/) {
-    if (mCurrentState.active.transform.tx() == x && mCurrentState.active.transform.ty() == y)
-        return false;
-
-    mCurrentState.active.transform.set(x, y);
-
-    mCurrentState.sequence++;
-    mCurrentState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
 bool BufferStateLayer::setTransparentRegionHint(const Region& transparent) {
     mCurrentState.transparentRegionHint = transparent;
     mCurrentState.modified = true;
@@ -267,21 +269,26 @@
     return true;
 }
 
-bool BufferStateLayer::setMatrix(const layer_state_t::matrix22_t& matrix,
-                                 bool allowNonRectPreservingTransforms) {
-    ui::Transform t;
-    t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
-
-    if (!allowNonRectPreservingTransforms && !t.preserveRects()) {
-        ALOGW("Attempt to set rotation matrix without permission ACCESS_SURFACE_FLINGER ignored");
-        return false;
+Rect BufferStateLayer::getBufferSize(const State& s) const {
+    // for buffer state layers we use the display frame size as the buffer size.
+    if (getActiveWidth(s) < UINT32_MAX && getActiveHeight(s) < UINT32_MAX) {
+        return Rect(getActiveWidth(s), getActiveHeight(s));
     }
 
-    mCurrentState.sequence++;
-    mCurrentState.active.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
-    mCurrentState.modified = true;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
+    // if the display frame is not defined, use the parent bounds as the buffer size.
+    const auto& p = mDrawingParent.promote();
+    if (p != nullptr) {
+        Rect parentBounds = Rect(p->computeBounds(Region()));
+        if (!parentBounds.isEmpty()) {
+            return parentBounds;
+        }
+    }
+
+    // if there is no parent layer, use the buffer's bounds as the buffer size
+    if (s.buffer) {
+        return s.buffer->getBounds();
+    }
+    return Rect::INVALID_RECT;
 }
 // -----------------------------------------------------------------------
 
@@ -317,8 +324,14 @@
     return getDrawingState().dataspace;
 }
 
+// Crop that applies to the buffer
 Rect BufferStateLayer::getDrawingCrop() const {
-    return Rect::INVALID_RECT;
+    const State& s(getDrawingState());
+
+    if (s.crop.isEmpty() && s.buffer) {
+        return s.buffer->getBounds();
+    }
+    return s.crop;
 }
 
 uint32_t BufferStateLayer::getDrawingScalingMode() const {
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 315d5af..3f891d3 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -62,6 +62,7 @@
     bool setTransform(uint32_t transform) override;
     bool setTransformToDisplayInverse(bool transformToDisplayInverse) override;
     bool setCrop(const Rect& crop) override;
+    bool setFrame(const Rect& frame) override;
     bool setBuffer(const sp<GraphicBuffer>& buffer) override;
     bool setAcquireFence(const sp<Fence>& fence) override;
     bool setDataspace(ui::Dataspace dataspace) override;
@@ -71,18 +72,22 @@
     bool setSidebandStream(const sp<NativeHandle>& sidebandStream) override;
     bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) override;
 
-    bool setSize(uint32_t w, uint32_t h) override;
-    bool setPosition(float x, float y, bool immediate) override;
-    bool setTransparentRegionHint(const Region& transparent) override;
-    bool setMatrix(const layer_state_t::matrix22_t& matrix,
-                   bool allowNonRectPreservingTransforms) override;
-
     // Override to ignore legacy layer state properties that are not used by BufferStateLayer
-    bool setCrop_legacy(const Rect& /*crop*/, bool /*immediate*/) override { return false; };
+    bool setSize(uint32_t /*w*/, uint32_t /*h*/) override { return false; }
+    bool setPosition(float /*x*/, float /*y*/, bool /*immediate*/) override { return false; }
+    bool setTransparentRegionHint(const Region& transparent) override;
+    bool setMatrix(const layer_state_t::matrix22_t& /*matrix*/,
+                   bool /*allowNonRectPreservingTransforms*/) override {
+        return false;
+    }
+    bool setCrop_legacy(const Rect& /*crop*/, bool /*immediate*/) override { return false; }
+    bool setOverrideScalingMode(int32_t /*overrideScalingMode*/) override { return false; }
     void deferTransactionUntil_legacy(const sp<IBinder>& /*barrierHandle*/,
                                       uint64_t /*frameNumber*/) override {}
     void deferTransactionUntil_legacy(const sp<Layer>& /*barrierLayer*/,
                                       uint64_t /*frameNumber*/) override {}
+
+    Rect getBufferSize(const State& s) const override;
     // -----------------------------------------------------------------------
 
     // -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/Colorizer.h b/services/surfaceflinger/Colorizer.h
index d56b1c8..b7d61ce 100644
--- a/services/surfaceflinger/Colorizer.h
+++ b/services/surfaceflinger/Colorizer.h
@@ -17,7 +17,7 @@
 #ifndef ANDROID_SURFACE_FLINGER_COLORIZER_H
 #define ANDROID_SURFACE_FLINGER_COLORIZER_H
 
-#include <utils/String8.h>
+#include <android-base/stringprintf.h>
 
 namespace android {
 
@@ -40,19 +40,19 @@
         : mEnabled(enabled) {
     }
 
-    void colorize(String8& out, color c) {
+    void colorize(std::string& out, color c) {
         if (mEnabled) {
-            out.appendFormat("\e[%dm", c);
+            base::StringAppendF(&out, "\e[%dm", c);
         }
     }
 
-    void bold(String8& out) {
+    void bold(std::string& out) {
         if (mEnabled) {
             out.append("\e[1m");
         }
     }
 
-    void reset(String8& out) {
+    void reset(std::string& out) {
         if (mEnabled) {
             out.append("\e[0m");
         }
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 1215bd9..48fd47f 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -54,6 +54,7 @@
 // retrieve triple buffer setting from configstore
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
+using android::base::StringAppendF;
 using android::ui::ColorMode;
 using android::ui::Dataspace;
 using android::ui::Hdr;
@@ -412,10 +413,9 @@
         if (mGraphicBuffer == nullptr) {
             ALOGE("No buffer is ready for display [%s]", mDisplayName.c_str());
         } else {
-            int fd = mBufferReady.release();
-
             status_t res = mNativeWindow->queueBuffer(mNativeWindow.get(),
-                                                      mGraphicBuffer->getNativeBuffer(), fd);
+                                                      mGraphicBuffer->getNativeBuffer(),
+                                                      dup(mBufferReady));
             if (res != NO_ERROR) {
                 ALOGE("Error when queueing buffer for display [%s]: %d", mDisplayName.c_str(), res);
                 // We risk blocking on dequeueBuffer if the primary display failed
@@ -424,9 +424,12 @@
                     LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", res);
                 } else {
                     mNativeWindow->cancelBuffer(mNativeWindow.get(),
-                                                mGraphicBuffer->getNativeBuffer(), fd);
+                                                mGraphicBuffer->getNativeBuffer(),
+                                                dup(mBufferReady));
                 }
             }
+
+            mBufferReady.reset();
             mGraphicBuffer = nullptr;
         }
     }
@@ -715,33 +718,33 @@
                               mDisplayName.c_str());
 }
 
-void DisplayDevice::dump(String8& result) const {
+void DisplayDevice::dump(std::string& result) const {
     const ui::Transform& tr(mGlobalTransform);
     ANativeWindow* const window = mNativeWindow.get();
-    result.appendFormat("+ %s\n", getDebugName().c_str());
-    result.appendFormat("  layerStack=%u, (%4dx%4d), ANativeWindow=%p "
-                        "format=%d, orient=%2d (type=%08x), flips=%u, isSecure=%d, "
-                        "powerMode=%d, activeConfig=%d, numLayers=%zu\n",
-                        mLayerStack, mDisplayWidth, mDisplayHeight, window,
-                        ANativeWindow_getFormat(window), mOrientation, tr.getType(),
-                        getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig,
-                        mVisibleLayersSortedByZ.size());
-    result.appendFormat("   v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d],"
-                        "transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n",
-                        mViewport.left, mViewport.top, mViewport.right, mViewport.bottom,
-                        mFrame.left, mFrame.top, mFrame.right, mFrame.bottom, mScissor.left,
-                        mScissor.top, mScissor.right, mScissor.bottom, tr[0][0], tr[1][0], tr[2][0],
-                        tr[0][1], tr[1][1], tr[2][1], tr[0][2], tr[1][2], tr[2][2]);
+    StringAppendF(&result, "+ %s\n", getDebugName().c_str());
+    StringAppendF(&result,
+                  "  layerStack=%u, (%4dx%4d), ANativeWindow=%p "
+                  "format=%d, orient=%2d (type=%08x), flips=%u, isSecure=%d, "
+                  "powerMode=%d, activeConfig=%d, numLayers=%zu\n",
+                  mLayerStack, mDisplayWidth, mDisplayHeight, window,
+                  ANativeWindow_getFormat(window), mOrientation, tr.getType(), getPageFlipCount(),
+                  mIsSecure, mPowerMode, mActiveConfig, mVisibleLayersSortedByZ.size());
+    StringAppendF(&result,
+                  "   v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d],"
+                  "transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n",
+                  mViewport.left, mViewport.top, mViewport.right, mViewport.bottom, mFrame.left,
+                  mFrame.top, mFrame.right, mFrame.bottom, mScissor.left, mScissor.top,
+                  mScissor.right, mScissor.bottom, tr[0][0], tr[1][0], tr[2][0], tr[0][1], tr[1][1],
+                  tr[2][1], tr[0][2], tr[1][2], tr[2][2]);
     auto const surface = static_cast<Surface*>(window);
     ui::Dataspace dataspace = surface->getBuffersDataSpace();
-    result.appendFormat("   wideColorGamut=%d, hdr10=%d, colorMode=%s, dataspace: %s (%d)\n",
-                        mHasWideColorGamut, mHasHdr10, decodeColorMode(mActiveColorMode).c_str(),
-                        dataspaceDetails(static_cast<android_dataspace>(dataspace)).c_str(),
-                        dataspace);
+    StringAppendF(&result, "   wideColorGamut=%d, hdr10=%d, colorMode=%s, dataspace: %s (%d)\n",
+                  mHasWideColorGamut, mHasHdr10, decodeColorMode(mActiveColorMode).c_str(),
+                  dataspaceDetails(static_cast<android_dataspace>(dataspace)).c_str(), dataspace);
 
     String8 surfaceDump;
     mDisplaySurface->dumpAsString(surfaceDump);
-    result.append(surfaceDump);
+    result.append(surfaceDump.string(), surfaceDump.size());
 }
 
 // Map dataspace/intent to the best matched dataspace/colorMode/renderIntent
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index eb2c5c3..8357228 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -37,7 +37,6 @@
 #include <ui/Transform.h>
 #include <utils/Mutex.h>
 #include <utils/RefBase.h>
-#include <utils/String8.h>
 #include <utils/Timers.h>
 
 #include "DisplayHardware/DisplayIdentification.h"
@@ -201,7 +200,7 @@
      */
     uint32_t getPageFlipCount() const;
     std::string getDebugName() const;
-    void dump(String8& result) const;
+    void dump(std::string& result) const;
 
 private:
     const sp<SurfaceFlinger> mFlinger;
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index 5b641a2..d6237cb 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -1067,6 +1067,43 @@
     return error;
 }
 
+Error Composer::setDisplayContentSamplingEnabled(Display display, bool enabled,
+                                                 uint8_t componentMask, uint64_t maxFrames) {
+    if (!mClient_2_3) {
+        return Error::UNSUPPORTED;
+    }
+
+    auto enable = enabled ? V2_3::IComposerClient::DisplayedContentSampling::ENABLE
+                          : V2_3::IComposerClient::DisplayedContentSampling::DISABLE;
+    return mClient_2_3->setDisplayedContentSamplingEnabled(display, enable, componentMask,
+                                                           maxFrames);
+}
+
+Error Composer::getDisplayedContentSample(Display display, uint64_t maxFrames, uint64_t timestamp,
+                                          DisplayedFrameStats* outStats) {
+    if (!outStats) {
+        return Error::BAD_PARAMETER;
+    }
+    if (!mClient_2_3) {
+        return Error::UNSUPPORTED;
+    }
+    Error error = kDefaultError;
+    mClient_2_3->getDisplayedContentSample(display, maxFrames, timestamp,
+                                           [&](const auto tmpError, auto tmpNumFrames,
+                                               const auto& tmpSamples0, const auto& tmpSamples1,
+                                               const auto& tmpSamples2, const auto& tmpSamples3) {
+                                               error = tmpError;
+                                               if (error == Error::NONE) {
+                                                   outStats->numFrames = tmpNumFrames;
+                                                   outStats->component_0_sample = tmpSamples0;
+                                                   outStats->component_1_sample = tmpSamples1;
+                                                   outStats->component_2_sample = tmpSamples2;
+                                                   outStats->component_3_sample = tmpSamples3;
+                                               }
+                                           });
+    return error;
+}
+
 CommandReader::~CommandReader()
 {
     resetData();
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 61af348..38ee7ad 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -30,6 +30,7 @@
 #include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
 #include <gui/HdrMetadata.h>
 #include <math/mat4.h>
+#include <ui/DisplayedFrameStats.h>
 #include <ui/GraphicBuffer.h>
 #include <utils/StrongPointer.h>
 
@@ -192,6 +193,10 @@
     virtual Error getDisplayedContentSamplingAttributes(Display display, PixelFormat* outFormat,
                                                         Dataspace* outDataspace,
                                                         uint8_t* outComponentMask) = 0;
+    virtual Error setDisplayContentSamplingEnabled(Display display, bool enabled,
+                                                   uint8_t componentMask, uint64_t maxFrames) = 0;
+    virtual Error getDisplayedContentSample(Display display, uint64_t maxFrames, uint64_t timestamp,
+                                            DisplayedFrameStats* outStats) = 0;
     virtual Error getDisplayCapabilities(Display display,
                                          std::vector<DisplayCapability>* outCapabilities) = 0;
 };
@@ -396,6 +401,10 @@
     Error getDisplayedContentSamplingAttributes(Display display, PixelFormat* outFormat,
                                                 Dataspace* outDataspace,
                                                 uint8_t* outComponentMask) override;
+    Error setDisplayContentSamplingEnabled(Display display, bool enabled, uint8_t componentMask,
+                                           uint64_t maxFrames) override;
+    Error getDisplayedContentSample(Display display, uint64_t maxFrames, uint64_t timestamp,
+                                    DisplayedFrameStats* outStats) override;
     Error getDisplayCapabilities(Display display,
                                  std::vector<DisplayCapability>* outCapabilities) override;
 
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 2df2d3b..d2aa4ad 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -555,6 +555,19 @@
     return static_cast<Error>(intError);
 }
 
+Error Display::setDisplayContentSamplingEnabled(bool enabled, uint8_t componentMask,
+                                                uint64_t maxFrames) const {
+    auto intError =
+            mComposer.setDisplayContentSamplingEnabled(mId, enabled, componentMask, maxFrames);
+    return static_cast<Error>(intError);
+}
+
+Error Display::getDisplayedContentSample(uint64_t maxFrames, uint64_t timestamp,
+                                         android::DisplayedFrameStats* outStats) const {
+    auto intError = mComposer.getDisplayedContentSample(mId, maxFrames, timestamp, outStats);
+    return static_cast<Error>(intError);
+}
+
 Error Display::getReleaseFences(
         std::unordered_map<Layer*, sp<Fence>>* outFences) const
 {
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 8c0f50c..f5cb97e 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -40,6 +40,7 @@
 #include "PowerAdvisor.h"
 
 namespace android {
+    struct DisplayedFrameStats;
     class Fence;
     class FloatRect;
     class GraphicBuffer;
@@ -240,6 +241,11 @@
     [[clang::warn_unused_result]] Error getDisplayedContentSamplingAttributes(
             android::ui::PixelFormat* outFormat, android::ui::Dataspace* outDataspace,
             uint8_t* outComponentMask) const;
+    [[clang::warn_unused_result]] Error setDisplayContentSamplingEnabled(bool enabled,
+                                                                         uint8_t componentMask,
+                                                                         uint64_t maxFrames) const;
+    [[clang::warn_unused_result]] Error getDisplayedContentSample(
+            uint64_t maxFrames, uint64_t timestamp, android::DisplayedFrameStats* outStats) const;
     [[clang::warn_unused_result]] Error getReleaseFences(
             std::unordered_map<Layer*,
                     android::sp<android::Fence>>* outFences) const;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index a752a7d..0497571 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -756,15 +756,39 @@
     return NO_ERROR;
 }
 
+status_t HWComposer::setDisplayContentSamplingEnabled(DisplayId displayId, bool enabled,
+                                                      uint8_t componentMask, uint64_t maxFrames) {
+    RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
+    const auto error =
+            mDisplayData[displayId].hwcDisplay->setDisplayContentSamplingEnabled(enabled,
+                                                                                 componentMask,
+                                                                                 maxFrames);
+
+    if (error == HWC2::Error::Unsupported) RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION);
+    if (error == HWC2::Error::BadParameter) RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE);
+    RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
+    return NO_ERROR;
+}
+
+status_t HWComposer::getDisplayedContentSample(DisplayId displayId, uint64_t maxFrames,
+                                               uint64_t timestamp, DisplayedFrameStats* outStats) {
+    RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
+    const auto error =
+            mDisplayData[displayId].hwcDisplay->getDisplayedContentSample(maxFrames, timestamp,
+                                                                          outStats);
+    RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
+    return NO_ERROR;
+}
+
 bool HWComposer::isUsingVrComposer() const {
     return getComposer()->isUsingVrComposer();
 }
 
-void HWComposer::dump(String8& result) const {
+void HWComposer::dump(std::string& result) const {
     // TODO: In order to provide a dump equivalent to HWC1, we need to shadow
     // all the state going into the layers. This is probably better done in
     // Layer itself, but it's going to take a bit of work to get there.
-    result.append(mHwcDevice->dump().c_str());
+    result.append(mHwcDevice->dump());
 }
 
 std::optional<DisplayId> HWComposer::toPhysicalDisplayId(hwc2_display_t hwcDisplayId) const {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 0375f74..d9a0916 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -36,8 +36,8 @@
 
 namespace android {
 
+struct DisplayedFrameStats;
 class GraphicBuffer;
-class String8;
 class TestableSurfaceFlinger;
 struct CompositionInfo;
 
@@ -131,6 +131,10 @@
     status_t getDisplayedContentSamplingAttributes(DisplayId displayId, ui::PixelFormat* outFormat,
                                                    ui::Dataspace* outDataspace,
                                                    uint8_t* outComponentMask);
+    status_t setDisplayContentSamplingEnabled(DisplayId displayId, bool enabled,
+                                              uint8_t componentMask, uint64_t maxFrames);
+    status_t getDisplayedContentSample(DisplayId displayId, uint64_t maxFrames, uint64_t timestamp,
+                                       DisplayedFrameStats* outStats);
 
     // Events handling ---------------------------------------------------------
 
@@ -159,7 +163,7 @@
     bool isUsingVrComposer() const;
 
     // for debugging ----------------------------------------------------------
-    void dump(String8& out) const;
+    void dump(std::string& out) const;
 
     Hwc2::Composer* getComposer() const { return mHwcDevice->getComposer(); }
 
diff --git a/services/surfaceflinger/FrameTracker.cpp b/services/surfaceflinger/FrameTracker.cpp
index 1539873..f4cc49b 100644
--- a/services/surfaceflinger/FrameTracker.cpp
+++ b/services/surfaceflinger/FrameTracker.cpp
@@ -19,6 +19,7 @@
 
 #include <inttypes.h>
 
+#include <android-base/stringprintf.h>
 #include <android/log.h>
 #include <utils/String8.h>
 
@@ -230,17 +231,17 @@
             mFrameRecords[idx].actualPresentTime < INT64_MAX;
 }
 
-void FrameTracker::dumpStats(String8& result) const {
+void FrameTracker::dumpStats(std::string& result) const {
     Mutex::Autolock lock(mMutex);
     processFencesLocked();
 
     const size_t o = mOffset;
     for (size_t i = 1; i < NUM_FRAME_RECORDS; i++) {
         const size_t index = (o+i) % NUM_FRAME_RECORDS;
-        result.appendFormat("%" PRId64 "\t%" PRId64 "\t%" PRId64 "\n",
-            mFrameRecords[index].desiredPresentTime,
-            mFrameRecords[index].actualPresentTime,
-            mFrameRecords[index].frameReadyTime);
+        base::StringAppendF(&result, "%" PRId64 "\t%" PRId64 "\t%" PRId64 "\n",
+                            mFrameRecords[index].desiredPresentTime,
+                            mFrameRecords[index].actualPresentTime,
+                            mFrameRecords[index].frameReadyTime);
     }
     result.append("\n");
 }
diff --git a/services/surfaceflinger/FrameTracker.h b/services/surfaceflinger/FrameTracker.h
index b4a9fd6..555dcc1 100644
--- a/services/surfaceflinger/FrameTracker.h
+++ b/services/surfaceflinger/FrameTracker.h
@@ -90,7 +90,7 @@
     void logAndResetStats(const String8& name);
 
     // dumpStats dump appends the current frame display time history to the result string.
-    void dumpStats(String8& result) const;
+    void dumpStats(std::string& result) const;
 
 private:
     struct FrameRecord {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 15e416a..d628995 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -25,6 +25,8 @@
 #include <sys/types.h>
 #include <algorithm>
 
+#include <android-base/stringprintf.h>
+
 #include <cutils/compiler.h>
 #include <cutils/native_handle.h>
 #include <cutils/properties.h>
@@ -63,6 +65,8 @@
 
 namespace android {
 
+using base::StringAppendF;
+
 std::atomic<int32_t> Layer::sSequence{1};
 
 Layer::Layer(const LayerCreationArgs& args)
@@ -92,8 +96,8 @@
     mCurrentState.requested_legacy = mCurrentState.active_legacy;
     mCurrentState.appId = 0;
     mCurrentState.type = 0;
-    mCurrentState.active.w = 0;
-    mCurrentState.active.h = 0;
+    mCurrentState.active.w = UINT32_MAX;
+    mCurrentState.active.h = UINT32_MAX;
     mCurrentState.active.transform.set(0, 0);
     mCurrentState.transform = 0;
     mCurrentState.transformToDisplayInverse = false;
@@ -1399,7 +1403,7 @@
     info.mName = getName();
     sp<Layer> parent = getParent();
     info.mParentName = (parent == nullptr ? std::string("none") : parent->getName().string());
-    info.mType = String8(getTypeId());
+    info.mType = std::string(getTypeId());
     info.mTransparentRegion = ds.activeTransparentRegion_legacy;
     info.mVisibleRegion = visibleRegion;
     info.mSurfaceDamageRegion = surfaceDamageRegion;
@@ -1439,7 +1443,7 @@
     return info;
 }
 
-void Layer::miniDumpHeader(String8& result) {
+void Layer::miniDumpHeader(std::string& result) {
     result.append("-------------------------------");
     result.append("-------------------------------");
     result.append("-----------------------------\n");
@@ -1454,50 +1458,51 @@
     result.append("-----------------------------\n");
 }
 
-void Layer::miniDump(String8& result, DisplayId displayId) const {
+void Layer::miniDump(std::string& result, DisplayId displayId) const {
     if (!hasHwcLayer(displayId)) {
         return;
     }
 
-    String8 name;
+    std::string name;
     if (mName.length() > 77) {
         std::string shortened;
         shortened.append(mName.string(), 36);
         shortened.append("[...]");
         shortened.append(mName.string() + (mName.length() - 36), 36);
-        name = shortened.c_str();
+        name = shortened;
     } else {
-        name = mName;
+        name = std::string(mName.string(), mName.size());
     }
 
-    result.appendFormat(" %s\n", name.string());
+    StringAppendF(&result, " %s\n", name.c_str());
 
     const State& layerState(getDrawingState());
     const LayerBE::HWCInfo& hwcInfo = getBE().mHwcLayers.at(displayId);
     if (layerState.zOrderRelativeOf != nullptr || mDrawingParent != nullptr) {
-        result.appendFormat("  rel %6d | ", layerState.z);
+        StringAppendF(&result, "  rel %6d | ", layerState.z);
     } else {
-        result.appendFormat("  %10d | ", layerState.z);
+        StringAppendF(&result, "  %10d | ", layerState.z);
     }
-    result.appendFormat("%10s | ", to_string(getCompositionType(displayId)).c_str());
-    result.appendFormat("%10s | ", to_string(hwcInfo.transform).c_str());
+    StringAppendF(&result, "%10s | ", to_string(getCompositionType(displayId)).c_str());
+    StringAppendF(&result, "%10s | ", to_string(hwcInfo.transform).c_str());
     const Rect& frame = hwcInfo.displayFrame;
-    result.appendFormat("%4d %4d %4d %4d | ", frame.left, frame.top, frame.right, frame.bottom);
+    StringAppendF(&result, "%4d %4d %4d %4d | ", frame.left, frame.top, frame.right, frame.bottom);
     const FloatRect& crop = hwcInfo.sourceCrop;
-    result.appendFormat("%6.1f %6.1f %6.1f %6.1f\n", crop.left, crop.top, crop.right, crop.bottom);
+    StringAppendF(&result, "%6.1f %6.1f %6.1f %6.1f\n", crop.left, crop.top, crop.right,
+                  crop.bottom);
 
     result.append("- - - - - - - - - - - - - - - -\n");
 
     std::string compositionInfoStr;
     getBE().compositionInfo.dump(compositionInfoStr, "compositionInfo");
-    result.append(compositionInfoStr.c_str());
+    result.append(compositionInfoStr);
 
     result.append("- - - - - - - - - - - - - - - -");
     result.append("- - - - - - - - - - - - - - - -");
     result.append("- - - - - - - - - - - - - - -\n");
 }
 
-void Layer::dumpFrameStats(String8& result) const {
+void Layer::dumpFrameStats(std::string& result) const {
     mFrameTracker.dumpStats(result);
 }
 
@@ -1513,8 +1518,8 @@
     mFrameTracker.getStats(outStats);
 }
 
-void Layer::dumpFrameEvents(String8& result) {
-    result.appendFormat("- Layer %s (%s, %p)\n", getName().string(), getTypeId(), this);
+void Layer::dumpFrameEvents(std::string& result) {
+    StringAppendF(&result, "- Layer %s (%s, %p)\n", getName().string(), getTypeId(), this);
     Mutex::Autolock lock(mFrameEventHistoryMutex);
     mFrameEventHistory.checkFencesForCompletion();
     mFrameEventHistory.dump(result);
@@ -2121,10 +2126,6 @@
 
 InputWindowInfo Layer::fillInputInfo(const Rect& screenBounds) {
     InputWindowInfo info = mDrawingState.inputInfo;
-    info.frameLeft = screenBounds.left + info.surfaceInset;
-    info.frameTop = screenBounds.top + info.surfaceInset;
-    info.frameRight = screenBounds.right - info.surfaceInset;
-    info.frameBottom = screenBounds.bottom - info.surfaceInset;
 
     ui::Transform t = getTransform();
     const float xScale = t.sx();
@@ -2135,9 +2136,26 @@
         info.touchableRegion.scaleSelf(xScale, yScale);
     }
 
-    info.touchableRegion = info.touchableRegion.translate(
-            screenBounds.left,
-            screenBounds.top);
+    // Transform layer size to screen space and inset it by surface insets.
+    Rect layerBounds = getCroppedBufferSize(getDrawingState());
+    layerBounds = t.transform(layerBounds);
+    layerBounds.inset(info.surfaceInset, info.surfaceInset, info.surfaceInset, info.surfaceInset);
+
+    // Intersect with screen bounds to shrink the frame by the surface insets. The surface insets
+    // are not set on the screen bounds directly since the surface inset region may already be
+    // cropped by a parent layer.
+    Rect frame;
+    screenBounds.intersect(layerBounds, &frame);
+
+    info.frameLeft = frame.left;
+    info.frameTop = frame.top;
+    info.frameRight = frame.right;
+    info.frameBottom = frame.bottom;
+
+    // Position the touchable region relative to frame screen location and restrict it to frame
+    // bounds.
+    info.touchableRegion = info.touchableRegion.translate(info.frameLeft, info.frameTop);
+    info.touchableRegion = info.touchableRegion.intersect(frame);
     info.visible = isVisible();
     return info;
 }
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 6ea80c7..9e910a8 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -296,6 +296,7 @@
     virtual bool setTransform(uint32_t /*transform*/) { return false; };
     virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; };
     virtual bool setCrop(const Rect& /*crop*/) { return false; };
+    virtual bool setFrame(const Rect& /*frame*/) { return false; };
     virtual bool setBuffer(const sp<GraphicBuffer>& /*buffer*/) { return false; };
     virtual bool setAcquireFence(const sp<Fence>& /*fence*/) { return false; };
     virtual bool setDataspace(ui::Dataspace /*dataspace*/) { return false; };
@@ -565,10 +566,10 @@
     LayerDebugInfo getLayerDebugInfo() const;
 
     /* always call base class first */
-    static void miniDumpHeader(String8& result);
-    void miniDump(String8& result, DisplayId displayId) const;
-    void dumpFrameStats(String8& result) const;
-    void dumpFrameEvents(String8& result);
+    static void miniDumpHeader(std::string& result);
+    void miniDump(std::string& result, DisplayId displayId) const;
+    void dumpFrameStats(std::string& result) const;
+    void dumpFrameEvents(std::string& result);
     void clearFrameStats();
     void logFrameStats();
     void getFrameStats(FrameStats* outStats) const;
diff --git a/services/surfaceflinger/LayerBE.cpp b/services/surfaceflinger/LayerBE.cpp
index 70b00dd..e39babe 100644
--- a/services/surfaceflinger/LayerBE.cpp
+++ b/services/surfaceflinger/LayerBE.cpp
@@ -101,15 +101,8 @@
     result += base::StringPrintf("\tsourceCrop=%6.1f %6.1f %6.1f %6.1f\n", hwc.sourceCrop.left,
                                  hwc.sourceCrop.top, hwc.sourceCrop.right, hwc.sourceCrop.bottom);
 
-    {
-        //
-        // Keep a conversion from std::string to String8 and back until Region can use std::string
-        //
-        String8 regionString;
-        hwc.visibleRegion.dump(regionString, "visibleRegion");
-        hwc.surfaceDamage.dump(regionString, "surfaceDamage");
-        result += regionString.string();
-    }
+    hwc.visibleRegion.dump(result, "visibleRegion");
+    hwc.surfaceDamage.dump(result, "surfaceDamage");
 
     result += base::StringPrintf("\tcolor transform matrix:\n"
                                  "\t\t[%f, %f, %f, %f,\n"
diff --git a/services/surfaceflinger/LayerStats.cpp b/services/surfaceflinger/LayerStats.cpp
index c0174ae..a2d1feb 100644
--- a/services/surfaceflinger/LayerStats.cpp
+++ b/services/surfaceflinger/LayerStats.cpp
@@ -23,11 +23,13 @@
 
 #include <android-base/stringprintf.h>
 #include <log/log.h>
-#include <utils/String8.h>
 #include <utils/Trace.h>
 
 namespace android {
 
+using base::StringAppendF;
+using base::StringPrintf;
+
 void LayerStats::enable() {
     ATRACE_CALL();
     std::lock_guard<std::mutex> lock(mMutex);
@@ -64,26 +66,24 @@
         if (!layer) continue;
         traverseLayerTreeStatsLocked(layer->children, layerGlobal, outLayerShapeVec);
         std::string key = "";
-        base::StringAppendF(&key, ",%s", layer->type.c_str());
-        base::StringAppendF(&key, ",%s", layerCompositionType(layer->hwcCompositionType));
-        base::StringAppendF(&key, ",%d", layer->isProtected);
-        base::StringAppendF(&key, ",%s", layerTransform(layer->hwcTransform));
-        base::StringAppendF(&key, ",%s", layerPixelFormat(layer->activeBuffer.format).c_str());
-        base::StringAppendF(&key, ",%s", layer->dataspace.c_str());
-        base::StringAppendF(&key, ",%s",
-                            destinationLocation(layer->hwcFrame.left, layerGlobal.resolution[0],
-                                                true));
-        base::StringAppendF(&key, ",%s",
-                            destinationLocation(layer->hwcFrame.top, layerGlobal.resolution[1],
-                                                false));
-        base::StringAppendF(&key, ",%s",
-                            destinationSize(layer->hwcFrame.right - layer->hwcFrame.left,
-                                            layerGlobal.resolution[0], true));
-        base::StringAppendF(&key, ",%s",
-                            destinationSize(layer->hwcFrame.bottom - layer->hwcFrame.top,
-                                            layerGlobal.resolution[1], false));
-        base::StringAppendF(&key, ",%s", scaleRatioWH(layer).c_str());
-        base::StringAppendF(&key, ",%s", alpha(static_cast<float>(layer->color.a)));
+        StringAppendF(&key, ",%s", layer->type.c_str());
+        StringAppendF(&key, ",%s", layerCompositionType(layer->hwcCompositionType));
+        StringAppendF(&key, ",%d", layer->isProtected);
+        StringAppendF(&key, ",%s", layerTransform(layer->hwcTransform));
+        StringAppendF(&key, ",%s", layerPixelFormat(layer->activeBuffer.format).c_str());
+        StringAppendF(&key, ",%s", layer->dataspace.c_str());
+        StringAppendF(&key, ",%s",
+                      destinationLocation(layer->hwcFrame.left, layerGlobal.resolution[0], true));
+        StringAppendF(&key, ",%s",
+                      destinationLocation(layer->hwcFrame.top, layerGlobal.resolution[1], false));
+        StringAppendF(&key, ",%s",
+                      destinationSize(layer->hwcFrame.right - layer->hwcFrame.left,
+                                      layerGlobal.resolution[0], true));
+        StringAppendF(&key, ",%s",
+                      destinationSize(layer->hwcFrame.bottom - layer->hwcFrame.top,
+                                      layerGlobal.resolution[1], false));
+        StringAppendF(&key, ",%s", scaleRatioWH(layer).c_str());
+        StringAppendF(&key, ",%s", alpha(static_cast<float>(layer->color.a)));
 
         outLayerShapeVec->push_back(key);
         ALOGV("%s", key.c_str());
@@ -101,9 +101,9 @@
     traverseLayerTreeStatsLocked(layerTree.topLevelLayers, layerGlobal, &layerShapeVec);
 
     std::string layerShapeKey =
-            base::StringPrintf("%d,%s,%s,%s", static_cast<int32_t>(layerShapeVec.size()),
-                               layerGlobal.colorMode.c_str(), layerGlobal.colorTransform.c_str(),
-                               layerTransform(layerGlobal.globalTransform));
+            StringPrintf("%d,%s,%s,%s", static_cast<int32_t>(layerShapeVec.size()),
+                         layerGlobal.colorMode.c_str(), layerGlobal.colorTransform.c_str(),
+                         layerTransform(layerGlobal.globalTransform));
     ALOGV("%s", layerShapeKey.c_str());
 
     std::sort(layerShapeVec.begin(), layerShapeVec.end(), std::greater<std::string>());
@@ -114,7 +114,7 @@
     mLayerShapeStatsMap[layerShapeKey]++;
 }
 
-void LayerStats::dump(String8& result) {
+void LayerStats::dump(std::string& result) {
     ATRACE_CALL();
     ALOGD("Dumping");
     std::lock_guard<std::mutex> lock(mMutex);
@@ -122,7 +122,7 @@
     result.append("LayerType,CompositionType,IsProtected,Transform,PixelFormat,Dataspace,");
     result.append("DstX,DstY,DstWidth,DstHeight,WScale,HScale,Alpha\n");
     for (auto& u : mLayerShapeStatsMap) {
-        result.appendFormat("%u,%s\n", u.second, u.first.c_str());
+        StringAppendF(&result, "%u,%s\n", u.second, u.first.c_str());
     }
 }
 
diff --git a/services/surfaceflinger/LayerStats.h b/services/surfaceflinger/LayerStats.h
index 9de9cce..62b2688 100644
--- a/services/surfaceflinger/LayerStats.h
+++ b/services/surfaceflinger/LayerStats.h
@@ -24,7 +24,6 @@
 using namespace android::surfaceflinger;
 
 namespace android {
-class String8;
 
 class LayerStats {
 public:
@@ -33,7 +32,7 @@
     void clear();
     bool isEnabled();
     void logLayerStats(const LayersProto& layersProto);
-    void dump(String8& result);
+    void dump(std::string& result);
 
 private:
     // Traverse layer tree to get all visible layers' stats
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 172c418..b74b901 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -24,9 +24,9 @@
 
 #include <algorithm>
 
-#include <log/log.h>
+#include <android-base/stringprintf.h>
 #include <cutils/properties.h>
-#include <utils/String8.h>
+#include <log/log.h>
 #include <utils/Thread.h>
 #include <utils/Trace.h>
 
@@ -36,6 +36,7 @@
 #include "EventLog/EventLog.h"
 #include "SurfaceFlinger.h"
 
+using android::base::StringAppendF;
 using std::max;
 using std::min;
 
@@ -667,54 +668,56 @@
     }
 }
 
-void DispSync::dump(String8& result) const {
+void DispSync::dump(std::string& result) const {
     Mutex::Autolock lock(mMutex);
-    result.appendFormat("present fences are %s\n", mIgnorePresentFences ? "ignored" : "used");
-    result.appendFormat("mPeriod: %" PRId64 " ns (%.3f fps; skipCount=%d)\n", mPeriod,
-                        1000000000.0 / mPeriod, mRefreshSkipCount);
-    result.appendFormat("mPhase: %" PRId64 " ns\n", mPhase);
-    result.appendFormat("mError: %" PRId64 " ns (sqrt=%.1f)\n", mError, sqrt(mError));
-    result.appendFormat("mNumResyncSamplesSincePresent: %d (limit %d)\n",
-                        mNumResyncSamplesSincePresent, MAX_RESYNC_SAMPLES_WITHOUT_PRESENT);
-    result.appendFormat("mNumResyncSamples: %zd (max %d)\n", mNumResyncSamples, MAX_RESYNC_SAMPLES);
+    StringAppendF(&result, "present fences are %s\n", mIgnorePresentFences ? "ignored" : "used");
+    StringAppendF(&result, "mPeriod: %" PRId64 " ns (%.3f fps; skipCount=%d)\n", mPeriod,
+                  1000000000.0 / mPeriod, mRefreshSkipCount);
+    StringAppendF(&result, "mPhase: %" PRId64 " ns\n", mPhase);
+    StringAppendF(&result, "mError: %" PRId64 " ns (sqrt=%.1f)\n", mError, sqrt(mError));
+    StringAppendF(&result, "mNumResyncSamplesSincePresent: %d (limit %d)\n",
+                  mNumResyncSamplesSincePresent, MAX_RESYNC_SAMPLES_WITHOUT_PRESENT);
+    StringAppendF(&result, "mNumResyncSamples: %zd (max %d)\n", mNumResyncSamples,
+                  MAX_RESYNC_SAMPLES);
 
-    result.appendFormat("mResyncSamples:\n");
+    result.append("mResyncSamples:\n");
     nsecs_t previous = -1;
     for (size_t i = 0; i < mNumResyncSamples; i++) {
         size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
         nsecs_t sampleTime = mResyncSamples[idx];
         if (i == 0) {
-            result.appendFormat("  %" PRId64 "\n", sampleTime);
+            StringAppendF(&result, "  %" PRId64 "\n", sampleTime);
         } else {
-            result.appendFormat("  %" PRId64 " (+%" PRId64 ")\n", sampleTime,
-                                sampleTime - previous);
+            StringAppendF(&result, "  %" PRId64 " (+%" PRId64 ")\n", sampleTime,
+                          sampleTime - previous);
         }
         previous = sampleTime;
     }
 
-    result.appendFormat("mPresentFences [%d]:\n", NUM_PRESENT_SAMPLES);
+    StringAppendF(&result, "mPresentFences [%d]:\n", NUM_PRESENT_SAMPLES);
     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
     previous = Fence::SIGNAL_TIME_INVALID;
     for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
         size_t idx = (i + mPresentSampleOffset) % NUM_PRESENT_SAMPLES;
         nsecs_t presentTime = mPresentFences[idx]->getSignalTime();
         if (presentTime == Fence::SIGNAL_TIME_PENDING) {
-            result.appendFormat("  [unsignaled fence]\n");
+            StringAppendF(&result, "  [unsignaled fence]\n");
         } else if (presentTime == Fence::SIGNAL_TIME_INVALID) {
-            result.appendFormat("  [invalid fence]\n");
+            StringAppendF(&result, "  [invalid fence]\n");
         } else if (previous == Fence::SIGNAL_TIME_PENDING ||
                    previous == Fence::SIGNAL_TIME_INVALID) {
-            result.appendFormat("  %" PRId64 "  (%.3f ms ago)\n", presentTime,
-                                (now - presentTime) / 1000000.0);
+            StringAppendF(&result, "  %" PRId64 "  (%.3f ms ago)\n", presentTime,
+                          (now - presentTime) / 1000000.0);
         } else {
-            result.appendFormat("  %" PRId64 " (+%" PRId64 " / %.3f)  (%.3f ms ago)\n", presentTime,
-                                presentTime - previous, (presentTime - previous) / (double)mPeriod,
-                                (now - presentTime) / 1000000.0);
+            StringAppendF(&result, "  %" PRId64 " (+%" PRId64 " / %.3f)  (%.3f ms ago)\n",
+                          presentTime, presentTime - previous,
+                          (presentTime - previous) / (double)mPeriod,
+                          (now - presentTime) / 1000000.0);
         }
         previous = presentTime;
     }
 
-    result.appendFormat("current monotonic time: %" PRId64 "\n", now);
+    StringAppendF(&result, "current monotonic time: %" PRId64 "\n", now);
 }
 
 // TODO(b/113612090): Figure out how much of this is still relevant.
diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h
index 5d19093..4a90f10 100644
--- a/services/surfaceflinger/Scheduler/DispSync.h
+++ b/services/surfaceflinger/Scheduler/DispSync.h
@@ -29,7 +29,6 @@
 
 namespace android {
 
-class String8;
 class FenceTime;
 
 class DispSync {
@@ -57,7 +56,7 @@
     virtual void setIgnorePresentFences(bool ignore) = 0;
     virtual nsecs_t expectedPresentTime() = 0;
 
-    virtual void dump(String8& result) const = 0;
+    virtual void dump(std::string& result) const = 0;
 };
 
 namespace impl {
@@ -161,7 +160,7 @@
     nsecs_t expectedPresentTime();
 
     // dump appends human-readable debug info to the result string.
-    void dump(String8& result) const override;
+    void dump(std::string& result) const override;
 
 private:
     void updateModelLocked();
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 9bee9a3..49e7ef6 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -22,18 +22,20 @@
 #include <chrono>
 #include <cstdint>
 
+#include <android-base/stringprintf.h>
+
 #include <cutils/compiler.h>
 #include <cutils/sched_policy.h>
 
 #include <gui/DisplayEventReceiver.h>
 
 #include <utils/Errors.h>
-#include <utils/String8.h>
 #include <utils/Trace.h>
 
 #include "EventThread.h"
 
 using namespace std::chrono_literals;
+using android::base::StringAppendF;
 
 // ---------------------------------------------------------------------------
 
@@ -384,18 +386,18 @@
     }
 }
 
-void EventThread::dump(String8& result) const {
+void EventThread::dump(std::string& result) const {
     std::lock_guard<std::mutex> lock(mMutex);
-    result.appendFormat("VSYNC state: %s\n", mDebugVsyncEnabled ? "enabled" : "disabled");
-    result.appendFormat("  soft-vsync: %s\n", mUseSoftwareVSync ? "enabled" : "disabled");
-    result.appendFormat("  numListeners=%zu,\n  events-delivered: %u\n",
-                        mDisplayEventConnections.size(), mVSyncEvent[0].vsync.count);
+    StringAppendF(&result, "VSYNC state: %s\n", mDebugVsyncEnabled ? "enabled" : "disabled");
+    StringAppendF(&result, "  soft-vsync: %s\n", mUseSoftwareVSync ? "enabled" : "disabled");
+    StringAppendF(&result, "  numListeners=%zu,\n  events-delivered: %u\n",
+                  mDisplayEventConnections.size(), mVSyncEvent[0].vsync.count);
     for (const wp<Connection>& weak : mDisplayEventConnections) {
         sp<Connection> connection = weak.promote();
-        result.appendFormat("    %p: count=%d\n", connection.get(),
-                            connection != nullptr ? connection->count : 0);
+        StringAppendF(&result, "    %p: count=%d\n", connection.get(),
+                      connection != nullptr ? connection->count : 0);
     }
-    result.appendFormat("  other-events-pending: %zu\n", mPendingEvents.size());
+    StringAppendF(&result, "  other-events-pending: %zu\n", mPendingEvents.size());
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 5e7ed13..15b5bba 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -40,7 +40,6 @@
 
 class EventThreadTest;
 class SurfaceFlinger;
-class String8;
 
 // ---------------------------------------------------------------------------
 
@@ -76,7 +75,7 @@
     // called when receiving a hotplug event
     virtual void onHotplugReceived(DisplayType displayType, bool connected) = 0;
 
-    virtual void dump(String8& result) const = 0;
+    virtual void dump(std::string& result) const = 0;
 
     virtual void setPhaseOffset(nsecs_t phaseOffset) = 0;
 };
@@ -131,7 +130,7 @@
     // called when receiving a hotplug event
     void onHotplugReceived(DisplayType displayType, bool connected) override;
 
-    void dump(String8& result) const override;
+    void dump(std::string& result) const override;
 
     void setPhaseOffset(nsecs_t phaseOffset) override;
 
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 4457f72..5b8cc10 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -133,7 +133,7 @@
     mConnections[handle->id]->thread->onScreenReleased();
 }
 
-void Scheduler::dump(const sp<Scheduler::ConnectionHandle>& handle, String8& result) const {
+void Scheduler::dump(const sp<Scheduler::ConnectionHandle>& handle, std::string& result) const {
     RETURN_IF_INVALID();
     mConnections.at(handle->id)->thread->dump(result);
 }
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 764ad00..ea90824 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -91,7 +91,7 @@
     void onScreenReleased(const sp<ConnectionHandle>& handle);
 
     // Should be called when dumpsys command is received.
-    void dump(const sp<ConnectionHandle>& handle, String8& result) const;
+    void dump(const sp<ConnectionHandle>& handle, std::string& result) const;
 
     // Offers ability to modify phase offset in the event thread.
     void setPhaseOffset(const sp<ConnectionHandle>& handle, nsecs_t phaseOffset);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a8de576..a8442c5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -113,6 +113,7 @@
 
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
+using base::StringAppendF;
 using ui::ColorMode;
 using ui::Dataspace;
 using ui::Hdr;
@@ -1123,8 +1124,7 @@
     if (!outFormat || !outDataspace || !outComponentMask) {
         return BAD_VALUE;
     }
-    Mutex::Autolock _l(mStateLock);
-    const auto display = getDisplayDeviceLocked(displayToken);
+    const auto display = getDisplayDevice(displayToken);
     if (!display || !display->getId()) {
         ALOGE("getDisplayedContentSamplingAttributes: Bad display token: %p", display.get());
         return BAD_VALUE;
@@ -1133,6 +1133,32 @@
                                                                  outDataspace, outComponentMask);
 }
 
+status_t SurfaceFlinger::setDisplayContentSamplingEnabled(const sp<IBinder>& displayToken,
+                                                          bool enable, uint8_t componentMask,
+                                                          uint64_t maxFrames) const {
+    const auto display = getDisplayDevice(displayToken);
+    if (!display || !display->getId()) {
+        ALOGE("setDisplayContentSamplingEnabled: Bad display token: %p", display.get());
+        return BAD_VALUE;
+    }
+
+    return getHwComposer().setDisplayContentSamplingEnabled(*display->getId(), enable,
+                                                            componentMask, maxFrames);
+}
+
+status_t SurfaceFlinger::getDisplayedContentSample(const sp<IBinder>& displayToken,
+                                                   uint64_t maxFrames, uint64_t timestamp,
+                                                   DisplayedFrameStats* outStats) const {
+    const auto display = getDisplayDevice(displayToken);
+    if (!display || !display->getId()) {
+        ALOGE("getDisplayContentSample: Bad display token: %p", displayToken.get());
+        return BAD_VALUE;
+    }
+
+    return getHwComposer().getDisplayedContentSample(*display->getId(), maxFrames, timestamp,
+                                                     outStats);
+}
+
 status_t SurfaceFlinger::enableVSyncInjections(bool enable) {
     postMessageSync(new LambdaMessage([&] {
         Mutex::Autolock _l(mStateLock);
@@ -3493,7 +3519,7 @@
 
     uint32_t flags = 0;
 
-    const uint32_t what = s.what;
+    const uint64_t what = s.what;
     bool geometryAppliesWithResize =
             what & layer_state_t::eGeometryAppliesWithResize;
 
@@ -3665,6 +3691,9 @@
     if (what & layer_state_t::eCropChanged) {
         if (layer->setCrop(s.crop)) flags |= eTraversalNeeded;
     }
+    if (what & layer_state_t::eFrameChanged) {
+        if (layer->setFrame(s.frame)) flags |= eTraversalNeeded;
+    }
     if (what & layer_state_t::eBufferChanged) {
         if (layer->setBuffer(s.buffer)) flags |= eTraversalNeeded;
     }
@@ -4082,7 +4111,7 @@
 
 status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args, bool asProto)
         NO_THREAD_SAFETY_ANALYSIS {
-    String8 result;
+    std::string result;
 
     IPCThreadState* ipc = IPCThreadState::self();
     const int pid = ipc->getCallingPid();
@@ -4090,8 +4119,8 @@
 
     if ((uid != AID_SHELL) &&
             !PermissionCache::checkPermission(sDump, pid, uid)) {
-        result.appendFormat("Permission Denial: "
-                "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid);
+        StringAppendF(&result, "Permission Denial: can't dump SurfaceFlinger from pid=%d, uid=%d\n",
+                      pid, uid);
     } else {
         // Try to get the main lock, but give up after one second
         // (this would indicate SF is stuck, but we want to be able to
@@ -4099,9 +4128,10 @@
         status_t err = mStateLock.timedLock(s2ns(1));
         bool locked = (err == NO_ERROR);
         if (!locked) {
-            result.appendFormat(
-                    "SurfaceFlinger appears to be unresponsive (%s [%d]), "
-                    "dumping anyways (no locks held)\n", strerror(-err), err);
+            StringAppendF(&result,
+                          "SurfaceFlinger appears to be unresponsive (%s [%d]), dumping anyways "
+                          "(no locks held)\n",
+                          strerror(-err), err);
         }
 
         bool dumpAll = true;
@@ -4219,21 +4249,18 @@
             mStateLock.unlock();
         }
     }
-    write(fd, result.string(), result.size());
+    write(fd, result.c_str(), result.size());
     return NO_ERROR;
 }
 
-void SurfaceFlinger::listLayersLocked(const Vector<String16>& /* args */,
-        size_t& /* index */, String8& result) const
-{
-    mCurrentState.traverseInZOrder([&](Layer* layer) {
-        result.appendFormat("%s\n", layer->getName().string());
-    });
+void SurfaceFlinger::listLayersLocked(const Vector<String16>& /* args */, size_t& /* index */,
+                                      std::string& result) const {
+    mCurrentState.traverseInZOrder(
+            [&](Layer* layer) { StringAppendF(&result, "%s\n", layer->getName().string()); });
 }
 
 void SurfaceFlinger::dumpStatsLocked(const Vector<String16>& args, size_t& index,
-        String8& result) const
-{
+                                     std::string& result) const {
     String8 name;
     if (index < args.size()) {
         name = String8(args[index]);
@@ -4244,7 +4271,7 @@
         displayId && getHwComposer().isConnected(*displayId)) {
         const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
         const nsecs_t period = activeConfig->getVsyncPeriod();
-        result.appendFormat("%" PRId64 "\n", period);
+        StringAppendF(&result, "%" PRId64 "\n", period);
     }
 
     if (name.isEmpty()) {
@@ -4259,8 +4286,7 @@
 }
 
 void SurfaceFlinger::clearStatsLocked(const Vector<String16>& args, size_t& index,
-        String8& /* result */)
-{
+                                      std::string& /* result */) {
     String8 name;
     if (index < args.size()) {
         name = String8(args[index]);
@@ -4286,37 +4312,34 @@
     mAnimFrameTracker.logAndResetStats(String8("<win-anim>"));
 }
 
-void SurfaceFlinger::appendSfConfigString(String8& result) const
-{
+void SurfaceFlinger::appendSfConfigString(std::string& result) const {
     result.append(" [sf");
 
     if (isLayerTripleBufferingDisabled())
         result.append(" DISABLE_TRIPLE_BUFFERING");
 
-    result.appendFormat(" PRESENT_TIME_OFFSET=%" PRId64 , dispSyncPresentTimeOffset);
-    result.appendFormat(" FORCE_HWC_FOR_RBG_TO_YUV=%d", useHwcForRgbToYuv);
-    result.appendFormat(" MAX_VIRT_DISPLAY_DIM=%" PRIu64, maxVirtualDisplaySize);
-    result.appendFormat(" RUNNING_WITHOUT_SYNC_FRAMEWORK=%d", !hasSyncFramework);
-    result.appendFormat(" NUM_FRAMEBUFFER_SURFACE_BUFFERS=%" PRId64,
-                        maxFrameBufferAcquiredBuffers);
+    StringAppendF(&result, " PRESENT_TIME_OFFSET=%" PRId64, dispSyncPresentTimeOffset);
+    StringAppendF(&result, " FORCE_HWC_FOR_RBG_TO_YUV=%d", useHwcForRgbToYuv);
+    StringAppendF(&result, " MAX_VIRT_DISPLAY_DIM=%" PRIu64, maxVirtualDisplaySize);
+    StringAppendF(&result, " RUNNING_WITHOUT_SYNC_FRAMEWORK=%d", !hasSyncFramework);
+    StringAppendF(&result, " NUM_FRAMEBUFFER_SURFACE_BUFFERS=%" PRId64,
+                  maxFrameBufferAcquiredBuffers);
     result.append("]");
 }
 
-void SurfaceFlinger::dumpStaticScreenStats(String8& result) const
-{
-    result.appendFormat("Static screen stats:\n");
+void SurfaceFlinger::dumpStaticScreenStats(std::string& result) const {
+    result.append("Static screen stats:\n");
     for (size_t b = 0; b < SurfaceFlingerBE::NUM_BUCKETS - 1; ++b) {
         float bucketTimeSec = getBE().mFrameBuckets[b] / 1e9;
         float percent = 100.0f *
                 static_cast<float>(getBE().mFrameBuckets[b]) / getBE().mTotalTime;
-        result.appendFormat("  < %zd frames: %.3f s (%.1f%%)\n",
-                b + 1, bucketTimeSec, percent);
+        StringAppendF(&result, "  < %zd frames: %.3f s (%.1f%%)\n", b + 1, bucketTimeSec, percent);
     }
     float bucketTimeSec = getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1] / 1e9;
     float percent = 100.0f *
             static_cast<float>(getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1]) / getBE().mTotalTime;
-    result.appendFormat("  %zd+ frames: %.3f s (%.1f%%)\n",
-            SurfaceFlingerBE::NUM_BUCKETS - 1, bucketTimeSec, percent);
+    StringAppendF(&result, "  %zd+ frames: %.3f s (%.1f%%)\n", SurfaceFlingerBE::NUM_BUCKETS - 1,
+                  bucketTimeSec, percent);
 }
 
 void SurfaceFlinger::recordBufferingStats(const char* layerName,
@@ -4337,8 +4360,8 @@
     }
 }
 
-void SurfaceFlinger::dumpFrameEventsLocked(String8& result) {
-    result.appendFormat("Layer frame timestamps:\n");
+void SurfaceFlinger::dumpFrameEventsLocked(std::string& result) {
+    result.append("Layer frame timestamps:\n");
 
     const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
     const size_t count = currentLayers.size();
@@ -4347,7 +4370,7 @@
     }
 }
 
-void SurfaceFlinger::dumpBufferingStats(String8& result) const {
+void SurfaceFlinger::dumpBufferingStats(std::string& result) const {
     result.append("Buffering stats:\n");
     result.append("  [Layer name] <Active time> <Two buffer> "
             "<Double buffered> <Triple buffered>\n");
@@ -4373,15 +4396,13 @@
     for (const auto& sortedPair : sorted) {
         float activeTime = sortedPair.first;
         const BufferTuple& values = sortedPair.second;
-        result.appendFormat("  [%s] %.2f %.3f %.3f %.3f\n",
-                std::get<0>(values).c_str(), activeTime,
-                std::get<1>(values), std::get<2>(values),
-                std::get<3>(values));
+        StringAppendF(&result, "  [%s] %.2f %.3f %.3f %.3f\n", std::get<0>(values).c_str(),
+                      activeTime, std::get<1>(values), std::get<2>(values), std::get<3>(values));
     }
     result.append("\n");
 }
 
-void SurfaceFlinger::dumpDisplayIdentificationData(String8& result) const {
+void SurfaceFlinger::dumpDisplayIdentificationData(std::string& result) const {
     for (const auto& [token, display] : mDisplays) {
         const auto displayId = display->getId();
         if (!displayId) {
@@ -4392,8 +4413,9 @@
             continue;
         }
 
-        result.appendFormat("Display %s (HWC display %" PRIu64 "): ", to_string(*displayId).c_str(),
-                            *hwcDisplayId);
+        StringAppendF(&result,
+                      "Display %s (HWC display %" PRIu64 "): ", to_string(*displayId).c_str(),
+                      *hwcDisplayId);
         uint8_t port;
         DisplayIdentificationData data;
         if (!getHwComposer().getDisplayIdentificationData(*hwcDisplayId, &port, &data)) {
@@ -4404,7 +4426,7 @@
         if (!isEdid(data)) {
             result.append("unknown identification data: ");
             for (uint8_t byte : data) {
-                result.appendFormat("%x ", byte);
+                StringAppendF(&result, "%x ", byte);
             }
             result.append("\n");
             continue;
@@ -4414,23 +4436,23 @@
         if (!edid) {
             result.append("invalid EDID: ");
             for (uint8_t byte : data) {
-                result.appendFormat("%x ", byte);
+                StringAppendF(&result, "%x ", byte);
             }
             result.append("\n");
             continue;
         }
 
-        result.appendFormat("port=%u pnpId=%s displayName=\"", port, edid->pnpId.data());
+        StringAppendF(&result, "port=%u pnpId=%s displayName=\"", port, edid->pnpId.data());
         result.append(edid->displayName.data(), edid->displayName.length());
         result.append("\"\n");
     }
 }
 
-void SurfaceFlinger::dumpWideColorInfo(String8& result) const {
-    result.appendFormat("Device has wide color display: %d\n", hasWideColorDisplay);
-    result.appendFormat("Device uses color management: %d\n", useColorManagement);
-    result.appendFormat("DisplayColorSetting: %s\n",
-            decodeDisplayColorSetting(mDisplayColorSetting).c_str());
+void SurfaceFlinger::dumpWideColorInfo(std::string& result) const {
+    StringAppendF(&result, "Device has wide color display: %d\n", hasWideColorDisplay);
+    StringAppendF(&result, "Device uses color management: %d\n", useColorManagement);
+    StringAppendF(&result, "DisplayColorSetting: %s\n",
+                  decodeDisplayColorSetting(mDisplayColorSetting).c_str());
 
     // TODO: print out if wide-color mode is active or not
 
@@ -4440,22 +4462,20 @@
             continue;
         }
 
-        result.appendFormat("Display %s color modes:\n", to_string(*displayId).c_str());
+        StringAppendF(&result, "Display %s color modes:\n", to_string(*displayId).c_str());
         std::vector<ColorMode> modes = getHwComposer().getColorModes(*displayId);
         for (auto&& mode : modes) {
-            result.appendFormat("    %s (%d)\n", decodeColorMode(mode).c_str(), mode);
+            StringAppendF(&result, "    %s (%d)\n", decodeColorMode(mode).c_str(), mode);
         }
 
         ColorMode currentMode = display->getActiveColorMode();
-        result.appendFormat("    Current color mode: %s (%d)\n",
-                            decodeColorMode(currentMode).c_str(), currentMode);
+        StringAppendF(&result, "    Current color mode: %s (%d)\n",
+                      decodeColorMode(currentMode).c_str(), currentMode);
     }
     result.append("\n");
 }
 
-void SurfaceFlinger::dumpFrameCompositionInfo(String8& result) const {
-    std::string stringResult;
-
+void SurfaceFlinger::dumpFrameCompositionInfo(std::string& result) const {
     for (const auto& [token, display] : mDisplays) {
         const auto it = getBE().mEndOfFrameCompositionInfo.find(token);
         if (it == getBE().mEndOfFrameCompositionInfo.end()) {
@@ -4463,15 +4483,13 @@
         }
 
         const auto& compositionInfoList = it->second;
-        stringResult += base::StringPrintf("%s\n", display->getDebugName().c_str());
-        stringResult += base::StringPrintf("numComponents: %zu\n", compositionInfoList.size());
+        StringAppendF(&result, "%s\n", display->getDebugName().c_str());
+        StringAppendF(&result, "numComponents: %zu\n", compositionInfoList.size());
         for (const auto& compositionInfo : compositionInfoList) {
-            compositionInfo.dump(stringResult, nullptr);
-            stringResult += base::StringPrintf("\n");
+            compositionInfo.dump(result, nullptr);
+            result.append("\n");
         }
     }
-
-    result.append(stringResult.c_str());
 }
 
 LayersProto SurfaceFlinger::dumpProtoInfo(LayerVector::StateSet stateSet) const {
@@ -4510,8 +4528,7 @@
 }
 
 void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
-        String8& result) const
-{
+                                   std::string& result) const {
     bool colorize = false;
     if (index < args.size()
             && (args[index] == String16("--color"))) {
@@ -4559,16 +4576,17 @@
     if (const auto displayId = getInternalDisplayId();
         displayId && getHwComposer().isConnected(*displayId)) {
         const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
-        result.appendFormat("Display %s: app phase %" PRId64 " ns, "
-                            "sf phase %" PRId64 " ns, "
-                            "early app phase %" PRId64 " ns, "
-                            "early sf phase %" PRId64 " ns, "
-                            "early app gl phase %" PRId64 " ns, "
-                            "early sf gl phase %" PRId64 " ns, "
-                            "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
-                            to_string(*displayId).c_str(), vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs,
-                            appEarlyOffset, sfEarlyOffset, appEarlyGlOffset, sfEarlyGlOffset,
-                            dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
+        StringAppendF(&result,
+                      "Display %s: app phase %" PRId64 " ns, "
+                      "sf phase %" PRId64 " ns, "
+                      "early app phase %" PRId64 " ns, "
+                      "early sf phase %" PRId64 " ns, "
+                      "early app gl phase %" PRId64 " ns, "
+                      "early sf gl phase %" PRId64 " ns, "
+                      "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
+                      to_string(*displayId).c_str(), vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs,
+                      appEarlyOffset, sfEarlyOffset, appEarlyGlOffset, sfEarlyGlOffset,
+                      dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
     }
     result.append("\n");
 
@@ -4577,7 +4595,7 @@
     dumpStaticScreenStats(result);
     result.append("\n");
 
-    result.appendFormat("Missed frame count: %u\n\n", mFrameMissedCount.load());
+    StringAppendF(&result, "Missed frame count: %u\n\n", mFrameMissedCount.load());
 
     dumpBufferingStats(result);
 
@@ -4585,15 +4603,15 @@
      * Dump the visible layer list
      */
     colorizer.bold(result);
-    result.appendFormat("Visible layers (count = %zu)\n", mNumLayers);
-    result.appendFormat("GraphicBufferProducers: %zu, max %zu\n",
-                        mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize);
+    StringAppendF(&result, "Visible layers (count = %zu)\n", mNumLayers);
+    StringAppendF(&result, "GraphicBufferProducers: %zu, max %zu\n",
+                  mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize);
     colorizer.reset(result);
 
     {
         LayersProto layersProto = dumpProtoInfo(LayerVector::StateSet::Current);
         auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
-        result.append(LayerProtoParser::layerTreeToString(layerTree).c_str());
+        result.append(LayerProtoParser::layerTreeToString(layerTree));
         result.append("\n");
     }
 
@@ -4606,7 +4624,7 @@
      */
 
     colorizer.bold(result);
-    result.appendFormat("Displays (%zu entries)\n", mDisplays.size());
+    StringAppendF(&result, "Displays (%zu entries)\n", mDisplays.size());
     colorizer.reset(result);
     for (const auto& [token, display] : mDisplays) {
         display->dump(result);
@@ -4625,27 +4643,28 @@
 
     if (const auto display = getDefaultDisplayDeviceLocked()) {
         display->undefinedRegion.dump(result, "undefinedRegion");
-        result.appendFormat("  orientation=%d, isPoweredOn=%d\n", display->getOrientation(),
-                            display->isPoweredOn());
+        StringAppendF(&result, "  orientation=%d, isPoweredOn=%d\n", display->getOrientation(),
+                      display->isPoweredOn());
     }
-    result.appendFormat("  transaction-flags         : %08x\n"
-                        "  gpu_to_cpu_unsupported    : %d\n",
-                        mTransactionFlags.load(), !mGpuToCpuSupported);
+    StringAppendF(&result,
+                  "  transaction-flags         : %08x\n"
+                  "  gpu_to_cpu_unsupported    : %d\n",
+                  mTransactionFlags.load(), !mGpuToCpuSupported);
 
     if (const auto displayId = getInternalDisplayId();
         displayId && getHwComposer().isConnected(*displayId)) {
         const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
-        result.appendFormat("  refresh-rate              : %f fps\n"
-                            "  x-dpi                     : %f\n"
-                            "  y-dpi                     : %f\n",
-                            1e9 / activeConfig->getVsyncPeriod(), activeConfig->getDpiX(),
-                            activeConfig->getDpiY());
+        StringAppendF(&result,
+                      "  refresh-rate              : %f fps\n"
+                      "  x-dpi                     : %f\n"
+                      "  y-dpi                     : %f\n",
+                      1e9 / activeConfig->getVsyncPeriod(), activeConfig->getDpiX(),
+                      activeConfig->getDpiY());
     }
 
-    result.appendFormat("  transaction time: %f us\n",
-            inTransactionDuration/1000.0);
+    StringAppendF(&result, "  transaction time: %f us\n", inTransactionDuration / 1000.0);
 
-    result.appendFormat("  use Scheduler: %s\n", mUseScheduler ? "true" : "false");
+    StringAppendF(&result, "  use Scheduler: %s\n", mUseScheduler ? "true" : "false");
     /*
      * VSYNC state
      */
@@ -4671,7 +4690,7 @@
             continue;
         }
 
-        result.appendFormat("Display %s HWC layers:\n", to_string(*displayId).c_str());
+        StringAppendF(&result, "Display %s HWC layers:\n", to_string(*displayId).c_str());
         Layer::miniDumpHeader(result);
         mCurrentState.traverseInZOrder([&](Layer* layer) { layer->miniDump(result, *displayId); });
         result.append("\n");
@@ -4684,8 +4703,7 @@
     result.append("h/w composer state:\n");
     colorizer.reset(result);
     bool hwcDisabled = mDebugDisableHWC || mDebugRegion;
-    result.appendFormat("  h/w composer %s\n",
-            hwcDisabled ? "disabled" : "enabled");
+    StringAppendF(&result, "  h/w composer %s\n", hwcDisabled ? "disabled" : "enabled");
     getHwComposer().dump(result);
 
     /*
@@ -4699,7 +4717,7 @@
      */
     if (mVrFlingerRequestsDisplay && mVrFlinger) {
         result.append("VrFlinger state:\n");
-        result.append(mVrFlinger->Dump().c_str());
+        result.append(mVrFlinger->Dump());
         result.append("\n");
     }
 }
@@ -4778,7 +4796,9 @@
         case SET_ACTIVE_COLOR_MODE:
         case INJECT_VSYNC:
         case SET_POWER_MODE:
-        case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES: {
+        case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES:
+        case SET_DISPLAY_CONTENT_SAMPLING_ENABLED:
+        case GET_DISPLAYED_CONTENT_SAMPLE: {
             if (!callingThreadHasUnscopedSurfaceFlingerAccess()) {
                 IPCThreadState* ipc = IPCThreadState::self();
                 ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d",
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 9039a14..9f52058 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -483,6 +483,12 @@
     virtual status_t getDisplayedContentSamplingAttributes(
             const sp<IBinder>& display, ui::PixelFormat* outFormat, ui::Dataspace* outDataspace,
             uint8_t* outComponentMask) const override;
+    virtual status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable,
+                                                      uint8_t componentMask,
+                                                      uint64_t maxFrames) const override;
+    virtual status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
+                                               uint64_t timestamp,
+                                               DisplayedFrameStats* outStats) const override;
 
     /* ------------------------------------------------------------------------
      * DeathRecipient interface
@@ -803,25 +809,25 @@
         return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
     }
 
-    void listLayersLocked(const Vector<String16>& args, size_t& index, String8& result) const;
-    void dumpStatsLocked(const Vector<String16>& args, size_t& index, String8& result) const;
-    void clearStatsLocked(const Vector<String16>& args, size_t& index, String8& result);
-    void dumpAllLocked(const Vector<String16>& args, size_t& index, String8& result) const;
+    void listLayersLocked(const Vector<String16>& args, size_t& index, std::string& result) const;
+    void dumpStatsLocked(const Vector<String16>& args, size_t& index, std::string& result) const;
+    void clearStatsLocked(const Vector<String16>& args, size_t& index, std::string& result);
+    void dumpAllLocked(const Vector<String16>& args, size_t& index, std::string& result) const;
     bool startDdmConnection();
-    void appendSfConfigString(String8& result) const;
+    void appendSfConfigString(std::string& result) const;
 
     void logFrameStats();
 
-    void dumpStaticScreenStats(String8& result) const;
+    void dumpStaticScreenStats(std::string& result) const;
     // Not const because each Layer needs to query Fences and cache timestamps.
-    void dumpFrameEventsLocked(String8& result);
+    void dumpFrameEventsLocked(std::string& result);
 
     void recordBufferingStats(const char* layerName,
             std::vector<OccupancyTracker::Segment>&& history);
-    void dumpBufferingStats(String8& result) const;
-    void dumpDisplayIdentificationData(String8& result) const;
-    void dumpWideColorInfo(String8& result) const;
-    void dumpFrameCompositionInfo(String8& result) const;
+    void dumpBufferingStats(std::string& result) const;
+    void dumpDisplayIdentificationData(std::string& result) const;
+    void dumpWideColorInfo(std::string& result) const;
+    void dumpFrameCompositionInfo(std::string& result) const;
     LayersProto dumpProtoInfo(LayerVector::StateSet stateSet) const;
     LayersProto dumpVisibleLayersProtoInfo(const DisplayDevice& display) const;
 
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index 1835929..b7e9a91 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -20,6 +20,7 @@
 #include "SurfaceTracing.h"
 
 #include <android-base/file.h>
+#include <android-base/stringprintf.h>
 #include <log/log.h>
 #include <utils/SystemClock.h>
 #include <utils/Trace.h>
@@ -120,12 +121,13 @@
     return NO_ERROR;
 }
 
-void SurfaceTracing::dump(String8& result) const {
+void SurfaceTracing::dump(std::string& result) const {
     std::lock_guard<std::mutex> protoGuard(mTraceMutex);
 
-    result.appendFormat("Tracing state: %s\n", mEnabled ? "enabled" : "disabled");
-    result.appendFormat("  number of entries: %zu (%.2fMB / %.2fMB)\n", mBuffer.frameCount(),
-                        float(mBuffer.used()) / float(1_MB), float(mBuffer.size()) / float(1_MB));
+    base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled");
+    base::StringAppendF(&result, "  number of entries: %zu (%.2fMB / %.2fMB)\n",
+                        mBuffer.frameCount(), float(mBuffer.used()) / float(1_MB),
+                        float(mBuffer.size()) / float(1_MB));
 }
 
 } // namespace android
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index ec01be7..fd919af 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -18,7 +18,6 @@
 
 #include <layerproto/LayerProtoHeader.h>
 #include <utils/Errors.h>
-#include <utils/String8.h>
 
 #include <memory>
 #include <mutex>
@@ -43,7 +42,7 @@
     void traceLayers(const char* where, LayersProto);
 
     bool isEnabled() const;
-    void dump(String8& result) const;
+    void dump(std::string& result) const;
 
 private:
     static constexpr auto kDefaultBufferCapInByte = 100_MB;
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 2b9f5c8..6a5488a 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -33,7 +33,7 @@
 namespace android {
 
 void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, size_t& index,
-                          String8& result) {
+                          std::string& result) {
     ATRACE_CALL();
 
     if (args.size() > index + 10) {
@@ -564,7 +564,7 @@
     return mEnabled.load();
 }
 
-void TimeStats::dump(bool asProto, std::optional<uint32_t> maxLayers, String8& result) {
+void TimeStats::dump(bool asProto, std::optional<uint32_t> maxLayers, std::string& result) {
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
@@ -582,7 +582,7 @@
         result.append(timeStatsProto.SerializeAsString().c_str(), timeStatsProto.ByteSize());
     } else {
         ALOGD("Dumping TimeStats as text");
-        result.append(mTimeStats.toString(maxLayers).c_str());
+        result.append(mTimeStats.toString(maxLayers));
         result.append("\n");
     }
 }
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 0b24c46..71c3ed7 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -24,7 +24,6 @@
 #include <ui/FenceTime.h>
 
 #include <utils/String16.h>
-#include <utils/String8.h>
 #include <utils/Vector.h>
 
 #include <deque>
@@ -35,7 +34,6 @@
 using namespace android::surfaceflinger;
 
 namespace android {
-class String8;
 
 class TimeStats {
     struct FrameTime {
@@ -79,7 +77,7 @@
     TimeStats() = default;
     ~TimeStats() = default;
 
-    void parseArgs(bool asProto, const Vector<String16>& args, size_t& index, String8& result);
+    void parseArgs(bool asProto, const Vector<String16>& args, size_t& index, std::string& result);
     bool isEnabled();
 
     void incrementTotalFrames();
@@ -117,7 +115,7 @@
     void enable();
     void disable();
     void clear();
-    void dump(bool asProto, std::optional<uint32_t> maxLayers, String8& result);
+    void dump(bool asProto, std::optional<uint32_t> maxLayers, std::string& result);
 
     std::atomic<bool> mEnabled = false;
     std::mutex mMutex;
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index b0360a2..cef598c 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -396,7 +396,7 @@
                                           BufferUsage::COMPOSER_OVERLAY,
                                   "test");
         fillGraphicBufferColor(buffer, Rect(0, 0, bufferWidth, bufferHeight), color);
-        Transaction().setBuffer(layer, buffer).setSize(layer, bufferWidth, bufferHeight).apply();
+        Transaction().setBuffer(layer, buffer).apply();
     }
 
     void fillLayerColor(uint32_t mLayerType, const sp<SurfaceControl>& layer, const Color& color,
@@ -484,13 +484,14 @@
     uint32_t mDisplayWidth;
     uint32_t mDisplayHeight;
     uint32_t mDisplayLayerStack;
+    Rect mDisplayRect = Rect::INVALID_RECT;
 
     // leave room for ~256 layers
     const int32_t mLayerZBase = std::numeric_limits<int32_t>::max() - 256;
 
-    void setPositionWithResizeHelper(uint32_t layerType);
-    void setSizeBasicHelper(uint32_t layerType);
-    void setMatrixWithResizeHelper(uint32_t layerType);
+    void setRelativeZBasicHelper(uint32_t layerType);
+    void setRelativeZGroupHelper(uint32_t layerType);
+    void setAlphaBasicHelper(uint32_t layerType);
 
     sp<SurfaceControl> mBlackBgSurface;
     bool mColorManagementUsed;
@@ -505,6 +506,8 @@
         SurfaceComposerClient::getDisplayInfo(mDisplay, &info);
         mDisplayWidth = info.w;
         mDisplayHeight = info.h;
+        mDisplayRect =
+                Rect(static_cast<int32_t>(mDisplayWidth), static_cast<int32_t>(mDisplayHeight));
 
         // After a new buffer is queued, SurfaceFlinger is notified and will
         // latch the new buffer on next vsync.  Let's heuristically wait for 3
@@ -575,31 +578,33 @@
         ::testing::Values(static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferQueue),
                           static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferState)));
 
-TEST_P(LayerTypeTransactionTest, SetPositionBasic) {
+TEST_F(LayerTransactionTest, SetPositionBasic_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
 
     {
         SCOPED_TRACE("default position");
+        const Rect rect(0, 0, 32, 32);
         auto shot = screenshot();
-        shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
-        shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+        shot->expectColor(rect, Color::RED);
+        shot->expectBorder(rect, Color::BLACK);
     }
 
     Transaction().setPosition(layer, 5, 10).apply();
     {
         SCOPED_TRACE("new position");
+        const Rect rect(5, 10, 37, 42);
         auto shot = screenshot();
-        shot->expectColor(Rect(5, 10, 37, 42), Color::RED);
-        shot->expectBorder(Rect(5, 10, 37, 42), Color::BLACK);
+        shot->expectColor(rect, Color::RED);
+        shot->expectBorder(rect, Color::BLACK);
     }
 }
 
-TEST_P(LayerTypeTransactionTest, SetPositionRounding) {
+TEST_F(LayerTransactionTest, SetPositionRounding_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
 
     // GLES requires only 4 bits of subpixel precision during rasterization
     // XXX GLES composition does not match HWC composition due to precision
@@ -618,28 +623,28 @@
     }
 }
 
-TEST_P(LayerTypeTransactionTest, SetPositionOutOfBounds) {
+TEST_F(LayerTransactionTest, SetPositionOutOfBounds_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
 
     Transaction().setPosition(layer, -32, -32).apply();
     {
         SCOPED_TRACE("negative coordinates");
-        screenshot()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+        screenshot()->expectColor(mDisplayRect, Color::BLACK);
     }
 
     Transaction().setPosition(layer, mDisplayWidth, mDisplayHeight).apply();
     {
         SCOPED_TRACE("positive coordinates");
-        screenshot()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+        screenshot()->expectColor(mDisplayRect, Color::BLACK);
     }
 }
 
-TEST_P(LayerTypeTransactionTest, SetPositionPartiallyOutOfBounds) {
+TEST_F(LayerTransactionTest, SetPositionPartiallyOutOfBounds_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
 
     // partially out of bounds
     Transaction().setPosition(layer, -30, -30).apply();
@@ -657,10 +662,10 @@
     }
 }
 
-void LayerTransactionTest::setPositionWithResizeHelper(uint32_t layerType) {
+TEST_F(LayerTransactionTest, SetPositionWithResize_BufferQueue) {
     sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32, layerType));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer, Color::RED, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
 
     // setPosition is applied immediately by default, with or without resize
     // pending
@@ -668,39 +673,18 @@
     {
         SCOPED_TRACE("resize pending");
         auto shot = screenshot();
-        Rect rect;
-        switch (layerType) {
-            case ISurfaceComposerClient::eFXSurfaceBufferQueue:
-                rect = {5, 10, 37, 42};
-                break;
-            case ISurfaceComposerClient::eFXSurfaceBufferState:
-                rect = {5, 10, 69, 74};
-                break;
-            default:
-                ASSERT_FALSE(true) << "Unsupported layer type";
-        }
-
+        const Rect rect(5, 10, 37, 42);
         shot->expectColor(rect, Color::RED);
         shot->expectBorder(rect, Color::BLACK);
     }
 
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer, Color::RED, 64, 64));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
     {
         SCOPED_TRACE("resize applied");
         screenshot()->expectColor(Rect(5, 10, 69, 74), Color::RED);
     }
 }
 
-TEST_F(LayerTransactionTest, SetPositionWithResize_BufferQueue) {
-    ASSERT_NO_FATAL_FAILURE(
-            setPositionWithResizeHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
-}
-
-TEST_F(LayerTransactionTest, SetPositionWithResize_BufferState) {
-    ASSERT_NO_FATAL_FAILURE(
-            setPositionWithResizeHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
-}
-
 TEST_F(LayerTransactionTest, SetPositionWithNextResize_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
@@ -757,55 +741,38 @@
     }
 }
 
-void LayerTransactionTest::setSizeBasicHelper(uint32_t layerType) {
+TEST_F(LayerTransactionTest, SetSizeBasic_BufferQueue) {
     sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32, layerType));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer, Color::RED, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
 
     Transaction().setSize(layer, 64, 64).apply();
     {
         SCOPED_TRACE("resize pending");
         auto shot = screenshot();
-        Rect rect;
-        switch (layerType) {
-            case ISurfaceComposerClient::eFXSurfaceBufferQueue:
-                rect = {0, 0, 32, 32};
-                break;
-            case ISurfaceComposerClient::eFXSurfaceBufferState:
-                rect = {0, 0, 64, 64};
-                break;
-            default:
-                ASSERT_FALSE(true) << "Unsupported layer type";
-        }
+        const Rect rect(0, 0, 32, 32);
         shot->expectColor(rect, Color::RED);
         shot->expectBorder(rect, Color::BLACK);
     }
 
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer, Color::RED, 64, 64));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
     {
         SCOPED_TRACE("resize applied");
         auto shot = screenshot();
-        shot->expectColor(Rect(0, 0, 64, 64), Color::RED);
-        shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK);
+        const Rect rect(0, 0, 64, 64);
+        shot->expectColor(rect, Color::RED);
+        shot->expectBorder(rect, Color::BLACK);
     }
 }
 
-TEST_F(LayerTransactionTest, SetSizeBasic_BufferQueue) {
-    setSizeBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue);
-}
-
-TEST_F(LayerTransactionTest, SetSizeBasic_BufferState) {
-    setSizeBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferState);
-}
-
 TEST_P(LayerTypeTransactionTest, SetSizeInvalid) {
     // cannot test robustness against invalid sizes (zero or really huge)
 }
 
-TEST_P(LayerTypeTransactionTest, SetSizeWithScaleToWindow) {
+TEST_F(LayerTransactionTest, SetSizeWithScaleToWindow_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
 
     // setSize is immediate with SCALE_TO_WINDOW, unlike setPosition
     Transaction()
@@ -867,18 +834,31 @@
     }
 }
 
-TEST_P(LayerTypeTransactionTest, SetRelativeZBasic) {
+void LayerTransactionTest::setRelativeZBasicHelper(uint32_t layerType) {
     sp<SurfaceControl> layerR;
     sp<SurfaceControl> layerG;
-    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
-    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32, layerType));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerR, Color::RED, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32, layerType));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerG, Color::GREEN, 32, 32));
 
-    Transaction()
-            .setPosition(layerG, 16, 16)
-            .setRelativeLayer(layerG, layerR->getHandle(), 1)
-            .apply();
+    switch (layerType) {
+        case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+            Transaction()
+                    .setPosition(layerG, 16, 16)
+                    .setRelativeLayer(layerG, layerR->getHandle(), 1)
+                    .apply();
+            break;
+        case ISurfaceComposerClient::eFXSurfaceBufferState:
+            Transaction()
+                    .setFrame(layerR, Rect(0, 0, 32, 32))
+                    .setFrame(layerG, Rect(16, 16, 48, 48))
+                    .setRelativeLayer(layerG, layerR->getHandle(), 1)
+                    .apply();
+            break;
+        default:
+            ASSERT_FALSE(true) << "Unsupported layer type";
+    }
     {
         SCOPED_TRACE("layerG above");
         auto shot = screenshot();
@@ -895,6 +875,14 @@
     }
 }
 
+TEST_F(LayerTransactionTest, SetRelativeZBasic_BufferQueue) {
+    ASSERT_NO_FATAL_FAILURE(setRelativeZBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
+}
+
+TEST_F(LayerTransactionTest, SetRelativeZBasic_BufferState) {
+    ASSERT_NO_FATAL_FAILURE(setRelativeZBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
+}
+
 TEST_P(LayerTypeTransactionTest, SetRelativeZNegative) {
     sp<SurfaceControl> parent =
             LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
@@ -920,28 +908,44 @@
     std::unique_ptr<ScreenCapture> screenshot;
     // only layerB is in this range
     sp<IBinder> parentHandle = parent->getHandle();
-    ScreenCapture::captureLayers(&screenshot, parentHandle);
+    ScreenCapture::captureLayers(&screenshot, parentHandle, Rect(0, 0, 32, 32));
     screenshot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
 }
 
-TEST_P(LayerTypeTransactionTest, SetRelativeZGroup) {
+void LayerTransactionTest::setRelativeZGroupHelper(uint32_t layerType) {
     sp<SurfaceControl> layerR;
     sp<SurfaceControl> layerG;
     sp<SurfaceControl> layerB;
-    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
-    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
-    ASSERT_NO_FATAL_FAILURE(layerB = createLayer("test B", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerB, Color::BLUE, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test", 32, 32, layerType));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerR, Color::RED, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test", 32, 32, layerType));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerG, Color::GREEN, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(layerB = createLayer("test", 32, 32, layerType));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerB, Color::BLUE, 32, 32));
 
     // layerR = 0, layerG = layerR + 3, layerB = 2
-    Transaction()
-            .setPosition(layerG, 8, 8)
-            .setRelativeLayer(layerG, layerR->getHandle(), 3)
-            .setPosition(layerB, 16, 16)
-            .setLayer(layerB, mLayerZBase + 2)
-            .apply();
+    switch (layerType) {
+        case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+            Transaction()
+                    .setPosition(layerG, 8, 8)
+                    .setRelativeLayer(layerG, layerR->getHandle(), 3)
+                    .setPosition(layerB, 16, 16)
+                    .setLayer(layerB, mLayerZBase + 2)
+                    .apply();
+            break;
+        case ISurfaceComposerClient::eFXSurfaceBufferState:
+            Transaction()
+                    .setFrame(layerR, Rect(0, 0, 32, 32))
+                    .setFrame(layerG, Rect(8, 8, 40, 40))
+                    .setRelativeLayer(layerG, layerR->getHandle(), 3)
+                    .setFrame(layerB, Rect(16, 16, 48, 48))
+                    .setLayer(layerB, mLayerZBase + 2)
+                    .apply();
+            break;
+        default:
+            ASSERT_FALSE(true) << "Unsupported layer type";
+    }
+
     {
         SCOPED_TRACE("(layerR < layerG) < layerB");
         auto shot = screenshot();
@@ -991,6 +995,14 @@
     }
 }
 
+TEST_F(LayerTransactionTest, SetRelativeZGroup_BufferQueue) {
+    ASSERT_NO_FATAL_FAILURE(setRelativeZGroupHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
+}
+
+TEST_F(LayerTransactionTest, SetRelativeZGroup_BufferState) {
+    ASSERT_NO_FATAL_FAILURE(setRelativeZGroupHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
+}
+
 TEST_P(LayerTypeTransactionTest, SetRelativeZBug64572777) {
     sp<SurfaceControl> layerR;
     sp<SurfaceControl> layerG;
@@ -1018,7 +1030,7 @@
     Transaction().setFlags(layer, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden).apply();
     {
         SCOPED_TRACE("layer hidden");
-        screenshot()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+        screenshot()->expectColor(mDisplayRect, Color::BLACK);
     }
 
     Transaction().setFlags(layer, 0, layer_state_t::eLayerHidden).apply();
@@ -1130,7 +1142,7 @@
     Transaction()
             .setTransparentRegionHint(layer, Region(top))
             .setBuffer(layer, buffer)
-            .setSize(layer, 32, 32)
+            .setFrame(layer, Rect(0, 0, 32, 32))
             .apply();
     {
         SCOPED_TRACE("top transparent");
@@ -1154,7 +1166,7 @@
 
     ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, top, Color::RED));
     ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, bottom, Color::TRANSPARENT));
-    Transaction().setBuffer(layer, buffer).setSize(layer, 32, 32).apply();
+    Transaction().setBuffer(layer, buffer).apply();
     {
         SCOPED_TRACE("bottom transparent");
         auto shot = screenshot();
@@ -1163,7 +1175,7 @@
     }
 }
 
-TEST_P(LayerTypeTransactionTest, SetTransparentRegionHintOutOfBounds) {
+TEST_F(LayerTransactionTest, SetTransparentRegionHintOutOfBounds_BufferQueue) {
     sp<SurfaceControl> layerTransparent;
     sp<SurfaceControl> layerR;
     ASSERT_NO_FATAL_FAILURE(layerTransparent = createLayer("test transparent", 32, 32));
@@ -1171,30 +1183,64 @@
 
     // check that transparent region hint is bound by the layer size
     Transaction()
-            .setTransparentRegionHint(layerTransparent,
-                                      Region(Rect(0, 0, mDisplayWidth, mDisplayHeight)))
+            .setTransparentRegionHint(layerTransparent, Region(mDisplayRect))
             .setPosition(layerR, 16, 16)
             .setLayer(layerR, mLayerZBase + 1)
             .apply();
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerTransparent, Color::TRANSPARENT, 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(
+            fillBufferQueueLayerColor(layerTransparent, Color::TRANSPARENT, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layerR, Color::RED, 32, 32));
     screenshot()->expectColor(Rect(16, 16, 48, 48), Color::RED);
 }
 
-TEST_P(LayerTypeTransactionTest, SetAlphaBasic) {
+TEST_F(LayerTransactionTest, SetTransparentRegionHintOutOfBounds_BufferState) {
+    sp<SurfaceControl> layerTransparent;
+    sp<SurfaceControl> layerR;
+    ASSERT_NO_FATAL_FAILURE(layerTransparent = createLayer("test transparent", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(
+            layerR = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    // check that transparent region hint is bound by the layer size
+    Transaction()
+            .setTransparentRegionHint(layerTransparent, Region(mDisplayRect))
+            .setFrame(layerR, Rect(16, 16, 48, 48))
+            .setLayer(layerR, mLayerZBase + 1)
+            .apply();
+    ASSERT_NO_FATAL_FAILURE(
+            fillBufferQueueLayerColor(layerTransparent, Color::TRANSPARENT, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layerR, Color::RED, 32, 32));
+    screenshot()->expectColor(Rect(16, 16, 48, 48), Color::RED);
+}
+
+void LayerTransactionTest::setAlphaBasicHelper(uint32_t layerType) {
     sp<SurfaceControl> layer1;
     sp<SurfaceControl> layer2;
-    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer("test 1", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer("test 2", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer1, {64, 0, 0, 255}, 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer2, {0, 64, 0, 255}, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer("test 1", 32, 32, layerType));
+    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer("test 2", 32, 32, layerType));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer1, {64, 0, 0, 255}, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer2, {0, 64, 0, 255}, 32, 32));
 
-    Transaction()
-            .setAlpha(layer1, 0.25f)
-            .setAlpha(layer2, 0.75f)
-            .setPosition(layer2, 16, 0)
-            .setLayer(layer2, mLayerZBase + 1)
-            .apply();
+    switch (layerType) {
+        case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+            Transaction()
+                    .setAlpha(layer1, 0.25f)
+                    .setAlpha(layer2, 0.75f)
+                    .setPosition(layer2, 16, 0)
+                    .setLayer(layer2, mLayerZBase + 1)
+                    .apply();
+            break;
+        case ISurfaceComposerClient::eFXSurfaceBufferState:
+            Transaction()
+                    .setAlpha(layer1, 0.25f)
+                    .setAlpha(layer2, 0.75f)
+                    .setFrame(layer1, Rect(0, 0, 32, 32))
+                    .setFrame(layer2, Rect(16, 0, 48, 32))
+                    .setLayer(layer2, mLayerZBase + 1)
+                    .apply();
+            break;
+        default:
+            ASSERT_FALSE(true) << "Unsupported layer type";
+    }
     {
         auto shot = screenshot();
         uint8_t r = 16; // 64 * 0.25f
@@ -1207,6 +1253,14 @@
     }
 }
 
+TEST_F(LayerTransactionTest, SetAlphaBasic_BufferQueue) {
+    ASSERT_NO_FATAL_FAILURE(setAlphaBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
+}
+
+TEST_F(LayerTransactionTest, SetAlphaBasic_BufferState) {
+    ASSERT_NO_FATAL_FAILURE(setAlphaBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
+}
+
 TEST_P(LayerTypeTransactionTest, SetAlphaClamped) {
     const Color color = {64, 0, 0, 255};
     sp<SurfaceControl> layer;
@@ -1230,7 +1284,7 @@
     sp<SurfaceControl> layer;
     const uint8_t size = 64;
     const uint8_t testArea = 4;
-    const float cornerRadius = 16.0f;
+    const float cornerRadius = 20.0f;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", size, size));
     ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, size, size));
 
@@ -1238,13 +1292,43 @@
             .setCornerRadius(layer, cornerRadius)
             .apply();
     {
+        const uint8_t bottom = size - 1;
+        const uint8_t right = size - 1;
         auto shot = screenshot();
         // Transparent corners
         shot->expectColor(Rect(0, 0, testArea, testArea), Color::BLACK);
-        shot->expectColor(Rect(0, size - testArea, testArea, testArea), Color::BLACK);
-        shot->expectColor(Rect(size - testArea, 0, testArea, testArea), Color::BLACK);
-        shot->expectColor(Rect(size - testArea, size - testArea, testArea, testArea),
-            Color::BLACK);
+        shot->expectColor(Rect(size - testArea, 0, right, testArea), Color::BLACK);
+        shot->expectColor(Rect(0, bottom - testArea, testArea, bottom), Color::BLACK);
+        shot->expectColor(Rect(size - testArea, bottom - testArea, right, bottom), Color::BLACK);
+    }
+}
+
+TEST_P(LayerTypeTransactionTest, SetCornerRadiusChildCrop) {
+    sp<SurfaceControl> parent;
+    sp<SurfaceControl> child;
+    const uint8_t size = 64;
+    const uint8_t testArea = 4;
+    const float cornerRadius = 20.0f;
+    ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", size, size));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, size, size));
+    ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size / 2));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size / 2));
+
+    Transaction()
+            .setCornerRadius(parent, cornerRadius)
+            .reparent(child, parent->getHandle())
+            .setPosition(child, 0, size / 2)
+            .apply();
+    {
+        const uint8_t bottom = size - 1;
+        const uint8_t right = size - 1;
+        auto shot = screenshot();
+        // Top edge of child should not have rounded corners because it's translated in the parent
+        shot->expectColor(Rect(0, size / 2, right, static_cast<int>(bottom - cornerRadius)),
+            Color::GREEN);
+        // But bottom edges should have been clipped according to parent bounds
+        shot->expectColor(Rect(0, bottom - testArea, testArea, bottom), Color::BLACK);
+        shot->expectColor(Rect(right - testArea, bottom - testArea, right, bottom), Color::BLACK);
     }
 }
 
@@ -1362,7 +1446,7 @@
     Transaction().setLayerStack(layer, mDisplayLayerStack + 1).apply();
     {
         SCOPED_TRACE("non-existing layer stack");
-        screenshot()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+        screenshot()->expectColor(mDisplayRect, Color::BLACK);
     }
 
     Transaction().setLayerStack(layer, mDisplayLayerStack).apply();
@@ -1372,11 +1456,11 @@
     }
 }
 
-TEST_P(LayerTypeTransactionTest, SetMatrixBasic) {
+TEST_F(LayerTransactionTest, SetMatrixBasic_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(
-            fillLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
+                                                         Color::BLUE, Color::WHITE));
 
     Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f).setPosition(layer, 0, 0).apply();
     {
@@ -1414,11 +1498,57 @@
     }
 }
 
-TEST_P(LayerTypeTransactionTest, SetMatrixRot45) {
+TEST_F(LayerTransactionTest, SetMatrixBasic_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
+                                                         Color::BLUE, Color::WHITE));
+
+    Transaction()
+            .setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f)
+            .setFrame(layer, Rect(0, 0, 32, 32))
+            .apply();
+    {
+        SCOPED_TRACE("IDENTITY");
+        screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, Color::BLUE,
+                                     Color::WHITE);
+    }
+
+    Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).apply();
+    {
+        SCOPED_TRACE("FLIP_H");
+        screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, Color::BLUE,
+                                     Color::WHITE);
+    }
+
+    Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).apply();
+    {
+        SCOPED_TRACE("FLIP_V");
+        screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, Color::BLUE,
+                                     Color::WHITE);
+    }
+
+    Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).apply();
+    {
+        SCOPED_TRACE("ROT_90");
+        screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, Color::BLUE,
+                                     Color::WHITE);
+    }
+
+    Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).apply();
+    {
+        SCOPED_TRACE("SCALE");
+        screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, Color::BLUE,
+                                     Color::WHITE);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetMatrixRot45_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(
-            fillLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
+                                                         Color::BLUE, Color::WHITE));
 
     const float rot = M_SQRT1_2; // 45 degrees
     const float trans = M_SQRT2 * 16.0f;
@@ -1437,52 +1567,33 @@
     shot->expectColor(get8x8Rect(2 * unit, 3 * unit), Color::WHITE);
 }
 
-void LayerTransactionTest::setMatrixWithResizeHelper(uint32_t layerType) {
+TEST_F(LayerTransactionTest, SetMatrixWithResize_BufferQueue) {
     sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32, layerType));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer, Color::RED, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
 
     // setMatrix is applied after any pending resize, unlike setPosition
     Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setSize(layer, 64, 64).apply();
     {
         SCOPED_TRACE("resize pending");
         auto shot = screenshot();
-        Rect rect;
-        switch (layerType) {
-            case ISurfaceComposerClient::eFXSurfaceBufferQueue:
-                rect = {0, 0, 32, 32};
-                break;
-            case ISurfaceComposerClient::eFXSurfaceBufferState:
-                rect = {0, 0, 128, 128};
-                break;
-            default:
-                ASSERT_FALSE(true) << "Unsupported layer type";
-        }
+        const Rect rect(0, 0, 32, 32);
         shot->expectColor(rect, Color::RED);
         shot->expectBorder(rect, Color::BLACK);
     }
 
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer, Color::RED, 64, 64));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
     {
         SCOPED_TRACE("resize applied");
-        screenshot()->expectColor(Rect(0, 0, 128, 128), Color::RED);
+        const Rect rect(0, 0, 128, 128);
+        screenshot()->expectColor(rect, Color::RED);
     }
 }
 
-TEST_F(LayerTransactionTest, SetMatrixWithResize_BufferQueue) {
-    ASSERT_NO_FATAL_FAILURE(
-            setMatrixWithResizeHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
-}
-
-TEST_F(LayerTransactionTest, SetMatrixWithResize_BufferState) {
-    ASSERT_NO_FATAL_FAILURE(
-            setMatrixWithResizeHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
-}
-
-TEST_P(LayerTypeTransactionTest, SetMatrixWithScaleToWindow) {
+TEST_F(LayerTransactionTest, SetMatrixWithScaleToWindow_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
 
     // setMatrix is immediate with SCALE_TO_WINDOW, unlike setPosition
     Transaction()
@@ -1493,11 +1604,11 @@
     screenshot()->expectColor(Rect(0, 0, 128, 128), Color::RED);
 }
 
-TEST_P(LayerTypeTransactionTest, SetOverrideScalingModeBasic) {
+TEST_F(LayerTransactionTest, SetOverrideScalingModeBasic_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(
-            fillLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
+                                                         Color::BLUE, Color::WHITE));
 
     // XXX SCALE_CROP is not respected; calling setSize and
     // setOverrideScalingMode in separate transactions does not work
@@ -1547,8 +1658,8 @@
 
     Transaction().setCrop(layer, crop).apply();
     auto shot = screenshot();
-    shot->expectColor(crop, Color::RED);
-    shot->expectBorder(crop, Color::BLACK);
+    shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
 }
 
 TEST_F(LayerTransactionTest, SetCropEmpty_BufferQueue) {
@@ -1599,18 +1710,22 @@
     shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
 }
 
-TEST_F(LayerTransactionTest, SetCropOutOfBounds_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
-
-    Transaction().setCrop(layer, Rect(-128, -64, 128, 64)).apply();
-    auto shot = screenshot();
-    shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
-    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
-}
-
+// TODO (marissaw): change Layer to make crop to be in bounds instead of passing a bad crop to hwc
+// TEST_F(LayerTransactionTest, SetCropOutOfBounds_BufferState) {
+//    sp<SurfaceControl> layer;
+//    ASSERT_NO_FATAL_FAILURE(
+//            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+//    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+//
+//    Transaction()
+//            .setCrop(layer, Rect(-128, -64, 128, 64))
+//            .setFrame(layer, Rect(0, 0, 32, 32))
+//            .apply();
+//    auto shot = screenshot();
+//    shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+//    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+//}
+//
 TEST_F(LayerTransactionTest, SetCropWithTranslation_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
@@ -1630,12 +1745,12 @@
             layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
     ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
 
-    const Point position(32, 32);
+    const Rect frame(32, 32, 64, 64);
     const Rect crop(8, 8, 24, 24);
-    Transaction().setPosition(layer, position.x, position.y).setCrop(layer, crop).apply();
+    Transaction().setFrame(layer, frame).setCrop(layer, crop).apply();
     auto shot = screenshot();
-    shot->expectColor(crop + position, Color::RED);
-    shot->expectBorder(crop + position, Color::BLACK);
+    shot->expectColor(frame, Color::RED);
+    shot->expectBorder(frame, Color::BLACK);
 }
 
 TEST_F(LayerTransactionTest, SetCropWithScale_BufferQueue) {
@@ -1643,7 +1758,7 @@
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
     ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
 
-    // crop is affected by matrix
+    // crop_legacy is affected by matrix
     Transaction()
             .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
             .setCrop_legacy(layer, Rect(8, 8, 24, 24))
@@ -1653,22 +1768,6 @@
     shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
 }
 
-TEST_F(LayerTransactionTest, SetCropWithScale_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
-
-    // crop is affected by matrix
-    Transaction()
-            .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
-            .setCrop(layer, Rect(8, 8, 24, 24))
-            .apply();
-    auto shot = screenshot();
-    shot->expectColor(Rect(16, 16, 48, 48), Color::RED);
-    shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
-}
-
 TEST_F(LayerTransactionTest, SetCropWithResize_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
@@ -1692,30 +1791,6 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetCropWithResize_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
-
-    // setCrop_legacy is applied immediately by default, with or without resize pending
-    Transaction().setCrop(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply();
-    {
-        SCOPED_TRACE("new buffer pending");
-        auto shot = screenshot();
-        shot->expectColor(Rect(8, 8, 16, 16), Color::RED);
-        shot->expectBorder(Rect(8, 8, 16, 16), Color::BLACK);
-    }
-
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 16, 16));
-    {
-        SCOPED_TRACE("new buffer");
-        auto shot = screenshot();
-        shot->expectColor(Rect(8, 8, 16, 16), Color::RED);
-        shot->expectBorder(Rect(8, 8, 16, 16), Color::BLACK);
-    }
-}
-
 TEST_F(LayerTransactionTest, SetCropWithNextResize_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
@@ -1753,41 +1828,6 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetCropWithNextResize_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
-
-    // request setCrop_legacy to be applied with the next resize
-    Transaction().setCrop(layer, Rect(8, 8, 24, 24)).setGeometryAppliesWithResize(layer).apply();
-    {
-        SCOPED_TRACE("set crop 1");
-        screenshot()->expectColor(Rect(8, 8, 24, 24), Color::RED);
-    }
-
-    Transaction().setCrop(layer, Rect(4, 4, 12, 12)).apply();
-    {
-        SCOPED_TRACE("set crop 2");
-        screenshot()->expectColor(Rect(4, 4, 12, 12), Color::RED);
-    }
-
-    Transaction().setSize(layer, 16, 16).apply();
-    {
-        SCOPED_TRACE("resize");
-        screenshot()->expectColor(Rect(4, 4, 12, 12), Color::RED);
-    }
-
-    // finally resize
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 16, 16));
-    {
-        SCOPED_TRACE("new buffer");
-        auto shot = screenshot();
-        shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
-        shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
-    }
-}
-
 TEST_F(LayerTransactionTest, SetCropWithNextResizeScaleToWindow_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
@@ -1819,37 +1859,122 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetCropWithNextResizeScaleToWindow_BufferState) {
+TEST_F(LayerTransactionTest, SetFrameBasic_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+    const Rect frame(8, 8, 24, 24);
+
+    Transaction().setFrame(layer, frame).apply();
+    auto shot = screenshot();
+    shot->expectColor(frame, Color::RED);
+    shot->expectBorder(frame, Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetFrameEmpty_BufferState) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(
             layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
     ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
 
-    // all properties are applied immediate so setGeometryAppliesWithResize has no effect
-    Transaction()
-            .setCrop(layer, Rect(4, 4, 12, 12))
-            .setSize(layer, 16, 16)
-            .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
-            .setGeometryAppliesWithResize(layer)
-            .apply();
     {
-        SCOPED_TRACE("new crop pending");
-        auto shot = screenshot();
-        shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
-        shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
+        SCOPED_TRACE("empty rect");
+        Transaction().setFrame(layer, Rect(8, 8, 8, 8)).apply();
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
     }
 
-    Transaction().setPosition(layer, 1, 0).setGeometryAppliesWithResize(layer).apply();
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 16, 16));
-    Transaction().setPosition(layer, 0, 0).apply();
     {
-        SCOPED_TRACE("new crop applied");
-        auto shot = screenshot();
-        shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
-        shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
+        SCOPED_TRACE("negative rect");
+        Transaction().setFrame(layer, Rect(8, 8, 0, 0)).apply();
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
     }
 }
 
+TEST_F(LayerTransactionTest, SetFrameDefaultParentless_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 10, 10));
+
+    // A parentless layer will default to a frame with the same size as the buffer
+    auto shot = screenshot();
+    shot->expectColor(Rect(0, 0, 10, 10), Color::RED);
+    shot->expectBorder(Rect(0, 0, 10, 10), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetFrameDefaultBSParent_BufferState) {
+    sp<SurfaceControl> parent, child;
+    ASSERT_NO_FATAL_FAILURE(
+            parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32));
+    Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply();
+
+    ASSERT_NO_FATAL_FAILURE(
+            child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
+
+    Transaction().reparent(child, parent->getHandle()).apply();
+
+    // A layer will default to the frame of its parent
+    auto shot = screenshot();
+    shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetFrameDefaultBQParent_BufferState) {
+    sp<SurfaceControl> parent, child;
+    ASSERT_NO_FATAL_FAILURE(parent = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(parent, Color::RED, 32, 32));
+
+    ASSERT_NO_FATAL_FAILURE(
+            child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
+
+    Transaction().reparent(child, parent->getHandle()).apply();
+
+    // A layer will default to the frame of its parent
+    auto shot = screenshot();
+    shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetFrameUpdate_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+    Transaction().setFrame(layer, Rect(0, 0, 32, 32)).apply();
+
+    std::this_thread::sleep_for(500ms);
+
+    Transaction().setFrame(layer, Rect(16, 16, 48, 48)).apply();
+
+    auto shot = screenshot();
+    shot->expectColor(Rect(16, 16, 48, 48), Color::RED);
+    shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetFrameOutsideBounds_BufferState) {
+    sp<SurfaceControl> parent, child;
+    ASSERT_NO_FATAL_FAILURE(
+            parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(
+            child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    Transaction().reparent(child, parent->getHandle()).apply();
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32));
+    Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply();
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
+    Transaction().setFrame(child, Rect(0, 16, 32, 32)).apply();
+
+    auto shot = screenshot();
+    shot->expectColor(Rect(0, 0, 32, 16), Color::RED);
+    shot->expectColor(Rect(0, 16, 32, 32), Color::BLUE);
+    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
 TEST_F(LayerTransactionTest, SetBufferBasic_BufferState) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(
@@ -1906,6 +2031,7 @@
 
     ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer1, Color::RED, 64, 64));
 
+    Transaction().setFrame(layer1, Rect(0, 0, 64, 64)).apply();
     {
         SCOPED_TRACE("set layer 1 buffer red");
         auto shot = screenshot();
@@ -1914,6 +2040,7 @@
 
     ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer2, Color::BLUE, 32, 32));
 
+    Transaction().setFrame(layer2, Rect(0, 0, 32, 32)).apply();
     {
         SCOPED_TRACE("set layer 2 buffer blue");
         auto shot = screenshot();
@@ -1950,7 +2077,10 @@
     ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
                                                          Color::BLUE, Color::WHITE));
 
-    Transaction().setTransform(layer, NATIVE_WINDOW_TRANSFORM_ROT_90).apply();
+    Transaction()
+            .setFrame(layer, Rect(0, 0, 32, 32))
+            .setTransform(layer, NATIVE_WINDOW_TRANSFORM_ROT_90)
+            .apply();
 
     screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED, Color::WHITE,
                                  Color::GREEN, true /* filtered */);
@@ -1964,7 +2094,10 @@
     ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
                                                          Color::BLUE, Color::WHITE));
 
-    Transaction().setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_H).apply();
+    Transaction()
+            .setFrame(layer, Rect(0, 0, 32, 32))
+            .setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_H)
+            .apply();
 
     screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED, Color::WHITE,
                                  Color::BLUE, true /* filtered */);
@@ -1978,7 +2111,10 @@
     ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
                                                          Color::BLUE, Color::WHITE));
 
-    Transaction().setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_V).apply();
+    Transaction()
+            .setFrame(layer, Rect(0, 0, 32, 32))
+            .setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_V)
+            .apply();
 
     screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE, Color::RED,
                                  Color::GREEN, true /* filtered */);
@@ -2013,7 +2149,6 @@
     Transaction()
             .setBuffer(layer, buffer)
             .setAcquireFence(layer, fence)
-            .setSize(layer, 32, 32)
             .apply();
 
     auto shot = screenshot();
@@ -2036,7 +2171,6 @@
     Transaction()
             .setBuffer(layer, buffer)
             .setDataspace(layer, ui::Dataspace::UNKNOWN)
-            .setSize(layer, 32, 32)
             .apply();
 
     auto shot = screenshot();
@@ -2061,7 +2195,6 @@
     Transaction()
             .setBuffer(layer, buffer)
             .setHdrMetadata(layer, hdrMetadata)
-            .setSize(layer, 32, 32)
             .apply();
 
     auto shot = screenshot();
@@ -2086,7 +2219,6 @@
     Transaction()
             .setBuffer(layer, buffer)
             .setSurfaceDamageRegion(layer, region)
-            .setSize(layer, 32, 32)
             .apply();
 
     auto shot = screenshot();
@@ -2109,7 +2241,6 @@
     Transaction()
             .setBuffer(layer, buffer)
             .setApi(layer, NATIVE_WINDOW_API_CPU)
-            .setSize(layer, 32, 32)
             .apply();
 
     auto shot = screenshot();
@@ -2465,36 +2596,33 @@
 };
 
 class LayerCallbackTest : public LayerTransactionTest {
-protected:
+public:
     virtual sp<SurfaceControl> createBufferStateLayer() {
-        return createLayer(mClient, "test", mWidth, mHeight,
-                           ISurfaceComposerClient::eFXSurfaceBufferState);
+        return createLayer(mClient, "test", 0, 0, ISurfaceComposerClient::eFXSurfaceBufferState);
     }
 
-    virtual void fillTransaction(Transaction& transaction, CallbackHelper* callbackHelper,
-                                 const sp<SurfaceControl>& layer = nullptr) {
+    static void fillTransaction(Transaction& transaction, CallbackHelper* callbackHelper,
+                                const sp<SurfaceControl>& layer = nullptr) {
         if (layer) {
             sp<GraphicBuffer> buffer =
-                    new GraphicBuffer(mWidth, mHeight, PIXEL_FORMAT_RGBA_8888, 1,
+                    new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
                                       BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
                                               BufferUsage::COMPOSER_OVERLAY |
                                               BufferUsage::GPU_TEXTURE,
                                       "test");
-            fillGraphicBufferColor(buffer, Rect(0, 0, mWidth, mHeight), Color::RED);
+            fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
 
             sp<Fence> fence = new Fence(-1);
 
-            transaction.setBuffer(layer, buffer)
-                    .setAcquireFence(layer, fence)
-                    .setSize(layer, mWidth, mHeight);
+            transaction.setBuffer(layer, buffer).setAcquireFence(layer, fence);
         }
 
         transaction.addTransactionCompletedCallback(callbackHelper->function,
                                                     callbackHelper->getContext());
     }
 
-    void waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult,
-                         bool finalState = false) {
+    static void waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult,
+                                bool finalState = false) {
         TransactionStats transactionStats;
         ASSERT_NO_FATAL_FAILURE(helper.getTransactionStats(&transactionStats));
         EXPECT_NO_FATAL_FAILURE(expectedResult.verifyTransactionStats(transactionStats));
@@ -2504,9 +2632,9 @@
         }
     }
 
-    void waitForCallbacks(CallbackHelper& helper,
-                          const std::vector<ExpectedResult>& expectedResults,
-                          bool finalState = false) {
+    static void waitForCallbacks(CallbackHelper& helper,
+                                 const std::vector<ExpectedResult>& expectedResults,
+                                 bool finalState = false) {
         for (const auto& expectedResult : expectedResults) {
             waitForCallback(helper, expectedResult);
         }
@@ -2514,9 +2642,6 @@
             ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
         }
     }
-
-    uint32_t mWidth = 32;
-    uint32_t mHeight = 32;
 };
 
 TEST_F(LayerCallbackTest, Basic) {
@@ -2542,7 +2667,7 @@
     CallbackHelper callback;
     fillTransaction(transaction, &callback);
 
-    transaction.setPosition(layer, mWidth, mHeight).apply();
+    transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
 
     ExpectedResult expected;
     expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer);
@@ -2568,7 +2693,7 @@
     CallbackHelper callback;
     fillTransaction(transaction, &callback, layer);
 
-    transaction.setPosition(layer, -100, -100).apply();
+    transaction.setFrame(layer, Rect(-100, -100, 100, 100)).apply();
 
     ExpectedResult expected;
     expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
@@ -2585,7 +2710,8 @@
     fillTransaction(transaction1, &callback1, layer1);
     fillTransaction(transaction2, &callback2, layer2);
 
-    transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+    transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+    transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
 
     ExpectedResult expected;
     expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
@@ -2638,7 +2764,8 @@
     fillTransaction(transaction1, &callback1, layer1);
     fillTransaction(transaction2, &callback2);
 
-    transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+    transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+    transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
 
     ExpectedResult expected;
     expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
@@ -2654,9 +2781,9 @@
     ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
 
     sp<SurfaceControl> layer1, layer2;
-    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", mWidth, mHeight,
+    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
                                                  ISurfaceComposerClient::eFXSurfaceBufferState));
-    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", mWidth, mHeight,
+    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
                                                  ISurfaceComposerClient::eFXSurfaceBufferState));
 
     Transaction transaction1, transaction2;
@@ -2664,7 +2791,8 @@
     fillTransaction(transaction1, &callback1, layer1);
     fillTransaction(transaction2, &callback2, layer2);
 
-    transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+    transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+    transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
 
     ExpectedResult expected;
     expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
@@ -2729,7 +2857,7 @@
             fillTransaction(transaction, &callback);
         }
 
-        transaction.setPosition(layer, mWidth, mHeight).apply();
+        transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
 
         ExpectedResult expected;
         expected.addSurface((i == 0) ? ExpectedResult::Transaction::PRESENTED
@@ -2751,7 +2879,8 @@
         fillTransaction(transaction1, &callback1, layer1);
         fillTransaction(transaction2, &callback2, layer2);
 
-        transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+        transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+        transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
 
         ExpectedResult expected;
         expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
@@ -2772,9 +2901,9 @@
     ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
 
     sp<SurfaceControl> layer1, layer2;
-    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", mWidth, mHeight,
+    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
                                                  ISurfaceComposerClient::eFXSurfaceBufferState));
-    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", mWidth, mHeight,
+    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
                                                  ISurfaceComposerClient::eFXSurfaceBufferState));
 
     Transaction transaction1, transaction2;
@@ -2783,7 +2912,8 @@
         fillTransaction(transaction1, &callback1, layer1);
         fillTransaction(transaction2, &callback2, layer2);
 
-        transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+        transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+        transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
 
         ExpectedResult expected;
         expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
@@ -2804,9 +2934,9 @@
     ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
 
     sp<SurfaceControl> layer1, layer2;
-    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", mWidth, mHeight,
+    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
                                                  ISurfaceComposerClient::eFXSurfaceBufferState));
-    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", mWidth, mHeight,
+    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
                                                  ISurfaceComposerClient::eFXSurfaceBufferState));
 
     Transaction transaction1, transaction2;
@@ -2816,7 +2946,8 @@
     fillTransaction(transaction1, &callback1, layer1);
     fillTransaction(transaction2, &callback2, layer2);
 
-    transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+    transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+    transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
 
     ExpectedResult expected;
     expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
@@ -2842,9 +2973,9 @@
     ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
 
     sp<SurfaceControl> layer1, layer2;
-    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", mWidth, mHeight,
+    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
                                                  ISurfaceComposerClient::eFXSurfaceBufferState));
-    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", mWidth, mHeight,
+    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
                                                  ISurfaceComposerClient::eFXSurfaceBufferState));
 
     Transaction transaction1, transaction2;
@@ -2854,7 +2985,8 @@
     fillTransaction(transaction1, &callback1, layer1);
     fillTransaction(transaction2, &callback2, layer2);
 
-    transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+    transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+    transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
 
     ExpectedResult expected;
     expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
@@ -2866,7 +2998,7 @@
     fillTransaction(transaction1, &callback1);
     fillTransaction(transaction2, &callback2);
 
-    transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+    transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
 
     expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer2);
     EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
@@ -2930,7 +3062,7 @@
     CallbackHelper callback;
     fillTransaction(transaction, &callback, layer);
 
-    transaction.setPosition(layer, mWidth, mHeight).apply();
+    transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
 
     ExpectedResult expectedResult;
     expectedResult.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
@@ -2944,7 +3076,7 @@
 
         fillTransaction(transaction, &callback);
 
-        transaction.setPosition(layer, mWidth, mHeight).apply();
+        transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
 
         std::this_thread::sleep_for(200ms);
     }
@@ -4245,7 +4377,7 @@
     // red area to the right of the blue area
     mCapture->expectColor(Rect(30, 0, 59, 59), Color::RED);
 
-    Rect crop = Rect(0, 0, 30, 30);
+    const Rect crop = Rect(0, 0, 30, 30);
     ScreenCapture::captureLayers(&mCapture, redLayerHandle, crop);
     // Capturing the cropped screen, cropping out the shown red area, should leave only the blue
     // area visible.
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index d0cf1b7..35f30d7 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -117,7 +117,7 @@
             mScheduler->hotplugReceived(nullptr, EventThread::DisplayType::Primary, false));
     ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(nullptr));
     ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(nullptr));
-    String8 testString;
+    std::string testString;
     ASSERT_NO_FATAL_FAILURE(mScheduler->dump(nullptr, testString));
     EXPECT_TRUE(testString == "");
     ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(nullptr, 10));
@@ -146,7 +146,7 @@
     EXPECT_CALL(*mEventThread, onScreenReleased()).Times(0);
     ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(connectionHandle));
 
-    String8 testString;
+    std::string testString;
     EXPECT_CALL(*mEventThread, dump(_)).Times(0);
     ASSERT_NO_FATAL_FAILURE(mScheduler->dump(connectionHandle, testString));
     EXPECT_TRUE(testString == "");
@@ -176,7 +176,7 @@
     EXPECT_CALL(*mEventThread, onScreenReleased()).Times(1);
     ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(mConnectionHandle));
 
-    String8 testString("dump");
+    std::string testString("dump");
     EXPECT_CALL(*mEventThread, dump(testString)).Times(1);
     ASSERT_NO_FATAL_FAILURE(mScheduler->dump(mConnectionHandle, testString));
     EXPECT_TRUE(testString != "");
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 186ed79..bfd34cd 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -21,7 +21,6 @@
 
 #include <log/log.h>
 #include <utils/String16.h>
-#include <utils/String8.h>
 #include <utils/Vector.h>
 
 #include <random>
@@ -131,7 +130,7 @@
 
 std::string TimeStatsTest::inputCommand(InputCommand cmd, bool useProto) {
     size_t index = 0;
-    String8 result;
+    std::string result;
     Vector<String16> args;
 
     switch (cmd) {
@@ -162,7 +161,7 @@
     }
 
     EXPECT_NO_FATAL_FAILURE(mTimeStats->parseArgs(useProto, args, index, result));
-    return std::string(result.string(), result.size());
+    return result;
 }
 
 static std::string genLayerName(int32_t layerID) {
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 5a46c26..dfdda09 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -115,6 +115,9 @@
     MOCK_METHOD3(setLayerColorTransform, Error(Display, Layer, const float*));
     MOCK_METHOD4(getDisplayedContentSamplingAttributes,
                  Error(Display, PixelFormat*, Dataspace*, uint8_t*));
+    MOCK_METHOD4(setDisplayContentSamplingEnabled, Error(Display, bool, uint8_t, uint64_t));
+    MOCK_METHOD4(getDisplayedContentSample,
+                 Error(Display, uint64_t, uint64_t, DisplayedFrameStats*));
     MOCK_METHOD2(getDisplayCapabilities, Error(Display, std::vector<DisplayCapability>*));
 };
 
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
index 34e71cb..9213ae5 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
@@ -18,7 +18,6 @@
 
 #include <gmock/gmock.h>
 
-#include <utils/String8.h>
 #include "Scheduler/DispSync.h"
 
 namespace android {
@@ -44,7 +43,7 @@
     MOCK_METHOD1(setIgnorePresentFences, void(bool));
     MOCK_METHOD0(expectedPresentTime, nsecs_t());
 
-    MOCK_CONST_METHOD1(dump, void(String8&));
+    MOCK_CONST_METHOD1(dump, void(std::string&));
 };
 
 } // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index ad2463d..0a1c827 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -32,7 +32,7 @@
     MOCK_METHOD0(onScreenReleased, void());
     MOCK_METHOD0(onScreenAcquired, void());
     MOCK_METHOD2(onHotplugReceived, void(DisplayType, bool));
-    MOCK_CONST_METHOD1(dump, void(String8&));
+    MOCK_CONST_METHOD1(dump, void(std::string&));
     MOCK_METHOD1(setPhaseOffset, void(nsecs_t phaseOffset));
 };
 
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
index a416808..11e5631 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
@@ -38,7 +38,7 @@
     MOCK_METHOD0(createFramebuffer, std::unique_ptr<Framebuffer>());
     MOCK_METHOD0(createImage, std::unique_ptr<renderengine::Image>());
     MOCK_CONST_METHOD0(primeCache, void());
-    MOCK_METHOD1(dump, void(String8&));
+    MOCK_METHOD1(dump, void(std::string&));
     MOCK_CONST_METHOD0(useNativeFenceSync, bool());
     MOCK_CONST_METHOD0(useWaitSync, bool());
     MOCK_CONST_METHOD0(isCurrent, bool());
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
index 0a59f29..7a7e437 100644
--- a/services/vr/bufferhubd/Android.bp
+++ b/services/vr/bufferhubd/Android.bp
@@ -14,7 +14,6 @@
 
 sharedLibraries = [
     "libbase",
-    "libbinder",
     "libbufferhubservice",
     "libcutils",
     "libgtest_prod",
@@ -30,12 +29,9 @@
     name: "libbufferhubd",
     srcs: [
         "buffer_channel.cpp",
-        "buffer_client.cpp",
         "buffer_hub.cpp",
-        "buffer_hub_binder.cpp",
         "consumer_channel.cpp",
         "consumer_queue_channel.cpp",
-        "IBufferHub.cpp",
         "producer_channel.cpp",
         "producer_queue_channel.cpp",
     ],
@@ -45,10 +41,7 @@
         "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
     ],
     export_include_dirs: ["include"],
-    header_libs: [
-        "libdvr_headers",
-        "libnativewindow_headers",
-    ],
+    header_libs: ["libdvr_headers"],
     shared_libs: sharedLibraries,
     static_libs: [
         "libbufferhub",
diff --git a/services/vr/bufferhubd/IBufferHub.cpp b/services/vr/bufferhubd/IBufferHub.cpp
deleted file mode 100644
index 5980873..0000000
--- a/services/vr/bufferhubd/IBufferHub.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-#include <log/log.h>
-#include <private/dvr/IBufferHub.h>
-
-namespace android {
-namespace dvr {
-
-class BpBufferHub : public BpInterface<IBufferHub> {
- public:
-  explicit BpBufferHub(const sp<IBinder>& impl)
-      : BpInterface<IBufferHub>(impl) {}
-
-  sp<IBufferClient> createBuffer(uint32_t width, uint32_t height,
-                                 uint32_t layer_count, uint32_t format,
-                                 uint64_t usage,
-                                 uint64_t user_metadata_size) override;
-
-  status_t importBuffer(uint64_t token, sp<IBufferClient>* outClient) override;
-};
-
-IMPLEMENT_META_INTERFACE(BufferHub, "android.dvr.IBufferHub");
-
-// Transaction code
-enum {
-  CREATE_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
-  IMPORT_BUFFER,
-};
-
-sp<IBufferClient> BpBufferHub::createBuffer(uint32_t width, uint32_t height,
-                                            uint32_t layer_count,
-                                            uint32_t format, uint64_t usage,
-                                            uint64_t user_metadata_size) {
-  Parcel data, reply;
-  status_t ret = OK;
-  ret |= data.writeInterfaceToken(IBufferHub::getInterfaceDescriptor());
-  ret |= data.writeUint32(width);
-  ret |= data.writeUint32(height);
-  ret |= data.writeUint32(layer_count);
-  ret |= data.writeUint32(format);
-  ret |= data.writeUint64(usage);
-  ret |= data.writeUint64(user_metadata_size);
-
-  if (ret != OK) {
-    ALOGE("BpBufferHub::createBuffer: failed to write into parcel");
-    return nullptr;
-  }
-
-  ret = remote()->transact(CREATE_BUFFER, data, &reply);
-  if (ret == OK) {
-    return interface_cast<IBufferClient>(reply.readStrongBinder());
-  } else {
-    ALOGE("BpBufferHub::createBuffer: failed to transact; errno=%d", ret);
-    return nullptr;
-  }
-}
-
-status_t BpBufferHub::importBuffer(uint64_t token,
-                                   sp<IBufferClient>* outClient) {
-  Parcel data, reply;
-  status_t ret = OK;
-  ret |= data.writeInterfaceToken(IBufferHub::getInterfaceDescriptor());
-  ret |= data.writeUint64(token);
-  if (ret != OK) {
-    ALOGE("BpBufferHub::importBuffer: failed to write into parcel");
-    return ret;
-  }
-
-  ret = remote()->transact(IMPORT_BUFFER, data, &reply);
-  if (ret == OK) {
-    *outClient = interface_cast<IBufferClient>(reply.readStrongBinder());
-    return OK;
-  } else {
-    ALOGE("BpBufferHub::importBuffer: failed to transact; errno=%d", ret);
-    return ret;
-  }
-}
-
-status_t BnBufferHub::onTransact(uint32_t code, const Parcel& data,
-                                 Parcel* reply, uint32_t flags) {
-  switch (code) {
-    case CREATE_BUFFER: {
-      CHECK_INTERFACE(IBufferHub, data, reply);
-      uint32_t width = data.readUint32();
-      uint32_t height = data.readUint32();
-      uint32_t layer_count = data.readUint32();
-      uint32_t format = data.readUint32();
-      uint64_t usage = data.readUint64();
-      uint64_t user_metadata_size = data.readUint64();
-      sp<IBufferClient> ret = createBuffer(width, height, layer_count, format,
-                                           usage, user_metadata_size);
-      return reply->writeStrongBinder(IInterface::asBinder(ret));
-    }
-    case IMPORT_BUFFER: {
-      CHECK_INTERFACE(IBufferHub, data, reply);
-      uint64_t token = data.readUint64();
-      sp<IBufferClient> client;
-      status_t ret = importBuffer(token, &client);
-      if (ret == OK) {
-        return reply->writeStrongBinder(IInterface::asBinder(client));
-      } else {
-        return ret;
-      }
-    }
-    default:
-      // Should not reach except binder defined transactions such as dumpsys
-      return BBinder::onTransact(code, data, reply, flags);
-  }
-}
-
-}  // namespace dvr
-}  // namespace android
\ No newline at end of file
diff --git a/services/vr/bufferhubd/buffer_client.cpp b/services/vr/bufferhubd/buffer_client.cpp
deleted file mode 100644
index f14faf7..0000000
--- a/services/vr/bufferhubd/buffer_client.cpp
+++ /dev/null
@@ -1,18 +0,0 @@
-#include <private/dvr/buffer_client.h>
-#include <private/dvr/buffer_hub_binder.h>
-
-namespace android {
-namespace dvr {
-
-status_t BufferClient::duplicate(uint64_t* outToken) {
-  if (!buffer_node_) {
-    // Should never happen
-    ALOGE("BufferClient::duplicate: node is missing.");
-    return UNEXPECTED_NULL;
-  }
-  return service_->registerToken(std::weak_ptr<BufferNode>(buffer_node_),
-                                 outToken);
-}
-
-}  // namespace dvr
-}  // namespace android
\ No newline at end of file
diff --git a/services/vr/bufferhubd/buffer_hub_binder.cpp b/services/vr/bufferhubd/buffer_hub_binder.cpp
deleted file mode 100644
index 580433e..0000000
--- a/services/vr/bufferhubd/buffer_hub_binder.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-#include <stdio.h>
-
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
-#include <log/log.h>
-#include <private/dvr/buffer_hub_binder.h>
-#include <private/dvr/buffer_node.h>
-
-namespace android {
-namespace dvr {
-
-status_t BufferHubBinderService::start(
-    const std::shared_ptr<BufferHubService>& pdx_service) {
-  IPCThreadState::self()->disableBackgroundScheduling(true);
-
-  sp<BufferHubBinderService> service = new BufferHubBinderService();
-  service->pdx_service_ = pdx_service;
-
-  // Not using BinderService::publish because need to get an instance of this
-  // class (above). Following code is the same as
-  // BinderService::publishAndJoinThreadPool
-  sp<IServiceManager> sm = defaultServiceManager();
-  status_t result = sm->addService(
-      String16(getServiceName()), service,
-      /*allowIsolated =*/false,
-      /*dump flags =*/IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);
-  if (result != OK) {
-    ALOGE("Publishing bufferhubd failed with error %d", result);
-    return result;
-  }
-
-  sp<ProcessState> process_self(ProcessState::self());
-  process_self->startThreadPool();
-
-  return result;
-}
-
-status_t BufferHubBinderService::dump(int fd, const Vector<String16>& args) {
-  FILE* out = fdopen(dup(fd), "w");
-
-  // Currently not supporting args, so notify the user.
-  if (!args.isEmpty()) {
-    fprintf(out,
-            "Note: dumpsys bufferhubd currently does not support args."
-            "Input arguments are ignored.\n");
-  }
-
-  fprintf(out, "Binder service:\n");
-  // Active buffers
-  fprintf(out, "Active BufferClients: %zu\n", client_list_.size());
-  // TODO(b/117790952): print buffer information after BufferNode has it
-  // TODO(b/116526156): print more information once we have them
-
-  if (pdx_service_) {
-    fprintf(out, "\nPDX service:\n");
-    // BufferHubService::Dumpstate(size_t) is not actually using the param
-    // So just using 0 as the length
-    fprintf(out, "%s", pdx_service_->DumpState(0).c_str());
-  } else {
-    fprintf(out, "PDX service not registered or died.\n");
-  }
-
-  fclose(out);
-  return OK;
-}
-
-status_t BufferHubBinderService::registerToken(
-    const std::weak_ptr<BufferNode> node, uint64_t* outToken) {
-  do {
-    *outToken = token_engine_();
-  } while (token_map_.find(*outToken) != token_map_.end());
-
-  token_map_.emplace(*outToken, node);
-  return OK;
-}
-
-sp<IBufferClient> BufferHubBinderService::createBuffer(
-    uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
-    uint64_t usage, uint64_t user_metadata_size) {
-  std::shared_ptr<BufferNode> node = std::make_shared<BufferNode>(
-      width, height, layer_count, format, usage, user_metadata_size);
-
-  sp<BufferClient> client = new BufferClient(node, this);
-  // Add it to list for bookkeeping and dumpsys.
-  client_list_.push_back(client);
-
-  return client;
-}
-
-status_t BufferHubBinderService::importBuffer(uint64_t token,
-                                              sp<IBufferClient>* outClient) {
-  auto iter = token_map_.find(token);
-
-  if (iter == token_map_.end()) {  // Not found
-    ALOGE("BufferHubBinderService::importBuffer: token %" PRIu64
-          "does not exist.",
-          token);
-    return PERMISSION_DENIED;
-  }
-
-  if (iter->second.expired()) {  // Gone
-    ALOGW(
-        "BufferHubBinderService::importBuffer: the original node of token "
-        "%" PRIu64 "has gone.",
-        token);
-    token_map_.erase(iter);
-    return DEAD_OBJECT;
-  }
-
-  // Promote the weak_ptr
-  std::shared_ptr<BufferNode> node(iter->second);
-  if (!node) {
-    ALOGE("BufferHubBinderService::importBuffer: promote weak_ptr failed.");
-    token_map_.erase(iter);
-    return DEAD_OBJECT;
-  }
-
-  sp<BufferClient> client = new BufferClient(node, this);
-  *outClient = client;
-
-  token_map_.erase(iter);
-  client_list_.push_back(client);
-
-  return OK;
-}
-
-}  // namespace dvr
-}  // namespace android
diff --git a/services/vr/bufferhubd/bufferhubd.cpp b/services/vr/bufferhubd/bufferhubd.cpp
index e44cc2a..50cb3b7 100644
--- a/services/vr/bufferhubd/bufferhubd.cpp
+++ b/services/vr/bufferhubd/bufferhubd.cpp
@@ -6,7 +6,6 @@
 #include <log/log.h>
 #include <pdx/service_dispatcher.h>
 #include <private/dvr/buffer_hub.h>
-#include <private/dvr/buffer_hub_binder.h>
 
 int main(int, char**) {
   int ret = -1;
@@ -40,10 +39,6 @@
   CHECK_ERROR(!pdx_service, error, "Failed to create bufferhub pdx service\n");
   dispatcher->AddService(pdx_service);
 
-  ret = android::dvr::BufferHubBinderService::start(pdx_service);
-  CHECK_ERROR(ret != android::OK, error,
-              "Failed to create bufferhub binder service\n");
-
   ret = dvrSetSchedulerClass(0, "graphics");
   CHECK_ERROR(ret < 0, error, "Failed to set thread priority");
 
diff --git a/services/vr/bufferhubd/include/private/dvr/IBufferHub.h b/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
deleted file mode 100644
index 502c6d6..0000000
--- a/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef ANDROID_DVR_IBUFFERHUB_H
-#define ANDROID_DVR_IBUFFERHUB_H
-
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-#include <private/dvr/IBufferClient.h>
-
-namespace android {
-namespace dvr {
-
-class IBufferHub : public IInterface {
- public:
-  DECLARE_META_INTERFACE(BufferHub);
-
-  static const char* getServiceName() { return "bufferhubd"; }
-  virtual sp<IBufferClient> createBuffer(uint32_t width, uint32_t height,
-                                         uint32_t layer_count, uint32_t format,
-                                         uint64_t usage,
-                                         uint64_t user_metadata_size) = 0;
-
-  virtual status_t importBuffer(uint64_t token,
-                                sp<IBufferClient>* outClient) = 0;
-};
-
-class BnBufferHub : public BnInterface<IBufferHub> {
- public:
-  virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
-                              uint32_t flags = 0);
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_IBUFFERHUB_H
\ No newline at end of file
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_client.h b/services/vr/bufferhubd/include/private/dvr/buffer_client.h
deleted file mode 100644
index d79ec0a..0000000
--- a/services/vr/bufferhubd/include/private/dvr/buffer_client.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef ANDROID_DVR_BUFFERCLIENT_H
-#define ANDROID_DVR_BUFFERCLIENT_H
-
-#include <private/dvr/IBufferClient.h>
-#include <private/dvr/buffer_node.h>
-
-namespace android {
-namespace dvr {
-
-// Forward declaration to avoid circular dependency
-class BufferHubBinderService;
-
-class BufferClient : public BnBufferClient {
- public:
-  // Creates a server-side buffer client from an existing BufferNode. Note that
-  // this funciton takes ownership of the shared_ptr.
-  explicit BufferClient(std::shared_ptr<BufferNode> node,
-                        BufferHubBinderService* service)
-      : service_(service), buffer_node_(std::move(node)){};
-
-  // Binder IPC functions
-  bool isValid() override {
-    return buffer_node_ ? buffer_node_->IsValid() : false;
-  };
-
-  status_t duplicate(uint64_t* outToken) override;
-
- private:
-  // Hold a pointer to the service to bypass binder interface, as BufferClient
-  // and the service will be in the same process. Also, since service owns
-  // Client, if service dead the clients will be destroyed, so this pointer is
-  // guaranteed to be valid.
-  BufferHubBinderService* service_;
-
-  std::shared_ptr<BufferNode> buffer_node_;
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_IBUFFERCLIENT_H
\ No newline at end of file
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h b/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
deleted file mode 100644
index cf6124b..0000000
--- a/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef ANDROID_DVR_BUFFER_HUB_BINDER_H
-#define ANDROID_DVR_BUFFER_HUB_BINDER_H
-
-#include <random>
-#include <unordered_map>
-#include <vector>
-
-#include <binder/BinderService.h>
-#include <private/dvr/IBufferHub.h>
-#include <private/dvr/buffer_client.h>
-#include <private/dvr/buffer_hub.h>
-#include <private/dvr/buffer_node.h>
-
-namespace android {
-namespace dvr {
-
-class BufferHubBinderService : public BinderService<BufferHubBinderService>,
-                               public BnBufferHub {
- public:
-  static status_t start(const std::shared_ptr<BufferHubService>& pdx_service);
-  // Dumps bufferhub related information to given fd (usually stdout)
-  // usage: adb shell dumpsys bufferhubd
-  virtual status_t dump(int fd, const Vector<String16>& args) override;
-
-  // Marks a BufferNode to be duplicated.
-  // TODO(b/116681016): add importToken(int64_t)
-  status_t registerToken(const std::weak_ptr<BufferNode> node,
-                         uint64_t* outToken);
-
-  // Binder IPC functions
-  sp<IBufferClient> createBuffer(uint32_t width, uint32_t height,
-                                 uint32_t layer_count, uint32_t format,
-                                 uint64_t usage,
-                                 uint64_t user_metadata_size) override;
-
-  status_t importBuffer(uint64_t token, sp<IBufferClient>* outClient) override;
-
- private:
-  std::shared_ptr<BufferHubService> pdx_service_;
-
-  std::vector<sp<BufferClient>> client_list_;
-
-  // TODO(b/118180214): use a more secure implementation
-  std::mt19937_64 token_engine_;
-  // The mapping from token to a specific node. This is a many-to-one mapping.
-  // One node could be refered by 0 to multiple tokens.
-  std::unordered_map<uint64_t, std::weak_ptr<BufferNode>> token_map_;
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_BUFFER_HUB_BINDER_H
diff --git a/services/vr/bufferhubd/tests/Android.bp b/services/vr/bufferhubd/tests/Android.bp
deleted file mode 100644
index a611268..0000000
--- a/services/vr/bufferhubd/tests/Android.bp
+++ /dev/null
@@ -1,26 +0,0 @@
-cc_test {
-    name: "buffer_hub_binder_service-test",
-    srcs: ["buffer_hub_binder_service-test.cpp"],
-    cflags: [
-        "-DLOG_TAG=\"buffer_hub_binder_service-test\"",
-        "-DTRACE=0",
-        "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
-    ],
-    header_libs: ["libdvr_headers"],
-    static_libs: [
-        "libbufferhub",
-        "libbufferhubd",
-        "libgmock",
-    ],
-    shared_libs: [
-        "libbase",
-        "libbinder",
-        "liblog",
-        "libpdx_default_transport",
-        "libui",
-        "libutils",
-    ],
-
-    // TODO(b/117568153): Temporarily opt out using libcrt.
-    no_libcrt: true,
-}
diff --git a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp b/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
deleted file mode 100644
index 94b422a..0000000
--- a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-#include <binder/IServiceManager.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <private/dvr/IBufferClient.h>
-#include <private/dvr/IBufferHub.h>
-#include <ui/PixelFormat.h>
-
-namespace android {
-namespace dvr {
-
-namespace {
-
-using testing::IsNull;
-using testing::NotNull;
-
-const int kWidth = 640;
-const int kHeight = 480;
-const int kLayerCount = 1;
-const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
-const int kUsage = 0;
-const size_t kUserMetadataSize = 0;
-
-class BufferHubBinderServiceTest : public ::testing::Test {
- protected:
-  void SetUp() override {
-    status_t ret = getService<IBufferHub>(
-        String16(IBufferHub::getServiceName()), &service);
-    ASSERT_EQ(ret, OK);
-    ASSERT_THAT(service, NotNull());
-  }
-
-  sp<IBufferHub> service;
-};
-
-TEST_F(BufferHubBinderServiceTest, TestCreateBuffer) {
-  sp<IBufferClient> bufferClient = service->createBuffer(
-      kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize);
-  ASSERT_THAT(bufferClient, NotNull());
-  EXPECT_TRUE(bufferClient->isValid());
-}
-
-TEST_F(BufferHubBinderServiceTest, TestDuplicateAndImportBuffer) {
-  sp<IBufferClient> bufferClient = service->createBuffer(
-      kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize);
-  ASSERT_THAT(bufferClient, NotNull());
-  EXPECT_TRUE(bufferClient->isValid());
-
-  uint64_t token1 = 0ULL;
-  status_t ret = bufferClient->duplicate(&token1);
-  EXPECT_EQ(ret, OK);
-
-  // Tokens should be unique even corresponding to the same buffer
-  uint64_t token2 = 0ULL;
-  ret = bufferClient->duplicate(&token2);
-  EXPECT_EQ(ret, OK);
-  EXPECT_NE(token2, token1);
-
-  sp<IBufferClient> bufferClient1;
-  ret = service->importBuffer(token1, &bufferClient1);
-  EXPECT_EQ(ret, OK);
-  ASSERT_THAT(bufferClient1, NotNull());
-  EXPECT_TRUE(bufferClient1->isValid());
-
-  // Consumes the token to keep the service clean
-  sp<IBufferClient> bufferClient2;
-  ret = service->importBuffer(token2, &bufferClient2);
-  EXPECT_EQ(ret, OK);
-  ASSERT_THAT(bufferClient2, NotNull());
-  EXPECT_TRUE(bufferClient2->isValid());
-}
-
-TEST_F(BufferHubBinderServiceTest, TestImportUnexistingToken) {
-  // There is very little chance that this test fails if there is a token = 0
-  // in the service.
-  uint64_t unexistingToken = 0ULL;
-  sp<IBufferClient> bufferClient;
-  status_t ret = service->importBuffer(unexistingToken, &bufferClient);
-  EXPECT_EQ(ret, PERMISSION_DENIED);
-  EXPECT_THAT(bufferClient, IsNull());
-}
-
-}  // namespace
-
-}  // namespace dvr
-}  // namespace android
\ No newline at end of file
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index e4c50d5..09db37a 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -524,8 +524,8 @@
 @extension("VK_NV_shading_rate_image") define VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME "VK_NV_shading_rate_image"
 
 // 166
-@extension("VK_NV_raytracing") define VK_NV_RAYTRACING_SPEC_VERSION 2
-@extension("VK_NV_raytracing") define VK_NV_RAYTRACING_EXTENSION_NAME "VK_NV_raytracing"
+@extension("VK_NV_ray_tracing") define VK_NV_RAY_TRACING_SPEC_VERSION 3
+@extension("VK_NV_ray_tracing") define VK_NV_RAY_TRACING_EXTENSION_NAME "VK_NV_ray_tracing"
 
 // 167
 @extension("VK_NV_representative_fragment_test") define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_SPEC_VERSION 1
@@ -703,7 +703,7 @@
 @extension("VK_EXT_validation_cache") @nonDispatchHandle type u64 VkValidationCacheEXT
 
 // 166
-@extension("VK_NV_raytracing") @nonDispatchHandle type u64 VkAccelerationStructureNV
+@extension("VK_NV_ray_tracing") @nonDispatchHandle type u64 VkAccelerationStructureNV
 
 /////////////
 //  Enums  //
@@ -804,7 +804,7 @@
     //@extension("VK_EXT_inline_uniform_block") // 139
     VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT             = 1000138000,
 
-    //@extension("VK_NV_raytracing") // 166
+    //@extension("VK_NV_ray_tracing") // 166
     VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV            = 1000165000,
 }
 
@@ -816,7 +816,7 @@
     //@extension("VK_EXT_transform_feedback") // 29
     VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT             = 1000028004,
 
-    //@extension("VK_NV_raytracing") // 166
+    //@extension("VK_NV_ray_tracing") // 166
     VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV  = 1000165000,
 }
 
@@ -833,7 +833,7 @@
     VK_PIPELINE_BIND_POINT_GRAPHICS                         = 0x00000000,
     VK_PIPELINE_BIND_POINT_COMPUTE                          = 0x00000001,
 
-    //@extension("VK_NV_raytracing") // 166
+    //@extension("VK_NV_ray_tracing") // 166
     VK_PIPELINE_BIND_POINT_RAY_TRACING_NV                   = 1000165000,
 }
 
@@ -860,7 +860,7 @@
     VK_INDEX_TYPE_UINT16                                    = 0x00000000,
     VK_INDEX_TYPE_UINT32                                    = 0x00000001,
 
-    //@extension("VK_NV_raytracing") // 166
+    //@extension("VK_NV_ray_tracing") // 166
     VK_INDEX_TYPE_NONE_NV                                   = 1000165000,
 }
 
@@ -1796,7 +1796,7 @@
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV = 1000164002,
     VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV = 1000164005,
 
-    //@extension("VK_NV_raytracing") // 166
+    //@extension("VK_NV_ray_tracing") // 166
     VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV                   = 1000165000,
     VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV                 = 1000165001,
     VK_STRUCTURE_TYPE_GEOMETRY_NV                                           = 1000165003,
@@ -2030,7 +2030,7 @@
     //@extension("VK_EXT_validation_cache") // 161
     VK_OBJECT_TYPE_VALIDATION_CACHE_EXT                     = 1000160000,
 
-    //@extension("VK_NV_raytracing") // 166
+    //@extension("VK_NV_ray_tracing") // 166
     VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV                = 1000165000,
 }
 
@@ -2154,7 +2154,7 @@
     //@extension("VK_KHR_sampler_ycbcr_conversion") // 157
     VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT = 1000156000,
 
-    //@extension("VK_NV_raytracing") // 166
+    //@extension("VK_NV_ray_tracing") // 166
     VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT   = 1000165000,
 }
 
@@ -2330,32 +2330,32 @@
     VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV             = 3,
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 enum VkRayTracingShaderGroupTypeNV {
     VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV                 = 0,
     VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV     = 1,
     VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV    = 2,
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 enum VkGeometryTypeNV {
     VK_GEOMETRY_TYPE_TRIANGLES_NV                           = 0,
     VK_GEOMETRY_TYPE_AABBS_NV                               = 1,
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 enum VkAccelerationStructureTypeNV {
     VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV             = 0,
     VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV          = 1,
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 enum VkCopyAccelerationStructureModeNV {
     VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV            = 0,
     VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV          = 1,
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 enum VkAccelerationStructureMemoryRequirementsTypeNV {
     VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV            = 0,
     VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV     = 1,
@@ -2474,7 +2474,7 @@
     //@extension("VK_NV_shading_rate_image") // 165
     VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV                = 0x00800000,
 
-    //@extension("VK_NV_raytracing") // 166
+    //@extension("VK_NV_ray_tracing") // 166
     VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV            = 0x00200000,
     VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV           = 0x00400000,
 
@@ -2500,7 +2500,7 @@
     //@extension("VK_EXT_conditional_rendering") // 82
     VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT           = 0x00000200,
 
-    //@extension("VK_NV_raytracing") // 166
+    //@extension("VK_NV_ray_tracing") // 166
     VK_BUFFER_USAGE_RAY_TRACING_BIT_NV                      = 0x00000400,
 
     //@extension("VK_EXT_transform_feedback") // 29
@@ -2532,7 +2532,7 @@
 
     VK_SHADER_STAGE_ALL                                     = 0x7FFFFFFF,
 
-    //@extension("VK_NV_raytracing") // 166
+    //@extension("VK_NV_ray_tracing") // 166
     VK_SHADER_STAGE_RAYGEN_BIT_NV                           = 0x00000100,
     VK_SHADER_STAGE_ANY_HIT_BIT_NV                          = 0x00000200,
     VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV                      = 0x00000400,
@@ -2636,7 +2636,7 @@
     VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = 0x00000008,
     VK_PIPELINE_CREATE_DISPATCH_BASE_KHR                    = 0x00000010,
 
-    //@extension("VK_NV_raytracing") // 166
+    //@extension("VK_NV_ray_tracing") // 166
     VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NV                 = 0x00000020,
 }
 
@@ -2832,7 +2832,7 @@
     //@extension("VK_NV_shading_rate_image") // 165
     VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV             = 0x00400000,
 
-    //@extension("VK_NV_raytracing") // 166
+    //@extension("VK_NV_ray_tracing") // 166
     VK_PIPELINE_STAGE_RAY_TRACING_BIT_NV                    = 0x00200000,
     VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV   = 0x02000000,
 
@@ -2842,6 +2842,9 @@
 
     //@extension("VK_EXT_transform_feedback") // 29
     VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT            = 0x01000000,
+
+    //@extension("VK_NV_ray_tracing") // 166
+    VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV   = 0x02000000,
 }
 
 /// Render pass attachment description flags
@@ -3520,17 +3523,17 @@
     VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT     = 0x00000008,
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 type VkFlags VkGeometryFlagsNV
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 bitfield VkGeometryFlagBitsNV {
     VK_GEOMETRY_OPAQUE_BIT_NV                           = 0x00000001,
     VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NV  = 0x00000002,
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 type VkFlags VkGeometryInstanceFlagsNV
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 bitfield VkGeometryInstanceFlagBitsNV {
     VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV           = 0x00000001,
     VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_NV = 0x00000002,
@@ -3538,9 +3541,9 @@
     VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NV                 = 0x00000008,
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 type VkFlags VkBuildAccelerationStructureFlagsNV
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 bitfield VkBuildAccelerationStructureFlagBitsNV {
     VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV         = 0x00000001,
     VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV     = 0x00000002,
@@ -7276,7 +7279,7 @@
     const VkCoarseSampleOrderCustomNV*              pCustomSampleOrders
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 class VkRayTracingShaderGroupCreateInfoNV {
     VkStructureType                  sType
     const void*                      pNext
@@ -7287,7 +7290,7 @@
     u32                              intersectionShader
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 class VkRayTracingPipelineCreateInfoNV {
     VkStructureType                               sType
     const void*                                   pNext
@@ -7302,7 +7305,7 @@
     s32                                           basePipelineIndex
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 class VkGeometryTrianglesNV {
     VkStructureType                                 sType
     const void*                                     pNext
@@ -7319,7 +7322,7 @@
     VkDeviceSize                                    transformOffset
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 class VkGeometryAABBNV {
     VkStructureType                                 sType
     const void*                                     pNext
@@ -7329,13 +7332,13 @@
     VkDeviceSize                                    offset
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 class VkGeometryDataNV {
     VkGeometryTrianglesNV                           triangles
     VkGeometryAABBNV                                aabbs
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 class VkGeometryNV {
     VkStructureType                                 sType
     const void*                                     pNext
@@ -7344,7 +7347,7 @@
     VkGeometryFlagsNV                               flags
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 class VkAccelerationStructureInfoNV {
     VkStructureType                                 sType
     const void*                                     pNext
@@ -7355,7 +7358,7 @@
     const VkGeometryNV*                             pGeometries
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 class VkAccelerationStructureCreateInfoNV {
     VkStructureType                                 sType
     const void*                                     pNext
@@ -7363,7 +7366,7 @@
     VkAccelerationStructureInfoNV                   info
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 class VkBindAccelerationStructureMemoryInfoNV {
     VkStructureType                                 sType
     const void*                                     pNext
@@ -7374,7 +7377,7 @@
     const u32*                                      pDeviceIndices
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 class VkDescriptorAccelerationStructureInfoNV {
     VkStructureType                                 sType
     const void*                                     pNext
@@ -7382,7 +7385,7 @@
     const VkAccelerationStructureNV*                pAccelerationStructures
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 class VkAccelerationStructureMemoryRequirementsInfoNV {
     VkStructureType                                 sType
     const void*                                     pNext
@@ -7390,7 +7393,7 @@
     VkAccelerationStructureNV                       accelerationStructure
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 class VkPhysicalDeviceRaytracingPropertiesNV {
     VkStructureType                                 sType
     void*                                           pNext
@@ -11502,7 +11505,7 @@
         const VkCoarseSampleOrderCustomNV*          pCustomSampleOrders) {
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 cmd VkResult vkCreateAccelerationStructureNV(
         VkDevice                                    device,
         const VkAccelerationStructureCreateInfoNV*  pCreateInfo,
@@ -11511,21 +11514,21 @@
     return ?
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 cmd void vkDestroyAccelerationStructureNV(
         VkDevice                                    device,
         VkAccelerationStructureNV                   accelerationStructure,
         const VkAllocationCallbacks*                pAllocator) {
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 cmd void vkGetAccelerationStructureMemoryRequirementsNV(
         VkDevice                                                device,
         const VkAccelerationStructureMemoryRequirementsInfoNV*  pInfo,
         VkMemoryRequirements2KHR*                               pMemoryRequirements) {
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 cmd VkResult vkBindAccelerationStructureMemoryNV(
         VkDevice                                        device,
         u32                                             bindInfoCount,
@@ -11533,7 +11536,7 @@
     return ?
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 cmd void vkCmdBuildAccelerationStructureNV(
         VkCommandBuffer                             commandBuffer,
         const VkAccelerationStructureInfoNV*        pInfo,
@@ -11546,7 +11549,7 @@
         VkDeviceSize                                scratchOffset) {
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 cmd void vkCmdCopyAccelerationStructureNV(
         VkCommandBuffer                             commandBuffer,
         VkAccelerationStructureNV                   dst,
@@ -11554,7 +11557,7 @@
         VkCopyAccelerationStructureModeNV           mode) {
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 cmd void vkCmdTraceRaysNV(
         VkCommandBuffer                             commandBuffer,
         VkBuffer                                    raygenShaderBindingTableBuffer,
@@ -11573,7 +11576,7 @@
         u32                                         depth) {
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 cmd VkResult vkCreateRaytracingPipelinesNV(
         VkDevice                                    device,
         VkPipelineCache                             pipelineCache,
@@ -11584,7 +11587,7 @@
     return ?
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 cmd VkResult vkGetRaytracingShaderHandlesNV(
         VkDevice                                    device,
         VkPipeline                                  pipeline,
@@ -11595,7 +11598,7 @@
     return ?
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 cmd VkResult vkGetAccelerationStructureHandleNV(
         VkDevice                                    device,
         VkAccelerationStructureNV                   accelerationStructure,
@@ -11604,7 +11607,7 @@
     return ?
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 cmd void vkCmdWriteAccelerationStructurePropertiesNV(
         VkCommandBuffer                             commandBuffer,
         u32                                         accelerationStructureCount,
@@ -11614,7 +11617,7 @@
         u32                                         firstQuery) {
 }
 
-@extension("VK_NV_raytracing") // 166
+@extension("VK_NV_ray_tracing") // 166
 cmd VkResult vkCompileDeferredNV(
         VkDevice                                    device,
         VkPipeline                                  pipeline,