summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-17 21:05:31 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-17 21:05:31 +0000
commit8ad1f63e6209f7b58ccf38fc35fb457e06625d4d (patch)
tree7eb986f5a24d492374f09523eaee40811ef38f2f
parent89c808424fbce9e40c0d4e0d1920b3c64a191b7f (diff)
parentdccd7d4c75f3a988d2e66b84dd0eb247a8df9e95 (diff)
downloadnative-8ad1f63e6209f7b58ccf38fc35fb457e06625d4d.tar.gz
Snap for 8589293 from dccd7d4c75f3a988d2e66b84dd0eb247a8df9e95 to sc-v2-platform-releaseandroid-platform-12.1.0_r5android-platform-12.1.0_r4
Change-Id: I04b77150dbff74ce1a1ec675c0f5c844d33a62fe
-rw-r--r--cmds/dumpstate/dumpstate.cpp61
-rw-r--r--cmds/dumpstate/dumpstate.h3
-rw-r--r--cmds/dumpstate/tests/dumpstate_smoke_test.cpp8
-rw-r--r--cmds/installd/InstalldNativeService.cpp4
-rw-r--r--cmds/installd/tests/installd_service_test.cpp13
-rw-r--r--libs/gui/LayerState.cpp65
-rw-r--r--libs/gui/SurfaceComposerClient.cpp8
-rw-r--r--libs/gui/include/gui/LayerState.h7
-rw-r--r--libs/gui/include/gui/SurfaceComposerClient.h8
-rw-r--r--services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp89
-rw-r--r--services/surfaceflinger/Scheduler/RefreshRateConfigs.h7
-rw-r--r--services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp243
12 files changed, 482 insertions, 34 deletions
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 2d11b908c2..30ef4b9f55 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1793,8 +1793,8 @@ static Dumpstate::RunStatus dumpstate() {
// 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 @@ void dump_route_tables() {
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 83e6787ebf..34280d01e8 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -642,6 +642,9 @@ void do_dmesg();
/* 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 0712c0adcd..28e5ee2ca9 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -240,11 +240,11 @@ TEST_F(ZippedBugreportGenerationTest, Is1MBMBinSize) {
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 95d9377a89..b84be9b1e6 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1766,6 +1766,10 @@ binder::Status InstalldNativeService::getAppSize(const std::optional<std::string
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 36574974d9..b910ac103b 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -322,6 +322,19 @@ TEST_F(ServiceTest, GetAppSize) {
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 77a883b332..bf275a5900 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -391,6 +391,71 @@ void DisplayState::merge(const DisplayState& other) {
}
}
+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 725ea6571d..4bcc9d56c8 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -551,6 +551,13 @@ SurfaceComposerClient::Transaction::Transaction(const Transaction& other)
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 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel
if (composerState.read(*parcel) == BAD_VALUE) {
return BAD_VALUE;
}
-
composerStates[surfaceControlHandle] = composerState;
}
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 03e4aacdbe..2a8d30d2da 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -61,6 +61,12 @@ struct client_cache_t {
* 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 @@ struct layer_state_t {
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 0d1d1a37bd..76b6d44fd2 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -590,6 +590,14 @@ public:
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/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 0ee9fb353d..a56827e8f1 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -134,42 +134,37 @@ bool RefreshRateConfigs::isVoteAllowed(const LayerRequirement& layer,
return true;
}
-float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer,
- const RefreshRate& refreshRate,
- bool isSeamlessSwitch) const {
- if (!isVoteAllowed(layer, refreshRate)) {
- return 0;
- }
-
- // Slightly prefer seamless switches.
- constexpr float kSeamedSwitchPenalty = 0.95f;
- const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty;
-
- // If the layer wants Max, give higher score to the higher refresh rate
- if (layer.vote == LayerVoteType::Max) {
- const auto ratio = refreshRate.getFps().getValue() /
- mAppRequestRefreshRates.back()->getFps().getValue();
- // use ratio^2 to get a lower score the more we get further from peak
- return ratio * ratio;
- }
+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 time to render a frame
+ // 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] =
@@ -177,7 +172,7 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye
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;
+ return 1.0f;
}
if (displayFramesQuotient == 0) {
@@ -195,7 +190,29 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye
iter++;
}
- return (1.0f / iter) * seamlessness;
+ return (1.0f / iter);
+ }
+
+ return 0;
+}
+
+float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer,
+ const RefreshRate& refreshRate,
+ bool isSeamlessSwitch) const {
+ if (!isVoteAllowed(layer, refreshRate)) {
+ return 0;
+ }
+
+ // Slightly prefer seamless switches.
+ constexpr float kSeamedSwitchPenalty = 0.95f;
+ const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty;
+
+ // If the layer wants Max, give higher score to the higher refresh rate
+ if (layer.vote == LayerVoteType::Max) {
+ const auto ratio = refreshRate.getFps().getValue() /
+ mAppRequestRefreshRates.back()->getFps().getValue();
+ // use ratio^2 to get a lower score the more we get further from peak
+ return ratio * ratio;
}
if (layer.vote == LayerVoteType::ExplicitExact) {
@@ -210,7 +227,18 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye
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 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked(
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 @@ RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverr
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 @@ const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end)
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 @@ int RefreshRateConfigs::getFrameRateDivider(Fps displayFrameRate, Fps layerFrame
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 21867ccac9..99f217c2e2 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -344,6 +344,10 @@ public:
// 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 @@ private:
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 c1dba2bd61..77b75ab767 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -98,9 +98,15 @@ protected:
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 @@ protected:
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 @@ protected:
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 @@ protected:
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 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitDefault) {
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 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExactTouchBoost) {
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 @@ TEST_F(RefreshRateConfigsTest, getFrameRateDivider) {
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=*/