Merge "Remove HWC trace from default surface traces." into rvc-dev
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 466575f..a0b9cbb 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -84,7 +84,8 @@
android::base::unique_fd bugreport_fd,
android::base::unique_fd screenshot_fd,
int bugreport_mode,
- const sp<IDumpstateListener>& listener) {
+ const sp<IDumpstateListener>& listener,
+ bool is_screenshot_requested) {
MYLOGI("startBugreport() with mode: %d\n", bugreport_mode);
// Ensure there is only one bugreport in progress at a time.
@@ -118,7 +119,7 @@
std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
options->Initialize(static_cast<Dumpstate::BugreportMode>(bugreport_mode), bugreport_fd,
- screenshot_fd);
+ screenshot_fd, is_screenshot_requested);
if (bugreport_fd.get() == -1 || (options->do_screenshot && screenshot_fd.get() == -1)) {
MYLOGE("Invalid filedescriptor");
diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h
index 6dc0225..ac8d3ac 100644
--- a/cmds/dumpstate/DumpstateService.h
+++ b/cmds/dumpstate/DumpstateService.h
@@ -41,7 +41,8 @@
binder::Status startBugreport(int32_t calling_uid, const std::string& calling_package,
android::base::unique_fd bugreport_fd,
android::base::unique_fd screenshot_fd, int bugreport_mode,
- const sp<IDumpstateListener>& listener) override;
+ const sp<IDumpstateListener>& listener,
+ bool is_screenshot_requested) override;
// No-op
binder::Status cancelBugreport();
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index 3f359c8..ba008bb 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -64,10 +64,12 @@
* @param screenshotFd the file to which screenshot should be written
* @param bugreportMode the mode that specifies other run time options; must be one of above
* @param listener callback for updates; optional
+ * @param isScreenshotRequested indicates screenshot is requested or not
*/
void startBugreport(int callingUid, @utf8InCpp String callingPackage,
FileDescriptor bugreportFd, FileDescriptor screenshotFd,
- int bugreportMode, IDumpstateListener listener);
+ int bugreportMode, IDumpstateListener listener,
+ boolean isScreenshotRequested);
/*
* Cancels the bugreport currently in progress.
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 3440116..ec2b922 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1477,6 +1477,8 @@
ds.AddDir(WMTRACE_DATA_DIR, false);
}
+ ds.AddDir(SNAPSHOTCTL_LOG_DIR, false);
+
RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard);
/* Migrate the ril_dumpstate to a device specific dumpstate? */
@@ -1605,7 +1607,6 @@
ds.AddDir(RECOVERY_DATA_DIR, true);
ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
ds.AddDir(LOGPERSIST_DATA_DIR, false);
- ds.AddDir(SNAPSHOTCTL_LOG_DIR, false);
if (!PropertiesHelper::IsUserBuild()) {
ds.AddDir(PROFILE_DATA_DIR_CUR, true);
ds.AddDir(PROFILE_DATA_DIR_REF, true);
@@ -1728,6 +1729,8 @@
RunDumpsys("DUMPSYS", {"netpolicy"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
RunDumpsys("DUMPSYS", {"network_management"}, CommandOptions::WithTimeout(90).Build(),
SEC_TO_MSEC(10));
+ RunDumpsys("DUMPSYS", {"telephony.registry"}, CommandOptions::WithTimeout(90).Build(),
+ SEC_TO_MSEC(10));
if (include_sensitive_info) {
// Contains raw IP addresses, omit from reports on user builds.
RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
@@ -2246,20 +2249,21 @@
}
}
-static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) {
+static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options,
+ bool is_screenshot_requested) {
// Modify com.android.shell.BugreportProgressService#isDefaultScreenshotRequired as well for
// default system screenshots.
options->bugreport_mode = ModeToString(mode);
switch (mode) {
case Dumpstate::BugreportMode::BUGREPORT_FULL:
- options->do_screenshot = true;
+ options->do_screenshot = is_screenshot_requested;
options->dumpstate_hal_mode = DumpstateMode::FULL;
break;
case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
// Currently, the dumpstate binder is only used by Shell to update progress.
options->do_start_service = true;
options->do_progress_updates = true;
- options->do_screenshot = true;
+ options->do_screenshot = is_screenshot_requested;
options->dumpstate_hal_mode = DumpstateMode::INTERACTIVE;
break;
case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
@@ -2272,7 +2276,7 @@
options->do_start_service = true;
options->do_progress_updates = true;
options->do_zip_file = true;
- options->do_screenshot = true;
+ options->do_screenshot = is_screenshot_requested;
options->dumpstate_hal_mode = DumpstateMode::WEAR;
break;
// TODO(b/148168577) rename TELEPHONY everywhere to CONNECTIVITY.
@@ -2309,7 +2313,8 @@
void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
const android::base::unique_fd& bugreport_fd_in,
- const android::base::unique_fd& screenshot_fd_in) {
+ const android::base::unique_fd& screenshot_fd_in,
+ bool is_screenshot_requested) {
// In the new API world, date is always added; output is always a zip file.
// TODO(111441001): remove these options once they are obsolete.
do_add_date = true;
@@ -2319,7 +2324,7 @@
bugreport_fd.reset(dup(bugreport_fd_in.get()));
screenshot_fd.reset(dup(screenshot_fd_in.get()));
- SetOptionsFromMode(bugreport_mode, this);
+ SetOptionsFromMode(bugreport_mode, this, is_screenshot_requested);
}
Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) {
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 7e27787..7b8d282 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -390,7 +390,8 @@
/* Initializes options from the requested mode. */
void Initialize(BugreportMode bugreport_mode, const android::base::unique_fd& bugreport_fd,
- const android::base::unique_fd& screenshot_fd);
+ const android::base::unique_fd& screenshot_fd,
+ bool is_screenshot_requested);
/* Returns true if the options set so far are consistent. */
bool ValidateOptions() const;
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index f26e4db..047a1c3 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -451,7 +451,7 @@
sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout))));
android::binder::Status status =
ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd), std::move(screenshot_fd),
- Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener);
+ Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener, true);
// startBugreport is an async call. Verify binder call succeeded first, then wait till listener
// gets expected callbacks.
EXPECT_TRUE(status.isOk());
@@ -488,7 +488,7 @@
android::binder::Status status =
ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd), std::move(screenshot_fd),
2000, // invalid bugreport mode
- listener);
+ listener, false);
EXPECT_EQ(listener->getErrorCode(), IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
// The service should have died, freeing itself up for a new invocation.
@@ -519,13 +519,13 @@
sp<DumpstateListener> listener1(new DumpstateListener(dup(fileno(stdout))));
android::binder::Status status =
ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd), std::move(screenshot_fd),
- Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener1);
+ Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener1, true);
EXPECT_TRUE(status.isOk());
// try to make another call to startBugreport. This should fail.
sp<DumpstateListener> listener2(new DumpstateListener(dup(fileno(stdout))));
status = ds_binder->startBugreport(123, "com.dummy.package", std::move(bugreport_fd2), std::move(screenshot_fd2),
- Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener2);
+ Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener2, true);
EXPECT_FALSE(status.isOk());
WaitTillExecutionComplete(listener2.get());
EXPECT_EQ(listener2->getErrorCode(),
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 0a0c40e..2efb130 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -233,7 +233,7 @@
}
TEST_F(DumpOptionsTest, InitializeFullBugReport) {
- options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_FULL, fd, fd);
+ options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_FULL, fd, fd, true);
EXPECT_TRUE(options_.do_add_date);
EXPECT_TRUE(options_.do_screenshot);
EXPECT_TRUE(options_.do_zip_file);
@@ -250,7 +250,7 @@
}
TEST_F(DumpOptionsTest, InitializeInteractiveBugReport) {
- options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, fd, fd);
+ options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, fd, fd, true);
EXPECT_TRUE(options_.do_add_date);
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.do_progress_updates);
@@ -267,7 +267,7 @@
}
TEST_F(DumpOptionsTest, InitializeRemoteBugReport) {
- options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_REMOTE, fd, fd);
+ options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_REMOTE, fd, fd, false);
EXPECT_TRUE(options_.do_add_date);
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.is_remote_mode);
@@ -283,7 +283,7 @@
}
TEST_F(DumpOptionsTest, InitializeWearBugReport) {
- options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WEAR, fd, fd);
+ options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WEAR, fd, fd, true);
EXPECT_TRUE(options_.do_add_date);
EXPECT_TRUE(options_.do_screenshot);
EXPECT_TRUE(options_.do_zip_file);
@@ -300,7 +300,7 @@
}
TEST_F(DumpOptionsTest, InitializeTelephonyBugReport) {
- options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_TELEPHONY, fd, fd);
+ options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_TELEPHONY, fd, fd, false);
EXPECT_TRUE(options_.do_add_date);
EXPECT_FALSE(options_.do_screenshot);
EXPECT_TRUE(options_.do_zip_file);
@@ -317,7 +317,7 @@
}
TEST_F(DumpOptionsTest, InitializeWifiBugReport) {
- options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WIFI, fd, fd);
+ options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WIFI, fd, fd, false);
EXPECT_TRUE(options_.do_add_date);
EXPECT_FALSE(options_.do_screenshot);
EXPECT_TRUE(options_.do_zip_file);
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index 43b0da3..2174ce2 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -96,11 +96,11 @@
}
int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage,
- const std::unique_ptr<String16>& featureId, const String16& message) {
+ const std::unique_ptr<String16>& attributionTag, const String16& message) {
sp<IAppOpsService> service = getService();
int32_t mode = service != nullptr
- ? service->noteOperation(op, uid, callingPackage, featureId, shouldCollectNotes(op),
- message)
+ ? service->noteOperation(op, uid, callingPackage, attributionTag,
+ shouldCollectNotes(op), message)
: AppOpsManager::MODE_IGNORED;
return mode;
@@ -113,12 +113,12 @@
}
int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
- bool startIfModeDefault, const std::unique_ptr<String16>& featureId,
+ bool startIfModeDefault, const std::unique_ptr<String16>& attributionTag,
const String16& message) {
sp<IAppOpsService> service = getService();
int32_t mode = service != nullptr
? service->startOperation(getClientId(), op, uid, callingPackage,
- featureId, startIfModeDefault, shouldCollectNotes(op), message)
+ attributionTag, startIfModeDefault, shouldCollectNotes(op), message)
: AppOpsManager::MODE_IGNORED;
return mode;
@@ -129,10 +129,10 @@
}
void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage,
- const std::unique_ptr<String16>& callingFeatureId) {
+ const std::unique_ptr<String16>& attributionTag) {
sp<IAppOpsService> service = getService();
if (service != nullptr) {
- service->finishOperation(getClientId(), op, uid, callingPackage, callingFeatureId);
+ service->finishOperation(getClientId(), op, uid, callingPackage, attributionTag);
}
}
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index a5555a3..0714723 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -47,14 +47,14 @@
}
virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName,
- const std::unique_ptr<String16>& featureId, bool shouldCollectAsyncNotedOp,
+ const std::unique_ptr<String16>& attributionTag, bool shouldCollectAsyncNotedOp,
const String16& message) {
Parcel data, reply;
data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
data.writeInt32(code);
data.writeInt32(uid);
data.writeString16(packageName);
- data.writeString16(featureId);
+ data.writeString16(attributionTag);
data.writeInt32(shouldCollectAsyncNotedOp ? 1 : 0);
data.writeString16(message);
remote()->transact(NOTE_OPERATION_TRANSACTION, data, &reply);
@@ -64,7 +64,7 @@
}
virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
- const String16& packageName, const std::unique_ptr<String16>& featureId,
+ const String16& packageName, const std::unique_ptr<String16>& attributionTag,
bool startIfModeDefault, bool shouldCollectAsyncNotedOp, const String16& message) {
Parcel data, reply;
data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
@@ -72,7 +72,7 @@
data.writeInt32(code);
data.writeInt32(uid);
data.writeString16(packageName);
- data.writeString16(featureId);
+ data.writeString16(attributionTag);
data.writeInt32(startIfModeDefault ? 1 : 0);
data.writeInt32(shouldCollectAsyncNotedOp ? 1 : 0);
data.writeString16(message);
@@ -83,14 +83,14 @@
}
virtual void finishOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
- const String16& packageName, const std::unique_ptr<String16>& featureId) {
+ const String16& packageName, const std::unique_ptr<String16>& attributionTag) {
Parcel data, reply;
data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
data.writeStrongBinder(token);
data.writeInt32(code);
data.writeInt32(uid);
data.writeString16(packageName);
- data.writeString16(featureId);
+ data.writeString16(attributionTag);
remote()->transact(FINISH_OPERATION_TRANSACTION, data, &reply);
}
@@ -182,11 +182,11 @@
int32_t code = data.readInt32();
int32_t uid = data.readInt32();
String16 packageName = data.readString16();
- std::unique_ptr<String16> featureId;
- data.readString16(&featureId);
+ std::unique_ptr<String16> attributionTag;
+ data.readString16(&attributionTag);
bool shouldCollectAsyncNotedOp = data.readInt32() == 1;
String16 message = data.readString16();
- int32_t res = noteOperation(code, uid, packageName, featureId,
+ int32_t res = noteOperation(code, uid, packageName, attributionTag,
shouldCollectAsyncNotedOp, message);
reply->writeNoException();
reply->writeInt32(res);
@@ -198,12 +198,12 @@
int32_t code = data.readInt32();
int32_t uid = data.readInt32();
String16 packageName = data.readString16();
- std::unique_ptr<String16> featureId;
- data.readString16(&featureId);
+ std::unique_ptr<String16> attributionTag;
+ data.readString16(&attributionTag);
bool startIfModeDefault = data.readInt32() == 1;
bool shouldCollectAsyncNotedOp = data.readInt32() == 1;
String16 message = data.readString16();
- int32_t res = startOperation(token, code, uid, packageName, featureId,
+ int32_t res = startOperation(token, code, uid, packageName, attributionTag,
startIfModeDefault, shouldCollectAsyncNotedOp, message);
reply->writeNoException();
reply->writeInt32(res);
@@ -215,9 +215,9 @@
int32_t code = data.readInt32();
int32_t uid = data.readInt32();
String16 packageName = data.readString16();
- std::unique_ptr<String16> featureId;
- data.readString16(&featureId);
- finishOperation(token, code, uid, packageName, featureId);
+ std::unique_ptr<String16> attributionTag;
+ data.readString16(&attributionTag);
+ finishOperation(token, code, uid, packageName, attributionTag);
reply->writeNoException();
return NO_ERROR;
} break;
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
index 5b6eb68..2ee5930 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -134,18 +134,18 @@
// const String16&) instead
int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage);
int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage,
- const std::unique_ptr<String16>& featureId, const String16& message);
+ const std::unique_ptr<String16>& attributionTag, const String16& message);
// @Deprecated, use startOpNoThrow(int32_t, int32_t, const String16&, bool, const String16&,
// const String16&) instead
int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
bool startIfModeDefault);
int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
- bool startIfModeDefault, const std::unique_ptr<String16>& featureId,
+ bool startIfModeDefault, const std::unique_ptr<String16>& attributionTag,
const String16& message);
// @Deprecated, use finishOp(int32_t, int32_t, const String16&, bool, const String16&) instead
void finishOp(int32_t op, int32_t uid, const String16& callingPackage);
void finishOp(int32_t op, int32_t uid, const String16& callingPackage,
- const std::unique_ptr<String16>& featureId);
+ const std::unique_ptr<String16>& attributionTag);
void startWatchingMode(int32_t op, const String16& packageName,
const sp<IAppOpsCallback>& callback);
void stopWatchingMode(const sp<IAppOpsCallback>& callback);
diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h
index 1b4bcce..1ffb8de 100644
--- a/libs/binder/include/binder/IAppOpsService.h
+++ b/libs/binder/include/binder/IAppOpsService.h
@@ -36,13 +36,13 @@
virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName,
- const std::unique_ptr<String16>& featureId, bool shouldCollectAsyncNotedOp,
+ const std::unique_ptr<String16>& attributionTag, bool shouldCollectAsyncNotedOp,
const String16& message) = 0;
virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
- const String16& packageName, const std::unique_ptr<String16>& featureId,
+ const String16& packageName, const std::unique_ptr<String16>& attributionTag,
bool startIfModeDefault, bool shouldCollectAsyncNotedOp, const String16& message) = 0;
virtual void finishOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
- const String16& packageName, const std::unique_ptr<String16>& featureId) = 0;
+ const String16& packageName, const std::unique_ptr<String16>& attributionTag) = 0;
virtual void startWatchingMode(int32_t op, const String16& packageName,
const sp<IAppOpsCallback>& callback) = 0;
virtual void stopWatchingMode(const sp<IAppOpsCallback>& callback) = 0;
diff --git a/libs/binder/include/binder/Nullable.h b/libs/binder/include/binder/Nullable.h
new file mode 100644
index 0000000..b605bd3
--- /dev/null
+++ b/libs/binder/include/binder/Nullable.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <memory>
+#include <utility>
+
+namespace android {
+
+namespace aidl {
+
+// nullable/make_nullable provide source-level compatibility between std::opional and std::unique_ptr
+// usage:
+// nullable<Foo> a;
+// nullable<Foo> b = make_nullable<Foo>(...);
+// auto c = make_nullable<Foo>(...);
+// c.reset();
+// c = make_nullable<Foo>(...);
+// c = std::move(a);
+
+template <typename T>
+using nullable = std::unique_ptr<T>;
+
+template <typename T, typename... Args>
+inline nullable<T> make_nullable(Args&&... args) {
+ return std::make_unique<T>(std::forward<Args>(args)...);
+}
+
+} // namespace aidl
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 75dcdc8..649faa1 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -486,7 +486,6 @@
void AIBinder_incStrong(AIBinder* binder) {
if (binder == nullptr) {
- LOG(ERROR) << __func__ << ": on null binder";
return;
}
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index befabee..4809c1f 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -61,26 +61,25 @@
VNDKSP = 1,
};
-static constexpr const char* kNativeLibrariesSystemConfigPath[] = {"/etc/llndk.libraries.txt",
- "/etc/vndksp.libraries.txt"};
+static constexpr const char* kNativeLibrariesSystemConfigPath[] =
+ {"/apex/com.android.vndk.v{}/etc/llndk.libraries.{}.txt",
+ "/apex/com.android.vndk.v{}/etc/vndksp.libraries.{}.txt"};
static std::string vndkVersionStr() {
#ifdef __BIONIC__
- std::string version = android::base::GetProperty("ro.vndk.version", "");
- if (version != "" && version != "current") {
- return "." + version;
- }
+ return android::base::GetProperty("ro.vndk.version", "");
#endif
return "";
}
static void insertVndkVersionStr(std::string* fileName) {
LOG_ALWAYS_FATAL_IF(!fileName, "fileName should never be nullptr");
- size_t insertPos = fileName->find_last_of(".");
- if (insertPos == std::string::npos) {
- insertPos = fileName->length();
+ std::string version = vndkVersionStr();
+ size_t pos = fileName->find("{}");
+ while (pos != std::string::npos) {
+ fileName->replace(pos, 2, version);
+ pos = fileName->find("{}", pos + version.size());
}
- fileName->insert(insertPos, vndkVersionStr());
}
static bool readConfig(const std::string& configFile, std::vector<std::string>* soNames) {
@@ -103,11 +102,7 @@
}
static const std::string getSystemNativeLibraries(NativeLibrary type) {
- static const char* androidRootEnv = getenv("ANDROID_ROOT");
- static const std::string rootDir = androidRootEnv != nullptr ? androidRootEnv : "/system";
-
- std::string nativeLibrariesSystemConfig = rootDir + kNativeLibrariesSystemConfigPath[type];
-
+ std::string nativeLibrariesSystemConfig = kNativeLibrariesSystemConfigPath[type];
insertVndkVersionStr(&nativeLibrariesSystemConfig);
std::vector<std::string> soNames;
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 04c21a9..8d79cf8 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -1140,8 +1140,7 @@
return err;
}
- err = remote()->transact(BnSurfaceComposer::SET_FRAME_RATE, data, &reply,
- IBinder::FLAG_ONEWAY);
+ err = remote()->transact(BnSurfaceComposer::SET_FRAME_RATE, data, &reply);
if (err != NO_ERROR) {
ALOGE("setFrameRate: failed to transact: %s (%d)", strerror(-err), err);
return err;
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index a9c9b74..f7158d0 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -443,39 +443,18 @@
// ------------------------------- InputWindowCommands ----------------------------------------
void InputWindowCommands::merge(const InputWindowCommands& other) {
- transferTouchFocusCommands
- .insert(transferTouchFocusCommands.end(),
- std::make_move_iterator(other.transferTouchFocusCommands.begin()),
- std::make_move_iterator(other.transferTouchFocusCommands.end()));
-
syncInputWindows |= other.syncInputWindows;
}
void InputWindowCommands::clear() {
- transferTouchFocusCommands.clear();
syncInputWindows = false;
}
void InputWindowCommands::write(Parcel& output) const {
- output.writeUint32(static_cast<uint32_t>(transferTouchFocusCommands.size()));
- for (const auto& transferTouchFocusCommand : transferTouchFocusCommands) {
- output.writeStrongBinder(transferTouchFocusCommand.fromToken);
- output.writeStrongBinder(transferTouchFocusCommand.toToken);
- }
-
output.writeBool(syncInputWindows);
}
void InputWindowCommands::read(const Parcel& input) {
- size_t count = input.readUint32();
- transferTouchFocusCommands.clear();
- for (size_t i = 0; i < count; i++) {
- TransferTouchFocusCommand transferTouchFocusCommand;
- transferTouchFocusCommand.fromToken = input.readStrongBinder();
- transferTouchFocusCommand.toToken = input.readStrongBinder();
- transferTouchFocusCommands.emplace_back(transferTouchFocusCommand);
- }
-
syncInputWindows = input.readBool();
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index dc4860a..2307fbf 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1290,15 +1290,6 @@
return *this;
}
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::transferTouchFocus(
- const sp<IBinder>& fromToken, const sp<IBinder>& toToken) {
- InputWindowCommands::TransferTouchFocusCommand transferTouchFocusCommand;
- transferTouchFocusCommand.fromToken = fromToken;
- transferTouchFocusCommand.toToken = toToken;
- mInputWindowCommands.transferTouchFocusCommands.emplace_back(transferTouchFocusCommand);
- return *this;
-}
-
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::syncInputWindows() {
mInputWindowCommands.syncInputWindows = true;
return *this;
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 7e3d5d5..2b2f773 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -271,12 +271,6 @@
};
struct InputWindowCommands {
- struct TransferTouchFocusCommand {
- sp<IBinder> fromToken;
- sp<IBinder> toToken;
- };
-
- std::vector<TransferTouchFocusCommand> transferTouchFocusCommands;
bool syncInputWindows{false};
void merge(const InputWindowCommands& other);
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 0cf141d..2fb9538 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -507,7 +507,6 @@
#ifndef NO_INPUT
Transaction& setInputWindowInfo(const sp<SurfaceControl>& sc, const InputWindowInfo& info);
- Transaction& transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
Transaction& syncInputWindows();
#endif
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 0d4305b..e73f245 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -957,9 +957,13 @@
return NO_ERROR;
}
- if (bufferFence.get() >= 0 && !waitFence(std::move(bufferFence))) {
- ATRACE_NAME("Waiting before draw");
- sync_wait(bufferFence.get(), -1);
+ if (bufferFence.get() >= 0) {
+ // Duplicate the fence for passing to waitFence.
+ base::unique_fd bufferFenceDup(dup(bufferFence.get()));
+ if (bufferFenceDup < 0 || !waitFence(std::move(bufferFenceDup))) {
+ ATRACE_NAME("Waiting before draw");
+ sync_wait(bufferFence.get(), -1);
+ }
}
if (buffer == nullptr) {
diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
index 6fd4b80..d8e4059 100644
--- a/libs/ui/Gralloc4.cpp
+++ b/libs/ui/Gralloc4.cpp
@@ -77,6 +77,7 @@
outDescriptorInfo->layerCount = layerCount;
outDescriptorInfo->format = static_cast<hardware::graphics::common::V1_2::PixelFormat>(format);
outDescriptorInfo->usage = usage;
+ outDescriptorInfo->reservedSize = 0;
}
} // anonymous namespace
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 67d69b4..a58e87c 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -158,13 +158,16 @@
// NOTE: This is only valid if the backend is OpenGL
attrs.push_back(EGL_PLATFORM_ANGLE_EGL_HANDLE_ANGLE);
attrs.push_back(vendorEGL);
+
+ // Context virtualization is only available on GL back-end.
+ // Needed to support threading with GL back-end
+ attrs.push_back(EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE);
+ attrs.push_back(EGL_FALSE);
break;
default:
- ALOGV("%s: Requesting Unknown (%d) ANGLE back-end", __FUNCTION__, cnx->angleBackend);
+ ALOGE("%s: Requesting Unknown (%d) ANGLE back-end", __FUNCTION__, cnx->angleBackend);
break;
}
- attrs.push_back(EGL_PLATFORM_ANGLE_CONTEXT_VIRTUALIZATION_ANGLE);
- attrs.push_back(EGL_FALSE);
return true;
}
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 18f7f44..4e5c593 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -346,8 +346,6 @@
mPreviousBufferId = getCurrentBufferId();
mBufferInfo.mBuffer =
mConsumer->getCurrentBuffer(&mBufferInfo.mBufferSlot, &mBufferInfo.mFence);
- auto* layerCompositionState = editCompositionState();
- layerCompositionState->buffer = mBufferInfo.mBuffer;
if (mBufferInfo.mBuffer == nullptr) {
// this can only happen if the very first buffer was rejected.
@@ -441,7 +439,7 @@
mQueueItemCondition.broadcast();
}
- mFlinger->mInterceptor->saveBufferUpdate(this, item.mGraphicBuffer->getWidth(),
+ mFlinger->mInterceptor->saveBufferUpdate(layerId, item.mGraphicBuffer->getWidth(),
item.mGraphicBuffer->getHeight(), item.mFrameNumber);
mFlinger->signalLayerUpdate();
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index de5429b..3ed6889 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -616,7 +616,6 @@
mPreviousBufferId = getCurrentBufferId();
mBufferInfo.mBuffer = s.buffer;
mBufferInfo.mFence = s.acquireFence;
- editCompositionState()->buffer = mBufferInfo.mBuffer;
return NO_ERROR;
}
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
index 9aaef65..f24f314 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
@@ -104,9 +104,8 @@
return static_cast<uint16_t>(value >> 40);
}
-DisplayId DisplayId::fromEdid(uint8_t port, uint16_t manufacturerId, uint32_t displayNameHash) {
- return {(static_cast<Type>(manufacturerId) << 40) | (static_cast<Type>(displayNameHash) << 8) |
- port};
+DisplayId DisplayId::fromEdid(uint8_t port, uint16_t manufacturerId, uint32_t modelHash) {
+ return {(static_cast<Type>(manufacturerId) << 40) | (static_cast<Type>(modelHash) << 8) | port};
}
bool isEdid(const DisplayIdentificationData& data) {
@@ -209,23 +208,30 @@
view.remove_prefix(kDescriptorLength);
}
- if (displayName.empty()) {
+ std::string_view modelString = displayName;
+
+ if (modelString.empty()) {
ALOGW("Invalid EDID: falling back to serial number due to missing display name.");
- displayName = serialNumber;
+ modelString = serialNumber;
}
- if (displayName.empty()) {
+ if (modelString.empty()) {
ALOGW("Invalid EDID: falling back to ASCII text due to missing serial number.");
- displayName = asciiText;
+ modelString = asciiText;
}
- if (displayName.empty()) {
+ if (modelString.empty()) {
ALOGE("Invalid EDID: display name and fallback descriptors are missing.");
return {};
}
+ // Hash model string instead of using product code or (integer) serial number, since the latter
+ // have been observed to change on some displays with multiple inputs.
+ const auto modelHash = static_cast<uint32_t>(std::hash<std::string_view>()(modelString));
+
return Edid{.manufacturerId = manufacturerId,
- .pnpId = *pnpId,
- .displayName = displayName,
.productId = productId,
+ .pnpId = *pnpId,
+ .modelHash = modelHash,
+ .displayName = displayName,
.manufactureWeek = manufactureWeek,
.manufactureOrModelYear = manufactureOrModelYear};
}
@@ -253,10 +259,8 @@
return {};
}
- // Hash display name instead of using product code or serial number, since the latter have been
- // observed to change on some displays with multiple inputs.
- const auto hash = static_cast<uint32_t>(std::hash<std::string_view>()(edid->displayName));
- return DisplayIdentificationInfo{.id = DisplayId::fromEdid(port, edid->manufacturerId, hash),
+ const auto displayId = DisplayId::fromEdid(port, edid->manufacturerId, edid->modelHash);
+ return DisplayIdentificationInfo{.id = displayId,
.name = std::string(edid->displayName),
.deviceProductInfo = buildDeviceProductInfo(*edid)};
}
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
index 0a18ba1..d91b957 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
@@ -34,7 +34,7 @@
uint16_t manufacturerId() const;
- static DisplayId fromEdid(uint8_t port, uint16_t manufacturerId, uint32_t displayNameHash);
+ static DisplayId fromEdid(uint8_t port, uint16_t manufacturerId, uint32_t modelHash);
};
inline bool operator==(DisplayId lhs, DisplayId rhs) {
@@ -61,6 +61,7 @@
uint16_t manufacturerId;
uint16_t productId;
PnpId pnpId;
+ uint32_t modelHash;
std::string_view displayName;
uint8_t manufactureOrModelYear;
uint8_t manufactureWeek;
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 36544b6..aeffb0e 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -57,9 +57,12 @@
*/
FramebufferSurface::FramebufferSurface(HWComposer& hwc, DisplayId displayId,
- const sp<IGraphicBufferConsumer>& consumer)
+ const sp<IGraphicBufferConsumer>& consumer,
+ uint32_t maxWidth, uint32_t maxHeight)
: ConsumerBase(consumer),
mDisplayId(displayId),
+ mMaxWidth(maxWidth),
+ mMaxHeight(maxHeight),
mCurrentBufferSlot(-1),
mCurrentBuffer(),
mCurrentFence(Fence::NO_FENCE),
@@ -75,14 +78,16 @@
GRALLOC_USAGE_HW_RENDER |
GRALLOC_USAGE_HW_COMPOSER);
const auto& activeConfig = mHwc.getActiveConfig(displayId);
- mConsumer->setDefaultBufferSize(activeConfig->getWidth(),
- activeConfig->getHeight());
+ ui::Size limitedSize =
+ limitFramebufferSize(activeConfig->getWidth(), activeConfig->getHeight());
+ mConsumer->setDefaultBufferSize(limitedSize.width, limitedSize.height);
mConsumer->setMaxAcquiredBufferCount(
SurfaceFlinger::maxFrameBufferAcquiredBuffers - 1);
}
-void FramebufferSurface::resizeBuffers(const uint32_t width, const uint32_t height) {
- mConsumer->setDefaultBufferSize(width, height);
+void FramebufferSurface::resizeBuffers(uint32_t width, uint32_t height) {
+ ui::Size limitedSize = limitFramebufferSize(width, height);
+ mConsumer->setDefaultBufferSize(limitedSize.width, limitedSize.height);
}
status_t FramebufferSurface::beginFrame(bool /*mustRecompose*/) {
@@ -177,6 +182,29 @@
}
}
+ui::Size FramebufferSurface::limitFramebufferSize(uint32_t width, uint32_t height) {
+ // TODO(b/149495759): Use the ui::Size constructor once it no longer is broken.
+ ui::Size framebufferSize;
+ framebufferSize.width = width;
+ framebufferSize.height = height;
+ bool wasLimited = true;
+ if (width > mMaxWidth && mMaxWidth != 0) {
+ float aspectRatio = float(width) / float(height);
+ framebufferSize.height = mMaxWidth / aspectRatio;
+ framebufferSize.width = mMaxWidth;
+ wasLimited = true;
+ }
+ if (height > mMaxHeight && mMaxHeight != 0) {
+ float aspectRatio = float(width) / float(height);
+ framebufferSize.height = mMaxHeight;
+ framebufferSize.width = mMaxHeight * aspectRatio;
+ wasLimited = true;
+ }
+ ALOGI_IF(wasLimited, "framebuffer size has been limited to [%dx%d] from [%dx%d]",
+ framebufferSize.width, framebufferSize.height, width, height);
+ return framebufferSize;
+}
+
void FramebufferSurface::dumpAsString(String8& result) const {
Mutex::Autolock lock(mMutex);
result.appendFormat(" FramebufferSurface: dataspace: %s(%d)\n",
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 7f451a5..a1859f3 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -23,6 +23,7 @@
#include <compositionengine/DisplaySurface.h>
#include <compositionengine/impl/HwcBufferCache.h>
#include <gui/ConsumerBase.h>
+#include <ui/Size.h>
#include "DisplayIdentification.h"
@@ -39,7 +40,8 @@
class FramebufferSurface : public ConsumerBase, public compositionengine::DisplaySurface {
public:
FramebufferSurface(HWComposer& hwc, DisplayId displayId,
- const sp<IGraphicBufferConsumer>& consumer);
+ const sp<IGraphicBufferConsumer>& consumer, uint32_t maxWidth,
+ uint32_t maxHeight);
virtual status_t beginFrame(bool mustRecompose);
virtual status_t prepareFrame(CompositionType compositionType);
@@ -47,7 +49,7 @@
virtual void onFrameCommitted();
virtual void dumpAsString(String8& result) const;
- virtual void resizeBuffers(const uint32_t width, const uint32_t height);
+ virtual void resizeBuffers(uint32_t width, uint32_t height);
virtual const sp<Fence>& getClientTargetAcquireFence() const override;
@@ -58,6 +60,9 @@
virtual void dumpLocked(String8& result, const char* prefix) const;
+ // Limits the width and height by the maximum width specified in the constructor.
+ ui::Size limitFramebufferSize(uint32_t width, uint32_t height);
+
// nextBuffer waits for and then latches the next buffer from the
// BufferQueue and releases the previously latched buffer to the
// BufferQueue. The new buffer is returned in the 'buffer' argument.
@@ -66,6 +71,14 @@
const DisplayId mDisplayId;
+ // Framebuffer size has a dimension limitation in pixels based on the graphics capabilities of
+ // the device.
+ const uint32_t mMaxWidth;
+
+ // Framebuffer size has a dimension limitation in pixels based on the graphics capabilities of
+ // the device.
+ const uint32_t mMaxHeight;
+
// mCurrentBufferIndex is the slot index of the current buffer or
// INVALID_BUFFER_SLOT to indicate that either there is no current buffer
// or the buffer is not associated with a slot.
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 3765d0d..3d67a6b 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -116,6 +116,7 @@
mCurrentState.frameRateSelectionPriority = PRIORITY_UNSET;
mCurrentState.metadata = args.metadata;
mCurrentState.shadowRadius = 0.f;
+ mCurrentState.treeHasFrameRateVote = false;
// drawing state & current state are identical
mDrawingState = mCurrentState;
@@ -219,6 +220,9 @@
}
mFlinger->markLayerPendingRemovalLocked(this);
+ if (hasInput()) {
+ mFlinger->dirtyInput();
+ }
}
void Layer::onRemovedFromCurrentState() {
@@ -1334,6 +1338,44 @@
return true;
}
+void Layer::updateTreeHasFrameRateVote() {
+ const auto traverseTree = [&](const LayerVector::Visitor& visitor) {
+ auto parent = getParent();
+ while (parent) {
+ visitor(parent.get());
+ parent = parent->getParent();
+ }
+
+ traverse(LayerVector::StateSet::Current, visitor);
+ };
+
+ // update parents and children about the vote
+ // First traverse the tree and count how many layers has votes
+ int layersWithVote = 0;
+ traverseTree([&layersWithVote](Layer* layer) {
+ if (layer->mCurrentState.frameRate.rate > 0 ||
+ layer->mCurrentState.frameRate.type == FrameRateCompatibility::NoVote) {
+ layersWithVote++;
+ }
+ });
+
+ // Now update the other layers
+ bool transactionNeeded = false;
+ traverseTree([layersWithVote, &transactionNeeded](Layer* layer) {
+ if (layer->mCurrentState.treeHasFrameRateVote != layersWithVote > 0) {
+ layer->mCurrentState.sequence++;
+ layer->mCurrentState.treeHasFrameRateVote = layersWithVote > 0;
+ layer->mCurrentState.modified = true;
+ layer->setTransactionFlags(eTransactionNeeded);
+ transactionNeeded = true;
+ }
+ });
+
+ if (transactionNeeded) {
+ mFlinger->setTransactionFlags(eTraversalNeeded);
+ }
+}
+
bool Layer::setFrameRate(FrameRate frameRate) {
if (!mFlinger->useFrameRateApi) {
return false;
@@ -1345,12 +1387,26 @@
mCurrentState.sequence++;
mCurrentState.frameRate = frameRate;
mCurrentState.modified = true;
+
+ updateTreeHasFrameRateVote();
+
setTransactionFlags(eTransactionNeeded);
return true;
}
-Layer::FrameRate Layer::getFrameRate() const {
- return getDrawingState().frameRate;
+Layer::FrameRate Layer::getFrameRateForLayerTree() const {
+ const auto frameRate = getDrawingState().frameRate;
+ if (frameRate.rate > 0 || frameRate.type == FrameRateCompatibility::NoVote) {
+ return frameRate;
+ }
+
+ // This layer doesn't have a frame rate. If one of its ancestors or successors
+ // have a vote, return a NoVote for ancestors/successors to set the vote
+ if (getDrawingState().treeHasFrameRateVote) {
+ return {0, FrameRateCompatibility::NoVote};
+ }
+
+ return frameRate;
}
void Layer::deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber) {
@@ -1608,6 +1664,7 @@
mCurrentChildren.add(layer);
layer->setParent(this);
+ updateTreeHasFrameRateVote();
}
ssize_t Layer::removeChild(const sp<Layer>& layer) {
@@ -1615,7 +1672,24 @@
setTransactionFlags(eTransactionNeeded);
layer->setParent(nullptr);
- return mCurrentChildren.remove(layer);
+ const auto removeResult = mCurrentChildren.remove(layer);
+
+ updateTreeHasFrameRateVote();
+ layer->updateTreeHasFrameRateVote();
+
+ return removeResult;
+}
+
+void Layer::reparentChildren(const sp<Layer>& newParent) {
+ if (attachChildren()) {
+ setTransactionFlags(eTransactionNeeded);
+ }
+
+ for (const sp<Layer>& child : mCurrentChildren) {
+ newParent->addChild(child);
+ }
+ mCurrentChildren.clear();
+ updateTreeHasFrameRateVote();
}
bool Layer::reparentChildren(const sp<IBinder>& newParentHandle) {
@@ -1631,13 +1705,7 @@
return false;
}
- if (attachChildren()) {
- setTransactionFlags(eTransactionNeeded);
- }
- for (const sp<Layer>& child : mCurrentChildren) {
- newParent->addChild(child);
- }
- mCurrentChildren.clear();
+ reparentChildren(newParent);
return true;
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index e21a866..be80f78 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -259,6 +259,9 @@
int32_t frameRateSelectionPriority;
FrameRate frameRate;
+
+ // Indicates whether parents / children of this layer had set FrameRate
+ bool treeHasFrameRateVote;
};
explicit Layer(const LayerCreationArgs& args);
@@ -344,7 +347,8 @@
virtual void deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber);
virtual bool setOverrideScalingMode(int32_t overrideScalingMode);
virtual bool setMetadata(const LayerMetadata& data);
- virtual bool reparentChildren(const sp<IBinder>& layer);
+ bool reparentChildren(const sp<IBinder>& newParentHandle);
+ void reparentChildren(const sp<Layer>& newParent);
virtual void setChildrenDrawingParent(const sp<Layer>& layer);
virtual bool reparent(const sp<IBinder>& newParentHandle);
virtual bool detachChildren();
@@ -801,7 +805,7 @@
Rect getCroppedBufferSize(const Layer::State& s) const;
bool setFrameRate(FrameRate frameRate);
- virtual FrameRate getFrameRate() const;
+ virtual FrameRate getFrameRateForLayerTree() const;
protected:
// constant
@@ -830,6 +834,7 @@
// For unit tests
friend class TestableSurfaceFlinger;
friend class RefreshRateSelectionTest;
+ friend class SetFrameRateTest;
virtual void commitTransaction(const State& stateToCommit);
@@ -1017,6 +1022,8 @@
LayerVector makeChildrenTraversalList(LayerVector::StateSet stateSet,
const std::vector<Layer*>& layersInTree);
+ void updateTreeHasFrameRateVote();
+
// Cached properties computed from drawing state
// Effective transform taking into account parent transforms and any parent scaling.
ui::Transform mEffectiveTransform;
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
index d3364a0..e6c8654 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -120,7 +120,7 @@
// We latch the transparent region here, instead of above where we latch
// the rest of the geometry because it is only content but not necessarily
// resize dependent.
- if (!mFront.activeTransparentRegion_legacy.isTriviallyEqual(
+ if (!mFront.activeTransparentRegion_legacy.hasSameRects(
mFront.requestedTransparentRegion_legacy)) {
mFront.activeTransparentRegion_legacy = mFront.requestedTransparentRegion_legacy;
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 0031d70..68cd84f 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -201,9 +201,10 @@
void RegionSamplingThread::addListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
const sp<IRegionSamplingListener>& listener) {
- wp<Layer> stopLayer = stopLayerHandle != nullptr
- ? static_cast<Layer::Handle*>(stopLayerHandle.get())->owner
- : nullptr;
+ wp<Layer> stopLayer;
+ if (stopLayerHandle != nullptr && stopLayerHandle->localBinder() != nullptr) {
+ stopLayer = static_cast<Layer::Handle*>(stopLayerHandle.get())->owner;
+ }
sp<IBinder> asBinder = IInterface::asBinder(listener);
asBinder->linkToDeath(this);
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index a8e6756..8958d9a 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -39,7 +39,7 @@
namespace {
bool isLayerActive(const Layer& layer, const LayerInfo& info, nsecs_t threshold) {
- if (layer.getFrameRate().rate > 0) {
+ if (layer.getFrameRateForLayerTree().rate > 0) {
return layer.isVisible();
}
return layer.isVisible() && info.getLastUpdatedTime() >= threshold;
@@ -109,7 +109,7 @@
// Only use the layer if the reference still exists.
if (layer || CC_UNLIKELY(mTraceEnabled)) {
// Check if frame rate was set on layer.
- const auto frameRate = layer->getFrameRate();
+ const auto frameRate = layer->getFrameRateForLayerTree();
if (frameRate.rate > 0.f) {
const auto voteType = [&]() {
switch (frameRate.type) {
diff --git a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
index 6ef6ce4..8b08592 100644
--- a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
@@ -40,7 +40,7 @@
namespace {
bool isLayerActive(const Layer& layer, const LayerInfoV2& info, nsecs_t threshold) {
- if (layer.getFrameRate().rate > 0) {
+ if (layer.getFrameRateForLayerTree().rate > 0) {
return layer.isVisible();
}
return layer.isVisible() && info.getLastUpdatedTime() >= threshold;
@@ -166,7 +166,7 @@
if (const auto layer = weak.promote(); layer && isLayerActive(*layer, *info, threshold)) {
i++;
// Set layer vote if set
- const auto frameRate = layer->getFrameRate();
+ const auto frameRate = layer->getFrameRateForLayerTree();
const auto voteType = [&]() {
switch (frameRate.type) {
case Layer::FrameRateCompatibility::Default:
@@ -212,7 +212,5 @@
for (const auto& [layer, info] : activeLayers()) {
info->clearHistory();
}
-
- mActiveLayersEnd = 0;
}
} // namespace android::scheduler::impl
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 9edbaee..02d0b53 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -23,6 +23,9 @@
#include <chrono>
#include <cmath>
+#undef LOG_TAG
+#define LOG_TAG "RefreshRateConfigs"
+
namespace android::scheduler {
using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType;
@@ -95,22 +98,19 @@
}
const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2(
- const std::vector<LayerRequirement>& layers, bool touchActive) const {
+ const std::vector<LayerRequirement>& layers, bool touchActive,
+ bool* touchConsidered) const {
ATRACE_CALL();
ALOGV("getRefreshRateForContent %zu layers", layers.size());
+ *touchConsidered = false;
std::lock_guard lock(mLock);
- // For now if the touch is active return the peak refresh rate
- // This should be optimized to consider other layers as well.
- if (touchActive) {
- return *mAvailableRefreshRates.back();
- }
-
// If there are not layers, there is not content detection, so return the current
// refresh rate.
if (layers.empty()) {
- return getCurrentRefreshRateByPolicyLocked();
+ *touchConsidered = touchActive;
+ return touchActive ? *mAvailableRefreshRates.back() : getCurrentRefreshRateByPolicyLocked();
}
int noVoteLayers = 0;
@@ -118,17 +118,30 @@
int maxVoteLayers = 0;
int explicitDefaultVoteLayers = 0;
int explicitExactOrMultipleVoteLayers = 0;
+ float maxExplicitWeight = 0;
for (const auto& layer : layers) {
- if (layer.vote == LayerVoteType::NoVote)
+ if (layer.vote == LayerVoteType::NoVote) {
noVoteLayers++;
- else if (layer.vote == LayerVoteType::Min)
+ } else if (layer.vote == LayerVoteType::Min) {
minVoteLayers++;
- else if (layer.vote == LayerVoteType::Max)
+ } else if (layer.vote == LayerVoteType::Max) {
maxVoteLayers++;
- else if (layer.vote == LayerVoteType::ExplicitDefault)
+ } else if (layer.vote == LayerVoteType::ExplicitDefault) {
explicitDefaultVoteLayers++;
- else if (layer.vote == LayerVoteType::ExplicitExactOrMultiple)
+ maxExplicitWeight = std::max(maxExplicitWeight, layer.weight);
+ } else if (layer.vote == LayerVoteType::ExplicitExactOrMultiple) {
explicitExactOrMultipleVoteLayers++;
+ maxExplicitWeight = std::max(maxExplicitWeight, layer.weight);
+ }
+ }
+
+ // Consider the touch event if there are no ExplicitDefault layers.
+ // ExplicitDefault are mostly interactive (as opposed to ExplicitExactOrMultiple)
+ // and therefore if those posted an explicit vote we should not change it
+ // if get get a touch event.
+ if (touchActive && explicitDefaultVoteLayers == 0) {
+ *touchConsidered = true;
+ return *mAvailableRefreshRates.back();
}
// Only if all layers want Min we should return Min
@@ -168,16 +181,17 @@
const auto layerPeriod = round<nsecs_t>(1e9f / layer.desiredRefreshRate);
if (layer.vote == LayerVoteType::ExplicitDefault) {
const auto layerScore = [&]() {
- const auto [displayFramesQuot, displayFramesRem] =
- getDisplayFrames(layerPeriod, displayPeriod);
- if (displayFramesQuot == 0) {
- // Layer desired refresh rate is higher the display rate.
- return static_cast<float>(layerPeriod) / static_cast<float>(displayPeriod);
+ // 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 1.0f -
- (static_cast<float>(displayFramesRem) /
- static_cast<float>(layerPeriod));
+ return std::min(1.0f,
+ static_cast<float>(layerPeriod) /
+ static_cast<float>(actualLayerPeriod));
}();
ALOGV("%s (ExplicitDefault, weight %.2f) %.2fHz gives %s score of %.2f",
@@ -240,6 +254,7 @@
template <typename Iter>
const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) const {
+ constexpr auto EPSILON = 0.001f;
const RefreshRate* bestRefreshRate = begin->first;
float max = begin->second;
for (auto i = begin; i != end; ++i) {
@@ -248,7 +263,7 @@
ATRACE_INT(refreshRate->name.c_str(), round<int>(score * 100));
- if (score > max) {
+ if (score > max * (1 + EPSILON)) {
max = score;
bestRefreshRate = refreshRate;
}
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 9cd5959..87d4389 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -137,9 +137,11 @@
// Returns the refresh rate that fits best to the given layers. This function also gets a
// boolean flag that indicates whether user touched the screen recently to be factored in when
- // choosing the refresh rate.
+ // choosing the refresh rate and returns whether the refresh rate was chosen as a result of
+ // a touch event.
const RefreshRate& getRefreshRateForContentV2(const std::vector<LayerRequirement>& layers,
- bool touchActive) const EXCLUDES(mLock);
+ bool touchActive, bool* touchConsidered) const
+ EXCLUDES(mLock);
// Returns all the refresh rates supported by the device. This won't change at runtime.
const AllRefreshRatesMapType& getAllRefreshRates() const EXCLUDES(mLock);
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 96fa061..920f0ec 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -483,7 +483,7 @@
// that is currently on top. b/142507166 will give us this capability.
std::lock_guard<std::mutex> lock(mFeatureStateLock);
if (mLayerHistory) {
- mLayerHistory->clear();
+ // Layer History will be cleared based on RefreshRateConfigs::getRefreshRateForContentV2
mTouchTimer->reset();
@@ -620,10 +620,21 @@
return mRefreshRateConfigs.getRefreshRateForContent(mFeatures.contentRequirements).configId;
}
- return mRefreshRateConfigs
- .getRefreshRateForContentV2(mFeatures.contentRequirements,
- mTouchTimer && mFeatures.touch == TouchState::Active)
- .configId;
+ bool touchConsidered;
+ const auto& ret =
+ mRefreshRateConfigs
+ .getRefreshRateForContentV2(mFeatures.contentRequirements,
+ mTouchTimer &&
+ mFeatures.touch == TouchState::Active,
+ &touchConsidered)
+ .configId;
+ if (touchConsidered) {
+ // Clear layer history if refresh rate was selected based on touch to allow
+ // the hueristic to pick up with the new rate.
+ mLayerHistory->clear();
+ }
+
+ return ret;
}
std::optional<HwcConfigIndexType> Scheduler::getPreferredConfigId() {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ffb8ae9..cfaabfc 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -217,6 +217,8 @@
bool SurfaceFlinger::hasSyncFramework;
bool SurfaceFlinger::useVrFlinger;
int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
+uint32_t SurfaceFlinger::maxGraphicsWidth;
+uint32_t SurfaceFlinger::maxGraphicsHeight;
bool SurfaceFlinger::hasWideColorDisplay;
ui::Rotation SurfaceFlinger::internalDisplayOrientation = ui::ROTATION_0;
bool SurfaceFlinger::useColorManagement;
@@ -283,6 +285,9 @@
maxFrameBufferAcquiredBuffers = max_frame_buffer_acquired_buffers(2);
+ maxGraphicsWidth = std::max(max_graphics_width(0), 0);
+ maxGraphicsHeight = std::max(max_graphics_height(0), 0);
+
hasWideColorDisplay = has_wide_color_display(false);
useColorManagement = use_color_management(false);
@@ -359,11 +364,8 @@
property_get("ro.surface_flinger.supports_background_blur", value, "0");
bool supportsBlurs = atoi(value);
- property_get("debug.sf.disable_blurs", value, "0");
- bool disableBlurs = atoi(value);
- mEnableBlurs = supportsBlurs && !disableBlurs;
- ALOGI_IF(!mEnableBlurs, "Disabling blur effects. supported: %d, disabled: %d", supportsBlurs,
- disableBlurs);
+ mSupportsBlur = supportsBlurs;
+ ALOGI_IF(!mSupportsBlur, "Disabling blur effects, they are not supported.");
property_get("ro.sf.blurs_are_expensive", value, "0");
mBlursAreExpensive = atoi(value);
@@ -404,6 +406,7 @@
void SurfaceFlinger::binderDied(const wp<IBinder>& /* who */)
{
// the window manager died on us. prepare its eulogy.
+ mBootFinished = false;
// restore initial conditions (default device unblank, etc)
initializeDisplays();
@@ -520,6 +523,11 @@
void SurfaceFlinger::bootFinished()
{
+ if (mBootFinished == true) {
+ ALOGE("Extra call to bootFinished");
+ return;
+ }
+ mBootFinished = true;
if (mStartPropertySetThread->join() != NO_ERROR) {
ALOGE("Join StartPropertySetThread failed!");
}
@@ -614,7 +622,7 @@
.setUseColorManagerment(useColorManagement)
.setEnableProtectedContext(enable_protected_contents(false))
.setPrecacheToneMapperShaderOnly(false)
- .setSupportsBackgroundBlur(mEnableBlurs)
+ .setSupportsBackgroundBlur(mSupportsBlur)
.setContextPriority(useContextPriority
? renderengine::RenderEngine::ContextPriority::HIGH
: renderengine::RenderEngine::ContextPriority::MEDIUM)
@@ -696,6 +704,11 @@
property_get("persist.sys.sf.color_mode", value, "0");
mForceColorMode = static_cast<ColorMode>(atoi(value));
+
+ property_get("persist.sys.sf.disable_blurs", value, "0");
+ bool disableBlurs = atoi(value);
+ mDisableBlurs = disableBlurs;
+ ALOGI_IF(disableBlurs, "Disabling blur effects, user preference.");
}
void SurfaceFlinger::startBootAnim() {
@@ -2372,13 +2385,14 @@
sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
const wp<IBinder>& displayToken,
std::shared_ptr<compositionengine::Display> compositionDisplay,
- const DisplayDeviceState& state, const sp<compositionengine::DisplaySurface>& dispSurface,
+ const DisplayDeviceState& state,
+ const sp<compositionengine::DisplaySurface>& displaySurface,
const sp<IGraphicBufferProducer>& producer) {
auto displayId = compositionDisplay->getDisplayId();
DisplayDeviceCreationArgs creationArgs(this, displayToken, compositionDisplay);
creationArgs.sequenceId = state.sequenceId;
creationArgs.isSecure = state.isSecure;
- creationArgs.displaySurface = dispSurface;
+ creationArgs.displaySurface = displaySurface;
creationArgs.hasWideColorGamut = false;
creationArgs.supportedPerFrameMetadata = 0;
@@ -2454,6 +2468,140 @@
return display;
}
+void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken,
+ const DisplayDeviceState& state) {
+ int width = 0;
+ int height = 0;
+ ui::PixelFormat pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_UNKNOWN);
+ if (state.physical) {
+ const auto& activeConfig =
+ getCompositionEngine().getHwComposer().getActiveConfig(state.physical->id);
+ width = activeConfig->getWidth();
+ height = activeConfig->getHeight();
+ pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888);
+ } else if (state.surface != nullptr) {
+ int status = state.surface->query(NATIVE_WINDOW_WIDTH, &width);
+ ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status);
+ status = state.surface->query(NATIVE_WINDOW_HEIGHT, &height);
+ ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status);
+ int intPixelFormat;
+ status = state.surface->query(NATIVE_WINDOW_FORMAT, &intPixelFormat);
+ ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status);
+ pixelFormat = static_cast<ui::PixelFormat>(intPixelFormat);
+ } else {
+ // Virtual displays without a surface are dormant:
+ // they have external state (layer stack, projection,
+ // etc.) but no internal state (i.e. a DisplayDevice).
+ return;
+ }
+
+ compositionengine::DisplayCreationArgsBuilder builder;
+ if (const auto& physical = state.physical) {
+ builder.setPhysical({physical->id, physical->type});
+ }
+ builder.setPixels(ui::Size(width, height));
+ builder.setPixelFormat(pixelFormat);
+ builder.setIsSecure(state.isSecure);
+ builder.setLayerStackId(state.layerStack);
+ builder.setPowerAdvisor(&mPowerAdvisor);
+ builder.setUseHwcVirtualDisplays(mUseHwcVirtualDisplays || getHwComposer().isUsingVrComposer());
+ builder.setName(state.displayName);
+ const auto compositionDisplay = getCompositionEngine().createDisplay(builder.build());
+
+ sp<compositionengine::DisplaySurface> displaySurface;
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferProducer> bqProducer;
+ sp<IGraphicBufferConsumer> bqConsumer;
+ getFactory().createBufferQueue(&bqProducer, &bqConsumer, /*consumerIsSurfaceFlinger =*/false);
+
+ std::optional<DisplayId> displayId = compositionDisplay->getId();
+
+ if (state.isVirtual()) {
+ sp<VirtualDisplaySurface> vds =
+ new VirtualDisplaySurface(getHwComposer(), displayId, state.surface, bqProducer,
+ bqConsumer, state.displayName);
+
+ displaySurface = vds;
+ producer = vds;
+ } else {
+ ALOGE_IF(state.surface != nullptr,
+ "adding a supported display, but rendering "
+ "surface is provided (%p), ignoring it",
+ state.surface.get());
+
+ LOG_ALWAYS_FATAL_IF(!displayId);
+ displaySurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer,
+ maxGraphicsWidth, maxGraphicsHeight);
+ producer = bqProducer;
+ }
+
+ if (displaySurface != nullptr) {
+ mDisplays.emplace(displayToken,
+ setupNewDisplayDeviceInternal(displayToken, compositionDisplay, state,
+ displaySurface, producer));
+ if (!state.isVirtual()) {
+ LOG_ALWAYS_FATAL_IF(!displayId);
+ dispatchDisplayHotplugEvent(displayId->value, true);
+ }
+
+ const auto displayDevice = mDisplays[displayToken];
+ if (displayDevice->isPrimary()) {
+ mScheduler->onPrimaryDisplayAreaChanged(displayDevice->getWidth() *
+ displayDevice->getHeight());
+ }
+ }
+}
+
+void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) {
+ if (const auto display = getDisplayDeviceLocked(displayToken)) {
+ // Save display ID before disconnecting.
+ const auto displayId = display->getId();
+ display->disconnect();
+
+ if (!display->isVirtual()) {
+ LOG_ALWAYS_FATAL_IF(!displayId);
+ dispatchDisplayHotplugEvent(displayId->value, false);
+ }
+ }
+
+ mDisplays.erase(displayToken);
+}
+
+void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken,
+ const DisplayDeviceState& currentState,
+ const DisplayDeviceState& drawingState) {
+ const sp<IBinder> currentBinder = IInterface::asBinder(currentState.surface);
+ const sp<IBinder> drawingBinder = IInterface::asBinder(drawingState.surface);
+ if (currentBinder != drawingBinder) {
+ // changing the surface is like destroying and recreating the DisplayDevice
+ if (const auto display = getDisplayDeviceLocked(displayToken)) {
+ display->disconnect();
+ }
+ mDisplays.erase(displayToken);
+ processDisplayAdded(displayToken, currentState);
+ return;
+ }
+
+ if (const auto display = getDisplayDeviceLocked(displayToken)) {
+ if (currentState.layerStack != drawingState.layerStack) {
+ display->setLayerStack(currentState.layerStack);
+ }
+ if ((currentState.orientation != drawingState.orientation) ||
+ (currentState.viewport != drawingState.viewport) ||
+ (currentState.frame != drawingState.frame)) {
+ display->setProjection(currentState.orientation, currentState.viewport,
+ currentState.frame);
+ }
+ if (currentState.width != drawingState.width ||
+ currentState.height != drawingState.height) {
+ display->setDisplaySize(currentState.width, currentState.height);
+ if (display->isPrimary()) {
+ mScheduler->onPrimaryDisplayAreaChanged(currentState.width * currentState.height);
+ }
+ }
+ }
+}
+
void SurfaceFlinger::processDisplayChangesLocked() {
// here we take advantage of Vector's copy-on-write semantics to
// improve performance by skipping the transaction entirely when
@@ -2462,158 +2610,31 @@
const KeyedVector<wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays);
if (!curr.isIdenticalTo(draw)) {
mVisibleRegionsDirty = true;
- const size_t cc = curr.size();
- size_t dc = draw.size();
// find the displays that were removed
// (ie: in drawing state but not in current state)
// also handle displays that changed
// (ie: displays that are in both lists)
- for (size_t i = 0; i < dc;) {
- const ssize_t j = curr.indexOfKey(draw.keyAt(i));
+ for (size_t i = 0; i < draw.size(); i++) {
+ const wp<IBinder>& displayToken = draw.keyAt(i);
+ const ssize_t j = curr.indexOfKey(displayToken);
if (j < 0) {
// in drawing state but not in current state
- if (const auto display = getDisplayDeviceLocked(draw.keyAt(i))) {
- // Save display ID before disconnecting.
- const auto displayId = display->getId();
- display->disconnect();
-
- if (!display->isVirtual()) {
- LOG_ALWAYS_FATAL_IF(!displayId);
- dispatchDisplayHotplugEvent(displayId->value, false);
- }
- }
-
- mDisplays.erase(draw.keyAt(i));
+ processDisplayRemoved(displayToken);
} else {
// this display is in both lists. see if something changed.
- const DisplayDeviceState& state(curr[j]);
- const wp<IBinder>& displayToken = curr.keyAt(j);
- const sp<IBinder> state_binder = IInterface::asBinder(state.surface);
- const sp<IBinder> draw_binder = IInterface::asBinder(draw[i].surface);
- if (state_binder != draw_binder) {
- // changing the surface is like destroying and
- // recreating the DisplayDevice, so we just remove it
- // from the drawing state, so that it get re-added
- // below.
- if (const auto display = getDisplayDeviceLocked(displayToken)) {
- display->disconnect();
- }
- mDisplays.erase(displayToken);
- mDrawingState.displays.removeItemsAt(i);
- dc--;
- // at this point we must loop to the next item
- continue;
- }
-
- if (const auto display = getDisplayDeviceLocked(displayToken)) {
- if (state.layerStack != draw[i].layerStack) {
- display->setLayerStack(state.layerStack);
- }
- if ((state.orientation != draw[i].orientation) ||
- (state.viewport != draw[i].viewport) || (state.frame != draw[i].frame)) {
- display->setProjection(state.orientation, state.viewport, state.frame);
- }
- if (state.width != draw[i].width || state.height != draw[i].height) {
- display->setDisplaySize(state.width, state.height);
- if (display->isPrimary()) {
- mScheduler->onPrimaryDisplayAreaChanged(state.width * state.height);
- }
- }
- }
+ const DisplayDeviceState& currentState = curr[j];
+ const DisplayDeviceState& drawingState = draw[i];
+ processDisplayChanged(displayToken, currentState, drawingState);
}
- ++i;
}
// find displays that were added
// (ie: in current state but not in drawing state)
- for (size_t i = 0; i < cc; i++) {
- if (draw.indexOfKey(curr.keyAt(i)) < 0) {
- const DisplayDeviceState& state(curr[i]);
-
- int width = 0;
- int height = 0;
- ui::PixelFormat pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_UNKNOWN);
- if (state.physical) {
- const auto& activeConfig =
- getCompositionEngine().getHwComposer().getActiveConfig(
- state.physical->id);
- width = activeConfig->getWidth();
- height = activeConfig->getHeight();
- pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888);
- } else if (state.surface != nullptr) {
- int status = state.surface->query(NATIVE_WINDOW_WIDTH, &width);
- ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status);
- status = state.surface->query(NATIVE_WINDOW_HEIGHT, &height);
- ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status);
- int intPixelFormat;
- status = state.surface->query(NATIVE_WINDOW_FORMAT, &intPixelFormat);
- ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status);
- pixelFormat = static_cast<ui::PixelFormat>(intPixelFormat);
- } else {
- // Virtual displays without a surface are dormant:
- // they have external state (layer stack, projection,
- // etc.) but no internal state (i.e. a DisplayDevice).
- continue;
- }
-
- compositionengine::DisplayCreationArgsBuilder builder;
- if (const auto& physical = state.physical) {
- builder.setPhysical({physical->id, physical->type});
- }
- builder.setPixels(ui::Size(width, height));
- builder.setPixelFormat(pixelFormat);
- builder.setIsSecure(state.isSecure);
- builder.setLayerStackId(state.layerStack);
- builder.setPowerAdvisor(&mPowerAdvisor);
- builder.setUseHwcVirtualDisplays(mUseHwcVirtualDisplays ||
- getHwComposer().isUsingVrComposer());
- builder.setName(state.displayName);
- auto compositionDisplay = getCompositionEngine().createDisplay(builder.build());
-
- sp<compositionengine::DisplaySurface> dispSurface;
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferProducer> bqProducer;
- sp<IGraphicBufferConsumer> bqConsumer;
- getFactory().createBufferQueue(&bqProducer, &bqConsumer, false);
-
- std::optional<DisplayId> displayId = compositionDisplay->getId();
-
- if (state.isVirtual()) {
- sp<VirtualDisplaySurface> vds =
- new VirtualDisplaySurface(getHwComposer(), displayId, state.surface,
- bqProducer, bqConsumer, state.displayName);
-
- dispSurface = vds;
- producer = vds;
- } else {
- ALOGE_IF(state.surface != nullptr,
- "adding a supported display, but rendering "
- "surface is provided (%p), ignoring it",
- state.surface.get());
-
- LOG_ALWAYS_FATAL_IF(!displayId);
- dispSurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer);
- producer = bqProducer;
- }
-
- const wp<IBinder>& displayToken = curr.keyAt(i);
- if (dispSurface != nullptr) {
- mDisplays.emplace(displayToken,
- setupNewDisplayDeviceInternal(displayToken,
- compositionDisplay, state,
- dispSurface, producer));
- if (!state.isVirtual()) {
- LOG_ALWAYS_FATAL_IF(!displayId);
- dispatchDisplayHotplugEvent(displayId->value, true);
- }
-
- const auto displayDevice = mDisplays[displayToken];
- if (displayDevice->isPrimary()) {
- mScheduler->onPrimaryDisplayAreaChanged(displayDevice->getWidth() *
- displayDevice->getHeight());
- }
- }
+ for (size_t i = 0; i < curr.size(); i++) {
+ const wp<IBinder>& displayToken = curr.keyAt(i);
+ if (draw.indexOfKey(displayToken) < 0) {
+ processDisplayAdded(displayToken, curr[i]);
}
}
}
@@ -2788,7 +2809,7 @@
// input changes but all input changes will spring from these transactions
// so the cache is safe but not optimal. It seems like it might be annoyingly
// costly to cache and comapre the actual InputWindowHandle vector though.
- if (!mInputDirty) {
+ if (!mInputDirty && !mInputWindowCommands.syncInputWindows) {
return;
}
@@ -2808,7 +2829,7 @@
}
void SurfaceFlinger::commitInputWindowCommands() {
- mInputWindowCommands = mPendingInputWindowCommands;
+ mInputWindowCommands.merge(mPendingInputWindowCommands);
mPendingInputWindowCommands.clear();
}
@@ -3575,7 +3596,7 @@
if (layer->setCornerRadius(s.cornerRadius))
flags |= eTraversalNeeded;
}
- if (what & layer_state_t::eBackgroundBlurRadiusChanged) {
+ if (what & layer_state_t::eBackgroundBlurRadiusChanged && !mDisableBlurs) {
if (layer->setBackgroundBlurRadius(s.backgroundBlurRadius)) flags |= eTraversalNeeded;
}
if (what & layer_state_t::eLayerStackChanged) {
@@ -3745,10 +3766,6 @@
uint32_t SurfaceFlinger::addInputWindowCommands(const InputWindowCommands& inputWindowCommands) {
uint32_t flags = 0;
- if (!inputWindowCommands.transferTouchFocusCommands.empty()) {
- flags |= eTraversalNeeded;
- }
-
if (inputWindowCommands.syncInputWindows) {
flags |= eTraversalNeeded;
}
@@ -4474,12 +4491,11 @@
result.append("\n");
}
-LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const {
- Mutex::Autolock _l(mStateLock);
- const auto device = getDefaultDisplayDeviceLocked();
+LayersProto SurfaceFlinger::dumpDrawingStateProto(
+ uint32_t traceFlags, const sp<const DisplayDevice>& displayDevice) const {
LayersProto layersProto;
for (const sp<Layer>& layer : mDrawingState.layersSortedByZ) {
- layer->writeToProto(layersProto, traceFlags, device);
+ layer->writeToProto(layersProto, traceFlags, displayDevice);
}
return layersProto;
@@ -4511,7 +4527,10 @@
LayersProto SurfaceFlinger::dumpProtoFromMainThread(uint32_t traceFlags) {
LayersProto layersProto;
- postMessageSync(new LambdaMessage([&]() { layersProto = dumpDrawingStateProto(traceFlags); }));
+ postMessageSync(new LambdaMessage([&]() {
+ const auto& displayDevice = getDefaultDisplayDeviceLocked();
+ layersProto = dumpDrawingStateProto(traceFlags, displayDevice);
+ }));
return layersProto;
}
@@ -5783,6 +5802,7 @@
Mutex::Autolock _l(mStateLock);
mPendingSyncInputWindows = false;
+
mTransactionCV.broadcast();
}
@@ -6049,18 +6069,22 @@
return BAD_VALUE;
}
- Mutex::Autolock lock(mStateLock);
- if (authenticateSurfaceTextureLocked(surface)) {
- sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer();
- if (layer->setFrameRate(
- Layer::FrameRate(frameRate,
- Layer::FrameRate::convertCompatibility(compatibility)))) {
- setTransactionFlags(eTraversalNeeded);
+ postMessageAsync(new LambdaMessage([=]() NO_THREAD_SAFETY_ANALYSIS {
+ Mutex::Autolock lock(mStateLock);
+ if (authenticateSurfaceTextureLocked(surface)) {
+ sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer();
+ if (layer->setFrameRate(
+ Layer::FrameRate(frameRate,
+ Layer::FrameRate::convertCompatibility(compatibility)))) {
+ setTransactionFlags(eTraversalNeeded);
+ }
+ } else {
+ ALOGE("Attempt to set frame rate on an unrecognized IGraphicBufferProducer");
+ return BAD_VALUE;
}
- } else {
- ALOGE("Attempt to set frame rate on an unrecognized IGraphicBufferProducer");
- return BAD_VALUE;
- }
+ return NO_ERROR;
+ }));
+
return NO_ERROR;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a157a06..44e18a7 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -42,6 +42,7 @@
#include <system/graphics.h>
#include <ui/FenceTime.h>
#include <ui/PixelFormat.h>
+#include <ui/Size.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
@@ -225,6 +226,11 @@
// FramebufferSurface
static int64_t maxFrameBufferAcquiredBuffers;
+ // Controls the maximum width and height in pixels that the graphics pipeline can support for
+ // GPU fallback composition. For example, 8k devices with 4k GPUs, or 4k devices with 2k GPUs.
+ static uint32_t maxGraphicsWidth;
+ static uint32_t maxGraphicsHeight;
+
// Indicate if a device has wide color gamut display. This is typically
// found on devices with wide color gamut (e.g. Display-P3) display.
static bool hasWideColorDisplay;
@@ -814,9 +820,14 @@
const wp<IBinder>& displayToken,
std::shared_ptr<compositionengine::Display> compositionDisplay,
const DisplayDeviceState& state,
- const sp<compositionengine::DisplaySurface>& dispSurface,
+ const sp<compositionengine::DisplaySurface>& displaySurface,
const sp<IGraphicBufferProducer>& producer);
void processDisplayChangesLocked();
+ void processDisplayAdded(const wp<IBinder>& displayToken, const DisplayDeviceState& state);
+ void processDisplayRemoved(const wp<IBinder>& displayToken);
+ void processDisplayChanged(const wp<IBinder>& displayToken,
+ const DisplayDeviceState& currentState,
+ const DisplayDeviceState& drawingState);
void processDisplayHotplugEventsLocked();
void dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected);
@@ -917,7 +928,8 @@
void dumpDisplayIdentificationData(std::string& result) const;
void dumpRawDisplayIdentificationData(const DumpArgs&, std::string& result) const;
void dumpWideColorInfo(std::string& result) const;
- LayersProto dumpDrawingStateProto(uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
+ LayersProto dumpDrawingStateProto(uint32_t traceFlags = SurfaceTracing::TRACE_ALL,
+ const sp<const DisplayDevice>& displayDevice = nullptr) const;
void dumpOffscreenLayersProto(LayersProto& layersProto,
uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
// Dumps state from HW Composer
@@ -1048,8 +1060,10 @@
const std::shared_ptr<TimeStats> mTimeStats;
const std::unique_ptr<FrameTracer> mFrameTracer;
bool mUseHwcVirtualDisplays = false;
+ // If blurs should be enabled on this device.
+ bool mSupportsBlur = false;
// Disable blurs, for debugging
- bool mEnableBlurs = false;
+ std::atomic<bool> mDisableBlurs = false;
// If blurs are considered expensive and should require high GPU frequency.
bool mBlursAreExpensive = false;
std::atomic<uint32_t> mFrameMissedCount = 0;
@@ -1123,6 +1137,10 @@
// to linkToDeath
sp<IBinder> mWindowManager;
+ // We want to avoid multiple calls to BOOT_FINISHED as they come in on
+ // different threads without a lock and could trigger unsynchronized writes to
+ // to mWindowManager or mInputFlinger
+ std::atomic<bool> mBootFinished = false;
std::unique_ptr<dvr::VrFlinger> mVrFlinger;
std::atomic<bool> mVrFlingerRequestsDisplay = false;
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index f3352a5..9d78702 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -70,6 +70,22 @@
defaultValue);
}
+int32_t max_graphics_width(int32_t defaultValue) {
+ auto temp = SurfaceFlingerProperties::max_graphics_width();
+ if (temp.has_value()) {
+ return *temp;
+ }
+ return defaultValue;
+}
+
+int32_t max_graphics_height(int32_t defaultValue) {
+ auto temp = SurfaceFlingerProperties::max_graphics_height();
+ if (temp.has_value()) {
+ return *temp;
+ }
+ return defaultValue;
+}
+
bool has_wide_color_display(bool defaultValue) {
auto temp = SurfaceFlingerProperties::has_wide_color_display();
if (temp.has_value()) {
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index 12c711a..c63adfe 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -37,6 +37,9 @@
int64_t max_frame_buffer_acquired_buffers(int64_t defaultValue);
+int32_t max_graphics_width(int32_t defaultValue);
+int32_t max_graphics_height(int32_t defaultValue);
+
bool has_wide_color_display(bool defaultValue);
bool running_without_sync_framework(bool defaultValue);
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 1f9d46c..5b3cd69 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -524,11 +524,11 @@
deletion->set_id(getLayerId(layer));
}
-void SurfaceInterceptor::addBufferUpdateLocked(Increment* increment, const sp<const Layer>& layer,
+void SurfaceInterceptor::addBufferUpdateLocked(Increment* increment, int32_t layerId,
uint32_t width, uint32_t height, uint64_t frameNumber)
{
BufferUpdate* update(increment->mutable_buffer_update());
- update->set_id(getLayerId(layer));
+ update->set_id(layerId);
update->set_w(width);
update->set_h(height);
update->set_frame_number(frameNumber);
@@ -644,15 +644,22 @@
addSurfaceDeletionLocked(createTraceIncrementLocked(), layer);
}
-void SurfaceInterceptor::saveBufferUpdate(const sp<const Layer>& layer, uint32_t width,
+/**
+ * Here we pass the layer by ID instead of by sp<> since this is called without
+ * holding the state-lock from a Binder thread. If we required the caller
+ * to pass 'this' by sp<> the temporary sp<> constructed could end up
+ * being the last reference and we might accidentally destroy the Layer
+ * from this binder thread.
+ */
+void SurfaceInterceptor::saveBufferUpdate(int32_t layerId, uint32_t width,
uint32_t height, uint64_t frameNumber)
{
- if (!mEnabled || layer == nullptr) {
+ if (!mEnabled) {
return;
}
ATRACE_CALL();
std::lock_guard<std::mutex> protoGuard(mTraceMutex);
- addBufferUpdateLocked(createTraceIncrementLocked(), layer, width, height, frameNumber);
+ addBufferUpdateLocked(createTraceIncrementLocked(), layerId, width, height, frameNumber);
}
void SurfaceInterceptor::saveVSyncEvent(nsecs_t timestamp) {
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index a665f62..896bdcc 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -67,7 +67,7 @@
// Intercept surface data
virtual void saveSurfaceCreation(const sp<const Layer>& layer) = 0;
virtual void saveSurfaceDeletion(const sp<const Layer>& layer) = 0;
- virtual void saveBufferUpdate(const sp<const Layer>& layer, uint32_t width, uint32_t height,
+ virtual void saveBufferUpdate(int32_t layerId, uint32_t width, uint32_t height,
uint64_t frameNumber) = 0;
// Intercept display data
@@ -102,7 +102,7 @@
// Intercept surface data
void saveSurfaceCreation(const sp<const Layer>& layer) override;
void saveSurfaceDeletion(const sp<const Layer>& layer) override;
- void saveBufferUpdate(const sp<const Layer>& layer, uint32_t width, uint32_t height,
+ void saveBufferUpdate(int32_t layerId, uint32_t width, uint32_t height,
uint64_t frameNumber) override;
// Intercept display data
@@ -130,7 +130,7 @@
Increment* createTraceIncrementLocked();
void addSurfaceCreationLocked(Increment* increment, const sp<const Layer>& layer);
void addSurfaceDeletionLocked(Increment* increment, const sp<const Layer>& layer);
- void addBufferUpdateLocked(Increment* increment, const sp<const Layer>& layer, uint32_t width,
+ void addBufferUpdateLocked(Increment* increment, int32_t layerId, uint32_t width,
uint32_t height, uint64_t frameNumber);
void addVSyncUpdateLocked(Increment* increment, nsecs_t timestamp);
void addDisplayCreationLocked(Increment* increment, const DisplayDeviceState& info);
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index c5556ec..20c8d7a 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -45,19 +45,21 @@
}
void SurfaceTracing::addFirstEntry() {
+ const auto displayDevice = mFlinger.getDefaultDisplayDevice();
LayersTraceProto entry;
{
std::scoped_lock lock(mSfLock);
- entry = traceLayersLocked("tracing.enable");
+ entry = traceLayersLocked("tracing.enable", displayDevice);
}
addTraceToBuffer(entry);
}
LayersTraceProto SurfaceTracing::traceWhenNotified() {
+ const auto displayDevice = mFlinger.getDefaultDisplayDevice();
std::unique_lock<std::mutex> lock(mSfLock);
mCanStartTrace.wait(lock);
android::base::ScopedLockAssertion assumeLock(mSfLock);
- LayersTraceProto entry = traceLayersLocked(mWhere);
+ LayersTraceProto entry = traceLayersLocked(mWhere, displayDevice);
lock.unlock();
return entry;
}
@@ -160,13 +162,14 @@
mTraceFlags = flags;
}
-LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) {
+LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where,
+ const sp<const DisplayDevice>& displayDevice) {
ATRACE_CALL();
LayersTraceProto entry;
entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
entry.set_where(where);
- LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags));
+ LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags, displayDevice));
mFlinger.dumpOffscreenLayersProto(layers);
entry.mutable_layers()->Swap(&layers);
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index 57dc7c8..83872ed 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -16,17 +16,19 @@
#pragma once
+#include <android-base/thread_annotations.h>
#include <layerproto/LayerProtoHeader.h>
#include <utils/Errors.h>
#include <utils/StrongPointer.h>
-#include <android-base/thread_annotations.h>
#include <condition_variable>
#include <memory>
#include <mutex>
#include <queue>
#include <thread>
+#include "DisplayDevice.h"
+
using namespace android::surfaceflinger;
namespace android {
@@ -85,13 +87,15 @@
void mainLoop();
void addFirstEntry();
LayersTraceProto traceWhenNotified();
- LayersTraceProto traceLayersLocked(const char* where) REQUIRES(mSfLock);
+ LayersTraceProto traceLayersLocked(const char* where,
+ const sp<const DisplayDevice>& displayDevice)
+ REQUIRES(mSfLock);
// Returns true if trace is enabled.
bool addTraceToBuffer(LayersTraceProto& entry);
void writeProtoFileLocked() REQUIRES(mTraceLock);
- const SurfaceFlinger& mFlinger;
+ SurfaceFlinger& mFlinger;
status_t mLastErr = NO_ERROR;
std::thread mThread;
std::condition_variable mCanStartTrace;
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index 155f718..cfc301b 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -67,6 +67,26 @@
prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers"
}
+# Controls the maximum width in pixels that the graphics pipeline can support for GPU fallback
+# composition. For example, 8k displays with 4k GPUs, or 4k displays with 2k GPUs.
+prop {
+ api_name: "max_graphics_width"
+ type: Integer
+ scope: System
+ access: Readonly
+ prop_name: "ro.surface_flinger.max_graphics_width"
+}
+
+# Controls the maximum height in pixels that the graphics pipeline can support for GPU fallback
+# composition. For example, 8k displays with 4k GPUs, or 4k displays with 2k GPUs.
+prop {
+ api_name: "max_graphics_height"
+ type: Integer
+ scope: System
+ access: Readonly
+ prop_name: "ro.surface_flinger.max_graphics_height"
+}
+
# hasWideColorDisplay indicates that the device has
# or can support a wide-color display, e.g. color space
# greater than sRGB. Typical display may have same
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
index e62c127..ba60a7d 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
@@ -62,6 +62,16 @@
prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers"
}
prop {
+ api_name: "max_graphics_height"
+ type: Integer
+ prop_name: "ro.surface_flinger.max_graphics_height"
+ }
+ prop {
+ api_name: "max_graphics_width"
+ type: Integer
+ prop_name: "ro.surface_flinger.max_graphics_width"
+ }
+ prop {
api_name: "max_virtual_display_dimension"
type: Long
prop_name: "ro.surface_flinger.max_virtual_display_dimension"
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 1cd8731..2f2fb20 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -50,6 +50,7 @@
"PhaseOffsetsTest.cpp",
"SchedulerTest.cpp",
"SchedulerUtilsTest.cpp",
+ "SetFrameRateTest.cpp",
"RefreshRateConfigsTest.cpp",
"RefreshRateSelectionTest.cpp",
"RefreshRateStatsTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
index a023367..c2ddfce 100644
--- a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#include <functional>
+#include <string_view>
+
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -124,6 +127,10 @@
return DisplayIdentificationData(bytes, bytes + N - 1);
}
+uint32_t hash(const char* str) {
+ return static_cast<uint32_t>(std::hash<std::string_view>()(str));
+}
+
} // namespace
const DisplayIdentificationData& getInternalEdid() {
@@ -173,7 +180,8 @@
EXPECT_EQ(0x4ca3u, edid->manufacturerId);
EXPECT_STREQ("SEC", edid->pnpId.data());
// ASCII text should be used as fallback if display name and serial number are missing.
- EXPECT_EQ("121AT11-801", edid->displayName);
+ EXPECT_EQ(hash("121AT11-801"), edid->modelHash);
+ EXPECT_TRUE(edid->displayName.empty());
EXPECT_EQ(12610, edid->productId);
EXPECT_EQ(21, edid->manufactureOrModelYear);
EXPECT_EQ(0, edid->manufactureWeek);
@@ -182,6 +190,7 @@
ASSERT_TRUE(edid);
EXPECT_EQ(0x22f0u, edid->manufacturerId);
EXPECT_STREQ("HWP", edid->pnpId.data());
+ EXPECT_EQ(hash("HP ZR30w"), edid->modelHash);
EXPECT_EQ("HP ZR30w", edid->displayName);
EXPECT_EQ(10348, edid->productId);
EXPECT_EQ(22, edid->manufactureOrModelYear);
@@ -191,6 +200,7 @@
ASSERT_TRUE(edid);
EXPECT_EQ(0x4c2du, edid->manufacturerId);
EXPECT_STREQ("SAM", edid->pnpId.data());
+ EXPECT_EQ(hash("SAMSUNG"), edid->modelHash);
EXPECT_EQ("SAMSUNG", edid->displayName);
EXPECT_EQ(2302, edid->productId);
EXPECT_EQ(21, edid->manufactureOrModelYear);
@@ -200,6 +210,7 @@
ASSERT_TRUE(edid);
EXPECT_EQ(13481, edid->manufacturerId);
EXPECT_STREQ("MEI", edid->pnpId.data());
+ EXPECT_EQ(hash("Panasonic-TV"), edid->modelHash);
EXPECT_EQ("Panasonic-TV", edid->displayName);
EXPECT_EQ(41622, edid->productId);
EXPECT_EQ(29, edid->manufactureOrModelYear);
@@ -209,6 +220,7 @@
ASSERT_TRUE(edid);
EXPECT_EQ(8355, edid->manufacturerId);
EXPECT_STREQ("HEC", edid->pnpId.data());
+ EXPECT_EQ(hash("Hisense"), edid->modelHash);
EXPECT_EQ("Hisense", edid->displayName);
EXPECT_EQ(0, edid->productId);
EXPECT_EQ(29, edid->manufactureOrModelYear);
@@ -218,6 +230,7 @@
ASSERT_TRUE(edid);
EXPECT_EQ(3724, edid->manufacturerId);
EXPECT_STREQ("CTL", edid->pnpId.data());
+ EXPECT_EQ(hash("LP2361"), edid->modelHash);
EXPECT_EQ("LP2361", edid->displayName);
EXPECT_EQ(9373, edid->productId);
EXPECT_EQ(23, edid->manufactureOrModelYear);
@@ -234,13 +247,15 @@
auto edid = parseEdid(data);
ASSERT_TRUE(edid);
// Serial number should be used as fallback if display name is invalid.
- EXPECT_EQ("CN4202137Q", edid->displayName);
+ const auto modelHash = hash("CN4202137Q");
+ EXPECT_EQ(modelHash, edid->modelHash);
+ EXPECT_TRUE(edid->displayName.empty());
// Parsing should succeed even if EDID is truncated.
data.pop_back();
edid = parseEdid(data);
ASSERT_TRUE(edid);
- EXPECT_EQ("CN4202137Q", edid->displayName);
+ EXPECT_EQ(modelHash, edid->modelHash);
}
TEST(DisplayIdentificationTest, getPnpId) {
@@ -278,7 +293,7 @@
ASSERT_TRUE(displayIdInfo);
ASSERT_TRUE(displayIdInfo->deviceProductInfo);
const auto& info = *displayIdInfo->deviceProductInfo;
- EXPECT_STREQ("121AT11-801", info.name.data());
+ EXPECT_STREQ("", info.name.data());
EXPECT_STREQ("SEC", info.manufacturerPnpId.data());
EXPECT_STREQ("12610", info.productId.data());
ASSERT_TRUE(std::holds_alternative<ManufactureYear>(info.manufactureOrModelDate));
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index 18e9941..7557faf 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -84,7 +84,7 @@
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer, getFrameSelectionPriority()).WillRepeatedly(Return(1));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -113,7 +113,7 @@
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer, getFrameSelectionPriority()).WillRepeatedly(Return(1));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -137,15 +137,15 @@
EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer1, getFrameSelectionPriority()).WillRepeatedly(Return(1));
- EXPECT_CALL(*layer1, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
+ EXPECT_CALL(*layer1, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer2, getFrameSelectionPriority()).WillRepeatedly(Return(1));
- EXPECT_CALL(*layer2, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
+ EXPECT_CALL(*layer2, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer3, getFrameSelectionPriority()).WillRepeatedly(Return(1));
- EXPECT_CALL(*layer3, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
+ EXPECT_CALL(*layer3, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
nsecs_t time = mTime;
EXPECT_EQ(3, layerCount());
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
index 37da76b..8559a5e 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
@@ -91,7 +91,7 @@
TEST_F(LayerHistoryTestV2, oneLayer) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -122,7 +122,7 @@
TEST_F(LayerHistoryTestV2, oneInvisibleLayer) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -146,7 +146,7 @@
TEST_F(LayerHistoryTestV2, explicitTimestamp) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -167,7 +167,7 @@
TEST_F(LayerHistoryTestV2, oneLayerNoVote) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::NoVote);
@@ -194,7 +194,7 @@
TEST_F(LayerHistoryTestV2, oneLayerMinVote) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Min);
@@ -222,7 +222,7 @@
TEST_F(LayerHistoryTestV2, oneLayerMaxVote) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Max);
@@ -250,7 +250,7 @@
TEST_F(LayerHistoryTestV2, oneLayerExplicitVote) {
auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate())
+ EXPECT_CALL(*layer, getFrameRateForLayerTree())
.WillRepeatedly(
Return(Layer::FrameRate(73.4f, Layer::FrameRateCompatibility::Default)));
@@ -273,7 +273,8 @@
setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
ASSERT_TRUE(history().summarize(time).empty());
- // TODO: activeLayerCount() should be 0 but it is 1 since getFrameRate() returns a value > 0
+ // TODO: activeLayerCount() should be 0 but it is 1 since getFrameRateForLayerTree() returns a
+ // value > 0
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
}
@@ -281,7 +282,7 @@
TEST_F(LayerHistoryTestV2, oneLayerExplicitExactVote) {
auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate())
+ EXPECT_CALL(*layer, getFrameRateForLayerTree())
.WillRepeatedly(Return(
Layer::FrameRate(73.4f, Layer::FrameRateCompatibility::ExactOrMultiple)));
@@ -305,7 +306,8 @@
setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
ASSERT_TRUE(history().summarize(time).empty());
- // TODO: activeLayerCount() should be 0 but it is 1 since getFrameRate() returns a value > 0
+ // TODO: activeLayerCount() should be 0 but it is 1 since getFrameRateForLayerTree() returns a
+ // value > 0
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
}
@@ -316,13 +318,13 @@
auto layer3 = createLayer();
EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer1, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
+ EXPECT_CALL(*layer1, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer2, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
+ EXPECT_CALL(*layer2, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer3, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
+ EXPECT_CALL(*layer3, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
nsecs_t time = systemTime();
@@ -456,7 +458,7 @@
auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
nsecs_t time = systemTime();
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 4a179b6..dd04076 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -21,6 +21,7 @@
#include <log/log.h>
#include <thread>
+#include "../../Scheduler/RefreshRateConfigs.h"
#include "DisplayHardware/HWC2.h"
#include "Scheduler/RefreshRateConfigs.h"
@@ -248,6 +249,7 @@
}
TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_noLayers) {
+ bool ignored;
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_72, HWC_GROUP_ID_0, VSYNC_72},
@@ -263,16 +265,17 @@
auto layers = std::vector<LayerRequirement>{};
EXPECT_EQ(expected72Config,
refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/
- false));
+ false, &ignored));
// Current refresh rate can always be changed.
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_60);
EXPECT_EQ(expected60Config,
refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/
- false));
+ false, &ignored));
}
TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_90) {
+ bool ignored;
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
@@ -288,134 +291,163 @@
lr.vote = LayerVoteType::Min;
lr.name = "Min";
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.vote = LayerVoteType::Max;
lr.name = "Max";
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 90.0f;
lr.vote = LayerVoteType::Heuristic;
lr.name = "90Hz Heuristic";
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 60.0f;
lr.name = "60Hz Heuristic";
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 45.0f;
lr.name = "45Hz Heuristic";
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 30.0f;
lr.name = "30Hz Heuristic";
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 24.0f;
lr.name = "24Hz Heuristic";
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.name = "";
ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60, nullptr), 0);
lr.vote = LayerVoteType::Min;
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.vote = LayerVoteType::Max;
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 90.0f;
lr.vote = LayerVoteType::Heuristic;
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 60.0f;
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 45.0f;
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 30.0f;
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 24.0f;
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 90, 90, nullptr), 0);
lr.vote = LayerVoteType::Min;
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.vote = LayerVoteType::Max;
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 90.0f;
lr.vote = LayerVoteType::Heuristic;
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 60.0f;
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 45.0f;
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 30.0f;
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 24.0f;
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 0, 120, nullptr), 0);
lr.vote = LayerVoteType::Min;
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.vote = LayerVoteType::Max;
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 90.0f;
lr.vote = LayerVoteType::Heuristic;
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 60.0f;
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 45.0f;
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 30.0f;
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 24.0f;
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
}
TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_72_90) {
+ bool ignored;
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_72, HWC_GROUP_ID_0, VSYNC_72},
@@ -432,35 +464,43 @@
lr.vote = LayerVoteType::Min;
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.vote = LayerVoteType::Max;
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 90.0f;
lr.vote = LayerVoteType::Heuristic;
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 60.0f;
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 45.0f;
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 30.0f;
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 24.0f;
EXPECT_EQ(expected72Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
}
TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_72_90_120) {
+ bool ignored;
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30},
{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
@@ -486,24 +526,28 @@
lr2.desiredRefreshRate = 60.0f;
lr2.vote = LayerVoteType::Heuristic;
EXPECT_EQ(expected120Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 48.0f;
lr2.vote = LayerVoteType::Heuristic;
EXPECT_EQ(expected72Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 48.0f;
lr2.vote = LayerVoteType::Heuristic;
EXPECT_EQ(expected72Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
}
TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_90_120_DifferentTypes) {
+ bool ignored;
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30},
{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
@@ -531,7 +575,8 @@
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "60Hz Heuristic";
EXPECT_EQ(expected120Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -540,7 +585,8 @@
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "60Hz Heuristic";
EXPECT_EQ(expected120Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -549,7 +595,8 @@
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "60Hz ExplicitDefault";
EXPECT_EQ(expected120Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -558,7 +605,8 @@
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "90Hz Heuristic";
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -567,7 +615,8 @@
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "90Hz Heuristic";
EXPECT_EQ(expected72Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::ExplicitDefault;
@@ -576,7 +625,8 @@
lr2.vote = LayerVoteType::Heuristic;
lr2.name = "90Hz Heuristic";
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::Heuristic;
@@ -585,7 +635,8 @@
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "90Hz ExplicitDefault";
EXPECT_EQ(expected72Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -594,7 +645,8 @@
lr2.vote = LayerVoteType::ExplicitDefault;
lr2.name = "90Hz ExplicitDefault";
EXPECT_EQ(expected72Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr1.desiredRefreshRate = 24.0f;
lr1.vote = LayerVoteType::ExplicitDefault;
@@ -603,10 +655,12 @@
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.name = "90Hz ExplicitExactOrMultiple";
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
}
TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60) {
+ bool ignored;
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30}}};
@@ -621,35 +675,43 @@
lr.vote = LayerVoteType::Min;
EXPECT_EQ(expected30Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.vote = LayerVoteType::Max;
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 90.0f;
lr.vote = LayerVoteType::Heuristic;
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 60.0f;
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 45.0f;
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 30.0f;
EXPECT_EQ(expected30Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 24.0f;
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
}
TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_30_60_72_90) {
+ bool ignored;
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30},
{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
@@ -669,57 +731,71 @@
lr.vote = LayerVoteType::Min;
lr.name = "Min";
EXPECT_EQ(expected30Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.vote = LayerVoteType::Max;
lr.name = "Max";
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 90.0f;
lr.vote = LayerVoteType::Heuristic;
lr.name = "90Hz Heuristic";
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr.desiredRefreshRate = 60.0f;
lr.name = "60Hz Heuristic";
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true,
+ &ignored));
lr.desiredRefreshRate = 45.0f;
lr.name = "45Hz Heuristic";
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true,
+ &ignored));
lr.desiredRefreshRate = 30.0f;
lr.name = "30Hz Heuristic";
EXPECT_EQ(expected30Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true,
+ &ignored));
lr.desiredRefreshRate = 24.0f;
lr.name = "24Hz Heuristic";
EXPECT_EQ(expected72Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true,
+ &ignored));
lr.desiredRefreshRate = 24.0f;
lr.vote = LayerVoteType::ExplicitExactOrMultiple;
lr.name = "24Hz ExplicitExactOrMultiple";
EXPECT_EQ(expected72Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ true,
+ &ignored));
}
TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_PriorityTest) {
+ bool ignored;
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30},
{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
@@ -739,48 +815,56 @@
lr1.vote = LayerVoteType::Min;
lr2.vote = LayerVoteType::Max;
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr1.vote = LayerVoteType::Min;
lr2.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 24.0f;
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr1.vote = LayerVoteType::Min;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 24.0f;
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr1.vote = LayerVoteType::Max;
lr2.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 60.0f;
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr1.vote = LayerVoteType::Max;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 60.0f;
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 15.0f;
lr2.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 45.0f;
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 30.0f;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 45.0f;
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
}
TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_24FpsVideo) {
+ bool ignored;
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
@@ -798,7 +882,8 @@
for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) {
lr.desiredRefreshRate = fps;
const auto& refreshRate =
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false);
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored);
printf("%.2fHz chooses %s\n", fps, refreshRate.name.c_str());
EXPECT_EQ(expected60Config, refreshRate);
}
@@ -833,6 +918,7 @@
}
TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_Explicit) {
+ bool ignored;
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
@@ -852,21 +938,24 @@
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 90.0f;
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr1.vote = LayerVoteType::ExplicitDefault;
lr1.desiredRefreshRate = 90.0f;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 60.0f;
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 90.0f;
lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 60.0f;
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
}
TEST_F(RefreshRateConfigsTest, testInPolicy) {
@@ -880,6 +969,7 @@
}
TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_75HzContent) {
+ bool ignored;
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
@@ -897,13 +987,15 @@
for (float fps = 75.0f; fps < 100.0f; fps += 0.1f) {
lr.desiredRefreshRate = fps;
const auto& refreshRate =
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false);
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored);
printf("%.2fHz chooses %s\n", fps, refreshRate.name.c_str());
EXPECT_EQ(expected90Config, refreshRate);
}
}
TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_Multiples) {
+ bool ignored;
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
@@ -925,7 +1017,8 @@
lr2.desiredRefreshRate = 90.0f;
lr2.name = "90Hz Heuristic";
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 60.0f;
@@ -934,7 +1027,8 @@
lr2.desiredRefreshRate = 90.0f;
lr2.name = "90Hz ExplicitDefault";
EXPECT_EQ(expected60Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 60.0f;
@@ -942,7 +1036,8 @@
lr2.vote = LayerVoteType::Max;
lr2.name = "Max";
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 30.0f;
@@ -951,7 +1046,8 @@
lr2.desiredRefreshRate = 90.0f;
lr2.name = "90Hz Heuristic";
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 30.0f;
@@ -959,10 +1055,12 @@
lr2.vote = LayerVoteType::Max;
lr2.name = "Max";
EXPECT_EQ(expected90Config,
- refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false));
+ refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
+ &ignored));
}
TEST_F(RefreshRateConfigsTest, scrollWhileWatching60fps_60_90) {
+ bool ignored;
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
@@ -982,28 +1080,32 @@
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::NoVote;
lr2.name = "NoVote";
- EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers, false));
+ EXPECT_EQ(expected60Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, false, &ignored));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 60.0f;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::NoVote;
lr2.name = "NoVote";
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers, true));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, true, &ignored));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 60.0f;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Max;
lr2.name = "Max";
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers, true));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, true, &ignored));
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
lr1.desiredRefreshRate = 60.0f;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Max;
lr2.name = "Max";
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers, false));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, false, &ignored));
// The other layer starts to provide buffers
lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
@@ -1012,7 +1114,108 @@
lr2.vote = LayerVoteType::Heuristic;
lr2.desiredRefreshRate = 90.0f;
lr2.name = "90Hz Heuristic";
- EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers, false));
+ EXPECT_EQ(expected90Config,
+ refreshRateConfigs->getRefreshRateForContentV2(layers, false, &ignored));
+}
+
+TEST_F(RefreshRateConfigsTest, touchConsidered) {
+ bool touchConsidered;
+ std::vector<RefreshRateConfigs::InputConfig> configs{
+ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
+ {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ refreshRateConfigs->getRefreshRateForContentV2({}, false, &touchConsidered);
+ EXPECT_EQ(false, touchConsidered);
+
+ refreshRateConfigs->getRefreshRateForContentV2({}, true, &touchConsidered);
+ EXPECT_EQ(true, touchConsidered);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+ LayerRequirement{.weight = 1.0f}};
+ auto& lr1 = layers[0];
+ auto& lr2 = layers[1];
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 60.0f;
+ lr1.name = "60Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.name = "NoVote";
+ refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered);
+ EXPECT_EQ(true, touchConsidered);
+
+ lr1.vote = LayerVoteType::ExplicitDefault;
+ lr1.desiredRefreshRate = 60.0f;
+ lr1.name = "60Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.name = "NoVote";
+ refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered);
+ EXPECT_EQ(false, touchConsidered);
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 60.0f;
+ lr1.name = "60Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.name = "NoVote";
+ refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered);
+ EXPECT_EQ(true, touchConsidered);
+
+ lr1.vote = LayerVoteType::ExplicitDefault;
+ lr1.desiredRefreshRate = 60.0f;
+ lr1.name = "60Hz ExplicitExactrMultiple";
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.name = "NoVote";
+ refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered);
+ EXPECT_EQ(false, touchConsidered);
+}
+
+TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_ExplicitDefault) {
+ bool ignored;
+ std::vector<RefreshRateConfigs::InputConfig> configs{
+ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
+ {HWC_CONFIG_ID_72, HWC_GROUP_ID_0, VSYNC_72},
+ {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90},
+ {HWC_CONFIG_ID_120, HWC_GROUP_ID_0, VSYNC_120}}};
+
+ auto refreshRateConfigs = std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/
+ HWC_CONFIG_ID_60);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ // Prepare a table with the vote and the expected refresh rate
+ const std::vector<std::pair<float, float>> testCases = {
+ {130, 120}, {120, 120}, {119, 120}, {110, 120},
+
+ {100, 90}, {90, 90}, {89, 90},
+
+ {80, 72}, {73, 72}, {72, 72}, {71, 72}, {70, 72},
+
+ {65, 60}, {60, 60}, {59, 60}, {58, 60},
+
+ {55, 90}, {50, 90}, {45, 90},
+
+ {42, 120}, {40, 120}, {39, 120},
+
+ {37, 72}, {36, 72}, {35, 72},
+
+ {30, 60},
+ };
+
+ for (const auto& test : testCases) {
+ lr.vote = LayerVoteType::ExplicitDefault;
+ lr.desiredRefreshRate = test.first;
+
+ std::stringstream ss;
+ ss << "ExplicitDefault " << test.first << " fps";
+ lr.name = ss.str();
+
+ const auto& refreshRate =
+ refreshRateConfigs->getRefreshRateForContentV2(layers, false, &ignored);
+ EXPECT_FLOAT_EQ(refreshRate.fps, test.second)
+ << "Expecting " << test.first << "fps => " << test.second << "Hz";
+ }
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
new file mode 100644
index 0000000..b069085
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -0,0 +1,473 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/LayerMetadata.h>
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+#include "BufferQueueLayer.h"
+#include "BufferStateLayer.h"
+#include "EffectLayer.h"
+#include "Layer.h"
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/MockDispSync.h"
+#include "mock/MockEventControlThread.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockMessageQueue.h"
+
+namespace android {
+
+using testing::_;
+using testing::DoAll;
+using testing::Mock;
+using testing::Return;
+using testing::SetArgPointee;
+
+using android::Hwc2::IComposer;
+using android::Hwc2::IComposerClient;
+
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+
+using FrameRate = Layer::FrameRate;
+using FrameRateCompatibility = Layer::FrameRateCompatibility;
+
+class LayerFactory {
+public:
+ virtual ~LayerFactory() = default;
+
+ virtual std::string name() = 0;
+ virtual sp<Layer> createLayer(TestableSurfaceFlinger& flinger) = 0;
+
+protected:
+ static constexpr uint32_t WIDTH = 100;
+ static constexpr uint32_t HEIGHT = 100;
+ static constexpr uint32_t LAYER_FLAGS = 0;
+};
+
+class BufferQueueLayerFactory : public LayerFactory {
+public:
+ std::string name() override { return "BufferQueueLayer"; }
+ sp<Layer> createLayer(TestableSurfaceFlinger& flinger) override {
+ sp<Client> client;
+ LayerCreationArgs args(flinger.flinger(), client, "buffer-queue-layer", WIDTH, HEIGHT,
+ LAYER_FLAGS, LayerMetadata());
+ return new BufferQueueLayer(args);
+ }
+};
+
+class BufferStateLayerFactory : public LayerFactory {
+public:
+ std::string name() override { return "BufferStateLayer"; }
+ sp<Layer> createLayer(TestableSurfaceFlinger& flinger) override {
+ sp<Client> client;
+ LayerCreationArgs args(flinger.flinger(), client, "buffer-queue-layer", WIDTH, HEIGHT,
+ LAYER_FLAGS, LayerMetadata());
+ return new BufferStateLayer(args);
+ }
+};
+
+class EffectLayerFactory : public LayerFactory {
+public:
+ std::string name() override { return "EffectLayer"; }
+ sp<Layer> createLayer(TestableSurfaceFlinger& flinger) override {
+ sp<Client> client;
+ LayerCreationArgs args(flinger.flinger(), client, "color-layer", WIDTH, HEIGHT, LAYER_FLAGS,
+ LayerMetadata());
+ return new EffectLayer(args);
+ }
+};
+
+std::string PrintToStringParamName(
+ const ::testing::TestParamInfo<std::shared_ptr<LayerFactory>>& info) {
+ return info.param->name();
+}
+
+/**
+ * This class tests the behaviour of Layer::SetFrameRate and Layer::GetFrameRate
+ */
+class SetFrameRateTest : public ::testing::TestWithParam<std::shared_ptr<LayerFactory>> {
+protected:
+ const FrameRate FRAME_RATE_VOTE1 = FrameRate(67.f, FrameRateCompatibility::Default);
+ const FrameRate FRAME_RATE_VOTE2 = FrameRate(14.f, FrameRateCompatibility::ExactOrMultiple);
+ const FrameRate FRAME_RATE_VOTE3 = FrameRate(99.f, FrameRateCompatibility::NoVote);
+ const FrameRate FRAME_RATE_TREE = FrameRate(0, FrameRateCompatibility::NoVote);
+ const FrameRate FRAME_RATE_NO_VOTE = FrameRate(0, FrameRateCompatibility::Default);
+
+ SetFrameRateTest();
+
+ void setupScheduler();
+ void setupComposer(uint32_t virtualDisplayCount);
+
+ void addChild(sp<Layer> layer, sp<Layer> child);
+ void removeChild(sp<Layer> layer, sp<Layer> child);
+ void reparentChildren(sp<Layer> layer, sp<Layer> child);
+ void commitTransaction();
+
+ TestableSurfaceFlinger mFlinger;
+ Hwc2::mock::Composer* mComposer = nullptr;
+ mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
+
+ std::vector<sp<Layer>> mLayers;
+};
+
+SetFrameRateTest::SetFrameRateTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+
+ mFlinger.mutableUseFrameRateApi() = true;
+
+ setupScheduler();
+ setupComposer(0);
+
+ mFlinger.mutableEventQueue().reset(mMessageQueue);
+}
+void SetFrameRateTest::addChild(sp<Layer> layer, sp<Layer> child) {
+ layer.get()->addChild(child.get());
+}
+
+void SetFrameRateTest::removeChild(sp<Layer> layer, sp<Layer> child) {
+ layer.get()->removeChild(child.get());
+}
+
+void SetFrameRateTest::reparentChildren(sp<Layer> parent, sp<Layer> newParent) {
+ parent.get()->reparentChildren(newParent);
+}
+
+void SetFrameRateTest::commitTransaction() {
+ for (auto layer : mLayers) {
+ layer.get()->commitTransaction(layer.get()->getCurrentState());
+ }
+}
+
+void SetFrameRateTest::setupScheduler() {
+ auto eventThread = std::make_unique<mock::EventThread>();
+ auto sfEventThread = std::make_unique<mock::EventThread>();
+
+ EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*eventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(eventThread.get(), ResyncCallback(),
+ ISurfaceComposer::eConfigChangedSuppress)));
+
+ EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), ResyncCallback(),
+ ISurfaceComposer::eConfigChangedSuppress)));
+
+ auto primaryDispSync = std::make_unique<mock::DispSync>();
+
+ EXPECT_CALL(*primaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0));
+ EXPECT_CALL(*primaryDispSync, getPeriod())
+ .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+ EXPECT_CALL(*primaryDispSync, expectedPresentTime()).WillRepeatedly(Return(0));
+ mFlinger.setupScheduler(std::move(primaryDispSync),
+ std::make_unique<mock::EventControlThread>(), std::move(eventThread),
+ std::move(sfEventThread));
+}
+
+void SetFrameRateTest::setupComposer(uint32_t virtualDisplayCount) {
+ mComposer = new Hwc2::mock::Composer();
+ EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
+ mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+
+ Mock::VerifyAndClear(mComposer);
+}
+
+namespace {
+/* ------------------------------------------------------------------------
+ * Test cases
+ */
+TEST_P(SetFrameRateTest, SetAndGet) {
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ const auto& layerFactory = GetParam();
+
+ auto layer = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ layer->setFrameRate(FRAME_RATE_VOTE1);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_VOTE1, layer->getFrameRateForLayerTree());
+}
+
+TEST_P(SetFrameRateTest, SetAndGetParent) {
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ const auto& layerFactory = GetParam();
+
+ auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+ addChild(parent, child1);
+ addChild(child1, child2);
+
+ child2->setFrameRate(FRAME_RATE_VOTE1);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
+
+ child2->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+}
+
+TEST_P(SetFrameRateTest, SetAndGetParentAllVote) {
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ const auto& layerFactory = GetParam();
+
+ auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+ addChild(parent, child1);
+ addChild(child1, child2);
+
+ child2->setFrameRate(FRAME_RATE_VOTE1);
+ child1->setFrameRate(FRAME_RATE_VOTE2);
+ parent->setFrameRate(FRAME_RATE_VOTE3);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
+
+ child2->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree());
+
+ child1->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree());
+
+ parent->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+}
+
+TEST_P(SetFrameRateTest, SetAndGetChild) {
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ const auto& layerFactory = GetParam();
+
+ auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+ addChild(parent, child1);
+ addChild(child1, child2);
+
+ parent->setFrameRate(FRAME_RATE_VOTE1);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree());
+
+ parent->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+}
+
+TEST_P(SetFrameRateTest, SetAndGetChildAllVote) {
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ const auto& layerFactory = GetParam();
+
+ auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+ addChild(parent, child1);
+ addChild(child1, child2);
+
+ child2->setFrameRate(FRAME_RATE_VOTE1);
+ child1->setFrameRate(FRAME_RATE_VOTE2);
+ parent->setFrameRate(FRAME_RATE_VOTE3);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
+
+ parent->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
+
+ child1->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
+
+ child2->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+}
+
+TEST_P(SetFrameRateTest, SetAndGetChildAddAfterVote) {
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ const auto& layerFactory = GetParam();
+
+ auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+ addChild(parent, child1);
+
+ parent->setFrameRate(FRAME_RATE_VOTE1);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+
+ addChild(child1, child2);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree());
+
+ parent->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+}
+
+TEST_P(SetFrameRateTest, SetAndGetChildRemoveAfterVote) {
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ const auto& layerFactory = GetParam();
+
+ auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+ addChild(parent, child1);
+ addChild(child1, child2);
+
+ parent->setFrameRate(FRAME_RATE_VOTE1);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree());
+
+ removeChild(child1, child2);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+
+ parent->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+}
+
+TEST_P(SetFrameRateTest, SetAndGetParentNotInTree) {
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ const auto& layerFactory = GetParam();
+
+ auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child2_1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+ addChild(parent, child1);
+ addChild(child1, child2);
+ addChild(child1, child2_1);
+
+ child2->setFrameRate(FRAME_RATE_VOTE1);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2_1->getFrameRateForLayerTree());
+
+ child2->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2_1->getFrameRateForLayerTree());
+}
+
+TEST_P(SetFrameRateTest, SetAndGetRearentChildren) {
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ const auto& layerFactory = GetParam();
+
+ auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto parent2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+ addChild(parent, child1);
+ addChild(child1, child2);
+
+ child2->setFrameRate(FRAME_RATE_VOTE1);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, parent2->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
+
+ reparentChildren(parent, parent2);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, parent2->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
+
+ child2->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, parent2->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+}
+
+INSTANTIATE_TEST_SUITE_P(PerLayerType, SetFrameRateTest,
+ testing::Values(std::make_shared<BufferQueueLayerFactory>(),
+ std::make_shared<BufferStateLayerFactory>(),
+ std::make_shared<EffectLayerFactory>()),
+ PrintToStringParamName);
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 84e55ae..414085c 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -394,6 +394,7 @@
auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; }
auto& mutableInternalHwcDisplayId() { return getHwComposer().mInternalHwcDisplayId; }
auto& mutableExternalHwcDisplayId() { return getHwComposer().mExternalHwcDisplayId; }
+ auto& mutableUseFrameRateApi() { return mFlinger->useFrameRateApi; }
auto fromHandle(const sp<IBinder>& handle) {
Mutex::Autolock _l(mFlinger->mStateLock);
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
index e2f6abd..119f580 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -31,7 +31,7 @@
MOCK_METHOD0(getFrameSelectionPriority, int32_t());
MOCK_CONST_METHOD0(isVisible, bool());
MOCK_METHOD0(createClone, sp<Layer>());
- MOCK_CONST_METHOD0(getFrameRate, FrameRate());
+ MOCK_CONST_METHOD0(getFrameRateForLayerTree, FrameRate());
};
} // namespace android::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
index 458b2f3..5beee1c 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
@@ -39,7 +39,7 @@
const Vector<DisplayState>&, uint32_t));
MOCK_METHOD1(saveSurfaceCreation, void(const sp<const Layer>&));
MOCK_METHOD1(saveSurfaceDeletion, void(const sp<const Layer>&));
- MOCK_METHOD4(saveBufferUpdate, void(const sp<const Layer>&, uint32_t, uint32_t, uint64_t));
+ MOCK_METHOD4(saveBufferUpdate, void(int32_t, uint32_t, uint32_t, uint64_t));
MOCK_METHOD1(saveDisplayCreation, void(const DisplayDeviceState&));
MOCK_METHOD1(saveDisplayDeletion, void(int32_t));
MOCK_METHOD2(savePowerModeUpdate, void(int32_t, int32_t));