Merge "RESTRICT AUTOMERGE SurfaceFlinger: fix a potential race condition in stealReceiveChannel" into sc-v2-dev
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 2d11b90..30ef4b9 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1793,8 +1793,8 @@
     // Add linker configuration directory
     ds.AddDir(LINKERCONFIG_DIR, true);
 
-    /* Dump cgroupfs */
-    ds.AddDir(CGROUPFS_DIR, true);
+    /* Dump frozen cgroupfs */
+    dump_frozen_cgroupfs();
 
     if (ds.dump_pool_) {
         WAIT_TASK_WITH_CONSENT_CHECK(DUMP_INCIDENT_REPORT_TASK, ds.dump_pool_);
@@ -4007,6 +4007,63 @@
     fclose(fp);
 }
 
+void dump_frozen_cgroupfs(const char *dir, int level,
+        int (*dump_from_fd)(const char* title, const char* path, int fd)) {
+    DIR *dirp;
+    struct dirent *d;
+    char *newpath = nullptr;
+
+    dirp = opendir(dir);
+    if (dirp == nullptr) {
+        MYLOGE("%s: %s\n", dir, strerror(errno));
+        return;
+    }
+
+    for (; ((d = readdir(dirp))); free(newpath), newpath = nullptr) {
+        if ((d->d_name[0] == '.')
+         && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
+          || (d->d_name[1] == '\0'))) {
+            continue;
+        }
+        if (d->d_type == DT_DIR) {
+            asprintf(&newpath, "%s/%s/", dir, d->d_name);
+            if (!newpath) {
+                continue;
+            }
+            if (level == 0 && !strncmp(d->d_name, "uid_", 4)) {
+                dump_frozen_cgroupfs(newpath, 1, dump_from_fd);
+            } else if (level == 1 && !strncmp(d->d_name, "pid_", 4)) {
+                char *freezer = nullptr;
+                asprintf(&freezer, "%s/%s", newpath, "cgroup.freeze");
+                if (freezer) {
+                    FILE* fp = fopen(freezer, "r");
+                    if (fp != NULL) {
+                        int frozen;
+                        fscanf(fp, "%d", &frozen);
+                        if (frozen > 0) {
+                            dump_files("", newpath, skip_none, dump_from_fd);
+                        }
+                        fclose(fp);
+                    }
+                    free(freezer);
+                }
+            }
+        }
+    }
+    closedir(dirp);
+}
+
+void dump_frozen_cgroupfs() {
+    if (!ds.IsZipping()) {
+        MYLOGD("Not adding cgroupfs because it's not a zipped bugreport\n");
+        return;
+    }
+    MYLOGD("Adding frozen processes from %s\n", CGROUPFS_DIR);
+    DurationReporter duration_reporter("FROZEN CGROUPFS");
+    if (PropertiesHelper::IsDryRun()) return;
+    dump_frozen_cgroupfs(CGROUPFS_DIR, 0, _add_file_from_fd);
+}
+
 void Dumpstate::UpdateProgress(int32_t delta_sec) {
     if (progress_ == nullptr) {
         MYLOGE("UpdateProgress: progress_ not set\n");
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 83e6787..34280d0 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -642,6 +642,9 @@
 /* Prints the contents of all the routing tables, both IPv4 and IPv6. */
 void dump_route_tables();
 
+/* Dump subdirectories of cgroupfs if the corresponding process is frozen */
+void dump_frozen_cgroupfs();
+
 /* Play a sound via Stagefright */
 void play_sound(const char *path);
 
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 0712c0a..28e5ee2 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -240,11 +240,11 @@
     EXPECT_GE(st.st_size, 1000000 /* 1MB */);
 }
 
-TEST_F(ZippedBugreportGenerationTest, TakesBetween30And300Seconds) {
-    EXPECT_GE(duration, 30s) << "Expected completion in more than 30s. Actual time "
-                             << duration.count() << " s.";
+TEST_F(ZippedBugreportGenerationTest, TakesBetween20And300Seconds) {
+    EXPECT_GE(duration, 20s) << "Expected completion in more than 20s. Actual time "
+                             << duration.count() << " ms.";
     EXPECT_LE(duration, 300s) << "Expected completion in less than 300s. Actual time "
-                              << duration.count() << " s.";
+                              << duration.count() << " ms.";
 }
 
 /**
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 95d9377..b84be9b 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1766,6 +1766,10 @@
         const std::vector<std::string>& codePaths, std::vector<int64_t>* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
+    if (packageNames.size() != ceDataInodes.size()) {
+        return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+                         "packageNames/ceDataInodes size mismatch.");
+    }
     for (const auto& packageName : packageNames) {
         CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     }
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index 3657497..b910ac1 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -322,6 +322,19 @@
         system(removeCommand.c_str());
     }
 }
+TEST_F(ServiceTest, GetAppSizeWrongSizes) {
+    int32_t externalStorageAppId = -1;
+    std::vector<int64_t> externalStorageSize;
+
+    std::vector<std::string> codePaths;
+    std::vector<std::string> packageNames = {"package1", "package2"};
+    std::vector<int64_t> ceDataInodes = {0};
+
+    EXPECT_BINDER_FAIL(service->getAppSize(std::nullopt, packageNames, 0,
+                                           InstalldNativeService::FLAG_USE_QUOTA,
+                                           externalStorageAppId, ceDataInodes, codePaths,
+                                           &externalStorageSize));
+}
 static bool mkdirs(const std::string& path, mode_t mode) {
     struct stat sb;
     if (stat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode)) {
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 77a883b..bf275a5 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -391,6 +391,71 @@
     }
 }
 
+void layer_state_t::sanitize(int32_t permissions) {
+    // TODO: b/109894387
+    //
+    // SurfaceFlinger's renderer is not prepared to handle cropping in the face of arbitrary
+    // rotation. To see the problem observe that if we have a square parent, and a child
+    // of the same size, then we rotate the child 45 degrees around its center, the child
+    // must now be cropped to a non rectangular 8 sided region.
+    //
+    // Of course we can fix this in the future. For now, we are lucky, SurfaceControl is
+    // private API, and arbitrary rotation is used in limited use cases, for instance:
+    // - WindowManager only uses rotation in one case, which is on a top level layer in which
+    //   cropping is not an issue.
+    // - Launcher, as a privileged app, uses this to transition an application to PiP
+    //   (picture-in-picture) mode.
+    //
+    // However given that abuse of rotation matrices could lead to surfaces extending outside
+    // of cropped areas, we need to prevent non-root clients without permission
+    // ACCESS_SURFACE_FLINGER nor ROTATE_SURFACE_FLINGER
+    // (a.k.a. everyone except WindowManager / tests / Launcher) from setting non rectangle
+    // preserving transformations.
+    if (what & eMatrixChanged) {
+        if (!(permissions & Permission::ROTATE_SURFACE_FLINGER)) {
+            ui::Transform t;
+            t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
+            if (!t.preserveRects()) {
+                what &= ~eMatrixChanged;
+                ALOGE("Stripped non rect preserving matrix in sanitize");
+            }
+        }
+    }
+
+    if (what & layer_state_t::eInputInfoChanged) {
+        if (!(permissions & Permission::ACCESS_SURFACE_FLINGER)) {
+            what &= ~eInputInfoChanged;
+            ALOGE("Stripped attempt to set eInputInfoChanged in sanitize");
+        }
+    }
+    if (what & layer_state_t::eTrustedOverlayChanged) {
+        if (!(permissions & Permission::ACCESS_SURFACE_FLINGER)) {
+            what &= ~eTrustedOverlayChanged;
+            ALOGE("Stripped attempt to set eTrustedOverlay in sanitize");
+        }
+    }
+    if (what & layer_state_t::eDropInputModeChanged) {
+        if (!(permissions & Permission::ACCESS_SURFACE_FLINGER)) {
+            what &= ~eDropInputModeChanged;
+            ALOGE("Stripped attempt to set eDropInputModeChanged in sanitize");
+        }
+    }
+    if (what & layer_state_t::eFrameRateSelectionPriority) {
+        if (!(permissions & Permission::ACCESS_SURFACE_FLINGER)) {
+            what &= ~eFrameRateSelectionPriority;
+            ALOGE("Stripped attempt to set eFrameRateSelectionPriority in sanitize");
+        }
+    }
+    if (what & layer_state_t::eFrameRateChanged) {
+        if (!ValidateFrameRate(frameRate, frameRateCompatibility,
+                               changeFrameRateStrategy,
+                               "layer_state_t::sanitize",
+                               permissions & Permission::ACCESS_SURFACE_FLINGER)) {
+            what &= ~eFrameRateChanged; // logged in ValidateFrameRate
+        }
+    }
+}
+
 void layer_state_t::merge(const layer_state_t& other) {
     if (other.what & ePositionChanged) {
         what |= ePositionChanged;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 725ea65..4bcc9d5 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -551,6 +551,13 @@
     mListenerCallbacks = other.mListenerCallbacks;
 }
 
+void SurfaceComposerClient::Transaction::sanitize() {
+    for (auto & [handle, composerState] : mComposerStates) {
+        composerState.state.sanitize(0 /* permissionMask */);
+    }
+    mInputWindowCommands.clear();
+}
+
 std::unique_ptr<SurfaceComposerClient::Transaction>
 SurfaceComposerClient::Transaction::createFromParcel(const Parcel* parcel) {
     auto transaction = std::make_unique<Transaction>();
@@ -635,7 +642,6 @@
         if (composerState.read(*parcel) == BAD_VALUE) {
             return BAD_VALUE;
         }
-
         composerStates[surfaceControlHandle] = composerState;
     }
 
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 6529a4e..f93b799 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -70,6 +70,7 @@
     mLayerId = other->mLayerId;
     mWidth = other->mWidth;
     mHeight = other->mHeight;
+    mFormat = other->mFormat;
     mCreateFlags = other->mCreateFlags;
 }
 
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 03e4aac..2a8d30d 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -61,6 +61,12 @@
  * Used to communicate layer information between SurfaceFlinger and its clients.
  */
 struct layer_state_t {
+    enum Permission {
+        ACCESS_SURFACE_FLINGER = 0x1,
+        ROTATE_SURFACE_FLINGER = 0x2,
+        INTERNAL_SYSTEM_WINDOW = 0x4,
+    };
+
     enum {
         eLayerHidden = 0x01,         // SURFACE_HIDDEN in SurfaceControl.java
         eLayerOpaque = 0x02,         // SURFACE_OPAQUE
@@ -128,6 +134,7 @@
     status_t read(const Parcel& input);
     bool hasBufferChanges() const;
     bool hasValidBuffer() const;
+    void sanitize(int32_t permissions);
 
     struct matrix22_t {
         float dsdx{0};
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 0d1d1a3..76b6d44 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -590,6 +590,14 @@
         void setAnimationTransaction();
         void setEarlyWakeupStart();
         void setEarlyWakeupEnd();
+
+        /**
+         * Strip the transaction of all permissioned requests, required when
+         * accepting transactions across process boundaries.
+         *
+         * TODO (b/213644870): Remove all permissioned things from Transaction
+         */
+        void sanitize();
     };
 
     status_t clearLayerFrameStats(const sp<IBinder>& token) const;
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index 9ee4636..ed14ec6 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -118,12 +118,13 @@
     mutable sp<Surface>         mSurfaceData;
     mutable sp<BLASTBufferQueue> mBbq;
     mutable sp<SurfaceControl> mBbqChild;
-    int32_t mLayerId;
-    uint32_t mTransformHint;
-    uint32_t mWidth;
-    uint32_t mHeight;
-    PixelFormat mFormat;
-    uint32_t mCreateFlags;
+
+    int32_t mLayerId = 0;
+    uint32_t mTransformHint = 0;
+    uint32_t mWidth = 0;
+    uint32_t mHeight = 0;
+    PixelFormat mFormat = PIXEL_FORMAT_NONE;
+    uint32_t mCreateFlags = 0;
 };
 
 }; // namespace android
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 0ee9fb3..a56827e 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -134,6 +134,68 @@
     return true;
 }
 
+float RefreshRateConfigs::calculateNonExactMatchingLayerScoreLocked(
+        const LayerRequirement& layer, const RefreshRate& refreshRate) const {
+    constexpr float kScoreForFractionalPairs = .8f;
+
+    const auto displayPeriod = refreshRate.getVsyncPeriod();
+    const auto layerPeriod = layer.desiredRefreshRate.getPeriodNsecs();
+    if (layer.vote == LayerVoteType::ExplicitDefault) {
+        // Find the actual rate the layer will render, assuming
+        // that layerPeriod is the minimal period to render a frame.
+        // For example if layerPeriod is 20ms and displayPeriod is 16ms,
+        // then the actualLayerPeriod will be 32ms, because it is the
+        // smallest multiple of the display period which is >= layerPeriod.
+        auto actualLayerPeriod = displayPeriod;
+        int multiplier = 1;
+        while (layerPeriod > actualLayerPeriod + MARGIN_FOR_PERIOD_CALCULATION) {
+            multiplier++;
+            actualLayerPeriod = displayPeriod * multiplier;
+        }
+
+        // Because of the threshold we used above it's possible that score is slightly
+        // above 1.
+        return std::min(1.0f,
+                        static_cast<float>(layerPeriod) / static_cast<float>(actualLayerPeriod));
+    }
+
+    if (layer.vote == LayerVoteType::ExplicitExactOrMultiple ||
+        layer.vote == LayerVoteType::Heuristic) {
+        if (isFractionalPairOrMultiple(refreshRate.getFps(), layer.desiredRefreshRate)) {
+            return kScoreForFractionalPairs;
+        }
+
+        // Calculate how many display vsyncs we need to present a single frame for this
+        // layer
+        const auto [displayFramesQuotient, displayFramesRemainder] =
+                getDisplayFrames(layerPeriod, displayPeriod);
+        static constexpr size_t MAX_FRAMES_TO_FIT = 10; // Stop calculating when score < 0.1
+        if (displayFramesRemainder == 0) {
+            // Layer desired refresh rate matches the display rate.
+            return 1.0f;
+        }
+
+        if (displayFramesQuotient == 0) {
+            // Layer desired refresh rate is higher than the display rate.
+            return (static_cast<float>(layerPeriod) / static_cast<float>(displayPeriod)) *
+                    (1.0f / (MAX_FRAMES_TO_FIT + 1));
+        }
+
+        // Layer desired refresh rate is lower than the display rate. Check how well it fits
+        // the cadence.
+        auto diff = std::abs(displayFramesRemainder - (displayPeriod - displayFramesRemainder));
+        int iter = 2;
+        while (diff > MARGIN_FOR_PERIOD_CALCULATION && iter < MAX_FRAMES_TO_FIT) {
+            diff = diff - (displayPeriod - diff);
+            iter++;
+        }
+
+        return (1.0f / iter);
+    }
+
+    return 0;
+}
+
 float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer,
                                                     const RefreshRate& refreshRate,
                                                     bool isSeamlessSwitch) const {
@@ -153,51 +215,6 @@
         return ratio * ratio;
     }
 
-    const auto displayPeriod = refreshRate.getVsyncPeriod();
-    const auto layerPeriod = layer.desiredRefreshRate.getPeriodNsecs();
-    if (layer.vote == LayerVoteType::ExplicitDefault) {
-        // Find the actual rate the layer will render, assuming
-        // that layerPeriod is the minimal time to render a frame
-        auto actualLayerPeriod = displayPeriod;
-        int multiplier = 1;
-        while (layerPeriod > actualLayerPeriod + MARGIN_FOR_PERIOD_CALCULATION) {
-            multiplier++;
-            actualLayerPeriod = displayPeriod * multiplier;
-        }
-        return std::min(1.0f,
-                        static_cast<float>(layerPeriod) / static_cast<float>(actualLayerPeriod));
-    }
-
-    if (layer.vote == LayerVoteType::ExplicitExactOrMultiple ||
-        layer.vote == LayerVoteType::Heuristic) {
-        // Calculate how many display vsyncs we need to present a single frame for this
-        // layer
-        const auto [displayFramesQuotient, displayFramesRemainder] =
-                getDisplayFrames(layerPeriod, displayPeriod);
-        static constexpr size_t MAX_FRAMES_TO_FIT = 10; // Stop calculating when score < 0.1
-        if (displayFramesRemainder == 0) {
-            // Layer desired refresh rate matches the display rate.
-            return 1.0f * seamlessness;
-        }
-
-        if (displayFramesQuotient == 0) {
-            // Layer desired refresh rate is higher than the display rate.
-            return (static_cast<float>(layerPeriod) / static_cast<float>(displayPeriod)) *
-                    (1.0f / (MAX_FRAMES_TO_FIT + 1));
-        }
-
-        // Layer desired refresh rate is lower than the display rate. Check how well it fits
-        // the cadence.
-        auto diff = std::abs(displayFramesRemainder - (displayPeriod - displayFramesRemainder));
-        int iter = 2;
-        while (diff > MARGIN_FOR_PERIOD_CALCULATION && iter < MAX_FRAMES_TO_FIT) {
-            diff = diff - (displayPeriod - diff);
-            iter++;
-        }
-
-        return (1.0f / iter) * seamlessness;
-    }
-
     if (layer.vote == LayerVoteType::ExplicitExact) {
         const int divider = getFrameRateDivider(refreshRate.getFps(), layer.desiredRefreshRate);
         if (mSupportsFrameRateOverride) {
@@ -210,7 +227,18 @@
         return divider == 1;
     }
 
-    return 0;
+    // If the layer frame rate is a divider of the refresh rate it should score
+    // the highest score.
+    if (getFrameRateDivider(refreshRate.getFps(), layer.desiredRefreshRate) > 0) {
+        return 1.0f * seamlessness;
+    }
+
+    // The layer frame rate is not a divider of the refresh rate,
+    // there is a small penalty attached to the score to favor the frame rates
+    // the exactly matches the display refresh rate or a multiple.
+    constexpr float kNonExactMatchingPenalty = 0.95f;
+    return calculateNonExactMatchingLayerScoreLocked(layer, refreshRate) * seamlessness *
+            kNonExactMatchingPenalty;
 }
 
 struct RefreshRateScore {
@@ -422,7 +450,7 @@
 
             const auto layerScore =
                     calculateLayerScoreLocked(layer, *scores[i].refreshRate, isSeamlessSwitch);
-            ALOGV("%s gives %s score of %.2f", formatLayerInfo(layer, weight).c_str(),
+            ALOGV("%s gives %s score of %.4f", formatLayerInfo(layer, weight).c_str(),
                   scores[i].refreshRate->getName().c_str(), layerScore);
             scores[i].score += weight * layerScore;
         }
@@ -583,7 +611,7 @@
 
 template <typename Iter>
 const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) const {
-    constexpr auto EPSILON = 0.001f;
+    constexpr auto kEpsilon = 0.0001f;
     const RefreshRate* bestRefreshRate = begin->refreshRate;
     float max = begin->score;
     for (auto i = begin; i != end; ++i) {
@@ -592,7 +620,7 @@
 
         ATRACE_INT(refreshRate->getName().c_str(), round<int>(score * 100));
 
-        if (score > max * (1 + EPSILON)) {
+        if (score > max * (1 + kEpsilon)) {
             max = score;
             bestRefreshRate = refreshRate;
         }
@@ -945,6 +973,17 @@
     return static_cast<int>(numPeriodsRounded);
 }
 
+bool RefreshRateConfigs::isFractionalPairOrMultiple(Fps smaller, Fps bigger) {
+    if (smaller.getValue() > bigger.getValue()) {
+        return isFractionalPairOrMultiple(bigger, smaller);
+    }
+
+    const auto multiplier = std::round(bigger.getValue() / smaller.getValue());
+    constexpr float kCoef = 1000.f / 1001.f;
+    return bigger.equalsWithMargin(Fps(smaller.getValue() * multiplier / kCoef)) ||
+            bigger.equalsWithMargin(Fps(smaller.getValue() * multiplier * kCoef));
+}
+
 void RefreshRateConfigs::dump(std::string& result) const {
     std::lock_guard lock(mLock);
     base::StringAppendF(&result, "DesiredDisplayModeSpecs (DisplayManager): %s\n\n",
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 21867cc..99f217c 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -344,6 +344,10 @@
     // layer refresh rate.
     static int getFrameRateDivider(Fps displayFrameRate, Fps layerFrameRate);
 
+    // Returns if the provided frame rates have a ratio t*1000/1001 or t*1001/1000
+    // for an integer t.
+    static bool isFractionalPairOrMultiple(Fps, Fps);
+
     using UidToFrameRateOverride = std::map<uid_t, Fps>;
     // Returns the frame rate override for each uid.
     //
@@ -446,6 +450,9 @@
     float calculateLayerScoreLocked(const LayerRequirement&, const RefreshRate&,
                                     bool isSeamlessSwitch) const REQUIRES(mLock);
 
+    float calculateNonExactMatchingLayerScoreLocked(const LayerRequirement&,
+                                                    const RefreshRate&) const REQUIRES(mLock);
+
     void updateDisplayModes(const DisplayModes& mode, DisplayModeId currentModeId) EXCLUDES(mLock);
 
     void initializeIdleTimer();
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index c1dba2b..77b75ab 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -98,9 +98,15 @@
     static inline const DisplayModeId HWC_CONFIG_ID_30 = DisplayModeId(4);
     static inline const DisplayModeId HWC_CONFIG_ID_25 = DisplayModeId(5);
     static inline const DisplayModeId HWC_CONFIG_ID_50 = DisplayModeId(6);
+    static inline const DisplayModeId HWC_CONFIG_ID_24 = DisplayModeId(7);
+    static inline const DisplayModeId HWC_CONFIG_ID_24_FRAC = DisplayModeId(8);
+    static inline const DisplayModeId HWC_CONFIG_ID_30_FRAC = DisplayModeId(9);
+    static inline const DisplayModeId HWC_CONFIG_ID_60_FRAC = DisplayModeId(10);
 
     // Test configs
     DisplayModePtr mConfig60 = createDisplayMode(HWC_CONFIG_ID_60, 0, Fps(60.0f).getPeriodNsecs());
+    DisplayModePtr mConfig60Frac =
+            createDisplayMode(HWC_CONFIG_ID_60_FRAC, 0, Fps(59.94f).getPeriodNsecs());
     DisplayModePtr mConfig90 = createDisplayMode(HWC_CONFIG_ID_90, 0, Fps(90.0f).getPeriodNsecs());
     DisplayModePtr mConfig90DifferentGroup =
             createDisplayMode(HWC_CONFIG_ID_90, 1, Fps(90.0f).getPeriodNsecs());
@@ -116,9 +122,15 @@
     DisplayModePtr mConfig30 = createDisplayMode(HWC_CONFIG_ID_30, 0, Fps(30.0f).getPeriodNsecs());
     DisplayModePtr mConfig30DifferentGroup =
             createDisplayMode(HWC_CONFIG_ID_30, 1, Fps(30.0f).getPeriodNsecs());
+    DisplayModePtr mConfig30Frac =
+            createDisplayMode(HWC_CONFIG_ID_30_FRAC, 0, Fps(29.97f).getPeriodNsecs());
+    DisplayModePtr mConfig25 = createDisplayMode(HWC_CONFIG_ID_25, 0, Fps(25.0f).getPeriodNsecs());
     DisplayModePtr mConfig25DifferentGroup =
             createDisplayMode(HWC_CONFIG_ID_25, 1, Fps(25.0f).getPeriodNsecs());
     DisplayModePtr mConfig50 = createDisplayMode(HWC_CONFIG_ID_50, 0, Fps(50.0f).getPeriodNsecs());
+    DisplayModePtr mConfig24 = createDisplayMode(HWC_CONFIG_ID_24, 0, Fps(24.0f).getPeriodNsecs());
+    DisplayModePtr mConfig24Frac =
+            createDisplayMode(HWC_CONFIG_ID_24_FRAC, 0, Fps(23.976f).getPeriodNsecs());
 
     // Test device configurations
     // The positions of the configs in the arrays below MUST match their IDs. For example,
@@ -145,6 +157,11 @@
                                        mConfig50};
     DisplayModes m60_120Device = {mConfig60, mConfig120};
 
+    // This is a typical TV configuration.
+    DisplayModes m24_25_30_50_60WithFracDevice = {mConfig24, mConfig24Frac, mConfig25,
+                                                  mConfig30, mConfig30Frac, mConfig50,
+                                                  mConfig60, mConfig60Frac};
+
     // Expected RefreshRate objects
     RefreshRate mExpected60Config = {mConfig60, RefreshRate::ConstructorTag(0)};
     RefreshRate mExpectedAlmost60Config = {createDisplayMode(HWC_CONFIG_ID_60, 0, 16666665),
@@ -158,7 +175,6 @@
     RefreshRate mExpected30Config = {mConfig30, RefreshRate::ConstructorTag(0)};
     RefreshRate mExpected120Config = {mConfig120, RefreshRate::ConstructorTag(0)};
 
-private:
     DisplayModePtr createDisplayMode(DisplayModeId modeId, int32_t group, int64_t vsyncPeriod,
                                      ui::Size resolution = ui::Size());
 };
@@ -1230,7 +1246,109 @@
         const auto& refreshRate =
                 refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
         EXPECT_TRUE(refreshRate.getFps().equalsWithMargin(Fps(test.second)))
-                << "Expecting " << test.first << "fps => " << test.second << "Hz";
+                << "Expecting " << test.first << "fps => " << test.second << "Hz"
+                << " but it was " << refreshRate.getFps();
+    }
+}
+
+TEST_F(RefreshRateConfigsTest,
+       getBestRefreshRate_ExplicitExactOrMultiple_WithFractionalRefreshRates) {
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    auto& lr = layers[0];
+
+    // Test that 23.976 will choose 24 if 23.976 is not supported
+    {
+        android::DisplayModes modes = {mConfig24,     mConfig25, mConfig30,
+                                       mConfig30Frac, mConfig60, mConfig60Frac};
+        auto refreshRateConfigs =
+                std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+        lr.vote = LayerVoteType::ExplicitExactOrMultiple;
+        lr.desiredRefreshRate = Fps(23.976f);
+        lr.name = "ExplicitExactOrMultiple 23.976 fps";
+        EXPECT_EQ(HWC_CONFIG_ID_24,
+                  refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+                          .getModeId());
+    }
+
+    // Test that 24 will choose 23.976 if 24 is not supported
+    {
+        android::DisplayModes modes = {mConfig24Frac, mConfig25, mConfig30,
+                                       mConfig30Frac, mConfig60, mConfig60Frac};
+        auto refreshRateConfigs =
+                std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
+        lr.desiredRefreshRate = Fps(24.f);
+        lr.name = "ExplicitExactOrMultiple 24 fps";
+        EXPECT_EQ(HWC_CONFIG_ID_24_FRAC,
+                  refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+                          .getModeId());
+    }
+
+    // Test that 29.97 will prefer 59.94 over 60 and 30
+    {
+        android::DisplayModes modes = {mConfig24, mConfig24Frac, mConfig25,
+                                       mConfig30, mConfig60,     mConfig60Frac};
+        auto refreshRateConfigs =
+                std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
+        lr.desiredRefreshRate = Fps(29.97f);
+        lr.name = "ExplicitExactOrMultiple 29.97f fps";
+        EXPECT_EQ(HWC_CONFIG_ID_60_FRAC,
+                  refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+                          .getModeId());
+    }
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExact_WithFractionalRefreshRates) {
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    auto& lr = layers[0];
+
+    // Test that voting for supported refresh rate will select this refresh rate
+    {
+        auto refreshRateConfigs =
+                std::make_unique<RefreshRateConfigs>(m24_25_30_50_60WithFracDevice,
+                                                     /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+        for (auto desiredRefreshRate : {23.976f, 24.f, 25.f, 29.97f, 30.f, 50.f, 59.94f, 60.f}) {
+            lr.vote = LayerVoteType::ExplicitExact;
+            lr.desiredRefreshRate = Fps(desiredRefreshRate);
+            std::stringstream ss;
+            ss << "ExplicitExact " << desiredRefreshRate << " fps";
+            lr.name = ss.str();
+
+            auto selecteRefreshRate =
+                    refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
+
+            EXPECT_TRUE(selecteRefreshRate.getFps().equalsWithMargin(lr.desiredRefreshRate))
+                    << "Expecting " << lr.desiredRefreshRate << " but it was "
+                    << selecteRefreshRate.getFps();
+        }
+    }
+
+    // Test that 23.976 will choose 24 if 23.976 is not supported
+    {
+        android::DisplayModes modes = {mConfig24,     mConfig25, mConfig30,
+                                       mConfig30Frac, mConfig60, mConfig60Frac};
+        auto refreshRateConfigs =
+                std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
+        lr.vote = LayerVoteType::ExplicitExact;
+        lr.desiredRefreshRate = Fps(23.976f);
+        lr.name = "ExplicitExact 23.976 fps";
+        EXPECT_EQ(HWC_CONFIG_ID_24,
+                  refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+                          .getModeId());
+    }
+
+    // Test that 24 will choose 23.976 if 24 is not supported
+    {
+        android::DisplayModes modes = {mConfig24Frac, mConfig25, mConfig30,
+                                       mConfig30Frac, mConfig60, mConfig60Frac};
+        auto refreshRateConfigs =
+                std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
+        lr.desiredRefreshRate = Fps(24.f);
+        lr.name = "ExplicitExact 24 fps";
+        EXPECT_EQ(HWC_CONFIG_ID_24_FRAC,
+                  refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+                          .getModeId());
     }
 }
 
@@ -2028,6 +2146,100 @@
               refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
 }
 
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_FractionalRefreshRates_ExactAndDefault) {
+    RefreshRateConfigs::Config config = {.enableFrameRateOverride = true};
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m24_25_30_50_60WithFracDevice,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60, config);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 0.5f},
+                                                LayerRequirement{.weight = 0.5f}};
+    auto& explicitDefaultLayer = layers[0];
+    auto& explicitExactOrMultipleLayer = layers[1];
+
+    explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple;
+    explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple";
+    explicitExactOrMultipleLayer.desiredRefreshRate = Fps(60);
+
+    explicitDefaultLayer.vote = LayerVoteType::ExplicitDefault;
+    explicitDefaultLayer.name = "ExplicitDefault";
+    explicitDefaultLayer.desiredRefreshRate = Fps(59.94f);
+
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+// b/190578904
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_deviceWithCloseRefreshRates) {
+    constexpr int kMinRefreshRate = 10;
+    constexpr int kMaxRefreshRate = 240;
+
+    DisplayModes displayModes;
+    for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) {
+        constexpr int32_t kGroup = 0;
+        const auto refreshRate = Fps(static_cast<float>(fps));
+        displayModes.push_back(
+                createDisplayMode(DisplayModeId(fps), kGroup, refreshRate.getPeriodNsecs()));
+    }
+
+    const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false};
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(displayModes,
+                                                 /*currentConfigId=*/displayModes[0]->getId());
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    const auto testRefreshRate = [&](Fps fps, LayerVoteType vote) {
+        layers[0].desiredRefreshRate = fps;
+        layers[0].vote = vote;
+        EXPECT_EQ(fps.getIntValue(),
+                  refreshRateConfigs->getBestRefreshRate(layers, globalSignals)
+                          .getFps()
+                          .getIntValue())
+                << "Failed for " << RefreshRateConfigs::layerVoteTypeString(vote);
+    };
+
+    for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) {
+        const auto refreshRate = Fps(static_cast<float>(fps));
+        testRefreshRate(refreshRate, LayerVoteType::Heuristic);
+        testRefreshRate(refreshRate, LayerVoteType::ExplicitDefault);
+        testRefreshRate(refreshRate, LayerVoteType::ExplicitExactOrMultiple);
+        testRefreshRate(refreshRate, LayerVoteType::ExplicitExact);
+    }
+}
+
+// b/190578904
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_conflictingVotes) {
+    const DisplayModes displayModes = {
+            createDisplayMode(DisplayModeId(0), 0, Fps(43.0f).getPeriodNsecs()),
+            createDisplayMode(DisplayModeId(1), 0, Fps(53.0f).getPeriodNsecs()),
+            createDisplayMode(DisplayModeId(2), 0, Fps(55.0f).getPeriodNsecs()),
+            createDisplayMode(DisplayModeId(3), 0, Fps(60.0f).getPeriodNsecs()),
+    };
+
+    const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false};
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(displayModes,
+                                                 /*currentConfigId=*/displayModes[0]->getId());
+
+    const auto layers = std::vector<LayerRequirement>{
+            LayerRequirement{
+                    .vote = LayerVoteType::ExplicitDefault,
+                    .desiredRefreshRate = Fps(43.0f),
+                    .seamlessness = Seamlessness::SeamedAndSeamless,
+                    .weight = 0.41f,
+            },
+            LayerRequirement{
+                    .vote = LayerVoteType::ExplicitExactOrMultiple,
+                    .desiredRefreshRate = Fps(53.0f),
+                    .seamlessness = Seamlessness::SeamedAndSeamless,
+                    .weight = 0.41f,
+            },
+    };
+
+    EXPECT_EQ(53,
+              refreshRateConfigs->getBestRefreshRate(layers, globalSignals).getFps().getIntValue());
+}
+
 TEST_F(RefreshRateConfigsTest, testComparisonOperator) {
     EXPECT_TRUE(mExpected60Config < mExpected90Config);
     EXPECT_FALSE(mExpected60Config < mExpected60Config);
@@ -2123,6 +2335,33 @@
     EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(Fps(60.f), Fps(59.94f)));
 }
 
+TEST_F(RefreshRateConfigsTest, isFractionalPairOrMultiple) {
+    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(23.976f), Fps(24.f)));
+    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(24.f), Fps(23.976f)));
+
+    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(29.97f), Fps(30.f)));
+    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(30.f), Fps(29.97f)));
+
+    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(59.94f), Fps(60.f)));
+    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(60.f), Fps(59.94f)));
+
+    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(29.97f), Fps(60.f)));
+    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(60.f), Fps(29.97f)));
+
+    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(59.94f), Fps(30.f)));
+    EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(30.f), Fps(59.94f)));
+
+    const std::vector<float> refreshRates = {23.976f, 24.f, 25.f, 29.97f, 30.f, 50.f, 59.94f, 60.f};
+    for (auto refreshRate : refreshRates) {
+        EXPECT_FALSE(
+                RefreshRateConfigs::isFractionalPairOrMultiple(Fps(refreshRate), Fps(refreshRate)));
+    }
+
+    EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(24.f), Fps(25.f)));
+    EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(23.978f), Fps(25.f)));
+    EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(29.97f), Fps(59.94f)));
+}
+
 TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_noLayers) {
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device, /*currentConfigId=*/