Merge "add function to traversal the crates"
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 9e3520d..f8a68b4 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -31,6 +31,7 @@
 #include <sys/file.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
+#include <sys/mount.h>
 #include <sys/resource.h>
 #include <sys/stat.h>
 #include <sys/statvfs.h>
@@ -87,6 +88,9 @@
 static constexpr const char* kCpPath = "/system/bin/cp";
 static constexpr const char* kXattrDefault = "user.default";
 
+static constexpr const char* kDataMirrorCePath = "/data_mirror/data_ce";
+static constexpr const char* kDataMirrorDePath = "/data_mirror/data_de";
+
 static constexpr const int MIN_RESTRICTED_HOME_SDK_VERSION = 24; // > M
 
 static constexpr const char* PKG_LIB_POSTFIX = "/lib";
@@ -100,6 +104,13 @@
 static constexpr const char* kPropApkVerityMode = "ro.apk_verity.mode";
 static constexpr const char* kFuseProp = "persist.sys.fuse";
 
+/**
+ * Property to control if app data isolation is enabled.
+ */
+static constexpr const char* kAppDataIsolationEnabledProperty = "persist.zygote.app_data_isolation";
+
+static std::atomic<bool> sAppDataIsolationEnabled(false);
+
 namespace {
 
 constexpr const char* kDump = "android.permission.DUMP";
@@ -259,6 +270,8 @@
     sp<ProcessState> ps(ProcessState::self());
     ps->startThreadPool();
     ps->giveThreadPoolName();
+    sAppDataIsolationEnabled = android::base::GetBoolProperty(
+            kAppDataIsolationEnabledProperty, false);
     return android::OK;
 }
 
@@ -451,9 +464,12 @@
 
         // And return the CE inode of the top-level data directory so we can
         // clear contents while CE storage is locked
-        if ((_aidl_return != nullptr)
-                && get_path_inode(path, reinterpret_cast<ino_t*>(_aidl_return)) != 0) {
-            return error("Failed to get_path_inode for " + path);
+        if (_aidl_return != nullptr) {
+            ino_t result;
+            if (get_path_inode(path, &result) != 0) {
+                return error("Failed to get_path_inode for " + path);
+            }
+            *_aidl_return = static_cast<uint64_t>(result);
         }
     }
     if (flags & FLAG_STORAGE_DE) {
@@ -2690,6 +2706,89 @@
     return ok();
 }
 
+// Mount volume's CE and DE storage to mirror
+binder::Status InstalldNativeService::onPrivateVolumeMounted(
+        const std::unique_ptr<std::string>& uuid) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(uuid);
+    if (!sAppDataIsolationEnabled) {
+        return ok();
+    }
+    if (!uuid) {
+        return error("Should not happen, mounting uuid == null");
+    }
+
+    const char* uuid_ = uuid->c_str();
+    // Mount CE mirror
+    std::string mirrorVolCePath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_));
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+    if (fs_prepare_dir(mirrorVolCePath.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
+        return error("Failed to create CE mirror");
+    }
+    auto cePath = StringPrintf("%s/user_ce", create_data_path(uuid_).c_str());
+    if (TEMP_FAILURE_RETRY(mount(cePath.c_str(), mirrorVolCePath.c_str(), NULL,
+            MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC, nullptr)) == -1) {
+        return error("Failed to mount " + mirrorVolCePath);
+    }
+
+    // Mount DE mirror
+    std::string mirrorVolDePath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_));
+    if (fs_prepare_dir(mirrorVolDePath.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
+        return error("Failed to create DE mirror");
+    }
+    auto dePath = StringPrintf("%s/user_de", create_data_path(uuid_).c_str());
+    if (TEMP_FAILURE_RETRY(mount(dePath.c_str(), mirrorVolDePath.c_str(), NULL,
+            MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC, nullptr)) == -1) {
+        return error("Failed to mount " + mirrorVolDePath);
+    }
+    return ok();
+}
+
+// Unmount volume's CE and DE storage from mirror
+binder::Status InstalldNativeService::onPrivateVolumeRemoved(
+        const std::unique_ptr<std::string>& uuid) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_UUID(uuid);
+    if (!sAppDataIsolationEnabled) {
+        return ok();
+    }
+    if (!uuid) {
+        // It happens when private volume failed to mount.
+        LOG(INFO) << "Ignore unmount uuid=null";
+        return ok();
+    }
+    const char* uuid_ = uuid->c_str();
+
+    binder::Status res = ok();
+
+    std::string mirrorCeVolPath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_));
+    std::string mirrorDeVolPath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_));
+
+    // Unmount CE storage
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+    if (TEMP_FAILURE_RETRY(umount(mirrorCeVolPath.c_str())) != 0) {
+        if (errno != ENOENT) {
+            res = error(StringPrintf("Failed to umount %s %s", mirrorCeVolPath.c_str(),
+                                strerror(errno)));
+        }
+    }
+    if (delete_dir_contents_and_dir(mirrorCeVolPath, true) != 0) {
+        res = error("Failed to delete " + mirrorCeVolPath);
+    }
+
+    // Unmount DE storage
+    if (TEMP_FAILURE_RETRY(umount(mirrorDeVolPath.c_str())) != 0) {
+        if (errno != ENOENT) {
+            res = error(StringPrintf("Failed to umount %s %s", mirrorDeVolPath.c_str(),
+                                strerror(errno)));
+        }
+    }
+    if (delete_dir_contents_and_dir(mirrorDeVolPath, true) != 0) {
+        res = error("Failed to delete " + mirrorDeVolPath);
+    }
+    return res;
+}
+
 std::string InstalldNativeService::findDataMediaPath(
         const std::unique_ptr<std::string>& uuid, userid_t userid) {
     std::lock_guard<std::recursive_mutex> lock(mMountsLock);
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index aff3733..bf11002 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -156,6 +156,8 @@
     binder::Status invalidateMounts();
     binder::Status isQuotaSupported(const std::unique_ptr<std::string>& volumeUuid,
             bool* _aidl_return);
+    binder::Status onPrivateVolumeMounted(const std::unique_ptr<std::string>& volumeUuid);
+    binder::Status onPrivateVolumeRemoved(const std::unique_ptr<std::string>& volumeUuid);
 
     binder::Status prepareAppProfile(const std::string& packageName,
             int32_t userId, int32_t appId, const std::string& profileName,
diff --git a/cmds/installd/QuotaUtils.cpp b/cmds/installd/QuotaUtils.cpp
index b238dd3..a71e01c 100644
--- a/cmds/installd/QuotaUtils.cpp
+++ b/cmds/installd/QuotaUtils.cpp
@@ -61,6 +61,10 @@
         std::getline(in, target, ' ');
         std::getline(in, ignored);
 
+        if (target.compare(0, 13, "/data_mirror/") == 0) {
+            continue;
+        }
+
         if (source.compare(0, 11, "/dev/block/") == 0) {
             struct dqblk dq;
             if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0,
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index f6a4530..891b26d 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -117,6 +117,8 @@
             int appId, @utf8InCpp String seInfo, int user, int snapshotId, int storageflags);
     void destroyAppDataSnapshot(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
             int userId, long ceSnapshotInode, int snapshotId, int storageFlags);
+    void onPrivateVolumeMounted(@nullable @utf8InCpp String volumeUuid);
+    void onPrivateVolumeRemoved(@nullable @utf8InCpp String volumeUuid);
 
     void migrateLegacyObbData();
 
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
index 7871667..2ef97a3 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
@@ -421,13 +421,41 @@
 }
 
 /**
+ * Convenience API for writing a non-null parcelable.
+ */
+template <typename P>
+static inline binder_status_t AParcel_writeParcelable(AParcel* parcel, const P& p) {
+    binder_status_t status = AParcel_writeInt32(parcel, 1);  // non-null
+    if (status != STATUS_OK) {
+        return status;
+    }
+    return p.writeToParcel(parcel);
+}
+
+/**
+ * Convenience API for reading a non-null parcelable.
+ */
+template <typename P>
+static inline binder_status_t AParcel_readParcelable(const AParcel* parcel, P* p) {
+    int32_t null;
+    binder_status_t status = AParcel_readInt32(parcel, &null);
+    if (status != STATUS_OK) {
+        return status;
+    }
+    if (null == 0) {
+        return STATUS_UNEXPECTED_NULL;
+    }
+    return p->readFromParcel(parcel);
+}
+
+/**
  * Writes a parcelable object of type P inside a std::vector<P> at index 'index' to 'parcel'.
  */
 template <typename P>
 binder_status_t AParcel_writeStdVectorParcelableElement(AParcel* parcel, const void* vectorData,
                                                         size_t index) {
     const std::vector<P>* vector = static_cast<const std::vector<P>*>(vectorData);
-    return vector->at(index).writeToParcel(parcel);
+    return AParcel_writeParcelable(parcel, vector->at(index));
 }
 
 /**
@@ -437,7 +465,7 @@
 binder_status_t AParcel_readStdVectorParcelableElement(const AParcel* parcel, void* vectorData,
                                                        size_t index) {
     std::vector<P>* vector = static_cast<std::vector<P>*>(vectorData);
-    return vector->at(index).readFromParcel(parcel);
+    return AParcel_readParcelable(parcel, &vector->at(index));
 }
 
 /**
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 34254e0..4f96ad3 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -62,8 +62,11 @@
 
 class ComposerCallbackBridge : public Hwc2::IComposerCallback {
 public:
-    ComposerCallbackBridge(ComposerCallback* callback, int32_t sequenceId)
-            : mCallback(callback), mSequenceId(sequenceId) {}
+    ComposerCallbackBridge(ComposerCallback* callback, int32_t sequenceId,
+                           bool vsyncSwitchingSupported)
+          : mCallback(callback),
+            mSequenceId(sequenceId),
+            mVsyncSwitchingSupported(vsyncSwitchingSupported) {}
 
     Return<void> onHotplug(Hwc2::Display display,
                            IComposerCallback::Connection conn) override
@@ -81,15 +84,23 @@
 
     Return<void> onVsync(Hwc2::Display display, int64_t timestamp) override
     {
-        mCallback->onVsyncReceived(mSequenceId, display, timestamp, std::nullopt);
+        if (!mVsyncSwitchingSupported) {
+            mCallback->onVsyncReceived(mSequenceId, display, timestamp, std::nullopt);
+        } else {
+            ALOGW("Unexpected onVsync callback on composer >= 2.4, ignoring.");
+        }
         return Void();
     }
 
     Return<void> onVsync_2_4(Hwc2::Display display, int64_t timestamp,
                              Hwc2::VsyncPeriodNanos vsyncPeriodNanos) override {
-        // TODO(b/140201379): use vsyncPeriodNanos in the new DispSync
-        mCallback->onVsyncReceived(mSequenceId, display, timestamp,
-                                   std::make_optional(vsyncPeriodNanos));
+        if (mVsyncSwitchingSupported) {
+            // TODO(b/140201379): use vsyncPeriodNanos in the new DispSync
+            mCallback->onVsyncReceived(mSequenceId, display, timestamp,
+                                       std::make_optional(vsyncPeriodNanos));
+        } else {
+            ALOGW("Unexpected onVsync_2_4 callback on composer <= 2.3, ignoring.");
+        }
         return Void();
     }
 
@@ -107,6 +118,7 @@
 private:
     ComposerCallback* mCallback;
     int32_t mSequenceId;
+    const bool mVsyncSwitchingSupported;
 };
 
 } // namespace anonymous
@@ -126,7 +138,8 @@
     }
     mRegisteredCallback = true;
     sp<ComposerCallbackBridge> callbackBridge(
-            new ComposerCallbackBridge(callback, sequenceId));
+            new ComposerCallbackBridge(callback, sequenceId,
+                                       mComposer->isVsyncPeriodSwitchSupported()));
     mComposer->registerCallback(callbackBridge);
 }
 
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 38a80a7..6598bd8 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -18,26 +18,139 @@
 #include "Client.h"
 #include "Layer.h"
 
+#include <gui/IProducerListener.h>
+
+#undef LOG_TAG
+#define LOG_TAG "RefreshRateOverlay"
+
 namespace android {
 
+void RefreshRateOverlay::SevenSegmentDrawer::drawRect(const Rect& r, const half4& color,
+                                                      const sp<GraphicBuffer>& buffer,
+                                                      uint8_t* pixels) {
+    for (int32_t j = r.top; j < r.bottom; j++) {
+        if (j >= buffer->getHeight()) {
+            break;
+        }
+
+        for (int32_t i = r.left; i < r.right; i++) {
+            if (i >= buffer->getWidth()) {
+                break;
+            }
+
+            uint8_t* iter = pixels + 4 * (i + (buffer->getStride() * j));
+            iter[0] = uint8_t(color.r * 255);
+            iter[1] = uint8_t(color.g * 255);
+            iter[2] = uint8_t(color.b * 255);
+            iter[3] = uint8_t(color.a * 255);
+        }
+    }
+}
+
+void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left,
+                                                         const half4& color,
+                                                         const sp<GraphicBuffer>& buffer,
+                                                         uint8_t* pixels) {
+    const Rect rect = [&]() {
+        switch (segment) {
+            case Segment::Upper:
+                return Rect(left, 0, left + DIGIT_WIDTH, DIGIT_SPACE);
+            case Segment::UpperLeft:
+                return Rect(left, 0, left + DIGIT_SPACE, DIGIT_HEIGHT / 2);
+            case Segment::UpperRight:
+                return Rect(left + DIGIT_WIDTH - DIGIT_SPACE, 0, left + DIGIT_WIDTH,
+                            DIGIT_HEIGHT / 2);
+            case Segment::Middle:
+                return Rect(left, DIGIT_HEIGHT / 2 - DIGIT_SPACE / 2, left + DIGIT_WIDTH,
+                            DIGIT_HEIGHT / 2 + DIGIT_SPACE / 2);
+            case Segment::LowerLeft:
+                return Rect(left, DIGIT_HEIGHT / 2, left + DIGIT_SPACE, DIGIT_HEIGHT);
+            case Segment::LowerRight:
+                return Rect(left + DIGIT_WIDTH - DIGIT_SPACE, DIGIT_HEIGHT / 2, left + DIGIT_WIDTH,
+                            DIGIT_HEIGHT);
+            case Segment::Buttom:
+                return Rect(left, DIGIT_HEIGHT - DIGIT_SPACE, left + DIGIT_WIDTH, DIGIT_HEIGHT);
+        }
+    }();
+
+    drawRect(rect, color, buffer, pixels);
+}
+
+void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, const half4& color,
+                                                       const sp<GraphicBuffer>& buffer,
+                                                       uint8_t* pixels) {
+    if (digit < 0 || digit > 9) return;
+
+    if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 7 ||
+        digit == 8 || digit == 9)
+        drawSegment(Segment::Upper, left, color, buffer, pixels);
+    if (digit == 0 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || digit == 9)
+        drawSegment(Segment::UpperLeft, left, color, buffer, pixels);
+    if (digit == 0 || digit == 1 || digit == 2 || digit == 3 || digit == 4 || digit == 7 ||
+        digit == 8 || digit == 9)
+        drawSegment(Segment::UpperRight, left, color, buffer, pixels);
+    if (digit == 2 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || digit == 8 ||
+        digit == 9)
+        drawSegment(Segment::Middle, left, color, buffer, pixels);
+    if (digit == 0 || digit == 2 || digit == 6 || digit == 8)
+        drawSegment(Segment::LowerLeft, left, color, buffer, pixels);
+    if (digit == 0 || digit == 1 || digit == 3 || digit == 4 || digit == 5 || digit == 6 ||
+        digit == 7 || digit == 8 || digit == 9)
+        drawSegment(Segment::LowerRight, left, color, buffer, pixels);
+    if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 8 ||
+        digit == 9)
+        drawSegment(Segment::Buttom, left, color, buffer, pixels);
+}
+
+sp<GraphicBuffer> RefreshRateOverlay::SevenSegmentDrawer::drawNumber(int number,
+                                                                     const half4& color) {
+    if (number < 0 || number > 1000) return nullptr;
+
+    const auto hundreds = number / 100;
+    const auto tens = (number / 10) % 10;
+    const auto ones = number % 10;
+
+    sp<GraphicBuffer> buffer =
+            new GraphicBuffer(BUFFER_WIDTH, BUFFER_HEIGHT, HAL_PIXEL_FORMAT_RGBA_8888, 1,
+                              GRALLOC_USAGE_SW_WRITE_RARELY, "RefreshRateOverlayBuffer");
+    uint8_t* pixels;
+    buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));
+    int left = 0;
+    if (hundreds != 0) {
+        drawDigit(hundreds, left, color, buffer, pixels);
+        left += DIGIT_WIDTH + DIGIT_SPACE;
+    }
+
+    if (tens != 0) {
+        drawDigit(tens, left, color, buffer, pixels);
+        left += DIGIT_WIDTH + DIGIT_SPACE;
+    }
+
+    drawDigit(ones, left, color, buffer, pixels);
+    buffer->unlock();
+    return buffer;
+}
+
 RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger)
       : mFlinger(flinger), mClient(new Client(&mFlinger)) {
     createLayer();
+    primeCache();
 }
 
 bool RefreshRateOverlay::createLayer() {
     const status_t ret =
-            mFlinger.createLayer(String8("RefreshRateOverlay"), mClient, 0, 0,
-                                 PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor,
-                                 LayerMetadata(), &mIBinder, &mGbp, nullptr);
+            mFlinger.createLayer(String8("RefreshRateOverlay"), mClient,
+                                 SevenSegmentDrawer::getWidth(), SevenSegmentDrawer::getHeight(),
+                                 PIXEL_FORMAT_RGBA_8888,
+                                 ISurfaceComposerClient::eFXSurfaceBufferState, LayerMetadata(),
+                                 &mIBinder, &mGbp, nullptr);
     if (ret) {
-        ALOGE("failed to create color layer");
+        ALOGE("failed to create buffer state layer");
         return false;
     }
 
     Mutex::Autolock _l(mFlinger.mStateLock);
     mLayer = mClient->getLayerUser(mIBinder);
-    mLayer->setCrop_legacy(Rect(50, 70, 200, 100));
 
     // setting Layer's Z requires resorting layersSortedByZ
     ssize_t idx = mFlinger.mCurrentState.layersSortedByZ.indexOf(mLayer);
@@ -49,9 +162,41 @@
     return true;
 }
 
+void RefreshRateOverlay::primeCache() {
+    auto allRefreshRates = mFlinger.mRefreshRateConfigs->getAllRefreshRates();
+    if (allRefreshRates.size() == 1) {
+        auto fps = allRefreshRates.begin()->second.fps;
+        half4 color = {LOW_FPS_COLOR, ALPHA};
+        mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color));
+        return;
+    }
+
+    std::vector<uint32_t> supportedFps;
+    supportedFps.reserve(allRefreshRates.size());
+    for (auto [ignored, refreshRate] : allRefreshRates) {
+        supportedFps.push_back(refreshRate.fps);
+    }
+
+    std::sort(supportedFps.begin(), supportedFps.end());
+    const auto mLowFps = supportedFps[0];
+    const auto mHighFps = supportedFps[supportedFps.size() - 1];
+    for (auto fps : supportedFps) {
+        const auto fpsScale = float(fps - mLowFps) / (mHighFps - mLowFps);
+        half4 color;
+        color.r = HIGH_FPS_COLOR.r * fpsScale + LOW_FPS_COLOR.r * (1 - fpsScale);
+        color.g = HIGH_FPS_COLOR.g * fpsScale + LOW_FPS_COLOR.g * (1 - fpsScale);
+        color.b = HIGH_FPS_COLOR.b * fpsScale + LOW_FPS_COLOR.b * (1 - fpsScale);
+        color.a = ALPHA;
+        mBufferCache.emplace(fps, SevenSegmentDrawer::drawNumber(fps, color));
+    }
+}
+
 void RefreshRateOverlay::changeRefreshRate(const RefreshRate& refreshRate) {
-    const half3& color = (refreshRate.fps > 65.0f) ? GREEN : RED;
-    mLayer->setColor(color);
+    auto buffer = mBufferCache[refreshRate.fps];
+    mLayer->setBuffer(buffer, 0, 0, {});
+    mLayer->setFrame(Rect(20, 120, 20 + SevenSegmentDrawer::getWidth(),
+                          120 + SevenSegmentDrawer::getHeight()));
+
     mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
 }
 
diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h
index 414bc47..6d34df2 100644
--- a/services/surfaceflinger/RefreshRateOverlay.h
+++ b/services/surfaceflinger/RefreshRateOverlay.h
@@ -28,7 +28,32 @@
     void changeRefreshRate(const RefreshRate& refreshRate);
 
 private:
+    class SevenSegmentDrawer {
+    public:
+        static sp<GraphicBuffer> drawNumber(int number, const half4& color);
+        static uint32_t getHeight() { return BUFFER_HEIGHT; }
+        static uint32_t getWidth() { return BUFFER_WIDTH; }
+
+    private:
+        enum class Segment { Upper, UpperLeft, UpperRight, Middle, LowerLeft, LowerRight, Buttom };
+
+        static void drawRect(const Rect& r, const half4& color, const sp<GraphicBuffer>& buffer,
+                             uint8_t* pixels);
+        static void drawSegment(Segment segment, int left, const half4& color,
+                                const sp<GraphicBuffer>& buffer, uint8_t* pixels);
+        static void drawDigit(int digit, int left, const half4& color,
+                              const sp<GraphicBuffer>& buffer, uint8_t* pixels);
+
+        static constexpr uint32_t DIGIT_HEIGHT = 100;
+        static constexpr uint32_t DIGIT_WIDTH = 64;
+        static constexpr uint32_t DIGIT_SPACE = 16;
+        static constexpr uint32_t BUFFER_HEIGHT = DIGIT_HEIGHT;
+        static constexpr uint32_t BUFFER_WIDTH =
+                3 * DIGIT_WIDTH + 2 * DIGIT_SPACE; // Digit|Space|Digit|Space|Digit
+    };
+
     bool createLayer();
+    void primeCache();
 
     SurfaceFlinger& mFlinger;
     sp<Client> mClient;
@@ -36,8 +61,11 @@
     sp<IBinder> mIBinder;
     sp<IGraphicBufferProducer> mGbp;
 
-    const half3 RED = half3(1.0f, 0.0f, 0.0f);
-    const half3 GREEN = half3(0.0f, 1.0f, 0.0f);
+    std::unordered_map<int, sp<GraphicBuffer>> mBufferCache;
+
+    static constexpr float ALPHA = 0.8f;
+    const half3 LOW_FPS_COLOR = half3(1.0f, 0.0f, 0.0f);
+    const half3 HIGH_FPS_COLOR = half3(0.0f, 1.0f, 0.0f);
 };
 
 }; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9d5081c..537489f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -4844,15 +4844,15 @@
                 return NO_ERROR;
             }
             case 1034: {
-                // TODO(b/129297325): expose this via developer menu option
                 n = data.readInt32();
-                if (n && !mRefreshRateOverlay &&
-                    mRefreshRateConfigs->refreshRateSwitchingSupported()) {
+                if (n == 1 && !mRefreshRateOverlay) {
                     mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(*this);
                     auto current = mRefreshRateConfigs->getCurrentRefreshRate();
                     mRefreshRateOverlay->changeRefreshRate(current);
-                } else if (!n) {
+                } else if (n == 0) {
                     mRefreshRateOverlay.reset();
+                } else {
+                    reply->writeBool(mRefreshRateOverlay != nullptr);
                 }
                 return NO_ERROR;
             }
diff --git a/services/surfaceflinger/tests/CommonTypes_test.cpp b/services/surfaceflinger/tests/CommonTypes_test.cpp
index a3e16f9..ab4af09 100644
--- a/services/surfaceflinger/tests/CommonTypes_test.cpp
+++ b/services/surfaceflinger/tests/CommonTypes_test.cpp
@@ -100,21 +100,21 @@
               static_cast<uint32_t>(HidlDataspace::RANGE_LIMITED));
 static_assert(static_cast<uint32_t>(AidlDataspace::RANGE_EXTENDED) ==
               static_cast<uint32_t>(HidlDataspace::RANGE_EXTENDED));
-static_assert(static_cast<uint32_t>(AidlDataspace::V0_SRGB_LINEAR) ==
+static_assert(static_cast<uint32_t>(AidlDataspace::SRGB_LINEAR) ==
               static_cast<uint32_t>(HidlDataspace::V0_SRGB_LINEAR));
-static_assert(static_cast<uint32_t>(AidlDataspace::V0_SCRGB_LINEAR) ==
+static_assert(static_cast<uint32_t>(AidlDataspace::SCRGB_LINEAR) ==
               static_cast<uint32_t>(HidlDataspace::V0_SCRGB_LINEAR));
-static_assert(static_cast<uint32_t>(AidlDataspace::V0_SRGB) ==
+static_assert(static_cast<uint32_t>(AidlDataspace::SRGB) ==
               static_cast<uint32_t>(HidlDataspace::V0_SRGB));
-static_assert(static_cast<uint32_t>(AidlDataspace::V0_SCRGB) ==
+static_assert(static_cast<uint32_t>(AidlDataspace::SCRGB) ==
               static_cast<uint32_t>(HidlDataspace::V0_SCRGB));
-static_assert(static_cast<uint32_t>(AidlDataspace::V0_JFIF) ==
+static_assert(static_cast<uint32_t>(AidlDataspace::JFIF) ==
               static_cast<uint32_t>(HidlDataspace::V0_JFIF));
-static_assert(static_cast<uint32_t>(AidlDataspace::V0_BT601_625) ==
+static_assert(static_cast<uint32_t>(AidlDataspace::BT601_625) ==
               static_cast<uint32_t>(HidlDataspace::V0_BT601_625));
-static_assert(static_cast<uint32_t>(AidlDataspace::V0_BT601_525) ==
+static_assert(static_cast<uint32_t>(AidlDataspace::BT601_525) ==
               static_cast<uint32_t>(HidlDataspace::V0_BT601_525));
-static_assert(static_cast<uint32_t>(AidlDataspace::V0_BT709) ==
+static_assert(static_cast<uint32_t>(AidlDataspace::BT709) ==
               static_cast<uint32_t>(HidlDataspace::V0_BT709));
 static_assert(static_cast<uint32_t>(AidlDataspace::DCI_P3_LINEAR) ==
               static_cast<uint32_t>(HidlDataspace::DCI_P3_LINEAR));
@@ -152,19 +152,3 @@
               static_cast<uint32_t>(HidlDataspace::JPEG_APP_SEGMENTS));
 static_assert(static_cast<uint32_t>(AidlDataspace::HEIF) ==
               static_cast<uint32_t>(HidlDataspace::HEIF));
-
-// Below are the dataspaces that have been deprecated for sometime. They are required to behave
-// the same as their V0_* counterparts. We redefined them in AIDL to be the same as the
-// their V0_* counterparts.
-static_assert(static_cast<uint32_t>(AidlDataspace::SRGB_LINEAR) ==
-              static_cast<uint32_t>(AidlDataspace::V0_SRGB_LINEAR));
-static_assert(static_cast<uint32_t>(AidlDataspace::SRGB) ==
-              static_cast<uint32_t>(AidlDataspace::V0_SRGB));
-static_assert(static_cast<uint32_t>(AidlDataspace::JFIF) ==
-              static_cast<uint32_t>(AidlDataspace::V0_JFIF));
-static_assert(static_cast<uint32_t>(AidlDataspace::BT601_625) ==
-              static_cast<uint32_t>(AidlDataspace::V0_BT601_625));
-static_assert(static_cast<uint32_t>(AidlDataspace::BT601_525) ==
-              static_cast<uint32_t>(AidlDataspace::V0_BT601_525));
-static_assert(static_cast<uint32_t>(AidlDataspace::BT709) ==
-              static_cast<uint32_t>(AidlDataspace::V0_BT709));
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index a020e74..aa7c19a 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -694,20 +694,6 @@
 
     const InstanceData& instance_data = GetData(pdev);
 
-    // TODO(b/143296550): Fill out the set of supported formats. Longer term,
-    // add a new gralloc method to query whether a (format, usage) pair is
-    // supported, and check that for each gralloc format that corresponds to a
-    // Vulkan format. Shorter term, just add a few more formats to the ones
-    // hardcoded below.
-
-    const VkSurfaceFormatKHR kFormats[] = {
-        {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
-        {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
-        {VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
-    };
-    const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
-    uint32_t total_num_formats = kNumFormats;
-
     bool wide_color_support = false;
     Surface& surface = *SurfaceFromHandle(surface_handle);
     int err = native_window_get_wide_color_support(surface.window.get(),
@@ -720,43 +706,72 @@
         wide_color_support &&
         instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
 
-    const VkSurfaceFormatKHR kWideColorFormats[] = {
-        {VK_FORMAT_R8G8B8A8_UNORM,
-         VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT},
-        {VK_FORMAT_R8G8B8A8_SRGB,
-         VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT},
-        {VK_FORMAT_R16G16B16A16_SFLOAT,
-         VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT},
-        {VK_FORMAT_R16G16B16A16_SFLOAT,
-         VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT},
-        {VK_FORMAT_A2B10G10R10_UNORM_PACK32,
-         VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT},
-    };
-    const uint32_t kNumWideColorFormats =
-        sizeof(kWideColorFormats) / sizeof(kWideColorFormats[0]);
+    AHardwareBuffer_Desc desc = {};
+    desc.width = 1;
+    desc.height = 1;
+    desc.layers = 1;
+    desc.usage = surface.consumer_usage |
+                 AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
+                 AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER;
+
+    // We must support R8G8B8A8
+    std::vector<VkSurfaceFormatKHR> all_formats = {
+        {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
+        {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}};
+
     if (wide_color_support) {
-        total_num_formats += kNumWideColorFormats;
+        all_formats.emplace_back(VkSurfaceFormatKHR{
+            VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT});
+        all_formats.emplace_back(VkSurfaceFormatKHR{
+            VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT});
+    }
+
+    desc.format = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
+    if (AHardwareBuffer_isSupported(&desc)) {
+        all_formats.emplace_back(VkSurfaceFormatKHR{
+            VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
+    }
+
+    desc.format = AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
+    if (AHardwareBuffer_isSupported(&desc)) {
+        all_formats.emplace_back(VkSurfaceFormatKHR{
+            VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
+        if (wide_color_support) {
+            all_formats.emplace_back(
+                VkSurfaceFormatKHR{VK_FORMAT_R16G16B16A16_SFLOAT,
+                                   VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT});
+            all_formats.emplace_back(
+                VkSurfaceFormatKHR{VK_FORMAT_R16G16B16A16_SFLOAT,
+                                   VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT});
+        }
+    }
+
+    desc.format = AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM;
+    if (AHardwareBuffer_isSupported(&desc)) {
+        all_formats.emplace_back(
+            VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
+                               VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
+        if (wide_color_support) {
+            all_formats.emplace_back(
+                VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
+                                   VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT});
+        }
     }
 
     VkResult result = VK_SUCCESS;
     if (formats) {
-        uint32_t out_count = 0;
-        uint32_t transfer_count = 0;
-        if (*count < total_num_formats)
+        uint32_t transfer_count = all_formats.size();
+        if (transfer_count > *count) {
+            transfer_count = *count;
             result = VK_INCOMPLETE;
-        transfer_count = std::min(*count, kNumFormats);
-        std::copy(kFormats, kFormats + transfer_count, formats);
-        out_count += transfer_count;
-        if (wide_color_support) {
-            transfer_count = std::min(*count - out_count, kNumWideColorFormats);
-            std::copy(kWideColorFormats, kWideColorFormats + transfer_count,
-                      formats + out_count);
-            out_count += transfer_count;
         }
-        *count = out_count;
+        std::copy(all_formats.begin(), all_formats.begin() + transfer_count,
+                  formats);
+        *count = transfer_count;
     } else {
-        *count = total_num_formats;
+        *count = all_formats.size();
     }
+
     return result;
 }