Merge "Clean up InputDispatcherPolicyInterface" into udc-dev
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 8ca927e..5dbf7ac 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -3362,23 +3362,25 @@
return;
}
- // Include the proto logging from WMShell.
- RunCommand(
- // Empty name because it's not intended to be classified as a bugreport section.
- // Actual logging files can be found as "/data/misc/wmtrace/shell_log.winscope"
- // in the bugreport.
- "", {"dumpsys", "activity", "service", "SystemUIService",
- "WMShell", "protolog", "save-for-bugreport"},
- CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
+ const std::vector<std::vector<std::string>> dumpTracesForBugReportCommands = {
+ {"dumpsys", "activity", "service", "SystemUIService", "WMShell", "protolog",
+ "save-for-bugreport"},
+ {"dumpsys", "activity", "service", "SystemUIService", "WMShell", "transitions", "tracing",
+ "save-for-bugreport"},
+ {"cmd", "input_method", "tracing", "save-for-bugreport"},
+ {"cmd", "window", "tracing", "save-for-bugreport"},
+ {"cmd", "window", "shell", "tracing", "save-for-bugreport"},
+ };
- for (const auto& service : {"input_method", "window", "window shell"}) {
+ for (const auto& command : dumpTracesForBugReportCommands) {
RunCommand(
// Empty name because it's not intended to be classified as a bugreport section.
// Actual tracing files can be found in "/data/misc/wmtrace/" in the bugreport.
- "", {"cmd", service, "tracing", "save-for-bugreport"},
+ "", command,
CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
}
+ // This command needs to be run as root
static const auto SURFACEFLINGER_COMMAND_SAVE_ALL_TRACES = std::vector<std::string> {
"service", "call", "SurfaceFlinger", "1042"
};
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 93d8cdf..5cbcf9f 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -997,17 +997,22 @@
EXPECT_FALSE(ds.dump_pool_);
}
-TEST_F(DumpstateBaseTest, PreDumpUiData) {
- // SurfaceFlinger's transactions trace is always enabled, i.e. it is always pre-dumped
- static const auto kTransactionsTrace =
- std::filesystem::path {"/data/misc/wmtrace/transactions_trace.winscope"};
+TEST_F(DumpstateTest, PreDumpUiData) {
+ // These traces are always enabled, i.e. they are always pre-dumped
+ const std::vector<std::filesystem::path> uiTraces = {
+ std::filesystem::path{"/data/misc/wmtrace/transactions_trace.winscope"},
+ std::filesystem::path{"/data/misc/wmtrace/transition_trace.winscope"},
+ std::filesystem::path{"/data/misc/wmtrace/shell_transition_trace.winscope"},
+ };
- std::system(("rm " + kTransactionsTrace.string()).c_str());
- EXPECT_FALSE(std::filesystem::exists(kTransactionsTrace));
+ for (const auto traceFile : uiTraces) {
+ std::system(("rm -f " + traceFile.string()).c_str());
+ EXPECT_FALSE(std::filesystem::exists(traceFile)) << traceFile << " was not deleted.";
- Dumpstate& ds_ = Dumpstate::GetInstance();
- ds_.PreDumpUiData();
- EXPECT_TRUE(std::filesystem::exists(kTransactionsTrace));
+ Dumpstate& ds_ = Dumpstate::GetInstance();
+ ds_.PreDumpUiData();
+ EXPECT_TRUE(std::filesystem::exists(traceFile)) << traceFile << " was not created.";
+ }
}
class ZippedBugReportStreamTest : public DumpstateBaseTest {
diff --git a/cmds/installd/utils_default.cpp b/cmds/installd/utils_default.cpp
index a6025e6..85ce450 100644
--- a/cmds/installd/utils_default.cpp
+++ b/cmds/installd/utils_default.cpp
@@ -23,7 +23,7 @@
// platform dependent logic.
int rm_package_dir(const std::string& package_dir) {
- return delete_dir_contents_and_dir(package_dir);
+ return rename_delete_dir_contents_and_dir(package_dir);
}
} // namespace installd
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index d73a30b..fb69513 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -93,9 +93,22 @@
libfuzzer_options: [
"max_len=50000",
],
- cc: [
- "smoreland@google.com",
- "waghpawan@google.com",
+ },
+}
+
+// Adding this new fuzzer to test the corpus generated by record_binder
+cc_fuzz {
+ name: "servicemanager_test_fuzzer",
+ defaults: [
+ "servicemanager_defaults",
+ "service_fuzzer_defaults",
+ ],
+ host_supported: true,
+ srcs: ["fuzzers/ServiceManagerTestFuzzer.cpp"],
+ fuzz_config: {
+ libfuzzer_options: [
+ "max_len=50000",
],
},
+ corpus: ["fuzzers/servicemamanager_fuzzer_corpus/*"],
}
diff --git a/cmds/servicemanager/fuzzers/ServiceManagerTestFuzzer.cpp b/cmds/servicemanager/fuzzers/ServiceManagerTestFuzzer.cpp
new file mode 100644
index 0000000..e19b6eb
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/ServiceManagerTestFuzzer.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fuzzbinder/libbinder_driver.h>
+#include <utils/StrongPointer.h>
+
+#include "Access.h"
+#include "ServiceManager.h"
+
+using ::android::Access;
+using ::android::Parcel;
+using ::android::ServiceManager;
+using ::android::sp;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider provider(data, size);
+ auto accessPtr = std::make_unique<Access>();
+ auto serviceManager = sp<ServiceManager>::make(std::move(accessPtr));
+
+ // Reserved bytes
+ provider.ConsumeBytes<uint8_t>(8);
+ uint32_t code = provider.ConsumeIntegral<uint32_t>();
+ uint32_t flag = provider.ConsumeIntegral<uint32_t>();
+ std::vector<uint8_t> parcelData = provider.ConsumeRemainingBytes<uint8_t>();
+
+ Parcel inputParcel;
+ inputParcel.setData(parcelData.data(), parcelData.size());
+
+ Parcel reply;
+ serviceManager->transact(code, inputParcel, &reply, flag);
+
+ serviceManager->clear();
+
+ return 0;
+}
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_1 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_1
new file mode 100644
index 0000000..39e5104
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_1
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_10 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_10
new file mode 100644
index 0000000..07319f8
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_10
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_11 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_11
new file mode 100644
index 0000000..39e5104
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_11
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_12 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_12
new file mode 100644
index 0000000..07319f8
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_12
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_13 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_13
new file mode 100644
index 0000000..39e5104
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_13
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_14 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_14
new file mode 100644
index 0000000..07319f8
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_14
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_15 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_15
new file mode 100644
index 0000000..39e5104
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_15
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_16 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_16
new file mode 100644
index 0000000..07319f8
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_16
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_17 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_17
new file mode 100644
index 0000000..39e5104
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_17
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_18 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_18
new file mode 100644
index 0000000..88ad474
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_18
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_19 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_19
new file mode 100644
index 0000000..fae15a2
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_19
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_2 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_2
new file mode 100644
index 0000000..e69ab49
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_2
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_20 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_20
new file mode 100644
index 0000000..39e5104
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_20
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_21 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_21
new file mode 100644
index 0000000..88ad474
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_21
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_22 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_22
new file mode 100644
index 0000000..fae15a2
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_22
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_23 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_23
new file mode 100644
index 0000000..39e5104
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_23
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_24 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_24
new file mode 100644
index 0000000..88ad474
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_24
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_25 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_25
new file mode 100644
index 0000000..fae15a2
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_25
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_26 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_26
new file mode 100644
index 0000000..39e5104
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_26
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_27 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_27
new file mode 100644
index 0000000..88ad474
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_27
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_28 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_28
new file mode 100644
index 0000000..fae15a2
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_28
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_29 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_29
new file mode 100644
index 0000000..39e5104
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_29
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_3 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_3
new file mode 100644
index 0000000..39e5104
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_3
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_30 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_30
new file mode 100644
index 0000000..88ad474
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_30
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_31 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_31
new file mode 100644
index 0000000..fae15a2
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_31
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_32 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_32
new file mode 100644
index 0000000..39e5104
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_32
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_33 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_33
new file mode 100644
index 0000000..88ad474
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_33
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_34 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_34
new file mode 100644
index 0000000..fae15a2
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_34
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_35 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_35
new file mode 100644
index 0000000..39e5104
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_35
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_36 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_36
new file mode 100644
index 0000000..88ad474
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_36
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_37 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_37
new file mode 100644
index 0000000..fae15a2
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_37
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_38 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_38
new file mode 100644
index 0000000..39e5104
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_38
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_39 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_39
new file mode 100644
index 0000000..b326907
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_39
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_4 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_4
new file mode 100644
index 0000000..05b27bf
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_4
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_40 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_40
new file mode 100644
index 0000000..39e5104
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_40
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_41 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_41
new file mode 100644
index 0000000..b326907
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_41
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_42 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_42
new file mode 100644
index 0000000..cdaa1f0
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_42
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_43 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_43
new file mode 100644
index 0000000..ff0941b
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_43
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_44 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_44
new file mode 100644
index 0000000..cdaa1f0
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_44
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_45 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_45
new file mode 100644
index 0000000..39e5104
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_45
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_46 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_46
new file mode 100644
index 0000000..7e5f948
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_46
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_5 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_5
new file mode 100644
index 0000000..39e5104
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_5
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_6 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_6
new file mode 100644
index 0000000..07319f8
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_6
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_7 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_7
new file mode 100644
index 0000000..39e5104
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_7
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_8 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_8
new file mode 100644
index 0000000..07319f8
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_8
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_9 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_9
new file mode 100644
index 0000000..39e5104
--- /dev/null
+++ b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_9
Binary files differ
diff --git a/headers/media_plugin/media/hardware/VideoAPI.h b/headers/media_plugin/media/hardware/VideoAPI.h
index a090876..5466680 100644
--- a/headers/media_plugin/media/hardware/VideoAPI.h
+++ b/headers/media_plugin/media/hardware/VideoAPI.h
@@ -127,6 +127,8 @@
PrimariesBT601_6_525, // Rec.ITU-R BT.601-6 525 or equivalent
PrimariesGenericFilm, // Generic Film
PrimariesBT2020, // Rec.ITU-R BT.2020 or equivalent
+ PrimariesRP431, // SMPTE RP 431-2 (DCI P3)
+ PrimariesEG432, // SMPTE EG 432-1 (Display P3)
PrimariesOther = 0xff,
};
@@ -173,6 +175,8 @@
StandardBT2020Constant, // PrimariesBT2020 and MatrixBT2020Constant
StandardBT470M, // PrimariesBT470_6M and MatrixBT470_6M
StandardFilm, // PrimariesGenericFilm and KR=0.253, KB=0.068
+ StandardDisplayP3, // PrimariesEG432 and MatrixBT601_6
+ // StandardAdobeRGB, // for placeholder only (not used by media)
StandardOther = 0xff,
};
@@ -282,6 +286,8 @@
case ColorAspects::PrimariesBT601_6_525: return "BT601_6_525";
case ColorAspects::PrimariesGenericFilm: return "GenericFilm";
case ColorAspects::PrimariesBT2020: return "BT2020";
+ case ColorAspects::PrimariesRP431: return "RP431";
+ case ColorAspects::PrimariesEG432: return "EG432";
case ColorAspects::PrimariesOther: return "Other";
default: return def;
}
@@ -332,6 +338,8 @@
case ColorAspects::StandardBT2020Constant: return "BT2020Constant";
case ColorAspects::StandardBT470M: return "BT470M";
case ColorAspects::StandardFilm: return "Film";
+ case ColorAspects::StandardDisplayP3: return "DisplayP3";
+ // case ColorAspects::StandardAdobeRGB: return "AdobeRGB";
case ColorAspects::StandardOther: return "Other";
default: return def;
}
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index daeebec..cce2e46 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -54,6 +54,12 @@
* The caller takes ownership of the ASurfaceControl returned and must release it
* using ASurfaceControl_release below.
*
+ * By default the \a ASurfaceControl will be visible and display any buffer submitted. In
+ * addition, the default buffer submission control may release and not display all buffers
+ * that are submitted before receiving a callback for the previous buffer. See
+ * \a ASurfaceTransaction_setVisibility and \a ASurfaceTransaction_setEnableBackPressure to
+ * change the default behaviors after creation.
+ *
* Available since API level 29.
*/
ASurfaceControl* ASurfaceControl_createFromWindow(ANativeWindow* parent, const char* debug_name)
@@ -548,11 +554,15 @@
* to the max display brightness. The system may not be able to, or may choose
* not to, deliver the requested range.
*
- * If unspecified, the system will attempt to provide the best range it can
- * for the given ambient conditions & device state. However, voluntarily
- * reducing the requested range can help improve battery life as well as can
- * improve quality by ensuring greater bit depth is allocated to the luminance
- * range in use.
+ * While requesting a large desired ratio will result in the most
+ * dynamic range, voluntarily reducing the requested range can help
+ * improve battery life as well as can improve quality by ensuring
+ * greater bit depth is allocated to the luminance range in use.
+ *
+ * Default value is 1.0f and indicates that extended range brightness
+ * is not being used, so the resulting SDR or HDR behavior will be
+ * determined entirely by the dataspace being used (ie, typically SDR
+ * however PQ or HLG transfer functions will still result in HDR)
*
* Must be finite && >= 1.0f
*
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 66d3435..1a40fdb 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -212,6 +212,11 @@
std::string languageTag;
// The layout type such as QWERTY or AZERTY.
std::string layoutType;
+
+ inline bool operator==(const KeyboardLayoutInfo& other) const {
+ return languageTag == other.languageTag && layoutType == other.layoutType;
+ }
+ inline bool operator!=(const KeyboardLayoutInfo& other) const { return !(*this == other); }
};
// The version of the Universal Stylus Initiative (USI) protocol supported by the input device.
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index 9423041..b2e8baa 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -26,9 +26,9 @@
#include <android-base/result.h>
#include <input/Input.h>
#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
#include <utils/Tokenizer.h>
#include <utils/Unicode.h>
+#include <map>
// Maximum number of keys supported by KeyCharacterMaps
#define MAX_KEYS 8192
@@ -152,13 +152,9 @@
void writeToParcel(Parcel* parcel) const;
#endif
- bool operator==(const KeyCharacterMap& other) const;
+ bool operator==(const KeyCharacterMap& other) const = default;
- bool operator!=(const KeyCharacterMap& other) const;
-
- KeyCharacterMap(const KeyCharacterMap& other);
-
- virtual ~KeyCharacterMap();
+ KeyCharacterMap(const KeyCharacterMap& other) = default;
private:
struct Behavior {
@@ -173,17 +169,18 @@
/* The replacement keycode if the key has to be replaced outright. */
int32_t replacementKeyCode = 0;
+
+ bool operator==(const Behavior&) const = default;
};
struct Key {
- Key();
- Key(const Key& other);
+ bool operator==(const Key&) const = default;
/* The single character label printed on the key, or 0 if none. */
- char16_t label;
+ char16_t label = 0;
/* The number or symbol character generated by the key, or 0 if none. */
- char16_t number;
+ char16_t number = 0;
/* The list of key behaviors sorted from most specific to least specific
* meta key binding. */
@@ -218,7 +215,6 @@
public:
Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format);
- ~Parser();
status_t parse();
private:
@@ -232,8 +228,8 @@
status_t parseCharacterLiteral(char16_t* outCharacter);
};
- KeyedVector<int32_t, Key*> mKeys;
- KeyboardType mType;
+ std::map<int32_t, Key> mKeys;
+ KeyboardType mType = KeyboardType::UNKNOWN;
std::string mLoadFileName;
bool mLayoutOverlayApplied = false;
diff --git a/libs/binder/IUidObserver.cpp b/libs/binder/IUidObserver.cpp
index d952dc7..1c35f53 100644
--- a/libs/binder/IUidObserver.cpp
+++ b/libs/binder/IUidObserver.cpp
@@ -67,9 +67,10 @@
remote()->transact(ON_UID_STATE_CHANGED_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
}
- virtual void onUidProcAdjChanged(uid_t uid) {
+ virtual void onUidProcAdjChanged(uid_t uid, int32_t adj) {
Parcel data, reply;
data.writeInt32((int32_t)uid);
+ data.writeInt32((int32_t)adj);
remote()->transact(ON_UID_PROC_ADJ_CHANGED_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
}
};
@@ -121,7 +122,8 @@
case ON_UID_PROC_ADJ_CHANGED_TRANSACTION: {
CHECK_INTERFACE(IUidObserver, data, reply);
uid_t uid = data.readInt32();
- onUidProcAdjChanged(uid);
+ int32_t adj = data.readInt32();
+ onUidProcAdjChanged(uid, adj);
return NO_ERROR;
} break;
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index ed3ce24..03fa699 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -928,7 +928,7 @@
transactionData.size() -
offsetof(RpcWireTransaction, data)};
Span<const uint32_t> objectTableSpan;
- if (session->getProtocolVersion().value() >
+ if (session->getProtocolVersion().value() >=
RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE) {
std::optional<Span<const uint8_t>> objectTableBytes =
parcelSpan.splitOff(transaction->parcelDataSize);
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index a323feb..cb64603 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -37,9 +37,9 @@
class RpcTransport;
class FdTrigger;
-constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_NEXT = 1;
+constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_NEXT = 2;
constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL = 0xF0000000;
-constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION = RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL;
+constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION = 1;
// Starting with this version:
//
diff --git a/libs/binder/include_activitymanager/binder/IUidObserver.h b/libs/binder/include_activitymanager/binder/IUidObserver.h
index 17f03a9..5ea7447 100644
--- a/libs/binder/include_activitymanager/binder/IUidObserver.h
+++ b/libs/binder/include_activitymanager/binder/IUidObserver.h
@@ -34,7 +34,7 @@
virtual void onUidIdle(uid_t uid, bool disabled) = 0;
virtual void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq,
int32_t capability) = 0;
- virtual void onUidProcAdjChanged(uid_t uid) = 0;
+ virtual void onUidProcAdjChanged(uid_t uid, int32_t adj) = 0;
enum {
ON_UID_GONE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
diff --git a/libs/binder/tests/binderRpcWireProtocolTest.cpp b/libs/binder/tests/binderRpcWireProtocolTest.cpp
index 3dab2c7..642cea4 100644
--- a/libs/binder/tests/binderRpcWireProtocolTest.cpp
+++ b/libs/binder/tests/binderRpcWireProtocolTest.cpp
@@ -237,14 +237,25 @@
checkRepr(kCurrentRepr, 0);
}
+TEST(RpcWire, V1) {
+ checkRepr(kCurrentRepr, 1);
+}
+
TEST(RpcWire, CurrentVersion) {
checkRepr(kCurrentRepr, RPC_WIRE_PROTOCOL_VERSION);
}
-static_assert(RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL,
+static_assert(RPC_WIRE_PROTOCOL_VERSION == 1,
"If the binder wire protocol is updated, this test should test additional versions. "
"The binder wire protocol should only be updated on upstream AOSP.");
+TEST(RpcWire, NextIsPlusOneReminder) {
+ if (RPC_WIRE_PROTOCOL_VERSION != RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) {
+ EXPECT_EQ(RPC_WIRE_PROTOCOL_VERSION + 1, RPC_WIRE_PROTOCOL_VERSION_NEXT)
+ << "Make sure to note what the next version should be.";
+ }
+}
+
TEST(RpcWire, ReleaseBranchHasFrozenRpcWireProtocol) {
if (RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) {
EXPECT_FALSE(base::GetProperty("ro.build.version.codename", "") == "REL")
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 7f7a043..5217209 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -33,6 +33,7 @@
#include <gui/BufferQueueCore.h>
#include <gui/IConsumerListener.h>
#include <gui/IProducerListener.h>
+#include <gui/TraceUtils.h>
#include <private/gui/BufferQueueThreadState.h>
#ifndef __ANDROID_VNDK__
@@ -646,7 +647,7 @@
status_t BufferQueueConsumer::setMaxAcquiredBufferCount(
int maxAcquiredBuffers) {
- ATRACE_CALL();
+ ATRACE_FORMAT("%s(%d)", __func__, maxAcquiredBuffers);
if (maxAcquiredBuffers < 1 ||
maxAcquiredBuffers > BufferQueueCore::MAX_MAX_ACQUIRED_BUFFERS) {
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 9eb1a9f..9a2343b 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -35,6 +35,7 @@
#include <gui/GLConsumer.h>
#include <gui/IConsumerListener.h>
#include <gui/IProducerListener.h>
+#include <gui/TraceUtils.h>
#include <private/gui/BufferQueueThreadState.h>
#include <utils/Log.h>
@@ -125,7 +126,7 @@
status_t BufferQueueProducer::setMaxDequeuedBufferCount(int maxDequeuedBuffers,
int* maxBufferCount) {
- ATRACE_CALL();
+ ATRACE_FORMAT("%s(%d)", __func__, maxDequeuedBuffers);
BQ_LOGV("setMaxDequeuedBufferCount: maxDequeuedBuffers = %d",
maxDequeuedBuffers);
@@ -502,6 +503,20 @@
if ((buffer == nullptr) ||
buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage))
{
+ if (CC_UNLIKELY(ATRACE_ENABLED())) {
+ if (buffer == nullptr) {
+ ATRACE_FORMAT_INSTANT("%s buffer reallocation: null", mConsumerName.string());
+ } else {
+ ATRACE_FORMAT_INSTANT("%s buffer reallocation actual %dx%d format:%d "
+ "layerCount:%d "
+ "usage:%d requested: %dx%d format:%d layerCount:%d "
+ "usage:%d ",
+ mConsumerName.string(), width, height, format,
+ BQ_LAYER_COUNT, usage, buffer->getWidth(),
+ buffer->getHeight(), buffer->getPixelFormat(),
+ buffer->getLayerCount(), buffer->getUsage());
+ }
+ }
mSlots[found].mAcquireCalled = false;
mSlots[found].mGraphicBuffer = nullptr;
mSlots[found].mRequestBufferCalled = false;
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index fee91a4..2322b70 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -897,11 +897,11 @@
SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(dataspace));
SAFE_PARCEL(output->writeBool, allowProtected);
SAFE_PARCEL(output->writeBool, grayscale);
-
SAFE_PARCEL(output->writeInt32, excludeHandles.size());
for (auto& excludeHandle : excludeHandles) {
SAFE_PARCEL(output->writeStrongBinder, excludeHandle);
}
+ SAFE_PARCEL(output->writeBool, hintForSeamlessTransition);
return NO_ERROR;
}
@@ -918,7 +918,6 @@
dataspace = static_cast<ui::Dataspace>(value);
SAFE_PARCEL(input->readBool, &allowProtected);
SAFE_PARCEL(input->readBool, &grayscale);
-
int32_t numExcludeHandles = 0;
SAFE_PARCEL_READ_SIZE(input->readInt32, &numExcludeHandles, input->dataSize());
excludeHandles.reserve(numExcludeHandles);
@@ -927,6 +926,7 @@
SAFE_PARCEL(input->readStrongBinder, &binder);
excludeHandles.emplace(binder);
}
+ SAFE_PARCEL(input->readBool, &hintForSeamlessTransition);
return NO_ERROR;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 7700aa4..eb5cc4f 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -898,7 +898,7 @@
}
void SurfaceComposerClient::Transaction::releaseBufferIfOverwriting(const layer_state_t& state) {
- if (!(state.what & layer_state_t::eBufferChanged)) {
+ if (!(state.what & layer_state_t::eBufferChanged) || !state.bufferData->hasBuffer()) {
return;
}
@@ -1642,28 +1642,25 @@
releaseBufferIfOverwriting(*s);
- if (buffer == nullptr) {
- s->what &= ~layer_state_t::eBufferChanged;
- s->bufferData = nullptr;
- return *this;
- }
-
std::shared_ptr<BufferData> bufferData = std::make_shared<BufferData>();
bufferData->buffer = buffer;
- uint64_t frameNumber = sc->resolveFrameNumber(optFrameNumber);
- bufferData->frameNumber = frameNumber;
- bufferData->producerId = producerId;
- bufferData->flags |= BufferData::BufferDataChange::frameNumberChanged;
- if (fence) {
- bufferData->acquireFence = *fence;
- bufferData->flags |= BufferData::BufferDataChange::fenceChanged;
+ if (buffer) {
+ uint64_t frameNumber = sc->resolveFrameNumber(optFrameNumber);
+ bufferData->frameNumber = frameNumber;
+ bufferData->producerId = producerId;
+ bufferData->flags |= BufferData::BufferDataChange::frameNumberChanged;
+ if (fence) {
+ bufferData->acquireFence = *fence;
+ bufferData->flags |= BufferData::BufferDataChange::fenceChanged;
+ }
+ bufferData->releaseBufferEndpoint =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ setReleaseBufferCallback(bufferData.get(), callback);
}
- bufferData->releaseBufferEndpoint =
- IInterface::asBinder(TransactionCompletedListener::getIInstance());
+
if (mIsAutoTimestamp) {
mDesiredPresentTime = systemTime();
}
- setReleaseBufferCallback(bufferData.get(), callback);
s->what |= layer_state_t::eBufferChanged;
s->bufferData = std::move(bufferData);
registerSurfaceControlForCallback(sc);
@@ -1684,6 +1681,25 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::unsetBuffer(
+ const sp<SurfaceControl>& sc) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+
+ if (!(s->what & layer_state_t::eBufferChanged)) {
+ return *this;
+ }
+
+ releaseBufferIfOverwriting(*s);
+
+ s->what &= ~layer_state_t::eBufferChanged;
+ s->bufferData = nullptr;
+ return *this;
+}
+
void SurfaceComposerClient::Transaction::setReleaseBufferCallback(BufferData* bufferData,
ReleaseBufferCallback callback) {
if (!callback) {
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
index aa58e2e..ec3266c 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -230,6 +230,10 @@
*/
void captureDisplay(in DisplayCaptureArgs args, IScreenCaptureListener listener);
+ /**
+ * Capture the specified screen. This requires the READ_FRAME_BUFFER
+ * permission.
+ */
void captureDisplayById(long displayId, IScreenCaptureListener listener);
/**
diff --git a/libs/gui/include/gui/DisplayCaptureArgs.h b/libs/gui/include/gui/DisplayCaptureArgs.h
index 5c794ae..2676e0a 100644
--- a/libs/gui/include/gui/DisplayCaptureArgs.h
+++ b/libs/gui/include/gui/DisplayCaptureArgs.h
@@ -41,7 +41,7 @@
bool captureSecureLayers{false};
int32_t uid{UNSET_UID};
// Force capture to be in a color space. If the value is ui::Dataspace::UNKNOWN, the captured
- // result will be in the display's colorspace.
+ // result will be in a colorspace appropriate for capturing the display contents
// The display may use non-RGB dataspace (ex. displayP3) that could cause pixel data could be
// different from SRGB (byte per color), and failed when checking colors in tests.
// NOTE: In normal cases, we want the screen to be captured in display's colorspace.
@@ -59,6 +59,15 @@
std::unordered_set<sp<IBinder>, SpHash<IBinder>> excludeHandles;
+ // Hint that the caller will use the screenshot animation as part of a transition animation.
+ // The canonical example would be screen rotation - in such a case any color shift in the
+ // screenshot is a detractor so composition in the display's colorspace is required.
+ // Otherwise, the system may choose a colorspace that is more appropriate for use-cases
+ // such as file encoding or for blending HDR content into an ap's UI, where the display's
+ // exact colorspace is not an appropriate intermediate result.
+ // Note that if the caller is requesting a specific dataspace, this hint does nothing.
+ bool hintForSeamlessTransition = false;
+
virtual status_t writeToParcel(Parcel* output) const;
virtual status_t readFromParcel(const Parcel* input);
};
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 5c88a07..a6f503e 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -233,9 +233,10 @@
// Geometry updates.
static constexpr uint64_t GEOMETRY_CHANGES = layer_state_t::eBufferCropChanged |
- layer_state_t::eBufferTransformChanged | layer_state_t::eCropChanged |
- layer_state_t::eDestinationFrameChanged | layer_state_t::eMatrixChanged |
- layer_state_t::ePositionChanged | layer_state_t::eTransformToDisplayInverseChanged |
+ layer_state_t::eBufferTransformChanged | layer_state_t::eCornerRadiusChanged |
+ layer_state_t::eCropChanged | layer_state_t::eDestinationFrameChanged |
+ layer_state_t::eMatrixChanged | layer_state_t::ePositionChanged |
+ layer_state_t::eTransformToDisplayInverseChanged |
layer_state_t::eTransparentRegionChanged;
// Buffer and related updates.
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index d431b43..945b164 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -541,6 +541,7 @@
const std::optional<sp<Fence>>& fence = std::nullopt,
const std::optional<uint64_t>& frameNumber = std::nullopt,
uint32_t producerId = 0, ReleaseBufferCallback callback = nullptr);
+ Transaction& unsetBuffer(const sp<SurfaceControl>& sc);
std::shared_ptr<BufferData> getAndClearBuffer(const sp<SurfaceControl>& sc);
/**
diff --git a/libs/gui/include/gui/test/CallbackUtils.h b/libs/gui/include/gui/test/CallbackUtils.h
index 08785b4..1c900e9 100644
--- a/libs/gui/include/gui/test/CallbackUtils.h
+++ b/libs/gui/include/gui/test/CallbackUtils.h
@@ -51,6 +51,7 @@
enum Buffer {
NOT_ACQUIRED = 0,
ACQUIRED,
+ ACQUIRED_NULL,
};
enum PreviousBuffer {
@@ -133,17 +134,28 @@
: mBufferResult(bufferResult), mPreviousBufferResult(previousBufferResult) {}
void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats,
- nsecs_t latchTime) const {
+ nsecs_t /* latchTime */) const {
const auto& [surfaceControl, latch, acquireTimeOrFence, presentFence,
previousReleaseFence, transformHint, frameEvents, ignore] =
- surfaceControlStats;
+ surfaceControlStats;
- ASSERT_TRUE(std::holds_alternative<nsecs_t>(acquireTimeOrFence));
- ASSERT_EQ(std::get<nsecs_t>(acquireTimeOrFence) > 0,
- mBufferResult == ExpectedResult::Buffer::ACQUIRED)
- << "bad acquire time";
- ASSERT_LE(std::get<nsecs_t>(acquireTimeOrFence), latchTime)
- << "acquire time should be <= latch time";
+ nsecs_t acquireTime = -1;
+ if (std::holds_alternative<nsecs_t>(acquireTimeOrFence)) {
+ acquireTime = std::get<nsecs_t>(acquireTimeOrFence);
+ } else {
+ auto fence = std::get<sp<Fence>>(acquireTimeOrFence);
+ if (fence) {
+ ASSERT_EQ(fence->wait(3000), NO_ERROR);
+ acquireTime = fence->getSignalTime();
+ }
+ }
+
+ if (mBufferResult == ExpectedResult::Buffer::ACQUIRED) {
+ ASSERT_GT(acquireTime, 0) << "acquire time should be valid";
+ } else {
+ ASSERT_LE(acquireTime, 0) << "acquire time should not be valid";
+ }
+ ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED);
if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED) {
ASSERT_NE(previousReleaseFence, nullptr)
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index f703901..12c9e53 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -85,63 +85,7 @@
// --- KeyCharacterMap ---
-KeyCharacterMap::KeyCharacterMap(const std::string& filename)
- : mType(KeyboardType::UNKNOWN), mLoadFileName(filename) {}
-
-KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other)
- : mType(other.mType),
- mLoadFileName(other.mLoadFileName),
- mLayoutOverlayApplied(other.mLayoutOverlayApplied),
- mKeyRemapping(other.mKeyRemapping),
- mKeysByScanCode(other.mKeysByScanCode),
- mKeysByUsageCode(other.mKeysByUsageCode) {
- for (size_t i = 0; i < other.mKeys.size(); i++) {
- mKeys.add(other.mKeys.keyAt(i), new Key(*other.mKeys.valueAt(i)));
- }
-}
-
-KeyCharacterMap::~KeyCharacterMap() {
- clear();
-}
-
-bool KeyCharacterMap::operator==(const KeyCharacterMap& other) const {
- if (mType != other.mType) {
- return false;
- }
- if (mLoadFileName != other.mLoadFileName) {
- return false;
- }
- if (mLayoutOverlayApplied != other.mLayoutOverlayApplied) {
- return false;
- }
- if (mKeys.size() != other.mKeys.size() || mKeyRemapping.size() != other.mKeyRemapping.size() ||
- mKeysByScanCode.size() != other.mKeysByScanCode.size() ||
- mKeysByUsageCode.size() != other.mKeysByUsageCode.size()) {
- return false;
- }
-
- for (size_t i = 0; i < mKeys.size(); i++) {
- if (mKeys.keyAt(i) != other.mKeys.keyAt(i)) {
- return false;
- }
- const Key* key = mKeys.valueAt(i);
- const Key* otherKey = other.mKeys.valueAt(i);
- if (key->label != otherKey->label || key->number != otherKey->number) {
- return false;
- }
- }
-
- if (mKeyRemapping != other.mKeyRemapping || mKeysByScanCode != other.mKeysByScanCode ||
- mKeysByUsageCode != other.mKeysByUsageCode) {
- return false;
- }
-
- return true;
-}
-
-bool KeyCharacterMap::operator!=(const KeyCharacterMap& other) const {
- return !(*this == other);
-}
+KeyCharacterMap::KeyCharacterMap(const std::string& filename) : mLoadFileName(filename) {}
base::Result<std::shared_ptr<KeyCharacterMap>> KeyCharacterMap::load(const std::string& filename,
Format format) {
@@ -207,10 +151,6 @@
void KeyCharacterMap::clear() {
mKeysByScanCode.clear();
mKeysByUsageCode.clear();
- for (size_t i = 0; i < mKeys.size(); i++) {
- Key* key = mKeys.editValueAt(i);
- delete key;
- }
mKeys.clear();
mLayoutOverlayApplied = false;
mType = KeyboardType::UNKNOWN;
@@ -233,24 +173,16 @@
if (mLayoutOverlayApplied) {
reloadBaseFromFile();
}
- for (size_t i = 0; i < overlay.mKeys.size(); i++) {
- int32_t keyCode = overlay.mKeys.keyAt(i);
- Key* key = overlay.mKeys.valueAt(i);
- ssize_t oldIndex = mKeys.indexOfKey(keyCode);
- if (oldIndex >= 0) {
- delete mKeys.valueAt(oldIndex);
- mKeys.editValueAt(oldIndex) = new Key(*key);
- } else {
- mKeys.add(keyCode, new Key(*key));
- }
+ for (const auto& [keyCode, key] : overlay.mKeys) {
+ mKeys.insert_or_assign(keyCode, key);
}
- for (auto const& it : overlay.mKeysByScanCode) {
- mKeysByScanCode.insert_or_assign(it.first, it.second);
+ for (const auto& [fromScanCode, toAndroidKeyCode] : overlay.mKeysByScanCode) {
+ mKeysByScanCode.insert_or_assign(fromScanCode, toAndroidKeyCode);
}
- for (auto const& it : overlay.mKeysByUsageCode) {
- mKeysByUsageCode.insert_or_assign(it.first, it.second);
+ for (const auto& [fromHidUsageCode, toAndroidKeyCode] : overlay.mKeysByUsageCode) {
+ mKeysByUsageCode.insert_or_assign(fromHidUsageCode, toAndroidKeyCode);
}
mLayoutOverlayApplied = true;
}
@@ -343,19 +275,15 @@
if (behavior.character == chars[i]) {
result = behavior.character;
if ((behavior.metaState & metaState) == behavior.metaState) {
- goto ExactMatch;
+ // Found exact match!
+ return result;
}
break;
}
}
}
}
- ExactMatch: ;
}
-#if DEBUG_MAPPING
- ALOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.",
- keyCode, toString(chars, numChars).string(), metaState, result);
-#endif
return result;
}
@@ -494,9 +422,9 @@
}
const KeyCharacterMap::Key* KeyCharacterMap::getKey(int32_t keyCode) const {
- ssize_t index = mKeys.indexOfKey(keyCode);
- if (index >= 0) {
- return mKeys.valueAt(index);
+ auto it = mKeys.find(keyCode);
+ if (it != mKeys.end()) {
+ return &it->second;
}
return nullptr;
}
@@ -550,19 +478,17 @@
return false;
}
- for (size_t i = 0; i < mKeys.size(); i++) {
- const Key* key = mKeys.valueAt(i);
-
+ for (const auto& [keyCode, key] : mKeys) {
// Try to find the most general behavior that maps to this character.
// For example, the base key behavior will usually be last in the list.
const Behavior* found = nullptr;
- for (const Behavior& behavior : key->behaviors) {
+ for (const Behavior& behavior : key.behaviors) {
if (behavior.character == ch) {
found = &behavior;
}
}
if (found != nullptr) {
- *outKeyCode = mKeys.keyAt(i);
+ *outKeyCode = keyCode;
*outMetaState = found->metaState;
return true;
}
@@ -714,11 +640,7 @@
return nullptr;
}
- Key* key = new Key();
- key->label = label;
- key->number = number;
- map->mKeys.add(keyCode, key);
-
+ Key key{.label = label, .number = number};
while (parcel->readInt32()) {
int32_t metaState = parcel->readInt32();
char16_t character = parcel->readInt32();
@@ -728,13 +650,14 @@
return nullptr;
}
- key->behaviors.push_back({
+ key.behaviors.push_back({
.metaState = metaState,
.character = character,
.fallbackKeyCode = fallbackKeyCode,
.replacementKeyCode = replacementKeyCode,
});
}
+ map->mKeys.emplace(keyCode, std::move(key));
if (parcel->errorCheck()) {
return nullptr;
@@ -790,13 +713,11 @@
size_t numKeys = mKeys.size();
parcel->writeInt32(numKeys);
- for (size_t i = 0; i < numKeys; i++) {
- int32_t keyCode = mKeys.keyAt(i);
- const Key* key = mKeys.valueAt(i);
+ for (const auto& [keyCode, key] : mKeys) {
parcel->writeInt32(keyCode);
- parcel->writeInt32(key->label);
- parcel->writeInt32(key->number);
- for (const Behavior& behavior : key->behaviors) {
+ parcel->writeInt32(key.label);
+ parcel->writeInt32(key.number);
+ for (const Behavior& behavior : key.behaviors) {
parcel->writeInt32(1);
parcel->writeInt32(behavior.metaState);
parcel->writeInt32(behavior.character);
@@ -826,22 +747,12 @@
}
#endif // __linux__
-// --- KeyCharacterMap::Key ---
-
-KeyCharacterMap::Key::Key() : label(0), number(0) {}
-
-KeyCharacterMap::Key::Key(const Key& other)
- : label(other.label), number(other.number), behaviors(other.behaviors) {}
-
// --- KeyCharacterMap::Parser ---
KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) :
mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) {
}
-KeyCharacterMap::Parser::~Parser() {
-}
-
status_t KeyCharacterMap::Parser::parse() {
while (!mTokenizer->isEof()) {
#if DEBUG_PARSER
@@ -1021,7 +932,7 @@
keyCodeToken.string());
return BAD_VALUE;
}
- if (mMap->mKeys.indexOfKey(*keyCode) >= 0) {
+ if (mMap->mKeys.find(*keyCode) != mMap->mKeys.end()) {
ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(),
keyCodeToken.string());
return BAD_VALUE;
@@ -1037,17 +948,17 @@
ALOGD_IF(DEBUG_PARSER, "Parsed beginning of key: keyCode=%d.", *keyCode);
mKeyCode = *keyCode;
- mMap->mKeys.add(*keyCode, new Key());
+ mMap->mKeys.emplace(*keyCode, Key{});
mState = STATE_KEY;
return NO_ERROR;
}
status_t KeyCharacterMap::Parser::parseKeyProperty() {
- Key* key = mMap->mKeys.valueFor(mKeyCode);
+ Key& key = mMap->mKeys[mKeyCode];
String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
if (token == "}") {
mState = STATE_TOP;
- return finishKey(*key);
+ return finishKey(key);
}
std::vector<Property> properties;
@@ -1184,43 +1095,41 @@
for (const Property& property : properties) {
switch (property.property) {
case PROPERTY_LABEL:
- if (key->label) {
- ALOGE("%s: Duplicate label for key.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
- key->label = behavior.character;
+ if (key.label) {
+ ALOGE("%s: Duplicate label for key.", mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+ key.label = behavior.character;
#if DEBUG_PARSER
- ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key->label);
+ ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key.label);
#endif
break;
case PROPERTY_NUMBER:
- if (key->number) {
- ALOGE("%s: Duplicate number for key.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
+ if (key.number) {
+ ALOGE("%s: Duplicate number for key.", mTokenizer->getLocation().string());
+ return BAD_VALUE;
}
- key->number = behavior.character;
+ key.number = behavior.character;
#if DEBUG_PARSER
- ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key->number);
+ ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key.number);
#endif
break;
case PROPERTY_META: {
- for (const Behavior& b : key->behaviors) {
- if (b.metaState == property.metaState) {
+ for (const Behavior& b : key.behaviors) {
+ if (b.metaState == property.metaState) {
ALOGE("%s: Duplicate key behavior for modifier.",
mTokenizer->getLocation().string());
return BAD_VALUE;
- }
+ }
}
Behavior newBehavior = behavior;
newBehavior.metaState = property.metaState;
- key->behaviors.push_front(newBehavior);
+ key.behaviors.push_front(newBehavior);
ALOGD_IF(DEBUG_PARSER,
"Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d replace=%d.",
- mKeyCode, key->behaviors.front().metaState, key->behaviors.front().character,
- key->behaviors.front().fallbackKeyCode,
- key->behaviors.front().replacementKeyCode);
+ mKeyCode, key.behaviors.front().metaState, key.behaviors.front().character,
+ key.behaviors.front().fallbackKeyCode,
+ key.behaviors.front().replacementKeyCode);
break;
}
}
diff --git a/libs/renderengine/skia/AutoBackendTexture.cpp b/libs/renderengine/skia/AutoBackendTexture.cpp
index 932be56..c412c9c 100644
--- a/libs/renderengine/skia/AutoBackendTexture.cpp
+++ b/libs/renderengine/skia/AutoBackendTexture.cpp
@@ -43,10 +43,12 @@
createProtectedImage, backendFormat,
isOutputBuffer);
mColorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format);
- ALOGE_IF(!mBackendTexture.isValid(),
- "Failed to create a valid texture. [%p]:[%d,%d] isProtected:%d isWriteable:%d "
- "format:%d",
- this, desc.width, desc.height, createProtectedImage, isOutputBuffer, desc.format);
+ if (!mBackendTexture.isValid() || !desc.width || !desc.height) {
+ LOG_ALWAYS_FATAL("Failed to create a valid texture. [%p]:[%d,%d] isProtected:%d "
+ "isWriteable:%d format:%d",
+ this, desc.width, desc.height, createProtectedImage, isOutputBuffer,
+ desc.format);
+ }
}
AutoBackendTexture::~AutoBackendTexture() {
diff --git a/libs/renderengine/skia/ColorSpaces.cpp b/libs/renderengine/skia/ColorSpaces.cpp
index 37ff5df..92b01e0 100644
--- a/libs/renderengine/skia/ColorSpaces.cpp
+++ b/libs/renderengine/skia/ColorSpaces.cpp
@@ -21,6 +21,8 @@
namespace skia {
// please keep in sync with hwui/utils/Color.cpp
+// TODO: Scale by the dimming ratio here instead of in a generic 3x3 transform
+// Otherwise there may be luminance shift for e.g., HLG.
sk_sp<SkColorSpace> toSkColorSpace(ui::Dataspace dataspace) {
skcms_Matrix3x3 gamut;
switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
@@ -61,13 +63,14 @@
case HAL_DATASPACE_TRANSFER_GAMMA2_8:
return SkColorSpace::MakeRGB({2.8f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
case HAL_DATASPACE_TRANSFER_ST2084:
- return SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, gamut);
+ return SkColorSpace::MakeRGB({-2.f, -1.55522297832f, 1.86045365631f, 32 / 2523.0f,
+ 2413 / 128.0f, -2392 / 128.0f, 8192 / 1305.0f},
+ gamut);
case HAL_DATASPACE_TRANSFER_SMPTE_170M:
return SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, gamut);
case HAL_DATASPACE_TRANSFER_HLG:
- // return HLG transfer but scale by 1/12
skcms_TransferFunction hlgFn;
- if (skcms_TransferFunction_makeScaledHLGish(&hlgFn, 1.f / 12.f, 2.f, 2.f,
+ if (skcms_TransferFunction_makeScaledHLGish(&hlgFn, 0.314509843, 2.f, 2.f,
1.f / 0.17883277f, 0.28466892f,
0.55991073f)) {
return SkColorSpace::MakeRGB(hlgFn, gamut);
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index 8256dd8..cfea85f 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -517,16 +517,18 @@
} else {
runtimeEffect = effectIter->second;
}
+
mat4 colorTransform = parameters.layer.colorTransform;
colorTransform *=
mat4::scale(vec4(parameters.layerDimmingRatio, parameters.layerDimmingRatio,
parameters.layerDimmingRatio, 1.f));
+
const auto targetBuffer = parameters.layer.source.buffer.buffer;
const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr;
const auto hardwareBuffer = graphicBuffer ? graphicBuffer->toAHardwareBuffer() : nullptr;
- return createLinearEffectShader(parameters.shader, effect, runtimeEffect, colorTransform,
- parameters.display.maxLuminance,
+ return createLinearEffectShader(parameters.shader, effect, runtimeEffect,
+ std::move(colorTransform), parameters.display.maxLuminance,
parameters.display.currentLuminanceNits,
parameters.layer.source.buffer.maxLuminanceNits,
hardwareBuffer, parameters.display.renderIntent);
@@ -911,12 +913,10 @@
continue;
}
- // If we need to map to linear space or color management is disabled, then mark the source
- // image with the same colorspace as the destination surface so that Skia's color
- // management is a no-op.
- const ui::Dataspace layerDataspace = (!mUseColorManagement || requiresLinearEffect)
- ? display.outputDataspace
- : layer.sourceDataspace;
+ // If color management is disabled, then mark the source image with the same colorspace as
+ // the destination surface so that Skia's color management is a no-op.
+ const ui::Dataspace layerDataspace =
+ !mUseColorManagement ? display.outputDataspace : layer.sourceDataspace;
SkPaint paint;
if (layer.source.buffer.buffer) {
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index ba190e0..980f8d1 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -176,11 +176,8 @@
mSensors = mSensorServer->getSensorList(mOpPackageName);
size_t count = mSensors.size();
- if (count == 0) {
- ALOGE("Failed to get Sensor list");
- mSensorServer.clear();
- return UNKNOWN_ERROR;
- }
+ // If count is 0, mSensorList will be non-null. This is old
+ // existing behavior and callers expect this.
mSensorList =
static_cast<Sensor const**>(malloc(count * sizeof(Sensor*)));
LOG_ALWAYS_FATAL_IF(mSensorList == nullptr, "mSensorList NULL");
diff --git a/libs/shaders/include/shaders/shaders.h b/libs/shaders/include/shaders/shaders.h
index 42b0cc1..5a4aaab 100644
--- a/libs/shaders/include/shaders/shaders.h
+++ b/libs/shaders/include/shaders/shaders.h
@@ -51,23 +51,20 @@
// Input dataspace of the source colors.
const ui::Dataspace inputDataspace = ui::Dataspace::SRGB;
- // Working dataspace for the output surface, for conversion from linear space.
+ // Working dataspace for the output surface.
const ui::Dataspace outputDataspace = ui::Dataspace::SRGB;
// Sets whether alpha premultiplication must be undone.
// This is required if the source colors use premultiplied alpha and is not opaque.
const bool undoPremultipliedAlpha = false;
- // "Fake" dataspace of the source colors. This is used for applying an EOTF to compute linear
- // RGB. This is used when Skia is expected to color manage the input image based on the
- // dataspace of the provided source image and destination surface. SkRuntimeEffects use the
- // destination color space as the working color space. RenderEngine deliberately sets the color
- // space for input images and destination surfaces to be the same whenever LinearEffects are
- // expected to be used so that color-management is controlled by RenderEngine, but other users
- // of a LinearEffect may not be able to control the color space of the images and surfaces. So
- // fakeInputDataspace is used to essentially masquerade the input dataspace to be the output
- // dataspace for correct conversion to linear colors.
- ui::Dataspace fakeInputDataspace = ui::Dataspace::UNKNOWN;
+ // "Fake" dataspace of the destination colors. This is used for applying an OETF to compute
+ // non-linear RGB. This is used when Skia is expected to color manage the input image based on
+ // the dataspace of the provided source image and destination surface. Some use-cases in
+ // RenderEngine expect to apply a different OETF than what is expected by Skia. As in,
+ // RenderEngine will color manage to a custom destination and "cast" the result to Skia's
+ // working space.
+ ui::Dataspace fakeOutputDataspace = ui::Dataspace::UNKNOWN;
enum SkSLType { Shader, ColorFilter };
SkSLType type = Shader;
@@ -76,7 +73,7 @@
static inline bool operator==(const LinearEffect& lhs, const LinearEffect& rhs) {
return lhs.inputDataspace == rhs.inputDataspace && lhs.outputDataspace == rhs.outputDataspace &&
lhs.undoPremultipliedAlpha == rhs.undoPremultipliedAlpha &&
- lhs.fakeInputDataspace == rhs.fakeInputDataspace;
+ lhs.fakeOutputDataspace == rhs.fakeOutputDataspace;
}
struct LinearEffectHasher {
@@ -89,7 +86,7 @@
size_t result = std::hash<ui::Dataspace>{}(le.inputDataspace);
result = HashCombine(result, std::hash<ui::Dataspace>{}(le.outputDataspace));
result = HashCombine(result, std::hash<bool>{}(le.undoPremultipliedAlpha));
- return HashCombine(result, std::hash<ui::Dataspace>{}(le.fakeInputDataspace));
+ return HashCombine(result, std::hash<ui::Dataspace>{}(le.fakeOutputDataspace));
}
};
@@ -99,10 +96,6 @@
// 2. Apply color transform matrices in linear space
std::string buildLinearEffectSkSL(const LinearEffect& linearEffect);
-// Generates a shader string that applies color transforms in linear space.
-// This is intended to be plugged into an SkColorFilter
-std::string buildLinearEffectSkSLForColorFilter(const LinearEffect& linearEffect);
-
// Generates a list of uniforms to set on the LinearEffect shader above.
std::vector<tonemap::ShaderUniform> buildLinearEffectUniforms(
const LinearEffect& linearEffect, const mat4& colorTransform, float maxDisplayLuminance,
diff --git a/libs/shaders/shaders.cpp b/libs/shaders/shaders.cpp
index a3c403e..b8f2be1 100644
--- a/libs/shaders/shaders.cpp
+++ b/libs/shaders/shaders.cpp
@@ -33,212 +33,107 @@
return static_cast<aidl::android::hardware::graphics::common::Dataspace>(dataspace);
}
-void generateEOTF(ui::Dataspace dataspace, std::string& shader) {
- switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) {
- case HAL_DATASPACE_TRANSFER_ST2084:
- shader.append(R"(
-
- float3 EOTF(float3 color) {
- float m1 = (2610.0 / 4096.0) / 4.0;
- float m2 = (2523.0 / 4096.0) * 128.0;
- float c1 = (3424.0 / 4096.0);
- float c2 = (2413.0 / 4096.0) * 32.0;
- float c3 = (2392.0 / 4096.0) * 32.0;
-
- float3 tmp = pow(clamp(color, 0.0, 1.0), 1.0 / float3(m2));
- tmp = max(tmp - c1, 0.0) / (c2 - c3 * tmp);
- return pow(tmp, 1.0 / float3(m1));
- }
- )");
- break;
- case HAL_DATASPACE_TRANSFER_HLG:
- shader.append(R"(
- float EOTF_channel(float channel) {
- const float a = 0.17883277;
- const float b = 0.28466892;
- const float c = 0.55991073;
- return channel <= 0.5 ? channel * channel / 3.0 :
- (exp((channel - c) / a) + b) / 12.0;
- }
-
- float3 EOTF(float3 color) {
- return float3(EOTF_channel(color.r), EOTF_channel(color.g),
- EOTF_channel(color.b));
- }
- )");
- break;
- case HAL_DATASPACE_TRANSFER_LINEAR:
- shader.append(R"(
- float3 EOTF(float3 color) {
- return color;
- }
- )");
- break;
- case HAL_DATASPACE_TRANSFER_SMPTE_170M:
- shader.append(R"(
-
- float EOTF_sRGB(float srgb) {
- return srgb <= 0.08125 ? srgb / 4.50 : pow((srgb + 0.099) / 1.099, 1 / 0.45);
- }
-
- float3 EOTF_sRGB(float3 srgb) {
- return float3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b));
- }
-
- float3 EOTF(float3 srgb) {
- return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb));
- }
- )");
- break;
- case HAL_DATASPACE_TRANSFER_GAMMA2_2:
- shader.append(R"(
-
- float EOTF_sRGB(float srgb) {
- return pow(srgb, 2.2);
- }
-
- float3 EOTF_sRGB(float3 srgb) {
- return float3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b));
- }
-
- float3 EOTF(float3 srgb) {
- return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb));
- }
- )");
- break;
- case HAL_DATASPACE_TRANSFER_GAMMA2_6:
- shader.append(R"(
-
- float EOTF_sRGB(float srgb) {
- return pow(srgb, 2.6);
- }
-
- float3 EOTF_sRGB(float3 srgb) {
- return float3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b));
- }
-
- float3 EOTF(float3 srgb) {
- return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb));
- }
- )");
- break;
- case HAL_DATASPACE_TRANSFER_GAMMA2_8:
- shader.append(R"(
-
- float EOTF_sRGB(float srgb) {
- return pow(srgb, 2.8);
- }
-
- float3 EOTF_sRGB(float3 srgb) {
- return float3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b));
- }
-
- float3 EOTF(float3 srgb) {
- return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb));
- }
- )");
- break;
- case HAL_DATASPACE_TRANSFER_SRGB:
- default:
- shader.append(R"(
-
- float EOTF_sRGB(float srgb) {
- return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4);
- }
-
- float3 EOTF_sRGB(float3 srgb) {
- return float3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b));
- }
-
- float3 EOTF(float3 srgb) {
- return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb));
- }
- )");
- break;
- }
-}
-
void generateXYZTransforms(std::string& shader) {
shader.append(R"(
- uniform float4x4 in_rgbToXyz;
- uniform float4x4 in_xyzToRgb;
+ uniform float3x3 in_rgbToXyz;
+ uniform float3x3 in_xyzToSrcRgb;
+ uniform float4x4 in_colorTransform;
float3 ToXYZ(float3 rgb) {
- return (in_rgbToXyz * float4(rgb, 1.0)).rgb;
+ return in_rgbToXyz * rgb;
}
- float3 ToRGB(float3 xyz) {
- return clamp((in_xyzToRgb * float4(xyz, 1.0)).rgb, 0.0, 1.0);
+ float3 ToSrcRGB(float3 xyz) {
+ return in_xyzToSrcRgb * xyz;
+ }
+
+ float3 ApplyColorTransform(float3 rgb) {
+ return (in_colorTransform * float4(rgb, 1.0)).rgb;
}
)");
}
-// Conversion from relative light to absolute light (maps from [0, 1] to [0, maxNits])
-void generateLuminanceScalesForOOTF(ui::Dataspace inputDataspace, ui::Dataspace outputDataspace,
- std::string& shader) {
+// Conversion from relative light to absolute light
+// Note that 1.0 == 203 nits.
+void generateLuminanceScalesForOOTF(ui::Dataspace inputDataspace, std::string& shader) {
switch (inputDataspace & HAL_DATASPACE_TRANSFER_MASK) {
- case HAL_DATASPACE_TRANSFER_ST2084:
- shader.append(R"(
- float3 ScaleLuminance(float3 xyz) {
- return xyz * 10000.0;
- }
- )");
- break;
case HAL_DATASPACE_TRANSFER_HLG:
+ // BT. 2408 says that a signal level of 0.75 == 203 nits for HLG, but that's after
+ // applying OOTF. But we haven't applied OOTF yet, so we need to scale by a different
+ // constant instead.
shader.append(R"(
- float3 ScaleLuminance(float3 xyz) {
- return xyz * 1000.0;
- }
- )");
+ float3 ScaleLuminance(float3 xyz) {
+ return xyz * 264.96;
+ }
+ )");
break;
default:
- switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) {
- case HAL_DATASPACE_TRANSFER_ST2084:
- case HAL_DATASPACE_TRANSFER_HLG:
- // SDR -> HDR tonemap
- shader.append(R"(
- float3 ScaleLuminance(float3 xyz) {
- return xyz * in_libtonemap_inputMaxLuminance;
- }
- )");
- break;
- default:
- // Input and output are both SDR, so no tone-mapping is expected so
- // no-op the luminance normalization.
- shader.append(R"(
- float3 ScaleLuminance(float3 xyz) {
- return xyz * in_libtonemap_displayMaxLuminance;
- }
- )");
- break;
- }
+ shader.append(R"(
+ float3 ScaleLuminance(float3 xyz) {
+ return xyz * 203.0;
+ }
+ )");
+ break;
}
}
// Normalizes from absolute light back to relative light (maps from [0, maxNits] back to [0, 1])
-static void generateLuminanceNormalizationForOOTF(ui::Dataspace outputDataspace,
+static void generateLuminanceNormalizationForOOTF(ui::Dataspace inputDataspace,
+ ui::Dataspace outputDataspace,
std::string& shader) {
switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) {
case HAL_DATASPACE_TRANSFER_ST2084:
shader.append(R"(
- float3 NormalizeLuminance(float3 xyz) {
- return xyz / 10000.0;
- }
- )");
+ float3 NormalizeLuminance(float3 xyz) {
+ return xyz / 203.0;
+ }
+ )");
break;
case HAL_DATASPACE_TRANSFER_HLG:
- shader.append(R"(
- float3 NormalizeLuminance(float3 xyz) {
- return xyz / 1000.0;
- }
- )");
+ switch (inputDataspace & HAL_DATASPACE_TRANSFER_MASK) {
+ case HAL_DATASPACE_TRANSFER_HLG:
+ shader.append(R"(
+ float3 NormalizeLuminance(float3 xyz) {
+ return xyz / 264.96;
+ }
+ )");
+ break;
+ default:
+ // Transcoding to HLG requires applying the inverse OOTF
+ // with the expectation that the OOTF is then applied during
+ // tonemapping downstream.
+ // BT. 2100-2 operates on normalized luminances, so renormalize to the input to
+ // correctly adjust gamma.
+ shader.append(R"(
+ float3 NormalizeLuminance(float3 xyz) {
+ float ootfGain = pow(xyz.y / 1000.0, -0.2 / 1.2);
+ return xyz * ootfGain / 203.0;
+ }
+ )");
+ break;
+ }
break;
default:
- shader.append(R"(
- float3 NormalizeLuminance(float3 xyz) {
- return xyz / in_libtonemap_displayMaxLuminance;
- }
- )");
- break;
+ switch (inputDataspace & HAL_DATASPACE_TRANSFER_MASK) {
+ case HAL_DATASPACE_TRANSFER_HLG:
+ case HAL_DATASPACE_TRANSFER_ST2084:
+ // libtonemap outputs a range [0, in_libtonemap_displayMaxLuminance], so
+ // normalize back to [0, 1] when the output is SDR.
+ shader.append(R"(
+ float3 NormalizeLuminance(float3 xyz) {
+ return xyz / in_libtonemap_displayMaxLuminance;
+ }
+ )");
+ break;
+ default:
+ // Otherwise normalize back down to the range [0, 1]
+ // TODO: get this working for extended range outputs
+ shader.append(R"(
+ float3 NormalizeLuminance(float3 xyz) {
+ return xyz / 203.0;
+ }
+ )");
+ break;
+ }
}
}
@@ -249,145 +144,34 @@
toAidlDataspace(outputDataspace))
.c_str());
- generateLuminanceScalesForOOTF(inputDataspace, outputDataspace, shader);
- generateLuminanceNormalizationForOOTF(outputDataspace, shader);
+ generateLuminanceScalesForOOTF(inputDataspace, shader);
+ generateLuminanceNormalizationForOOTF(inputDataspace, outputDataspace, shader);
+ // Some tonemappers operate on CIE luminance, other tonemappers operate on linear rgb
+ // luminance in the source gamut.
shader.append(R"(
- float3 OOTF(float3 linearRGB, float3 xyz) {
+ float3 OOTF(float3 linearRGB) {
float3 scaledLinearRGB = ScaleLuminance(linearRGB);
- float3 scaledXYZ = ScaleLuminance(xyz);
+ float3 scaledXYZ = ToXYZ(scaledLinearRGB);
- float gain = libtonemap_LookupTonemapGain(scaledLinearRGB, scaledXYZ);
+ float gain = libtonemap_LookupTonemapGain(ToSrcRGB(scaledXYZ), scaledXYZ);
return NormalizeLuminance(scaledXYZ * gain);
}
)");
}
-void generateOETF(ui::Dataspace dataspace, std::string& shader) {
- switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) {
- case HAL_DATASPACE_TRANSFER_ST2084:
- shader.append(R"(
-
- float3 OETF(float3 xyz) {
- float m1 = (2610.0 / 4096.0) / 4.0;
- float m2 = (2523.0 / 4096.0) * 128.0;
- float c1 = (3424.0 / 4096.0);
- float c2 = (2413.0 / 4096.0) * 32.0;
- float c3 = (2392.0 / 4096.0) * 32.0;
-
- float3 tmp = pow(xyz, float3(m1));
- tmp = (c1 + c2 * tmp) / (1.0 + c3 * tmp);
- return pow(tmp, float3(m2));
- }
- )");
- break;
- case HAL_DATASPACE_TRANSFER_HLG:
- shader.append(R"(
- float OETF_channel(float channel) {
- const float a = 0.17883277;
- const float b = 0.28466892;
- const float c = 0.55991073;
- return channel <= 1.0 / 12.0 ? sqrt(3.0 * channel) :
- a * log(12.0 * channel - b) + c;
- }
-
- float3 OETF(float3 linear) {
- return float3(OETF_channel(linear.r), OETF_channel(linear.g),
- OETF_channel(linear.b));
- }
- )");
- break;
- case HAL_DATASPACE_TRANSFER_LINEAR:
- shader.append(R"(
- float3 OETF(float3 linear) {
- return linear;
- }
- )");
- break;
- case HAL_DATASPACE_TRANSFER_SMPTE_170M:
- shader.append(R"(
- float OETF_sRGB(float linear) {
- return linear <= 0.018 ?
- linear * 4.50 : (pow(linear, 0.45) * 1.099) - 0.099;
- }
-
- float3 OETF_sRGB(float3 linear) {
- return float3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b));
- }
-
- float3 OETF(float3 linear) {
- return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb));
- }
- )");
- break;
- case HAL_DATASPACE_TRANSFER_GAMMA2_2:
- shader.append(R"(
- float OETF_sRGB(float linear) {
- return pow(linear, (1.0 / 2.2));
- }
-
- float3 OETF_sRGB(float3 linear) {
- return float3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b));
- }
-
- float3 OETF(float3 linear) {
- return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb));
- }
- )");
- break;
- case HAL_DATASPACE_TRANSFER_GAMMA2_6:
- shader.append(R"(
- float OETF_sRGB(float linear) {
- return pow(linear, (1.0 / 2.6));
- }
-
- float3 OETF_sRGB(float3 linear) {
- return float3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b));
- }
-
- float3 OETF(float3 linear) {
- return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb));
- }
- )");
- break;
- case HAL_DATASPACE_TRANSFER_GAMMA2_8:
- shader.append(R"(
- float OETF_sRGB(float linear) {
- return pow(linear, (1.0 / 2.8));
- }
-
- float3 OETF_sRGB(float3 linear) {
- return float3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b));
- }
-
- float3 OETF(float3 linear) {
- return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb));
- }
- )");
- break;
- case HAL_DATASPACE_TRANSFER_SRGB:
- default:
- shader.append(R"(
- float OETF_sRGB(float linear) {
- return linear <= 0.0031308 ?
- linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055;
- }
-
- float3 OETF_sRGB(float3 linear) {
- return float3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b));
- }
-
- float3 OETF(float3 linear) {
- return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb));
- }
- )");
- break;
- }
+void generateOETF(std::string& shader) {
+ // Only support gamma 2.2 for now
+ shader.append(R"(
+ float OETF(float3 linear) {
+ return sign(linear) * pow(abs(linear), (1.0 / 2.2));
+ }
+ )");
}
void generateEffectiveOOTF(bool undoPremultipliedAlpha, LinearEffect::SkSLType type,
- std::string& shader) {
+ bool needsCustomOETF, std::string& shader) {
switch (type) {
case LinearEffect::SkSLType::ColorFilter:
shader.append(R"(
@@ -408,11 +192,19 @@
c.rgb = c.rgb / (c.a + 0.0019);
)");
}
+ // We are using linear sRGB as a working space, with 1.0 == 203 nits
shader.append(R"(
- float3 linearRGB = EOTF(c.rgb);
- float3 xyz = ToXYZ(linearRGB);
- c.rgb = OETF(ToRGB(OOTF(linearRGB, xyz)));
+ c.rgb = ApplyColorTransform(OOTF(toLinearSrgb(c.rgb)));
)");
+ if (needsCustomOETF) {
+ shader.append(R"(
+ c.rgb = OETF(c.rgb);
+ )");
+ } else {
+ shader.append(R"(
+ c.rgb = fromLinearSrgb(c.rgb);
+ )");
+ }
if (undoPremultipliedAlpha) {
shader.append(R"(
c.rgb = c.rgb * (c.a + 0.0019);
@@ -424,33 +216,6 @@
)");
}
-// please keep in sync with toSkColorSpace function in renderengine/skia/ColorSpaces.cpp
-ColorSpace toColorSpace(ui::Dataspace dataspace) {
- switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
- case HAL_DATASPACE_STANDARD_BT709:
- return ColorSpace::sRGB();
- case HAL_DATASPACE_STANDARD_DCI_P3:
- return ColorSpace::DisplayP3();
- case HAL_DATASPACE_STANDARD_BT2020:
- case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
- return ColorSpace::BT2020();
- case HAL_DATASPACE_STANDARD_ADOBE_RGB:
- return ColorSpace::AdobeRGB();
- // TODO(b/208290320): BT601 format and variants return different primaries
- case HAL_DATASPACE_STANDARD_BT601_625:
- case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED:
- case HAL_DATASPACE_STANDARD_BT601_525:
- case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED:
- // TODO(b/208290329): BT407M format returns different primaries
- case HAL_DATASPACE_STANDARD_BT470M:
- // TODO(b/208290904): FILM format returns different primaries
- case HAL_DATASPACE_STANDARD_FILM:
- case HAL_DATASPACE_STANDARD_UNSPECIFIED:
- default:
- return ColorSpace::sRGB();
- }
-}
-
template <typename T, std::enable_if_t<std::is_trivially_copyable<T>::value, bool> = true>
std::vector<uint8_t> buildUniformValue(T value) {
std::vector<uint8_t> result;
@@ -463,17 +228,45 @@
std::string buildLinearEffectSkSL(const LinearEffect& linearEffect) {
std::string shaderString;
- generateEOTF(linearEffect.fakeInputDataspace == ui::Dataspace::UNKNOWN
- ? linearEffect.inputDataspace
- : linearEffect.fakeInputDataspace,
- shaderString);
generateXYZTransforms(shaderString);
generateOOTF(linearEffect.inputDataspace, linearEffect.outputDataspace, shaderString);
- generateOETF(linearEffect.outputDataspace, shaderString);
- generateEffectiveOOTF(linearEffect.undoPremultipliedAlpha, linearEffect.type, shaderString);
+
+ const bool needsCustomOETF = (linearEffect.fakeOutputDataspace & HAL_DATASPACE_TRANSFER_MASK) ==
+ HAL_DATASPACE_TRANSFER_GAMMA2_2;
+ if (needsCustomOETF) {
+ generateOETF(shaderString);
+ }
+ generateEffectiveOOTF(linearEffect.undoPremultipliedAlpha, linearEffect.type, needsCustomOETF,
+ shaderString);
return shaderString;
}
+ColorSpace toColorSpace(ui::Dataspace dataspace) {
+ switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
+ case HAL_DATASPACE_STANDARD_BT709:
+ return ColorSpace::sRGB();
+ case HAL_DATASPACE_STANDARD_DCI_P3:
+ return ColorSpace::DisplayP3();
+ case HAL_DATASPACE_STANDARD_BT2020:
+ case HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE:
+ return ColorSpace::BT2020();
+ case HAL_DATASPACE_STANDARD_ADOBE_RGB:
+ return ColorSpace::AdobeRGB();
+ // TODO(b/208290320): BT601 format and variants return different primaries
+ case HAL_DATASPACE_STANDARD_BT601_625:
+ case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED:
+ case HAL_DATASPACE_STANDARD_BT601_525:
+ case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED:
+ // TODO(b/208290329): BT407M format returns different primaries
+ case HAL_DATASPACE_STANDARD_BT470M:
+ // TODO(b/208290904): FILM format returns different primaries
+ case HAL_DATASPACE_STANDARD_FILM:
+ case HAL_DATASPACE_STANDARD_UNSPECIFIED:
+ default:
+ return ColorSpace::sRGB();
+ }
+}
+
// Generates a list of uniforms to set on the LinearEffect shader above.
std::vector<tonemap::ShaderUniform> buildLinearEffectUniforms(
const LinearEffect& linearEffect, const mat4& colorTransform, float maxDisplayLuminance,
@@ -481,29 +274,29 @@
aidl::android::hardware::graphics::composer3::RenderIntent renderIntent) {
std::vector<tonemap::ShaderUniform> uniforms;
- const ui::Dataspace inputDataspace = linearEffect.fakeInputDataspace == ui::Dataspace::UNKNOWN
- ? linearEffect.inputDataspace
- : linearEffect.fakeInputDataspace;
+ auto inputColorSpace = toColorSpace(linearEffect.inputDataspace);
+ auto outputColorSpace = toColorSpace(linearEffect.outputDataspace);
- if (inputDataspace == linearEffect.outputDataspace) {
- uniforms.push_back({.name = "in_rgbToXyz", .value = buildUniformValue<mat4>(mat4())});
- uniforms.push_back(
- {.name = "in_xyzToRgb", .value = buildUniformValue<mat4>(colorTransform)});
- } else {
- ColorSpace inputColorSpace = toColorSpace(inputDataspace);
- ColorSpace outputColorSpace = toColorSpace(linearEffect.outputDataspace);
- uniforms.push_back({.name = "in_rgbToXyz",
- .value = buildUniformValue<mat4>(mat4(inputColorSpace.getRGBtoXYZ()))});
- uniforms.push_back({.name = "in_xyzToRgb",
- .value = buildUniformValue<mat4>(
- colorTransform * mat4(outputColorSpace.getXYZtoRGB()))});
- }
+ uniforms.push_back(
+ {.name = "in_rgbToXyz",
+ .value = buildUniformValue<mat3>(ColorSpace::linearExtendedSRGB().getRGBtoXYZ())});
+ uniforms.push_back({.name = "in_xyzToSrcRgb",
+ .value = buildUniformValue<mat3>(inputColorSpace.getXYZtoRGB())});
+ // Transforms xyz colors to linear source colors, then applies the color transform, then
+ // transforms to linear extended RGB for skia to color manage.
+ uniforms.push_back({.name = "in_colorTransform",
+ .value = buildUniformValue<mat4>(
+ mat4(ColorSpace::linearExtendedSRGB().getXYZtoRGB()) *
+ // TODO: the color transform ideally should be applied
+ // in the source colorspace, but doing that breaks
+ // renderengine tests
+ mat4(outputColorSpace.getRGBtoXYZ()) * colorTransform *
+ mat4(outputColorSpace.getXYZtoRGB()))});
tonemap::Metadata metadata{.displayMaxLuminance = maxDisplayLuminance,
// If the input luminance is unknown, use display luminance (aka,
- // no-op any luminance changes)
- // This will be the case for eg screenshots in addition to
- // uncalibrated displays
+ // no-op any luminance changes).
+ // This is expected to only be meaningful for PQ content
.contentMaxLuminance =
maxLuminance > 0 ? maxLuminance : maxDisplayLuminance,
.currentDisplayLuminance = currentDisplayLuminanceNits > 0
diff --git a/libs/shaders/tests/shaders_test.cpp b/libs/shaders/tests/shaders_test.cpp
index d45fb24..ba8bed2 100644
--- a/libs/shaders/tests/shaders_test.cpp
+++ b/libs/shaders/tests/shaders_test.cpp
@@ -35,6 +35,10 @@
return arg.name == name && arg.value == value;
}
+MATCHER_P(UniformNameEq, name, "") {
+ return arg.name == name;
+}
+
template <typename T, std::enable_if_t<std::is_trivially_copyable<T>::value, bool> = true>
std::vector<uint8_t> buildUniformValue(T value) {
std::vector<uint8_t> result;
@@ -49,50 +53,44 @@
shaders::LinearEffect effect =
shaders::LinearEffect{.inputDataspace = ui::Dataspace::V0_SRGB_LINEAR,
.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR,
- .fakeInputDataspace = ui::Dataspace::UNKNOWN};
+ .fakeOutputDataspace = ui::Dataspace::UNKNOWN};
mat4 colorTransform = mat4::scale(vec4(.9, .9, .9, 1.));
auto uniforms =
shaders::buildLinearEffectUniforms(effect, colorTransform, 1.f, 1.f, 1.f, nullptr,
aidl::android::hardware::graphics::composer3::
RenderIntent::COLORIMETRIC);
- EXPECT_THAT(uniforms, Contains(UniformEq("in_rgbToXyz", buildUniformValue<mat4>(mat4()))));
EXPECT_THAT(uniforms,
- Contains(UniformEq("in_xyzToRgb", buildUniformValue<mat4>(colorTransform))));
+ Contains(UniformEq("in_rgbToXyz",
+ buildUniformValue<mat3>(
+ ColorSpace::linearExtendedSRGB().getRGBtoXYZ()))));
+ EXPECT_THAT(uniforms,
+ Contains(UniformEq("in_xyzToSrcRgb",
+ buildUniformValue<mat3>(
+ ColorSpace::linearSRGB().getXYZtoRGB()))));
+ // color transforms are already tested in renderengine's tests
+ EXPECT_THAT(uniforms, Contains(UniformNameEq("in_colorTransform")));
}
TEST_F(ShadersTest, buildLinearEffectUniforms_selectsGamutTransformMatrices) {
shaders::LinearEffect effect =
shaders::LinearEffect{.inputDataspace = ui::Dataspace::V0_SRGB,
.outputDataspace = ui::Dataspace::DISPLAY_P3,
- .fakeInputDataspace = ui::Dataspace::UNKNOWN};
+ .fakeOutputDataspace = ui::Dataspace::UNKNOWN};
ColorSpace inputColorSpace = ColorSpace::sRGB();
- ColorSpace outputColorSpace = ColorSpace::DisplayP3();
auto uniforms =
shaders::buildLinearEffectUniforms(effect, mat4(), 1.f, 1.f, 1.f, nullptr,
aidl::android::hardware::graphics::composer3::
RenderIntent::COLORIMETRIC);
EXPECT_THAT(uniforms,
Contains(UniformEq("in_rgbToXyz",
- buildUniformValue<mat4>(mat4(inputColorSpace.getRGBtoXYZ())))));
+ buildUniformValue<mat3>(
+ ColorSpace::linearExtendedSRGB().getRGBtoXYZ()))));
EXPECT_THAT(uniforms,
- Contains(UniformEq("in_xyzToRgb",
- buildUniformValue<mat4>(mat4(outputColorSpace.getXYZtoRGB())))));
-}
-
-TEST_F(ShadersTest, buildLinearEffectUniforms_respectsFakeInputDataspace) {
- shaders::LinearEffect effect =
- shaders::LinearEffect{.inputDataspace = ui::Dataspace::V0_SRGB,
- .outputDataspace = ui::Dataspace::DISPLAY_P3,
- .fakeInputDataspace = ui::Dataspace::DISPLAY_P3};
-
- auto uniforms =
- shaders::buildLinearEffectUniforms(effect, mat4(), 1.f, 1.f, 1.f, nullptr,
- aidl::android::hardware::graphics::composer3::
- RenderIntent::COLORIMETRIC);
- EXPECT_THAT(uniforms, Contains(UniformEq("in_rgbToXyz", buildUniformValue<mat4>(mat4()))));
- EXPECT_THAT(uniforms, Contains(UniformEq("in_xyzToRgb", buildUniformValue<mat4>(mat4()))));
+ Contains(UniformEq("in_xyzToSrcRgb",
+ buildUniformValue<mat3>(inputColorSpace.getXYZtoRGB()))));
+ EXPECT_THAT(uniforms, Contains(UniformNameEq("in_colorTransform")));
}
} // namespace android
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 501bf58..32c21f6 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -697,6 +697,11 @@
#define EGL_EXT_device_query 1
#endif /* EGL_EXT_device_query */
+#ifndef EGL_EXT_gl_colorspace_bt2020_hlg
+#define EGL_EXT_gl_colorspace_bt2020_hlg 1
+#define EGL_GL_COLORSPACE_BT2020_HLG_EXT 0x333E
+#endif /* EGL_EXT_gl_colorspace_bt2020_hlg */
+
#ifndef EGL_EXT_gl_colorspace_bt2020_linear
#define EGL_EXT_gl_colorspace_bt2020_linear 1
#define EGL_GL_COLORSPACE_BT2020_LINEAR_EXT 0x333F
diff --git a/opengl/libs/EGL/BlobCache.cpp b/opengl/libs/EGL/BlobCache.cpp
index aecfc6b..b3a4bc1 100644
--- a/opengl/libs/EGL/BlobCache.cpp
+++ b/opengl/libs/EGL/BlobCache.cpp
@@ -15,6 +15,7 @@
*/
//#define LOG_NDEBUG 0
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include "BlobCache.h"
@@ -22,6 +23,7 @@
#include <errno.h>
#include <inttypes.h>
#include <log/log.h>
+#include <utils/Trace.h>
#include <chrono>
@@ -230,6 +232,8 @@
}
int BlobCache::unflatten(void const* buffer, size_t size) {
+ ATRACE_NAME("BlobCache::unflatten");
+
// All errors should result in the BlobCache being in an empty state.
clear();
@@ -293,6 +297,8 @@
}
void BlobCache::clean() {
+ ATRACE_NAME("BlobCache::clean");
+
// Remove a random cache entry until the total cache size gets below half
// the maximum total cache size.
while (mTotalSize > mMaxTotalSize / 2) {
diff --git a/opengl/libs/EGL/FileBlobCache.cpp b/opengl/libs/EGL/FileBlobCache.cpp
index 1026842..4a0fac4 100644
--- a/opengl/libs/EGL/FileBlobCache.cpp
+++ b/opengl/libs/EGL/FileBlobCache.cpp
@@ -14,6 +14,8 @@
** limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include "FileBlobCache.h"
#include <errno.h>
@@ -24,6 +26,7 @@
#include <unistd.h>
#include <log/log.h>
+#include <utils/Trace.h>
// Cache file header
static const char* cacheFileMagic = "EGL$";
@@ -51,6 +54,8 @@
const std::string& filename)
: BlobCache(maxKeySize, maxValueSize, maxTotalSize)
, mFilename(filename) {
+ ATRACE_CALL();
+
if (mFilename.length() > 0) {
size_t headerSize = cacheFileHeaderSize;
@@ -117,6 +122,8 @@
}
void FileBlobCache::writeToFile() {
+ ATRACE_CALL();
+
if (mFilename.length() > 0) {
size_t cacheSize = getFlattenedSize();
size_t headerSize = cacheFileHeaderSize;
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index c2c856e..9823fc8 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -353,8 +353,9 @@
// Typically that means there is an HDR capable display attached, but could be
// support for attaching an HDR display. In either case, advertise support for
// HDR color spaces.
- mExtensionString.append(
- "EGL_EXT_gl_colorspace_bt2020_linear EGL_EXT_gl_colorspace_bt2020_pq ");
+ mExtensionString.append("EGL_EXT_gl_colorspace_bt2020_hlg "
+ "EGL_EXT_gl_colorspace_bt2020_linear "
+ "EGL_EXT_gl_colorspace_bt2020_pq ");
}
char const* start = gExtensionString;
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index 2bca14d..48718bb 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -18,6 +18,7 @@
#include "egl_platform_entries.h"
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <android/hardware_buffer.h>
@@ -29,7 +30,6 @@
#include <private/android/AHardwareBufferHelpers.h>
#include <stdlib.h>
#include <string.h>
-#include <aidl/android/hardware/graphics/common/PixelFormat.h>
#include <condition_variable>
#include <deque>
@@ -421,11 +421,14 @@
return HAL_DATASPACE_V0_SCRGB;
} else if (colorspace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT) {
return HAL_DATASPACE_V0_SCRGB_LINEAR;
+ } else if (colorspace == EGL_GL_COLORSPACE_BT2020_HLG_EXT) {
+ return static_cast<android_dataspace>(HAL_DATASPACE_BT2020_HLG);
} else if (colorspace == EGL_GL_COLORSPACE_BT2020_LINEAR_EXT) {
return HAL_DATASPACE_BT2020_LINEAR;
} else if (colorspace == EGL_GL_COLORSPACE_BT2020_PQ_EXT) {
return HAL_DATASPACE_BT2020_PQ;
}
+
return HAL_DATASPACE_UNKNOWN;
}
@@ -452,6 +455,9 @@
if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_scrgb_linear")) {
colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT);
}
+ if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_bt2020_hlg")) {
+ colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_HLG_EXT);
+ }
if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_bt2020_linear")) {
colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_LINEAR_EXT);
}
@@ -485,6 +491,7 @@
case EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT:
case EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT:
case EGL_GL_COLORSPACE_SCRGB_EXT:
+ case EGL_GL_COLORSPACE_BT2020_HLG_EXT:
case EGL_GL_COLORSPACE_BT2020_LINEAR_EXT:
case EGL_GL_COLORSPACE_BT2020_PQ_EXT:
case EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT:
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index e04481c..69df45b 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -224,6 +224,9 @@
"libinputservice_test",
"Bug-115739809",
"StructLayout_test",
+ // currently unused, but still must build correctly
+ "inputflinger",
+ "libinputflingerhost",
// native fuzzers
"inputflinger_latencytracker_fuzzer",
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 470f857..ed5cd10 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -54,6 +54,7 @@
#define INDENT4 " "
using namespace android::ftl::flag_operators;
+using android::base::Error;
using android::base::HwTimeoutMultiplier;
using android::base::Result;
using android::base::StringPrintf;
@@ -129,48 +130,68 @@
AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
}
-bool isValidKeyAction(int32_t action) {
+Result<void> checkKeyAction(int32_t action) {
switch (action) {
case AKEY_EVENT_ACTION_DOWN:
case AKEY_EVENT_ACTION_UP:
- return true;
+ return {};
default:
- return false;
+ return Error() << "Key event has invalid action code " << action;
}
}
-bool validateKeyEvent(int32_t action) {
- if (!isValidKeyAction(action)) {
- ALOGE("Key event has invalid action code 0x%x", action);
- return false;
- }
- return true;
+Result<void> validateKeyEvent(int32_t action) {
+ return checkKeyAction(action);
}
-bool isValidMotionAction(int32_t action, int32_t actionButton, int32_t pointerCount) {
+Result<void> checkMotionAction(int32_t action, int32_t actionButton, int32_t pointerCount) {
switch (MotionEvent::getActionMasked(action)) {
case AMOTION_EVENT_ACTION_DOWN:
- case AMOTION_EVENT_ACTION_UP:
- return pointerCount == 1;
+ case AMOTION_EVENT_ACTION_UP: {
+ if (pointerCount != 1) {
+ return Error() << "invalid pointer count " << pointerCount;
+ }
+ return {};
+ }
case AMOTION_EVENT_ACTION_MOVE:
case AMOTION_EVENT_ACTION_HOVER_ENTER:
case AMOTION_EVENT_ACTION_HOVER_MOVE:
- case AMOTION_EVENT_ACTION_HOVER_EXIT:
- return pointerCount >= 1;
+ case AMOTION_EVENT_ACTION_HOVER_EXIT: {
+ if (pointerCount < 1) {
+ return Error() << "invalid pointer count " << pointerCount;
+ }
+ return {};
+ }
case AMOTION_EVENT_ACTION_CANCEL:
case AMOTION_EVENT_ACTION_OUTSIDE:
case AMOTION_EVENT_ACTION_SCROLL:
- return true;
+ return {};
case AMOTION_EVENT_ACTION_POINTER_DOWN:
case AMOTION_EVENT_ACTION_POINTER_UP: {
const int32_t index = MotionEvent::getActionIndex(action);
- return index >= 0 && index < pointerCount && pointerCount > 1;
+ if (index < 0) {
+ return Error() << "invalid index " << index << " for "
+ << MotionEvent::actionToString(action);
+ }
+ if (index >= pointerCount) {
+ return Error() << "invalid index " << index << " for pointerCount " << pointerCount;
+ }
+ if (pointerCount <= 1) {
+ return Error() << "invalid pointer count " << pointerCount << " for "
+ << MotionEvent::actionToString(action);
+ }
+ return {};
}
case AMOTION_EVENT_ACTION_BUTTON_PRESS:
- case AMOTION_EVENT_ACTION_BUTTON_RELEASE:
- return actionButton != 0;
+ case AMOTION_EVENT_ACTION_BUTTON_RELEASE: {
+ if (actionButton == 0) {
+ return Error() << "action button should be nonzero for "
+ << MotionEvent::actionToString(action);
+ }
+ return {};
+ }
default:
- return false;
+ return Error() << "invalid action " << action;
}
}
@@ -178,32 +199,50 @@
return std::chrono::duration_cast<std::chrono::milliseconds>(t).count();
}
-bool validateMotionEvent(int32_t action, int32_t actionButton, size_t pointerCount,
- const PointerProperties* pointerProperties) {
- if (!isValidMotionAction(action, actionButton, pointerCount)) {
- ALOGE("Motion event has invalid action code 0x%x", action);
- return false;
+Result<void> validateMotionEvent(int32_t action, int32_t actionButton, size_t pointerCount,
+ const PointerProperties* pointerProperties) {
+ Result<void> actionCheck = checkMotionAction(action, actionButton, pointerCount);
+ if (!actionCheck.ok()) {
+ return actionCheck;
}
if (pointerCount < 1 || pointerCount > MAX_POINTERS) {
- ALOGE("Motion event has invalid pointer count %zu; value must be between 1 and %zu.",
- pointerCount, MAX_POINTERS);
- return false;
+ return Error() << "Motion event has invalid pointer count " << pointerCount
+ << "; value must be between 1 and " << MAX_POINTERS << ".";
}
std::bitset<MAX_POINTER_ID + 1> pointerIdBits;
for (size_t i = 0; i < pointerCount; i++) {
int32_t id = pointerProperties[i].id;
if (id < 0 || id > MAX_POINTER_ID) {
- ALOGE("Motion event has invalid pointer id %d; value must be between 0 and %d", id,
- MAX_POINTER_ID);
- return false;
+ return Error() << "Motion event has invalid pointer id " << id
+ << "; value must be between 0 and " << MAX_POINTER_ID;
}
if (pointerIdBits.test(id)) {
- ALOGE("Motion event has duplicate pointer id %d", id);
- return false;
+ return Error() << "Motion event has duplicate pointer id " << id;
}
pointerIdBits.set(id);
}
- return true;
+ return {};
+}
+
+Result<void> validateInputEvent(const InputEvent& event) {
+ switch (event.getType()) {
+ case InputEventType::KEY: {
+ const KeyEvent& key = static_cast<const KeyEvent&>(event);
+ const int32_t action = key.getAction();
+ return validateKeyEvent(action);
+ }
+ case InputEventType::MOTION: {
+ const MotionEvent& motion = static_cast<const MotionEvent&>(event);
+ const int32_t action = motion.getAction();
+ const size_t pointerCount = motion.getPointerCount();
+ const PointerProperties* pointerProperties = motion.getPointerProperties();
+ const int32_t actionButton = motion.getActionButton();
+ return validateMotionEvent(action, actionButton, pointerCount, pointerProperties);
+ }
+ default: {
+ return {};
+ }
+ }
}
std::string dumpRegion(const Region& region) {
@@ -459,14 +498,14 @@
// Returns true if the event type passed as argument represents a user activity.
bool isUserActivityEvent(const EventEntry& eventEntry) {
switch (eventEntry.type) {
+ case EventEntry::Type::CONFIGURATION_CHANGED:
+ case EventEntry::Type::DEVICE_RESET:
+ case EventEntry::Type::DRAG:
case EventEntry::Type::FOCUS:
case EventEntry::Type::POINTER_CAPTURE_CHANGED:
- case EventEntry::Type::DRAG:
- case EventEntry::Type::TOUCH_MODE_CHANGED:
case EventEntry::Type::SENSOR:
- case EventEntry::Type::CONFIGURATION_CHANGED:
+ case EventEntry::Type::TOUCH_MODE_CHANGED:
return false;
- case EventEntry::Type::DEVICE_RESET:
case EventEntry::Type::KEY:
case EventEntry::Type::MOTION:
return true;
@@ -1645,6 +1684,8 @@
doInterceptKeyBeforeDispatchingCommand(focusedWindowToken, *entry);
};
postCommandLocked(std::move(command));
+ // Poke user activity for keys not passed to user
+ pokeUserActivityLocked(*entry);
return false; // wait for the command to run
} else {
entry->interceptKeyResult = KeyEntry::InterceptKeyResult::CONTINUE;
@@ -1661,6 +1702,8 @@
*dropReason == DropReason::POLICY ? InputEventInjectionResult::SUCCEEDED
: InputEventInjectionResult::FAILED);
mReporter->reportDroppedKey(entry->id);
+ // Poke user activity for undispatched keys
+ pokeUserActivityLocked(*entry);
return true;
}
@@ -2164,7 +2207,7 @@
// event injection will be allowed.
const int32_t displayId = entry.displayId;
const int32_t action = entry.action;
- const int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;
+ const int32_t maskedAction = MotionEvent::getActionMasked(action);
// Update the touch state as needed based on the properties of the touch event.
outInjectionResult = InputEventInjectionResult::PENDING;
@@ -2291,16 +2334,11 @@
continue;
}
- if (isHoverAction) {
+ if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER ||
+ maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {
const int32_t pointerId = entry.pointerProperties[0].id;
- if (maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT) {
- // Pointer left. Remove it
- tempTouchState.removeHoveringPointer(entry.deviceId, pointerId);
- } else {
- // The "windowHandle" is the target of this hovering pointer.
- tempTouchState.addHoveringPointerToWindow(windowHandle, entry.deviceId,
- pointerId);
- }
+ // The "windowHandle" is the target of this hovering pointer.
+ tempTouchState.addHoveringPointerToWindow(windowHandle, entry.deviceId, pointerId);
}
// Set target flags.
@@ -2401,6 +2439,7 @@
const bool isStylus = isPointerFromStylus(entry, /*pointerIndex=*/0);
sp<WindowInfoHandle> oldTouchedWindowHandle =
tempTouchState.getFirstForegroundWindowHandle();
+ LOG_ALWAYS_FATAL_IF(oldTouchedWindowHandle == nullptr);
auto [newTouchedWindowHandle, _] = findTouchedWindowAtLocked(displayId, x, y, isStylus);
// Verify targeted injection.
@@ -2416,13 +2455,11 @@
newTouchedWindowHandle = nullptr;
}
- if (oldTouchedWindowHandle != newTouchedWindowHandle &&
- oldTouchedWindowHandle != nullptr && newTouchedWindowHandle != nullptr) {
- if (DEBUG_FOCUS) {
- ALOGD("Touch is slipping out of window %s into window %s in display %" PRId32,
- oldTouchedWindowHandle->getName().c_str(),
- newTouchedWindowHandle->getName().c_str(), displayId);
- }
+ if (!haveSameToken(oldTouchedWindowHandle, newTouchedWindowHandle)) {
+ ALOGD("Touch is slipping out of window %s into window %s in display %" PRId32,
+ oldTouchedWindowHandle->getName().c_str(),
+ newTouchedWindowHandle->getName().c_str(), displayId);
+
// Make a slippery exit from the old window.
std::bitset<MAX_POINTER_ID + 1> pointerIds;
const int32_t pointerId = entry.pointerProperties[0].id;
@@ -2666,9 +2703,6 @@
if (uint32_t(pointerIndex) == entry.pointerCount) {
LOG_ALWAYS_FATAL("Should find a valid pointer index by id %d", mDragState->pointerId);
- sendDropWindowCommandLocked(nullptr, 0, 0);
- mDragState.reset();
- return;
}
const int32_t maskedAction = entry.action & AMOTION_EVENT_ACTION_MASK;
@@ -2980,13 +3014,11 @@
}
int32_t displayId = getTargetDisplayId(eventEntry);
sp<WindowInfoHandle> focusedWindowHandle = getFocusedWindowHandleLocked(displayId);
+ const WindowInfo* windowDisablingUserActivityInfo = nullptr;
if (focusedWindowHandle != nullptr) {
const WindowInfo* info = focusedWindowHandle->getInfo();
if (info->inputConfig.test(WindowInfo::InputConfig::DISABLE_USER_ACTIVITY)) {
- if (DEBUG_DISPATCH_CYCLE) {
- ALOGD("Not poking user activity: disabled by window '%s'.", info->name.c_str());
- }
- return;
+ windowDisablingUserActivityInfo = info;
}
}
@@ -2997,7 +3029,13 @@
if (motionEntry.action == AMOTION_EVENT_ACTION_CANCEL) {
return;
}
-
+ if (windowDisablingUserActivityInfo != nullptr) {
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("Not poking user activity: disabled by window '%s'.",
+ windowDisablingUserActivityInfo->name.c_str());
+ }
+ return;
+ }
if (MotionEvent::isTouchEvent(motionEntry.source, motionEntry.action)) {
eventType = USER_ACTIVITY_EVENT_TOUCH;
}
@@ -3008,6 +3046,22 @@
if (keyEntry.flags & AKEY_EVENT_FLAG_CANCELED) {
return;
}
+ // If the key code is unknown, we don't consider it user activity
+ if (keyEntry.keyCode == AKEYCODE_UNKNOWN) {
+ return;
+ }
+ // Don't inhibit events that were intercepted or are not passed to
+ // the apps, like system shortcuts
+ if (windowDisablingUserActivityInfo != nullptr &&
+ keyEntry.interceptKeyResult != KeyEntry::InterceptKeyResult::SKIP &&
+ keyEntry.policyFlags & POLICY_FLAG_PASS_TO_USER) {
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("Not poking user activity: disabled by window '%s'.",
+ windowDisablingUserActivityInfo->name.c_str());
+ }
+ return;
+ }
+
eventType = USER_ACTIVITY_EVENT_BUTTON;
break;
}
@@ -3573,7 +3627,7 @@
const std::array<uint8_t, 32> InputDispatcher::getSignature(
const MotionEntry& motionEntry, const DispatchEntry& dispatchEntry) const {
- const int32_t actionMasked = dispatchEntry.resolvedAction & AMOTION_EVENT_ACTION_MASK;
+ const int32_t actionMasked = MotionEvent::getActionMasked(dispatchEntry.resolvedAction);
if (actionMasked != AMOTION_EVENT_ACTION_UP && actionMasked != AMOTION_EVENT_ACTION_DOWN) {
// Only sign events up and down events as the purely move events
// are tied to their up/down counterparts so signing would be redundant.
@@ -4093,7 +4147,9 @@
args.id, args.eventTime, args.deviceId, inputEventSourceToString(args.source).c_str(),
args.displayId, args.policyFlags, KeyEvent::actionToString(args.action), args.flags,
KeyEvent::getLabel(args.keyCode), args.scanCode, args.metaState, args.downTime);
- if (!validateKeyEvent(args.action)) {
+ Result<void> keyCheck = validateKeyEvent(args.action);
+ if (!keyCheck.ok()) {
+ LOG(ERROR) << "invalid key event: " << keyCheck.error();
return;
}
@@ -4190,9 +4246,10 @@
}
}
- if (!validateMotionEvent(args.action, args.actionButton, args.pointerCount,
- args.pointerProperties)) {
- LOG(ERROR) << "Invalid event: " << args.dump();
+ Result<void> motionCheck = validateMotionEvent(args.action, args.actionButton,
+ args.pointerCount, args.pointerProperties);
+ if (!motionCheck.ok()) {
+ LOG(ERROR) << "Invalid event: " << args.dump() << "; reason: " << motionCheck.error();
return;
}
@@ -4368,6 +4425,12 @@
InputEventInjectionSync syncMode,
std::chrono::milliseconds timeout,
uint32_t policyFlags) {
+ Result<void> eventValidation = validateInputEvent(*event);
+ if (!eventValidation.ok()) {
+ LOG(INFO) << "Injection failed: invalid event: " << eventValidation.error();
+ return InputEventInjectionResult::FAILED;
+ }
+
if (debugInboundEventDetails()) {
LOG(DEBUG) << __func__ << ": targetUid=" << toString(targetUid)
<< ", syncMode=" << ftl::enum_string(syncMode) << ", timeout=" << timeout.count()
@@ -4393,11 +4456,7 @@
switch (event->getType()) {
case InputEventType::KEY: {
const KeyEvent& incomingKey = static_cast<const KeyEvent&>(*event);
- int32_t action = incomingKey.getAction();
- if (!validateKeyEvent(action)) {
- return InputEventInjectionResult::FAILED;
- }
-
+ const int32_t action = incomingKey.getAction();
int32_t flags = incomingKey.getFlags();
if (policyFlags & POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY) {
flags |= AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT;
@@ -4439,20 +4498,13 @@
case InputEventType::MOTION: {
const MotionEvent& motionEvent = static_cast<const MotionEvent&>(*event);
- const int32_t action = motionEvent.getAction();
const bool isPointerEvent =
isFromSource(event->getSource(), AINPUT_SOURCE_CLASS_POINTER);
// If a pointer event has no displayId specified, inject it to the default display.
const uint32_t displayId = isPointerEvent && (event->getDisplayId() == ADISPLAY_ID_NONE)
? ADISPLAY_ID_DEFAULT
: event->getDisplayId();
- const size_t pointerCount = motionEvent.getPointerCount();
- const PointerProperties* pointerProperties = motionEvent.getPointerProperties();
- const int32_t actionButton = motionEvent.getActionButton();
int32_t flags = motionEvent.getFlags();
- if (!validateMotionEvent(action, actionButton, pointerCount, pointerProperties)) {
- return InputEventInjectionResult::FAILED;
- }
if (!(policyFlags & POLICY_FLAG_FILTERED)) {
nsecs_t eventTime = motionEvent.getEventTime();
@@ -4474,8 +4526,9 @@
std::unique_ptr<MotionEntry> injectedEntry =
std::make_unique<MotionEntry>(motionEvent.getId(), *sampleEventTimes,
resolvedDeviceId, motionEvent.getSource(),
- displayId, policyFlags, action, actionButton,
- flags, motionEvent.getMetaState(),
+ displayId, policyFlags, motionEvent.getAction(),
+ motionEvent.getActionButton(), flags,
+ motionEvent.getMetaState(),
motionEvent.getButtonState(),
motionEvent.getClassification(),
motionEvent.getEdgeFlags(),
@@ -4483,18 +4536,22 @@
motionEvent.getYPrecision(),
motionEvent.getRawXCursorPosition(),
motionEvent.getRawYCursorPosition(),
- motionEvent.getDownTime(), uint32_t(pointerCount),
- pointerProperties, samplePointerCoords);
+ motionEvent.getDownTime(),
+ motionEvent.getPointerCount(),
+ motionEvent.getPointerProperties(),
+ samplePointerCoords);
transformMotionEntryForInjectionLocked(*injectedEntry, motionEvent.getTransform());
injectedEntries.push(std::move(injectedEntry));
for (size_t i = motionEvent.getHistorySize(); i > 0; i--) {
sampleEventTimes += 1;
- samplePointerCoords += pointerCount;
+ samplePointerCoords += motionEvent.getPointerCount();
std::unique_ptr<MotionEntry> nextInjectedEntry =
std::make_unique<MotionEntry>(motionEvent.getId(), *sampleEventTimes,
resolvedDeviceId, motionEvent.getSource(),
- displayId, policyFlags, action, actionButton,
- flags, motionEvent.getMetaState(),
+ displayId, policyFlags,
+ motionEvent.getAction(),
+ motionEvent.getActionButton(), flags,
+ motionEvent.getMetaState(),
motionEvent.getButtonState(),
motionEvent.getClassification(),
motionEvent.getEdgeFlags(),
@@ -4503,7 +4560,8 @@
motionEvent.getRawXCursorPosition(),
motionEvent.getRawYCursorPosition(),
motionEvent.getDownTime(),
- uint32_t(pointerCount), pointerProperties,
+ motionEvent.getPointerCount(),
+ motionEvent.getPointerProperties(),
samplePointerCoords);
transformMotionEntryForInjectionLocked(*nextInjectedEntry,
motionEvent.getTransform());
@@ -6629,7 +6687,7 @@
const sp<WindowInfoHandle>& oldWindowHandle,
const sp<WindowInfoHandle>& newWindowHandle,
TouchState& state, int32_t pointerId,
- std::vector<InputTarget>& targets) {
+ std::vector<InputTarget>& targets) const {
std::bitset<MAX_POINTER_ID + 1> pointerIds;
pointerIds.set(pointerId);
const bool oldHasWallpaper = oldWindowHandle->getInfo()->inputConfig.test(
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 2a06908..0e9ccfb 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -707,8 +707,8 @@
void slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags,
const sp<android::gui::WindowInfoHandle>& oldWindowHandle,
const sp<android::gui::WindowInfoHandle>& newWindowHandle,
- TouchState& state, int32_t pointerId, std::vector<InputTarget>& targets)
- REQUIRES(mLock);
+ TouchState& state, int32_t pointerId,
+ std::vector<InputTarget>& targets) const REQUIRES(mLock);
void transferWallpaperTouch(ftl::Flags<InputTarget::Flags> oldTargetFlags,
ftl::Flags<InputTarget::Flags> newTargetFlags,
const sp<android::gui::WindowInfoHandle> fromWindowHandle,
diff --git a/services/inputflinger/host/Android.bp b/services/inputflinger/host/Android.bp
index 743587c..4d2839f 100644
--- a/services/inputflinger/host/Android.bp
+++ b/services/inputflinger/host/Android.bp
@@ -23,7 +23,7 @@
cc_library_shared {
name: "libinputflingerhost",
-
+ cpp_std: "c++20",
srcs: [
"InputFlinger.cpp",
"InputDriver.cpp",
@@ -64,14 +64,17 @@
srcs: ["main.cpp"],
- cflags: ["-Wall", "-Werror"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
shared_libs: [
"libbase",
"libbinder",
"libinputflingerhost",
"libutils",
- "libinput"
+ "libinput",
],
static_libs: [
"libarect",
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 582fb46..7388752 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -148,8 +148,12 @@
if (!changes.any() ||
changes.test(InputReaderConfiguration::Change::KEYBOARD_LAYOUT_ASSOCIATION)) {
- mKeyboardLayoutInfo =
+ std::optional<KeyboardLayoutInfo> newKeyboardLayoutInfo =
getValueByKey(config.keyboardLayoutAssociations, getDeviceContext().getLocation());
+ if (mKeyboardLayoutInfo != newKeyboardLayoutInfo) {
+ mKeyboardLayoutInfo = newKeyboardLayoutInfo;
+ bumpGeneration();
+ }
}
return out;
diff --git a/services/inputflinger/tests/FakeEventHub.cpp b/services/inputflinger/tests/FakeEventHub.cpp
index 4626f5a..212fceb 100644
--- a/services/inputflinger/tests/FakeEventHub.cpp
+++ b/services/inputflinger/tests/FakeEventHub.cpp
@@ -617,9 +617,11 @@
}
// If device sysfs changed -> reopen the device
if (!mRawLightInfos.empty() && !foundDevice->classes.test(InputDeviceClass::LIGHT)) {
+ InputDeviceIdentifier identifier = foundDevice->identifier;
+ ftl::Flags<InputDeviceClass> classes = foundDevice->classes;
removeDevice(foundDeviceId);
- addDevice(foundDeviceId, foundDevice->identifier.name,
- foundDevice->classes | InputDeviceClass::LIGHT, foundDevice->identifier.bus);
+ addDevice(foundDeviceId, identifier.name, classes | InputDeviceClass::LIGHT,
+ identifier.bus);
}
}
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 74e4bc5..0741be0 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -402,6 +402,16 @@
mInterceptKeyTimeout = timeout;
}
+ void assertUserActivityPoked() {
+ std::scoped_lock lock(mLock);
+ ASSERT_TRUE(mPokedUserActivity) << "Expected user activity to have been poked";
+ }
+
+ void assertUserActivityNotPoked() {
+ std::scoped_lock lock(mLock);
+ ASSERT_FALSE(mPokedUserActivity) << "Expected user activity not to have been poked";
+ }
+
private:
std::mutex mLock;
std::unique_ptr<InputEvent> mFilteredEvent GUARDED_BY(mLock);
@@ -423,6 +433,7 @@
sp<IBinder> mDropTargetWindowToken GUARDED_BY(mLock);
bool mNotifyDropWindowWasCalled GUARDED_BY(mLock) = false;
+ bool mPokedUserActivity GUARDED_BY(mLock) = false;
std::chrono::milliseconds mInterceptKeyTimeout = 0ms;
@@ -575,7 +586,10 @@
mLastNotifySwitch = NotifySwitchArgs(/*id=*/1, when, policyFlags, switchValues, switchMask);
}
- void pokeUserActivity(nsecs_t, int32_t, int32_t) override {}
+ void pokeUserActivity(nsecs_t, int32_t, int32_t) override {
+ std::scoped_lock lock(mLock);
+ mPokedUserActivity = true;
+ }
void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {
std::scoped_lock lock(mLock);
@@ -1187,6 +1201,10 @@
mInfo.setInputConfig(WindowInfo::InputConfig::NO_INPUT_CHANNEL, noInputChannel);
}
+ void setDisableUserActivity(bool disableUserActivity) {
+ mInfo.setInputConfig(WindowInfo::InputConfig::DISABLE_USER_ACTIVITY, disableUserActivity);
+ }
+
void setAlpha(float alpha) { mInfo.alpha = alpha; }
void setTouchOcclusionMode(TouchOcclusionMode mode) { mInfo.touchOcclusionMode = mode; }
@@ -1739,6 +1757,28 @@
return args;
}
+static NotifyKeyArgs generateSystemShortcutArgs(int32_t action,
+ int32_t displayId = ADISPLAY_ID_NONE) {
+ nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ // Define a valid key event.
+ NotifyKeyArgs args(/*id=*/0, currentTime, /*readTime=*/0, DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
+ displayId, 0, action, /* flags */ 0, AKEYCODE_C, KEY_C, AMETA_META_ON,
+ currentTime);
+
+ return args;
+}
+
+static NotifyKeyArgs generateAssistantKeyArgs(int32_t action,
+ int32_t displayId = ADISPLAY_ID_NONE) {
+ nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ // Define a valid key event.
+ NotifyKeyArgs args(/*id=*/0, currentTime, /*readTime=*/0, DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
+ displayId, 0, action, /* flags */ 0, AKEYCODE_ASSIST, KEY_ASSISTANT,
+ AMETA_NONE, currentTime);
+
+ return args;
+}
+
[[nodiscard]] static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source,
int32_t displayId,
const std::vector<PointF>& points) {
@@ -3954,6 +3994,7 @@
firstWindow->assertNoEvents();
const MotionEvent* event = secondWindow->consumeMotion();
+ ASSERT_NE(nullptr, event);
EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, event->getAction());
// Ensure that the events from the "getRaw" API are in logical display coordinates.
@@ -4527,6 +4568,94 @@
// Window should receive key down event.
window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
+
+ // Should have poked user activity
+ mFakePolicy->assertUserActivityPoked();
+}
+
+TEST_F(InputDispatcherTest, FocusedWindow_DisableUserActivity) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Fake Window", ADISPLAY_ID_DEFAULT);
+
+ window->setDisableUserActivity(true);
+ window->setFocusable(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ setFocusedWindow(window);
+
+ window->consumeFocusEvent(true);
+
+ mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
+
+ // Window should receive key down event.
+ window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
+
+ // Should have poked user activity
+ mFakePolicy->assertUserActivityNotPoked();
+}
+
+TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceiveSystemShortcut) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Fake Window", ADISPLAY_ID_DEFAULT);
+
+ window->setFocusable(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ setFocusedWindow(window);
+
+ window->consumeFocusEvent(true);
+
+ mDispatcher->notifyKey(generateSystemShortcutArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
+ mDispatcher->waitForIdle();
+
+ // System key is not passed down
+ window->assertNoEvents();
+
+ // Should have poked user activity
+ mFakePolicy->assertUserActivityPoked();
+}
+
+TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceiveAssistantKey) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Fake Window", ADISPLAY_ID_DEFAULT);
+
+ window->setFocusable(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ setFocusedWindow(window);
+
+ window->consumeFocusEvent(true);
+
+ mDispatcher->notifyKey(generateAssistantKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
+ mDispatcher->waitForIdle();
+
+ // System key is not passed down
+ window->assertNoEvents();
+
+ // Should have poked user activity
+ mFakePolicy->assertUserActivityPoked();
+}
+
+TEST_F(InputDispatcherTest, FocusedWindow_SystemKeyIgnoresDisableUserActivity) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Fake Window", ADISPLAY_ID_DEFAULT);
+
+ window->setDisableUserActivity(true);
+ window->setFocusable(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ setFocusedWindow(window);
+
+ window->consumeFocusEvent(true);
+
+ mDispatcher->notifyKey(generateSystemShortcutArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT));
+ mDispatcher->waitForIdle();
+
+ // System key is not passed down
+ window->assertNoEvents();
+
+ // Should have poked user activity
+ mFakePolicy->assertUserActivityPoked();
}
TEST_F(InputDispatcherTest, UnfocusedWindow_DoesNotReceiveFocusEventOrKeyEvent) {
@@ -6138,6 +6267,28 @@
touchAndAssertPositions(AMOTION_EVENT_ACTION_MOVE, touchedPoints, expectedPoints);
}
+/**
+ * When one of the windows is slippery, the touch should not slip into the other window with the
+ * same input channel.
+ */
+TEST_F(InputDispatcherMultiWindowSameTokenTests, TouchDoesNotSlipEvenIfSlippery) {
+ mWindow1->setSlippery(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow1, mWindow2}}});
+
+ // Touch down in window 1
+ mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {{50, 50}}));
+ consumeMotionEvent(mWindow1, ACTION_DOWN, {{50, 50}});
+
+ // Move touch to be above window 2. Even though window 1 is slippery, touch should not slip.
+ // That means the gesture should continue normally, without any ACTION_CANCEL or ACTION_DOWN
+ // getting generated.
+ mDispatcher->notifyMotion(generateMotionArgs(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {{150, 150}}));
+
+ consumeMotionEvent(mWindow1, ACTION_MOVE, {{150, 150}});
+}
+
class InputDispatcherSingleWindowAnr : public InputDispatcherTest {
virtual void SetUp() override {
InputDispatcherTest::SetUp();
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 0b50504..d56db11 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -3687,6 +3687,7 @@
mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
/*changes=*/{});
+ uint32_t generation = mReader->getContext()->getGeneration();
mFakePolicy->addKeyboardLayoutAssociation(DEVICE_LOCATION, DEVICE_KEYBOARD_LAYOUT_INFO);
unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
@@ -3697,6 +3698,14 @@
deviceInfo.getKeyboardLayoutInfo()->languageTag);
ASSERT_EQ(DEVICE_KEYBOARD_LAYOUT_INFO.layoutType,
deviceInfo.getKeyboardLayoutInfo()->layoutType);
+ ASSERT_TRUE(mReader->getContext()->getGeneration() != generation);
+
+ // Call change layout association with the same values: Generation shouldn't change
+ generation = mReader->getContext()->getGeneration();
+ mFakePolicy->addKeyboardLayoutAssociation(DEVICE_LOCATION, DEVICE_KEYBOARD_LAYOUT_INFO);
+ unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::Change::KEYBOARD_LAYOUT_ASSOCIATION);
+ ASSERT_TRUE(mReader->getContext()->getGeneration() == generation);
}
TEST_F(KeyboardInputMapperTest, LayoutInfoCorrectlyMapped) {
diff --git a/services/sensorservice/BatteryService.cpp b/services/sensorservice/BatteryService.cpp
index b0fbe5d..0ea548c 100644
--- a/services/sensorservice/BatteryService.cpp
+++ b/services/sensorservice/BatteryService.cpp
@@ -30,8 +30,8 @@
namespace android {
// ---------------------------------------------------------------------------
-BatteryService::BatteryService() : mBatteryStatService(nullptr) {
-}
+BatteryService::BatteryService()
+ : mBatteryStatService(nullptr), mLastWakeupSensorEventReportedMs(0) {}
bool BatteryService::addSensor(uid_t uid, int handle) {
Mutex::Autolock _l(mActivationsLock);
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index fe72a69..0aa1bcb 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -288,7 +288,7 @@
void onUidStateChanged(uid_t uid __unused, int32_t procState __unused,
int64_t procStateSeq __unused,
int32_t capability __unused) override {}
- void onUidProcAdjChanged(uid_t uid __unused) override {}
+ void onUidProcAdjChanged(uid_t uid __unused, int32_t adj __unused) override {}
void addOverrideUid(uid_t uid, bool active);
void removeOverrideUid(uid_t uid);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index 608c53a..ccff1ec 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -19,6 +19,7 @@
#include <optional>
#include <ostream>
#include <unordered_set>
+#include "ui/LayerStack.h"
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
@@ -140,7 +141,7 @@
ClientCompositionTargetSettings&) const = 0;
// Called after the layer is displayed to update the presentation fence
- virtual void onLayerDisplayed(ftl::SharedFuture<FenceResult>) = 0;
+ virtual void onLayerDisplayed(ftl::SharedFuture<FenceResult>, ui::LayerStack layerStack) = 0;
// Gets some kind of identifier for the layer for debug purposes.
virtual const char* getDebugName() const = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index 12e063b..15e4577 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -49,7 +49,8 @@
std::optional<compositionengine::LayerFE::LayerSettings>(
compositionengine::LayerFE::ClientCompositionTargetSettings&));
- MOCK_METHOD(void, onLayerDisplayed, (ftl::SharedFuture<FenceResult>), (override));
+ MOCK_METHOD(void, onLayerDisplayed, (ftl::SharedFuture<FenceResult>, ui::LayerStack),
+ (override));
MOCK_CONST_METHOD0(getDebugName, const char*());
MOCK_CONST_METHOD0(getSequence, int32_t());
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index d64231f..793959c 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1556,8 +1556,9 @@
releaseFence =
Fence::merge("LayerRelease", releaseFence, frame.clientTargetAcquireFence);
}
- layer->getLayerFE().onLayerDisplayed(
- ftl::yield<FenceResult>(std::move(releaseFence)).share());
+ layer->getLayerFE()
+ .onLayerDisplayed(ftl::yield<FenceResult>(std::move(releaseFence)).share(),
+ outputState.layerFilter.layerStack);
}
// We've got a list of layers needing fences, that are disjoint with
@@ -1565,7 +1566,8 @@
// supply them with the present fence.
for (auto& weakLayer : mReleasedLayers) {
if (const auto layer = weakLayer.promote()) {
- layer->onLayerDisplayed(ftl::yield<FenceResult>(frame.presentFence).share());
+ layer->onLayerDisplayed(ftl::yield<FenceResult>(frame.presentFence).share(),
+ outputState.layerFilter.layerStack);
}
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index aaf0f06..9e0e7b5 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -3220,16 +3220,19 @@
// are passed. This happens to work with the current implementation, but
// would not survive certain calls like Fence::merge() which would return a
// new instance.
- EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed(_))
- .WillOnce([&layer1Fence](ftl::SharedFuture<FenceResult> futureFenceResult) {
+ EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed(_, _))
+ .WillOnce([&layer1Fence](ftl::SharedFuture<FenceResult> futureFenceResult,
+ ui::LayerStack) {
EXPECT_EQ(FenceResult(layer1Fence), futureFenceResult.get());
});
- EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed(_))
- .WillOnce([&layer2Fence](ftl::SharedFuture<FenceResult> futureFenceResult) {
+ EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed(_, _))
+ .WillOnce([&layer2Fence](ftl::SharedFuture<FenceResult> futureFenceResult,
+ ui::LayerStack) {
EXPECT_EQ(FenceResult(layer2Fence), futureFenceResult.get());
});
- EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed(_))
- .WillOnce([&layer3Fence](ftl::SharedFuture<FenceResult> futureFenceResult) {
+ EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed(_, _))
+ .WillOnce([&layer3Fence](ftl::SharedFuture<FenceResult> futureFenceResult,
+ ui::LayerStack) {
EXPECT_EQ(FenceResult(layer3Fence), futureFenceResult.get());
});
@@ -3285,16 +3288,19 @@
EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted());
// Each released layer should be given the presentFence.
- EXPECT_CALL(*releasedLayer1, onLayerDisplayed(_))
- .WillOnce([&presentFence](ftl::SharedFuture<FenceResult> futureFenceResult) {
+ EXPECT_CALL(*releasedLayer1, onLayerDisplayed(_, _))
+ .WillOnce([&presentFence](ftl::SharedFuture<FenceResult> futureFenceResult,
+ ui::LayerStack) {
EXPECT_EQ(FenceResult(presentFence), futureFenceResult.get());
});
- EXPECT_CALL(*releasedLayer2, onLayerDisplayed(_))
- .WillOnce([&presentFence](ftl::SharedFuture<FenceResult> futureFenceResult) {
+ EXPECT_CALL(*releasedLayer2, onLayerDisplayed(_, _))
+ .WillOnce([&presentFence](ftl::SharedFuture<FenceResult> futureFenceResult,
+ ui::LayerStack) {
EXPECT_EQ(FenceResult(presentFence), futureFenceResult.get());
});
- EXPECT_CALL(*releasedLayer3, onLayerDisplayed(_))
- .WillOnce([&presentFence](ftl::SharedFuture<FenceResult> futureFenceResult) {
+ EXPECT_CALL(*releasedLayer3, onLayerDisplayed(_, _))
+ .WillOnce([&presentFence](ftl::SharedFuture<FenceResult> futureFenceResult,
+ ui::LayerStack) {
EXPECT_EQ(FenceResult(presentFence), futureFenceResult.get());
});
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index f28bfd4..f7049b9 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -329,14 +329,6 @@
}
}
-void AidlComposer::resetCommands(Display display) {
- mMutex.lock_shared();
- if (auto writer = getWriter(display)) {
- writer->get().reset();
- }
- mMutex.unlock_shared();
-}
-
Error AidlComposer::executeCommands(Display display) {
mMutex.lock_shared();
auto error = execute(display);
@@ -1054,9 +1046,8 @@
return Error::BAD_DISPLAY;
}
- const auto& commands = writer->get().getPendingCommands();
+ auto commands = writer->get().takePendingCommands();
if (commands.empty()) {
- writer->get().reset();
return Error::NONE;
}
@@ -1088,8 +1079,6 @@
}
}
- writer->get().reset();
-
return error;
}
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index 8313c09..ce05b38 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -72,10 +72,6 @@
void registerCallback(HWC2::ComposerCallback& callback) override;
- // Reset all pending commands in the command buffer. Useful if you want to
- // skip a frame but have already queued some commands.
- void resetCommands(Display) override;
-
// Explicitly flush all pending commands in the command buffer.
Error executeCommands(Display) override;
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index c65c572..cf67795 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -110,10 +110,6 @@
virtual void registerCallback(HWC2::ComposerCallback& callback) = 0;
- // Reset all pending commands in the command buffer. Useful if you want to
- // skip a frame but have already queued some commands.
- virtual void resetCommands(Display) = 0;
-
// Explicitly flush all pending commands in the command buffer.
virtual Error executeCommands(Display) = 0;
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index 23de4fa..e0f6c45 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -293,10 +293,6 @@
}
}
-void HidlComposer::resetCommands(Display) {
- mWriter.reset();
-}
-
Error HidlComposer::executeCommands(Display) {
return execute();
}
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index d04652b..0521acf 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -174,10 +174,6 @@
void registerCallback(HWC2::ComposerCallback& callback) override;
- // Reset all pending commands in the command buffer. Useful if you want to
- // skip a frame but have already queued some commands.
- void resetCommands(Display) override;
-
// Explicitly flush all pending commands in the command buffer.
Error executeCommands(Display) override;
diff --git a/services/surfaceflinger/DisplayRenderArea.cpp b/services/surfaceflinger/DisplayRenderArea.cpp
index 8f39e26..e55cd3e 100644
--- a/services/surfaceflinger/DisplayRenderArea.cpp
+++ b/services/surfaceflinger/DisplayRenderArea.cpp
@@ -35,21 +35,24 @@
const Rect& sourceCrop, ui::Size reqSize,
ui::Dataspace reqDataSpace,
bool useIdentityTransform,
+ bool hintForSeamlessTransition,
bool allowSecureLayers) {
if (auto display = displayWeak.promote()) {
// Using new to access a private constructor.
return std::unique_ptr<DisplayRenderArea>(
new DisplayRenderArea(std::move(display), sourceCrop, reqSize, reqDataSpace,
- useIdentityTransform, allowSecureLayers));
+ useIdentityTransform, hintForSeamlessTransition,
+ allowSecureLayers));
}
return nullptr;
}
DisplayRenderArea::DisplayRenderArea(sp<const DisplayDevice> display, const Rect& sourceCrop,
ui::Size reqSize, ui::Dataspace reqDataSpace,
- bool useIdentityTransform, bool allowSecureLayers)
- : RenderArea(reqSize, CaptureFill::OPAQUE, reqDataSpace, allowSecureLayers,
- applyDeviceOrientation(useIdentityTransform, *display)),
+ bool useIdentityTransform, bool hintForSeamlessTransition,
+ bool allowSecureLayers)
+ : RenderArea(reqSize, CaptureFill::OPAQUE, reqDataSpace, hintForSeamlessTransition,
+ allowSecureLayers, applyDeviceOrientation(useIdentityTransform, *display)),
mDisplay(std::move(display)),
mSourceCrop(sourceCrop) {}
diff --git a/services/surfaceflinger/DisplayRenderArea.h b/services/surfaceflinger/DisplayRenderArea.h
index ce5410a..9a4981c 100644
--- a/services/surfaceflinger/DisplayRenderArea.h
+++ b/services/surfaceflinger/DisplayRenderArea.h
@@ -30,6 +30,7 @@
static std::unique_ptr<RenderArea> create(wp<const DisplayDevice>, const Rect& sourceCrop,
ui::Size reqSize, ui::Dataspace,
bool useIdentityTransform,
+ bool hintForSeamlessTransition,
bool allowSecureLayers = true);
const ui::Transform& getTransform() const override;
@@ -39,7 +40,8 @@
private:
DisplayRenderArea(sp<const DisplayDevice>, const Rect& sourceCrop, ui::Size reqSize,
- ui::Dataspace, bool useIdentityTransform, bool allowSecureLayers = true);
+ ui::Dataspace, bool useIdentityTransform, bool hintForSeamlessTransition,
+ bool allowSecureLayers = true);
const sp<const DisplayDevice> mDisplay;
const Rect mSourceCrop;
diff --git a/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp b/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp
index cfa2b03..97af445 100644
--- a/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp
@@ -50,7 +50,7 @@
}
if (internalLayer) {
- sequence = getInternalLayerId(sInternalSequence++);
+ sequence = id.value_or(getInternalLayerId(sInternalSequence++));
} else if (id) {
sequence = *id;
sSequence = *id + 1;
diff --git a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
index 6cacfb5..cd9515c 100644
--- a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
@@ -38,7 +38,8 @@
RequestedLayerState& layer = *newLayer.get();
auto [it, inserted] = mIdToLayer.try_emplace(layer.id, References{.owner = layer});
if (!inserted) {
- LOG_ALWAYS_FATAL("Duplicate layer id %d found. Existing layer: %s", layer.id,
+ LOG_ALWAYS_FATAL("Duplicate layer id found. New layer: %s Existing layer: %s",
+ layer.getDebugString().c_str(),
it->second.owner.getDebugString().c_str());
}
mAddedLayers.push_back(newLayer.get());
@@ -200,8 +201,10 @@
if (layer->what & layer_state_t::eBackgroundColorChanged) {
if (layer->bgColorLayerId == UNASSIGNED_LAYER_ID && layer->bgColor.a != 0) {
- LayerCreationArgs backgroundLayerArgs(layer->id,
- /*internalLayer=*/true);
+ LayerCreationArgs
+ backgroundLayerArgs(LayerCreationArgs::getInternalLayerId(
+ LayerCreationArgs::sInternalSequence++),
+ /*internalLayer=*/true);
backgroundLayerArgs.parentId = layer->id;
backgroundLayerArgs.name = layer->name + "BackgroundColorLayer";
backgroundLayerArgs.flags = ISurfaceComposerClient::eFXSurfaceEffect;
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index b397b82..23bb54c 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -130,7 +130,8 @@
void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerState) {
const uint32_t oldFlags = flags;
const half oldAlpha = color.a;
- const bool hadBufferOrSideStream = hasValidBuffer() || sidebandStream != nullptr;
+ const bool hadBuffer = externalTexture != nullptr;
+ const bool hadSideStream = sidebandStream != nullptr;
const layer_state_t& clientState = resolvedComposerState.state;
const bool hadBlur = hasBlur();
uint64_t clientChanges = what | layer_state_t::diff(clientState);
@@ -146,23 +147,32 @@
changes |= RequestedLayerState::Changes::Geometry;
}
}
- if (clientState.what &
- (layer_state_t::eBufferChanged | layer_state_t::eSidebandStreamChanged)) {
- const bool hasBufferOrSideStream = hasValidBuffer() || sidebandStream != nullptr;
- if (hadBufferOrSideStream != hasBufferOrSideStream) {
+ if (clientState.what & layer_state_t::eBufferChanged) {
+ externalTexture = resolvedComposerState.externalTexture;
+ barrierProducerId = std::max(bufferData->producerId, barrierProducerId);
+ barrierFrameNumber = std::max(bufferData->frameNumber, barrierFrameNumber);
+ // TODO(b/277265947) log and flush transaction trace when we detect out of order updates
+
+ const bool hasBuffer = externalTexture != nullptr;
+ if (hasBuffer || hasBuffer != hadBuffer) {
+ changes |= RequestedLayerState::Changes::Buffer;
+ }
+
+ if (hasBuffer != hadBuffer) {
changes |= RequestedLayerState::Changes::Geometry |
RequestedLayerState::Changes::VisibleRegion |
RequestedLayerState::Changes::Visibility | RequestedLayerState::Changes::Input;
}
}
- if (clientState.what & layer_state_t::eBufferChanged) {
- barrierProducerId = std::max(bufferData->producerId, barrierProducerId);
- barrierFrameNumber = std::max(bufferData->frameNumber, barrierFrameNumber);
- // TODO(b/277265947) log and flush transaction trace when we detect out of order updates
- changes |= RequestedLayerState::Changes::Buffer;
- }
+
if (clientState.what & layer_state_t::eSidebandStreamChanged) {
changes |= RequestedLayerState::Changes::SidebandStream;
+ const bool hasSideStream = sidebandStream != nullptr;
+ if (hasSideStream != hadSideStream) {
+ changes |= RequestedLayerState::Changes::Geometry |
+ RequestedLayerState::Changes::VisibleRegion |
+ RequestedLayerState::Changes::Visibility | RequestedLayerState::Changes::Input;
+ }
}
if (what & (layer_state_t::eAlphaChanged)) {
if (oldAlpha == 0 || color.a == 0) {
@@ -236,10 +246,6 @@
// TODO(b/238781169) handle callbacks
}
- if (clientState.what & layer_state_t::eBufferChanged) {
- externalTexture = resolvedComposerState.externalTexture;
- }
-
if (clientState.what & layer_state_t::ePositionChanged) {
requestedTransform.set(x, y);
}
@@ -465,6 +471,10 @@
return hasFrameUpdate() && sidebandStream.get();
}
+bool RequestedLayerState::willReleaseBufferOnLatch() const {
+ return changes.test(Changes::Buffer) && !externalTexture;
+}
+
void RequestedLayerState::clearChanges() {
what = 0;
changes.clear();
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.h b/services/surfaceflinger/FrontEnd/RequestedLayerState.h
index f15f023..0ef50bc 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.h
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.h
@@ -79,6 +79,7 @@
bool hasFrameUpdate() const;
bool hasReadyFrame() const;
bool hasSidebandStreamFrame() const;
+ bool willReleaseBufferOnLatch() const;
// Layer serial number. This gives layers an explicit ordering, so we
// have a stable sort order when their layer stack and Z-order are
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 9c232b1..bfb7a22 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -254,7 +254,8 @@
mFlinger->mTunnelModeEnabledReporter->decrementTunnelModeCount();
}
if (mHadClonedChild) {
- mFlinger->mNumClones--;
+ auto& roots = mFlinger->mLayerMirrorRoots;
+ roots.erase(std::remove(roots.begin(), roots.end(), this), roots.end());
}
if (hasTrustedPresentationListener()) {
mFlinger->mNumTrustedPresentationListeners--;
@@ -2552,7 +2553,10 @@
return outputLayer ? outputLayer->getState().visibleRegion : Region();
}
-void Layer::setInitialValuesForClone(const sp<Layer>& clonedFrom) {
+void Layer::setInitialValuesForClone(const sp<Layer>& clonedFrom, uint32_t mirrorRootId) {
+ mSnapshot->path.id = clonedFrom->getSequence();
+ mSnapshot->path.mirrorRootId = mirrorRootId;
+
cloneDrawingState(clonedFrom.get());
mClonedFrom = clonedFrom;
mPremultipliedAlpha = clonedFrom->mPremultipliedAlpha;
@@ -2591,7 +2595,7 @@
mDrawingState.inputInfo = tmpInputInfo;
}
-void Layer::updateMirrorInfo() {
+bool Layer::updateMirrorInfo(const std::deque<Layer*>& cloneRootsPendingUpdates) {
if (mClonedChild == nullptr || !mClonedChild->isClonedFromAlive()) {
// If mClonedChild is null, there is nothing to mirror. If isClonedFromAlive returns false,
// it means that there is a clone, but the layer it was cloned from has been destroyed. In
@@ -2599,7 +2603,7 @@
// destroyed. The root, this layer, will still be around since the client can continue
// to hold a reference, but no cloned layers will be displayed.
mClonedChild = nullptr;
- return;
+ return true;
}
std::map<sp<Layer>, sp<Layer>> clonedLayersMap;
@@ -2614,6 +2618,13 @@
mClonedChild->updateClonedDrawingState(clonedLayersMap);
mClonedChild->updateClonedChildren(sp<Layer>::fromExisting(this), clonedLayersMap);
mClonedChild->updateClonedRelatives(clonedLayersMap);
+
+ for (Layer* root : cloneRootsPendingUpdates) {
+ if (clonedLayersMap.find(sp<Layer>::fromExisting(root)) != clonedLayersMap.end()) {
+ return false;
+ }
+ }
+ return true;
}
void Layer::updateClonedDrawingState(std::map<sp<Layer>, sp<Layer>>& clonedLayersMap) {
@@ -2653,7 +2664,7 @@
}
sp<Layer> clonedChild = clonedLayersMap[child];
if (clonedChild == nullptr) {
- clonedChild = child->createClone();
+ clonedChild = child->createClone(mirrorRoot->getSequence());
clonedLayersMap[child] = clonedChild;
}
addChildToDrawing(clonedChild);
@@ -2761,7 +2772,7 @@
void Layer::setClonedChild(const sp<Layer>& clonedChild) {
mClonedChild = clonedChild;
mHadClonedChild = true;
- mFlinger->mNumClones++;
+ mFlinger->mLayerMirrorRoots.push_back(this);
}
bool Layer::setDropInputMode(gui::DropInputMode mode) {
@@ -2795,7 +2806,8 @@
currentMaxAcquiredBufferCount);
}
-void Layer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult) {
+void Layer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult,
+ ui::LayerStack layerStack) {
// If we are displayed on multiple displays in a single composition cycle then we would
// need to do careful tracking to enable the use of the mLastClientCompositionFence.
// For example we can only use it if all the displays are client comp, and we need
@@ -2825,8 +2837,7 @@
// transaction doesn't need a previous release fence.
sp<CallbackHandle> ch;
for (auto& handle : mDrawingState.callbackHandles) {
- if (handle->releasePreviousBuffer &&
- mDrawingState.releaseBufferEndpoint == handle->listener) {
+ if (handle->releasePreviousBuffer && mPreviousReleaseBufferEndpoint == handle->listener) {
ch = handle;
break;
}
@@ -2842,6 +2853,7 @@
ch->previousReleaseFences.emplace_back(std::move(futureFenceResult));
ch->name = mName;
}
+ mPreviouslyPresentedLayerStacks.push_back(layerStack);
}
void Layer::onSurfaceFrameCreated(
@@ -2880,8 +2892,7 @@
}
for (auto& handle : mDrawingState.callbackHandles) {
- if (handle->releasePreviousBuffer &&
- mDrawingState.releaseBufferEndpoint == handle->listener) {
+ if (handle->releasePreviousBuffer && mPreviousReleaseBufferEndpoint == handle->listener) {
handle->previousReleaseCallbackId = mPreviousReleaseCallbackId;
break;
}
@@ -3018,14 +3029,22 @@
return true;
}
+void Layer::resetDrawingStateBufferInfo() {
+ mDrawingState.producerId = 0;
+ mDrawingState.frameNumber = 0;
+ mDrawingState.releaseBufferListener = nullptr;
+ mDrawingState.buffer = nullptr;
+ mDrawingState.acquireFence = sp<Fence>::make(-1);
+ mDrawingState.acquireFenceTime = std::make_unique<FenceTime>(mDrawingState.acquireFence);
+ mCallbackHandleAcquireTimeOrFence = mDrawingState.acquireFenceTime->getSignalTime();
+ mDrawingState.releaseBufferEndpoint = nullptr;
+}
+
bool Layer::setBuffer(std::shared_ptr<renderengine::ExternalTexture>& buffer,
const BufferData& bufferData, nsecs_t postTime, nsecs_t desiredPresentTime,
bool isAutoTimestamp, std::optional<nsecs_t> dequeueTime,
const FrameTimelineInfo& info) {
ATRACE_FORMAT("setBuffer %s - hasBuffer=%s", getDebugName(), (buffer ? "true" : "false"));
- if (!buffer) {
- return false;
- }
const bool frameNumberChanged =
bufferData.flags.test(BufferData::BufferDataChange::frameNumberChanged);
@@ -3057,12 +3076,24 @@
mLastClientCompositionFence);
mLastClientCompositionFence = nullptr;
}
- } else {
+ } else if (buffer) {
// if we are latching a buffer for the first time then clear the mLastLatchTime since
// we don't want to incorrectly classify a frame if we miss the desired present time.
updateLastLatchTime(0);
}
+ mDrawingState.desiredPresentTime = desiredPresentTime;
+ mDrawingState.isAutoTimestamp = isAutoTimestamp;
+ mDrawingState.latchedVsyncId = info.vsyncId;
+ mDrawingState.modified = true;
+ if (!buffer) {
+ resetDrawingStateBufferInfo();
+ setTransactionFlags(eTransactionNeeded);
+ mDrawingState.bufferSurfaceFrameTX = nullptr;
+ setFrameTimelineVsyncForBufferlessTransaction(info, postTime);
+ return true;
+ }
+
mDrawingState.producerId = bufferData.producerId;
mDrawingState.barrierProducerId =
std::max(mDrawingState.producerId, mDrawingState.barrierProducerId);
@@ -3073,7 +3104,6 @@
// TODO(b/277265947) log and flush transaction trace when we detect out of order updates
mDrawingState.releaseBufferListener = bufferData.releaseBufferListener;
mDrawingState.buffer = std::move(buffer);
- mDrawingState.clientCacheId = bufferData.cachedBuffer;
mDrawingState.acquireFence = bufferData.flags.test(BufferData::BufferDataChange::fenceChanged)
? bufferData.acquireFence
: Fence::NO_FENCE;
@@ -3086,15 +3116,11 @@
} else {
mCallbackHandleAcquireTimeOrFence = mDrawingState.acquireFenceTime->getSignalTime();
}
- mDrawingState.latchedVsyncId = info.vsyncId;
- mDrawingState.modified = true;
setTransactionFlags(eTransactionNeeded);
const int32_t layerId = getSequence();
mFlinger->mTimeStats->setPostTime(layerId, mDrawingState.frameNumber, getName().c_str(),
mOwnerUid, postTime, getGameMode());
- mDrawingState.desiredPresentTime = desiredPresentTime;
- mDrawingState.isAutoTimestamp = isAutoTimestamp;
if (mFlinger->mLegacyFrontEndEnabled) {
recordLayerHistoryBufferUpdate(getLayerProps());
@@ -3342,7 +3368,7 @@
const State& s(getDrawingState());
if (!s.buffer) {
- if (bgColorOnly) {
+ if (bgColorOnly || mBufferInfo.mBuffer) {
for (auto& handle : mDrawingState.callbackHandles) {
handle->latchTime = latchTime;
}
@@ -3389,12 +3415,19 @@
}
void Layer::gatherBufferInfo() {
- if (!mBufferInfo.mBuffer || !mDrawingState.buffer->hasSameBuffer(*mBufferInfo.mBuffer)) {
+ mPreviousReleaseCallbackId = {getCurrentBufferId(), mBufferInfo.mFrameNumber};
+ mPreviousReleaseBufferEndpoint = mBufferInfo.mReleaseBufferEndpoint;
+ if (!mDrawingState.buffer) {
+ mBufferInfo = {};
+ return;
+ }
+
+ if ((!mBufferInfo.mBuffer || !mDrawingState.buffer->hasSameBuffer(*mBufferInfo.mBuffer))) {
decrementPendingBufferCount();
}
- mPreviousReleaseCallbackId = {getCurrentBufferId(), mBufferInfo.mFrameNumber};
mBufferInfo.mBuffer = mDrawingState.buffer;
+ mBufferInfo.mReleaseBufferEndpoint = mDrawingState.releaseBufferEndpoint;
mBufferInfo.mFence = mDrawingState.acquireFence;
mBufferInfo.mFrameNumber = mDrawingState.frameNumber;
mBufferInfo.mPixelFormat =
@@ -3469,11 +3502,11 @@
}
}
-sp<Layer> Layer::createClone() {
+sp<Layer> Layer::createClone(uint32_t mirrorRootId) {
LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata());
args.textureName = mTextureName;
sp<Layer> layer = mFlinger->getFactory().createBufferStateLayer(args);
- layer->setInitialValuesForClone(sp<Layer>::fromExisting(this));
+ layer->setInitialValuesForClone(sp<Layer>::fromExisting(this), mirrorRootId);
return layer;
}
@@ -3924,6 +3957,10 @@
mBufferInfo.mFrameLatencyNeeded = false;
}
+bool Layer::willReleaseBufferOnLatch() const {
+ return !mDrawingState.buffer && mBufferInfo.mBuffer;
+}
+
bool Layer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) {
const bool bgColorOnly = mDrawingState.bgColorLayer != nullptr;
return latchBufferImpl(recomputeVisibleRegions, latchTime, bgColorOnly);
@@ -3947,9 +3984,6 @@
return false;
}
updateTexImage(latchTime, bgColorOnly);
- if (mDrawingState.buffer == nullptr) {
- return false;
- }
// Capture the old state of the layer for comparisons later
BufferInfo oldBufferInfo = mBufferInfo;
@@ -3958,6 +3992,18 @@
mCurrentFrameNumber = mDrawingState.frameNumber;
gatherBufferInfo();
+ if (mBufferInfo.mBuffer) {
+ // We latched a buffer that will be presented soon. Clear the previously presented layer
+ // stack list.
+ mPreviouslyPresentedLayerStacks.clear();
+ }
+
+ if (mDrawingState.buffer == nullptr) {
+ const bool bufferReleased = oldBufferInfo.mBuffer != nullptr;
+ recomputeVisibleRegions = bufferReleased;
+ return bufferReleased;
+ }
+
if (oldBufferInfo.mBuffer == nullptr) {
// the first time we receive a buffer, we need to trigger a
// geometry invalidation.
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 8d7c362..4374914 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -153,7 +153,6 @@
bool transformToDisplayInverse;
Region transparentRegionHint;
std::shared_ptr<renderengine::ExternalTexture> buffer;
- client_cache_t clientCacheId;
sp<Fence> acquireFence;
std::shared_ptr<FenceTime> acquireFenceTime;
HdrMetadata hdrMetadata;
@@ -249,7 +248,7 @@
// true if this layer is visible, false otherwise
virtual bool isVisible() const;
- virtual sp<Layer> createClone();
+ virtual sp<Layer> createClone(uint32_t mirrorRoot);
// Set a 2x2 transformation matrix on the layer. This transform
// will be applied after parent transforms, but before any final
@@ -455,6 +454,12 @@
bool bgColorOnly);
/*
+ * Returns true if the currently presented buffer will be released when this layer state
+ * is latched. This will return false if there is no buffer currently presented.
+ */
+ bool willReleaseBufferOnLatch() const;
+
+ /*
* Calls latchBuffer if the buffer has a frame queued and then releases the buffer.
* This is used if the buffer is just latched and releases to free up the buffer
* and will not be shown on screen.
@@ -536,6 +541,7 @@
std::shared_ptr<renderengine::ExternalTexture> mBuffer;
uint64_t mFrameNumber;
+ sp<IBinder> mReleaseBufferEndpoint;
bool mFrameLatencyNeeded{false};
float mDesiredHdrSdrRatio = 1.f;
@@ -547,7 +553,7 @@
const compositionengine::LayerFECompositionState* getCompositionState() const;
bool fenceHasSignaled() const;
void onPreComposition(nsecs_t refreshStartTime);
- void onLayerDisplayed(ftl::SharedFuture<FenceResult>);
+ void onLayerDisplayed(ftl::SharedFuture<FenceResult>, ui::LayerStack layerStack);
void setWasClientComposed(const sp<Fence>& fence) {
mLastClientCompositionFence = fence;
@@ -645,7 +651,7 @@
gui::WindowInfo::Type getWindowType() const { return mWindowType; }
- void updateMirrorInfo();
+ bool updateMirrorInfo(const std::deque<Layer*>& cloneRootsPendingUpdates);
/*
* doTransaction - process the transaction. This is a good place to figure
@@ -900,7 +906,10 @@
void setTransformHint(std::optional<ui::Transform::RotationFlags> transformHint) {
mTransformHint = transformHint;
}
-
+ // Keeps track of the previously presented layer stacks. This is used to get
+ // the release fences from the correct displays when we release the last buffer
+ // from the layer.
+ std::vector<ui::LayerStack> mPreviouslyPresentedLayerStacks;
// Exposed so SurfaceFlinger can assert that it's held
const sp<SurfaceFlinger> mFlinger;
@@ -913,7 +922,7 @@
friend class TransactionFrameTracerTest;
friend class TransactionSurfaceFrameTest;
- virtual void setInitialValuesForClone(const sp<Layer>& clonedFrom);
+ virtual void setInitialValuesForClone(const sp<Layer>& clonedFrom, uint32_t mirrorRootId);
void preparePerFrameCompositionState();
void preparePerFrameBufferCompositionState();
void preparePerFrameEffectsCompositionState();
@@ -1177,6 +1186,7 @@
half4 mBorderColor;
void setTransformHintLegacy(ui::Transform::RotationFlags);
+ void resetDrawingStateBufferInfo();
const uint32_t mTextureName;
@@ -1187,6 +1197,7 @@
std::optional<ui::Transform::RotationFlags> mTransformHint = std::nullopt;
ReleaseCallbackId mPreviousReleaseCallbackId = ReleaseCallbackId::INVALID_ID;
+ sp<IBinder> mPreviousReleaseBufferEndpoint;
uint64_t mPreviousReleasedFrameNumber = 0;
uint64_t mPreviousBarrierFrameNumber = 0;
diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp
index b9c8b78..e713263 100644
--- a/services/surfaceflinger/LayerFE.cpp
+++ b/services/surfaceflinger/LayerFE.cpp
@@ -325,8 +325,9 @@
caster.shadow = state;
}
-void LayerFE::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult) {
- mCompositionResult.releaseFences.emplace_back(std::move(futureFenceResult));
+void LayerFE::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult,
+ ui::LayerStack layerStack) {
+ mCompositionResult.releaseFences.emplace_back(std::move(futureFenceResult), layerStack);
}
CompositionResult&& LayerFE::stealCompositionResult() {
diff --git a/services/surfaceflinger/LayerFE.h b/services/surfaceflinger/LayerFE.h
index c23bd31..d584fb7 100644
--- a/services/surfaceflinger/LayerFE.h
+++ b/services/surfaceflinger/LayerFE.h
@@ -29,7 +29,7 @@
// TODO(b/238781169) update CE to no longer pass refreshStartTime to LayerFE::onPreComposition
// and remove this field.
nsecs_t refreshStartTime = 0;
- std::vector<ftl::SharedFuture<FenceResult>> releaseFences;
+ std::vector<std::pair<ftl::SharedFuture<FenceResult>, ui::LayerStack>> releaseFences;
sp<Fence> lastClientCompositionFence = nullptr;
};
@@ -40,7 +40,7 @@
// compositionengine::LayerFE overrides
const compositionengine::LayerFECompositionState* getCompositionState() const override;
bool onPreComposition(nsecs_t refreshStartTime, bool updatingOutputGeometryThisFrame) override;
- void onLayerDisplayed(ftl::SharedFuture<FenceResult>) override;
+ void onLayerDisplayed(ftl::SharedFuture<FenceResult>, ui::LayerStack) override;
const char* getDebugName() const override;
int32_t getSequence() const override;
bool hasRoundedCorners() const override;
diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp
index 1b8ff28..d606cff 100644
--- a/services/surfaceflinger/LayerRenderArea.cpp
+++ b/services/surfaceflinger/LayerRenderArea.cpp
@@ -40,8 +40,9 @@
LayerRenderArea::LayerRenderArea(SurfaceFlinger& flinger, sp<Layer> layer, const Rect& crop,
ui::Size reqSize, ui::Dataspace reqDataSpace, bool childrenOnly,
bool allowSecureLayers, const ui::Transform& layerTransform,
- const Rect& layerBufferSize)
- : RenderArea(reqSize, CaptureFill::CLEAR, reqDataSpace, allowSecureLayers),
+ const Rect& layerBufferSize, bool hintForSeamlessTransition)
+ : RenderArea(reqSize, CaptureFill::CLEAR, reqDataSpace, hintForSeamlessTransition,
+ allowSecureLayers),
mLayer(std::move(layer)),
mLayerTransform(layerTransform),
mLayerBufferSize(layerBufferSize),
@@ -84,7 +85,7 @@
// If layer is offscreen, update mirroring info if it exists
if (mLayer->isRemovedFromCurrentState()) {
mLayer->traverse(LayerVector::StateSet::Drawing,
- [&](Layer* layer) { layer->updateMirrorInfo(); });
+ [&](Layer* layer) { layer->updateMirrorInfo({}); });
mLayer->traverse(LayerVector::StateSet::Drawing,
[&](Layer* layer) { layer->updateCloneBufferInfo(); });
}
diff --git a/services/surfaceflinger/LayerRenderArea.h b/services/surfaceflinger/LayerRenderArea.h
index 9bb13b3..aa609ee 100644
--- a/services/surfaceflinger/LayerRenderArea.h
+++ b/services/surfaceflinger/LayerRenderArea.h
@@ -34,7 +34,8 @@
public:
LayerRenderArea(SurfaceFlinger& flinger, sp<Layer> layer, const Rect& crop, ui::Size reqSize,
ui::Dataspace reqDataSpace, bool childrenOnly, bool allowSecureLayers,
- const ui::Transform& layerTransform, const Rect& layerBufferSize);
+ const ui::Transform& layerTransform, const Rect& layerBufferSize,
+ bool hintForSeamlessTransition);
const ui::Transform& getTransform() const override;
bool isSecure() const override;
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 9a4261d..f1fd6db 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -355,6 +355,8 @@
if (isSetByHwc()) {
transaction.setFlags(surface, layer_state_t::eLayerIsRefreshRateIndicator,
layer_state_t::eLayerIsRefreshRateIndicator);
+ // Disable overlay layer caching when refresh rate is updated by the HWC.
+ transaction.setCachingHint(surface, gui::CachingHint::Disabled);
}
transaction.setFrameRate(surface, kFrameRate, kCompatibility, kSeamlessness);
return transaction;
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 531d277..8f658d5 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -277,10 +277,12 @@
const Rect sampledBounds = sampleRegion.bounds();
constexpr bool kUseIdentityTransform = false;
+ constexpr bool kHintForSeamlessTransition = false;
SurfaceFlinger::RenderAreaFuture renderAreaFuture = ftl::defer([=] {
return DisplayRenderArea::create(displayWeak, sampledBounds, sampledBounds.getSize(),
- ui::Dataspace::V0_SRGB, kUseIdentityTransform);
+ ui::Dataspace::V0_SRGB, kUseIdentityTransform,
+ kHintForSeamlessTransition);
});
std::unordered_set<sp<IRegionSamplingListener>, SpHash<IRegionSamplingListener>> listeners;
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index 910fce0..71b85bd 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -25,12 +25,14 @@
static float getCaptureFillValue(CaptureFill captureFill);
RenderArea(ui::Size reqSize, CaptureFill captureFill, ui::Dataspace reqDataSpace,
- bool allowSecureLayers = false, RotationFlags rotation = ui::Transform::ROT_0)
+ bool hintForSeamlessTransition, bool allowSecureLayers = false,
+ RotationFlags rotation = ui::Transform::ROT_0)
: mAllowSecureLayers(allowSecureLayers),
mReqSize(reqSize),
mReqDataSpace(reqDataSpace),
mCaptureFill(captureFill),
- mRotationFlags(rotation) {}
+ mRotationFlags(rotation),
+ mHintForSeamlessTransition(hintForSeamlessTransition) {}
static std::function<std::vector<std::pair<Layer*, sp<LayerFE>>>()> fromTraverseLayersLambda(
std::function<void(const LayerVector::Visitor&)> traverseLayers) {
@@ -90,6 +92,10 @@
// capture operation.
virtual sp<Layer> getParentLayer() const { return nullptr; }
+ // Returns whether the render result may be used for system animations that
+ // must preserve the exact colors of the display.
+ bool getHintForSeamlessTransition() const { return mHintForSeamlessTransition; }
+
protected:
const bool mAllowSecureLayers;
@@ -98,7 +104,7 @@
const ui::Dataspace mReqDataSpace;
const CaptureFill mCaptureFill;
const RotationFlags mRotationFlags;
- const Rect mLayerStackSpaceRect;
+ const bool mHintForSeamlessTransition;
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 74665a7..1c0bf0d 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -692,17 +692,27 @@
}
void EventThread::onNewVsyncSchedule(std::shared_ptr<scheduler::VsyncSchedule> schedule) {
+ // Hold onto the old registration until after releasing the mutex to avoid deadlock.
+ scheduler::VSyncCallbackRegistration oldRegistration =
+ onNewVsyncScheduleInternal(std::move(schedule));
+}
+
+scheduler::VSyncCallbackRegistration EventThread::onNewVsyncScheduleInternal(
+ std::shared_ptr<scheduler::VsyncSchedule> schedule) {
std::lock_guard<std::mutex> lock(mMutex);
const bool reschedule = mVsyncRegistration.cancel() == scheduler::CancelResult::Cancelled;
mVsyncSchedule = std::move(schedule);
- mVsyncRegistration =
- scheduler::VSyncCallbackRegistration(mVsyncSchedule->getDispatch(),
- createDispatchCallback(), mThreadName);
+ auto oldRegistration =
+ std::exchange(mVsyncRegistration,
+ scheduler::VSyncCallbackRegistration(mVsyncSchedule->getDispatch(),
+ createDispatchCallback(),
+ mThreadName));
if (reschedule) {
mVsyncRegistration.schedule({.workDuration = mWorkDuration.get().count(),
.readyDuration = mReadyDuration.count(),
.earliestVsync = mLastVsyncCallbackTime.ns()});
}
+ return oldRegistration;
}
scheduler::VSyncDispatch::Callback EventThread::createDispatchCallback() {
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 30869e9..684745b 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -174,7 +174,7 @@
size_t getEventThreadConnectionCount() override;
- void onNewVsyncSchedule(std::shared_ptr<scheduler::VsyncSchedule>) override;
+ void onNewVsyncSchedule(std::shared_ptr<scheduler::VsyncSchedule>) override EXCLUDES(mMutex);
private:
friend EventThreadTest;
@@ -201,6 +201,11 @@
scheduler::VSyncDispatch::Callback createDispatchCallback();
+ // Returns the old registration so it can be destructed outside the lock to
+ // avoid deadlock.
+ scheduler::VSyncCallbackRegistration onNewVsyncScheduleInternal(
+ std::shared_ptr<scheduler::VsyncSchedule>) EXCLUDES(mMutex);
+
const char* const mThreadName;
TracedOrdinal<int> mVsyncTracer;
TracedOrdinal<std::chrono::nanoseconds> mWorkDuration GUARDED_BY(mMutex);
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 3e12db6..9319543 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -50,8 +50,9 @@
#include "FrontEnd/LayerHandle.h"
#include "OneShotTimer.h"
#include "SurfaceFlingerProperties.h"
-#include "VSyncPredictor.h"
-#include "VSyncReactor.h"
+#include "VSyncTracker.h"
+#include "VsyncController.h"
+#include "VsyncSchedule.h"
#define RETURN_IF_INVALID_HANDLE(handle, ...) \
do { \
@@ -119,14 +120,13 @@
void Scheduler::registerDisplayInternal(PhysicalDisplayId displayId,
RefreshRateSelectorPtr selectorPtr,
- std::shared_ptr<VsyncSchedule> vsyncSchedule) {
+ VsyncSchedulePtr schedulePtr) {
demotePacesetterDisplay();
std::shared_ptr<VsyncSchedule> pacesetterVsyncSchedule;
{
std::scoped_lock lock(mDisplayLock);
- mRefreshRateSelectors.emplace_or_replace(displayId, std::move(selectorPtr));
- mVsyncSchedules.emplace_or_replace(displayId, std::move(vsyncSchedule));
+ mDisplays.emplace_or_replace(displayId, std::move(selectorPtr), std::move(schedulePtr));
pacesetterVsyncSchedule = promotePacesetterDisplayLocked();
}
@@ -139,13 +139,12 @@
std::shared_ptr<VsyncSchedule> pacesetterVsyncSchedule;
{
std::scoped_lock lock(mDisplayLock);
- mRefreshRateSelectors.erase(displayId);
- mVsyncSchedules.erase(displayId);
+ mDisplays.erase(displayId);
// Do not allow removing the final display. Code in the scheduler expects
// there to be at least one display. (This may be relaxed in the future with
// headless virtual display.)
- LOG_ALWAYS_FATAL_IF(mRefreshRateSelectors.empty(), "Cannot unregister all displays!");
+ LOG_ALWAYS_FATAL_IF(mDisplays.empty(), "Cannot unregister all displays!");
pacesetterVsyncSchedule = promotePacesetterDisplayLocked();
}
@@ -199,20 +198,27 @@
impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction() const {
return [this](uid_t uid) {
- const Fps refreshRate = pacesetterSelectorPtr()->getActiveMode().fps;
- const nsecs_t currentPeriod =
- getVsyncSchedule()->period().ns() ?: refreshRate.getPeriodNsecs();
+ const auto [refreshRate, period] = [this] {
+ std::scoped_lock lock(mDisplayLock);
+ const auto pacesetterOpt = pacesetterDisplayLocked();
+ LOG_ALWAYS_FATAL_IF(!pacesetterOpt);
+ const Display& pacesetter = *pacesetterOpt;
+ return std::make_pair(pacesetter.selectorPtr->getActiveMode().fps,
+ pacesetter.schedulePtr->period());
+ }();
+
+ const Period currentPeriod = period != Period::zero() ? period : refreshRate.getPeriod();
const auto frameRate = getFrameRateOverride(uid);
if (!frameRate.has_value()) {
- return currentPeriod;
+ return currentPeriod.ns();
}
const auto divisor = RefreshRateSelector::getFrameRateDivisor(refreshRate, *frameRate);
if (divisor <= 1) {
- return currentPeriod;
+ return currentPeriod.ns();
}
- return currentPeriod * divisor;
+ return currentPeriod.ns() * divisor;
};
}
@@ -400,11 +406,13 @@
void Scheduler::enableHardwareVsync(PhysicalDisplayId id) {
auto schedule = getVsyncSchedule(id);
+ LOG_ALWAYS_FATAL_IF(!schedule);
schedule->enableHardwareVsync(mSchedulerCallback);
}
void Scheduler::disableHardwareVsync(PhysicalDisplayId id, bool disallow) {
auto schedule = getVsyncSchedule(id);
+ LOG_ALWAYS_FATAL_IF(!schedule);
schedule->disableHardwareVsync(mSchedulerCallback, disallow);
}
@@ -413,23 +421,27 @@
std::scoped_lock lock(mDisplayLock);
ftl::FakeGuard guard(kMainThreadContext);
- for (const auto& [id, _] : mRefreshRateSelectors) {
+ for (const auto& [id, _] : mDisplays) {
resyncToHardwareVsyncLocked(id, allowToEnable);
}
}
void Scheduler::resyncToHardwareVsyncLocked(PhysicalDisplayId id, bool allowToEnable,
std::optional<Fps> refreshRate) {
- auto schedule = getVsyncScheduleLocked(id);
- if (schedule->isHardwareVsyncAllowed(allowToEnable)) {
+ const auto displayOpt = mDisplays.get(id);
+ if (!displayOpt) {
+ ALOGW("%s: Invalid display %s!", __func__, to_string(id).c_str());
+ return;
+ }
+ const Display& display = *displayOpt;
+
+ if (display.schedulePtr->isHardwareVsyncAllowed(allowToEnable)) {
if (!refreshRate) {
- auto selectorPtr = mRefreshRateSelectors.get(id);
- LOG_ALWAYS_FATAL_IF(!selectorPtr);
- refreshRate = selectorPtr->get()->getActiveMode().modePtr->getFps();
+ refreshRate = display.selectorPtr->getActiveMode().modePtr->getFps();
}
if (refreshRate->isValid()) {
- schedule->startPeriodTransition(mSchedulerCallback, refreshRate->getPeriod(),
- false /* force */);
+ display.schedulePtr->startPeriodTransition(mSchedulerCallback, refreshRate->getPeriod(),
+ false /* force */);
}
}
}
@@ -438,9 +450,13 @@
std::scoped_lock lock(mDisplayLock);
ftl::FakeGuard guard(kMainThreadContext);
- auto selectorPtr = mRefreshRateSelectors.get(id);
- LOG_ALWAYS_FATAL_IF(!selectorPtr);
- const auto mode = selectorPtr->get()->getActiveMode();
+ const auto displayOpt = mDisplays.get(id);
+ if (!displayOpt) {
+ ALOGW("%s: Invalid display %s!", __func__, to_string(id).c_str());
+ return;
+ }
+ const Display& display = *displayOpt;
+ const auto mode = display.selectorPtr->getActiveMode();
using fps_approx_ops::operator!=;
LOG_ALWAYS_FATAL_IF(renderFrameRate != mode.fps,
@@ -451,7 +467,7 @@
ALOGV("%s %s (%s)", __func__, to_string(mode.fps).c_str(),
to_string(mode.modePtr->getFps()).c_str());
- getVsyncScheduleLocked(id)->getTracker().setRenderRate(renderFrameRate);
+ display.schedulePtr->getTracker().setRenderRate(renderFrameRate);
}
void Scheduler::resync() {
@@ -470,12 +486,18 @@
const auto hwcVsyncPeriod = ftl::Optional(hwcVsyncPeriodIn).transform([](nsecs_t nanos) {
return Period::fromNs(nanos);
});
- return getVsyncSchedule(id)->addResyncSample(mSchedulerCallback, TimePoint::fromNs(timestamp),
- hwcVsyncPeriod);
+ auto schedule = getVsyncSchedule(id);
+ if (!schedule) {
+ ALOGW("%s: Invalid display %s!", __func__, to_string(id).c_str());
+ return false;
+ }
+ return schedule->addResyncSample(mSchedulerCallback, TimePoint::fromNs(timestamp),
+ hwcVsyncPeriod);
}
void Scheduler::addPresentFence(PhysicalDisplayId id, std::shared_ptr<FenceTime> fence) {
auto schedule = getVsyncSchedule(id);
+ LOG_ALWAYS_FATAL_IF(!schedule);
const bool needMoreSignals = schedule->getController().addPresentFence(std::move(fence));
if (needMoreSignals) {
schedule->enableHardwareVsync(mSchedulerCallback);
@@ -545,6 +567,7 @@
{
std::scoped_lock lock(mDisplayLock);
auto vsyncSchedule = getVsyncScheduleLocked(id);
+ LOG_ALWAYS_FATAL_IF(!vsyncSchedule);
vsyncSchedule->getController().setDisplayPowerMode(powerMode);
}
if (!isPacesetter) return;
@@ -558,22 +581,26 @@
mLayerHistory.clear();
}
-std::shared_ptr<const VsyncSchedule> Scheduler::getVsyncSchedule(
- std::optional<PhysicalDisplayId> idOpt) const {
+auto Scheduler::getVsyncSchedule(std::optional<PhysicalDisplayId> idOpt) const
+ -> ConstVsyncSchedulePtr {
std::scoped_lock lock(mDisplayLock);
return getVsyncScheduleLocked(idOpt);
}
-std::shared_ptr<const VsyncSchedule> Scheduler::getVsyncScheduleLocked(
- std::optional<PhysicalDisplayId> idOpt) const {
+auto Scheduler::getVsyncScheduleLocked(std::optional<PhysicalDisplayId> idOpt) const
+ -> ConstVsyncSchedulePtr {
ftl::FakeGuard guard(kMainThreadContext);
+
if (!idOpt) {
LOG_ALWAYS_FATAL_IF(!mPacesetterDisplayId, "Missing a pacesetter!");
idOpt = mPacesetterDisplayId;
}
- auto scheduleOpt = mVsyncSchedules.get(*idOpt);
- LOG_ALWAYS_FATAL_IF(!scheduleOpt);
- return std::const_pointer_cast<const VsyncSchedule>(scheduleOpt->get());
+
+ const auto displayOpt = mDisplays.get(*idOpt);
+ if (!displayOpt) {
+ return nullptr;
+ }
+ return displayOpt->get().schedulePtr;
}
void Scheduler::kernelIdleTimerCallback(TimerState state) {
@@ -597,9 +624,9 @@
// need to update the VsyncController model anyway.
std::scoped_lock lock(mDisplayLock);
ftl::FakeGuard guard(kMainThreadContext);
- constexpr bool disallow = false;
- for (auto& [_, schedule] : mVsyncSchedules) {
- schedule->disableHardwareVsync(mSchedulerCallback, disallow);
+ for (const auto& [_, display] : mDisplays) {
+ constexpr bool kDisallow = false;
+ display.schedulePtr->disableHardwareVsync(mSchedulerCallback, kDisallow);
}
}
@@ -664,12 +691,12 @@
to_string(*mPacesetterDisplayId).c_str());
getVsyncScheduleLocked()->dump(out);
}
- for (auto& [id, vsyncSchedule] : mVsyncSchedules) {
+ for (auto& [id, display] : mDisplays) {
if (id == mPacesetterDisplayId) {
continue;
}
base::StringAppendF(&out, "VsyncSchedule for follower %s:\n", to_string(id).c_str());
- vsyncSchedule->dump(out);
+ display.schedulePtr->dump(out);
}
}
@@ -699,25 +726,29 @@
std::shared_ptr<VsyncSchedule> Scheduler::promotePacesetterDisplayLocked(
std::optional<PhysicalDisplayId> pacesetterIdOpt) {
// TODO(b/241286431): Choose the pacesetter display.
- mPacesetterDisplayId = pacesetterIdOpt.value_or(mRefreshRateSelectors.begin()->first);
+ mPacesetterDisplayId = pacesetterIdOpt.value_or(mDisplays.begin()->first);
ALOGI("Display %s is the pacesetter", to_string(*mPacesetterDisplayId).c_str());
- auto vsyncSchedule = getVsyncScheduleLocked(*mPacesetterDisplayId);
- if (const auto pacesetterPtr = pacesetterSelectorPtrLocked()) {
- pacesetterPtr->setIdleTimerCallbacks(
+ std::shared_ptr<VsyncSchedule> newVsyncSchedulePtr;
+ if (const auto pacesetterOpt = pacesetterDisplayLocked()) {
+ const Display& pacesetter = *pacesetterOpt;
+
+ pacesetter.selectorPtr->setIdleTimerCallbacks(
{.platform = {.onReset = [this] { idleTimerCallback(TimerState::Reset); },
.onExpired = [this] { idleTimerCallback(TimerState::Expired); }},
.kernel = {.onReset = [this] { kernelIdleTimerCallback(TimerState::Reset); },
.onExpired =
[this] { kernelIdleTimerCallback(TimerState::Expired); }}});
- pacesetterPtr->startIdleTimer();
+ pacesetter.selectorPtr->startIdleTimer();
- const Fps refreshRate = pacesetterPtr->getActiveMode().modePtr->getFps();
- vsyncSchedule->startPeriodTransition(mSchedulerCallback, refreshRate.getPeriod(),
- true /* force */);
+ newVsyncSchedulePtr = pacesetter.schedulePtr;
+
+ const Fps refreshRate = pacesetter.selectorPtr->getActiveMode().modePtr->getFps();
+ newVsyncSchedulePtr->startPeriodTransition(mSchedulerCallback, refreshRate.getPeriod(),
+ true /* force */);
}
- return vsyncSchedule;
+ return newVsyncSchedulePtr;
}
void Scheduler::applyNewVsyncSchedule(std::shared_ptr<VsyncSchedule> vsyncSchedule) {
@@ -816,81 +847,35 @@
using RankedRefreshRates = RefreshRateSelector::RankedFrameRates;
display::PhysicalDisplayVector<RankedRefreshRates> perDisplayRanking;
-
- // Tallies the score of a refresh rate across `displayCount` displays.
- struct RefreshRateTally {
- explicit RefreshRateTally(float score) : score(score) {}
-
- float score;
- size_t displayCount = 1;
- };
-
- // Chosen to exceed a typical number of refresh rates across displays.
- constexpr size_t kStaticCapacity = 8;
- ftl::SmallMap<Fps, RefreshRateTally, kStaticCapacity, FpsApproxEqual> refreshRateTallies;
-
const auto globalSignals = makeGlobalSignals();
+ Fps pacesetterFps;
- for (const auto& [id, selectorPtr] : mRefreshRateSelectors) {
+ for (const auto& [id, display] : mDisplays) {
auto rankedFrameRates =
- selectorPtr->getRankedFrameRates(mPolicy.contentRequirements, globalSignals);
-
- for (const auto& [frameRateMode, score] : rankedFrameRates.ranking) {
- const auto [it, inserted] = refreshRateTallies.try_emplace(frameRateMode.fps, score);
-
- if (!inserted) {
- auto& tally = it->second;
- tally.score += score;
- tally.displayCount++;
- }
+ display.selectorPtr->getRankedFrameRates(mPolicy.contentRequirements,
+ globalSignals);
+ if (id == *mPacesetterDisplayId) {
+ pacesetterFps = rankedFrameRates.ranking.front().frameRateMode.fps;
}
-
perDisplayRanking.push_back(std::move(rankedFrameRates));
}
- auto maxScoreIt = refreshRateTallies.cbegin();
-
- // Find the first refresh rate common to all displays.
- while (maxScoreIt != refreshRateTallies.cend() &&
- maxScoreIt->second.displayCount != mRefreshRateSelectors.size()) {
- ++maxScoreIt;
- }
-
- if (maxScoreIt != refreshRateTallies.cend()) {
- // Choose the highest refresh rate common to all displays, if any.
- for (auto it = maxScoreIt + 1; it != refreshRateTallies.cend(); ++it) {
- const auto [fps, tally] = *it;
-
- if (tally.displayCount == mRefreshRateSelectors.size() &&
- tally.score > maxScoreIt->second.score) {
- maxScoreIt = it;
- }
- }
- }
-
- const std::optional<Fps> chosenFps = maxScoreIt != refreshRateTallies.cend()
- ? std::make_optional(maxScoreIt->first)
- : std::nullopt;
-
DisplayModeChoiceMap modeChoices;
-
using fps_approx_ops::operator==;
- for (auto& [ranking, signals] : perDisplayRanking) {
- if (!chosenFps) {
- const auto& [frameRateMode, _] = ranking.front();
- modeChoices.try_emplace(frameRateMode.modePtr->getPhysicalDisplayId(),
- DisplayModeChoice{frameRateMode, signals});
- continue;
- }
+ for (auto& [rankings, signals] : perDisplayRanking) {
+ const auto chosenFrameRateMode =
+ ftl::find_if(rankings,
+ [&](const auto& ranking) {
+ return ranking.frameRateMode.fps == pacesetterFps;
+ })
+ .transform([](const auto& scoredFrameRate) {
+ return scoredFrameRate.get().frameRateMode;
+ })
+ .value_or(rankings.front().frameRateMode);
- for (auto& [frameRateMode, _] : ranking) {
- if (frameRateMode.fps == *chosenFps) {
- modeChoices.try_emplace(frameRateMode.modePtr->getPhysicalDisplayId(),
- DisplayModeChoice{frameRateMode, signals});
- break;
- }
- }
+ modeChoices.try_emplace(chosenFrameRateMode.modePtr->getPhysicalDisplayId(),
+ DisplayModeChoice{chosenFrameRateMode, signals});
}
return modeChoices;
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 1f6d378..f13c878 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -32,7 +32,6 @@
#include <ui/GraphicTypes.h>
#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
-#include <ftl/algorithm.h>
#include <ftl/fake_guard.h>
#include <ftl/optional.h>
#include <scheduler/Features.h>
@@ -51,7 +50,6 @@
#include "RefreshRateSelector.h"
#include "Utils/Dumper.h"
#include "VsyncModulator.h"
-#include "VsyncSchedule.h"
namespace android::scheduler {
@@ -94,6 +92,8 @@
using GlobalSignals = RefreshRateSelector::GlobalSignals;
+class VsyncSchedule;
+
class Scheduler : android::impl::MessageQueue {
using Impl = android::impl::MessageQueue;
@@ -109,6 +109,9 @@
using RefreshRateSelectorPtr = std::shared_ptr<RefreshRateSelector>;
+ using ConstVsyncSchedulePtr = std::shared_ptr<const VsyncSchedule>;
+ using VsyncSchedulePtr = std::shared_ptr<VsyncSchedule>;
+
void registerDisplay(PhysicalDisplayId, RefreshRateSelectorPtr) REQUIRES(kMainThreadContext)
EXCLUDES(mDisplayLock);
void unregisterDisplay(PhysicalDisplayId) REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock);
@@ -193,8 +196,8 @@
// Sets the render rate for the scheduler to run at.
void setRenderRate(PhysicalDisplayId, Fps);
- void enableHardwareVsync(PhysicalDisplayId);
- void disableHardwareVsync(PhysicalDisplayId, bool disallow);
+ void enableHardwareVsync(PhysicalDisplayId) REQUIRES(kMainThreadContext);
+ void disableHardwareVsync(PhysicalDisplayId, bool disallow) REQUIRES(kMainThreadContext);
// Resyncs the scheduler to hardware vsync.
// If allowToEnable is true, then hardware vsync will be turned on.
@@ -216,7 +219,8 @@
// otherwise.
bool addResyncSample(PhysicalDisplayId, nsecs_t timestamp,
std::optional<nsecs_t> hwcVsyncPeriod);
- void addPresentFence(PhysicalDisplayId, std::shared_ptr<FenceTime>) EXCLUDES(mDisplayLock);
+ void addPresentFence(PhysicalDisplayId, std::shared_ptr<FenceTime>) EXCLUDES(mDisplayLock)
+ REQUIRES(kMainThreadContext);
// Layers are registered on creation, and unregistered when the weak reference expires.
void registerLayer(Layer*);
@@ -237,12 +241,12 @@
void setDisplayPowerMode(PhysicalDisplayId, hal::PowerMode powerMode)
REQUIRES(kMainThreadContext);
- std::shared_ptr<const VsyncSchedule> getVsyncSchedule(
- std::optional<PhysicalDisplayId> idOpt = std::nullopt) const EXCLUDES(mDisplayLock);
- std::shared_ptr<VsyncSchedule> getVsyncSchedule(
- std::optional<PhysicalDisplayId> idOpt = std::nullopt) EXCLUDES(mDisplayLock) {
- return std::const_pointer_cast<VsyncSchedule>(
- static_cast<const Scheduler*>(this)->getVsyncSchedule(idOpt));
+ ConstVsyncSchedulePtr getVsyncSchedule(std::optional<PhysicalDisplayId> = std::nullopt) const
+ EXCLUDES(mDisplayLock);
+
+ VsyncSchedulePtr getVsyncSchedule(std::optional<PhysicalDisplayId> idOpt = std::nullopt)
+ EXCLUDES(mDisplayLock) {
+ return std::const_pointer_cast<VsyncSchedule>(std::as_const(*this).getVsyncSchedule(idOpt));
}
// Returns true if a given vsync timestamp is considered valid vsync
@@ -339,9 +343,8 @@
// the caller on the main thread to avoid deadlock, since the timer thread locks it before exit.
void demotePacesetterDisplay() REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock, mPolicyLock);
- void registerDisplayInternal(PhysicalDisplayId, RefreshRateSelectorPtr,
- std::shared_ptr<VsyncSchedule>) REQUIRES(kMainThreadContext)
- EXCLUDES(mDisplayLock);
+ void registerDisplayInternal(PhysicalDisplayId, RefreshRateSelectorPtr, VsyncSchedulePtr)
+ REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock);
struct Policy;
@@ -420,16 +423,37 @@
// must lock for writes but not reads. See also mPolicyLock for locking order.
mutable std::mutex mDisplayLock;
- display::PhysicalDisplayMap<PhysicalDisplayId, RefreshRateSelectorPtr> mRefreshRateSelectors
- GUARDED_BY(mDisplayLock) GUARDED_BY(kMainThreadContext);
+ struct Display {
+ Display(RefreshRateSelectorPtr selectorPtr, VsyncSchedulePtr schedulePtr)
+ : selectorPtr(std::move(selectorPtr)), schedulePtr(std::move(schedulePtr)) {}
- // TODO (b/266715559): Store in the same map as mRefreshRateSelectors.
- display::PhysicalDisplayMap<PhysicalDisplayId, std::shared_ptr<VsyncSchedule>> mVsyncSchedules
- GUARDED_BY(mDisplayLock) GUARDED_BY(kMainThreadContext);
+ // Effectively const except in move constructor.
+ RefreshRateSelectorPtr selectorPtr;
+ VsyncSchedulePtr schedulePtr;
+ };
+
+ using DisplayRef = std::reference_wrapper<Display>;
+ using ConstDisplayRef = std::reference_wrapper<const Display>;
+
+ display::PhysicalDisplayMap<PhysicalDisplayId, Display> mDisplays GUARDED_BY(mDisplayLock)
+ GUARDED_BY(kMainThreadContext);
ftl::Optional<PhysicalDisplayId> mPacesetterDisplayId GUARDED_BY(mDisplayLock)
GUARDED_BY(kMainThreadContext);
+ ftl::Optional<DisplayRef> pacesetterDisplayLocked() REQUIRES(mDisplayLock) {
+ return static_cast<const Scheduler*>(this)->pacesetterDisplayLocked().transform(
+ [](const Display& display) { return std::ref(const_cast<Display&>(display)); });
+ }
+
+ ftl::Optional<ConstDisplayRef> pacesetterDisplayLocked() const REQUIRES(mDisplayLock) {
+ ftl::FakeGuard guard(kMainThreadContext);
+ return mPacesetterDisplayId.and_then([this](PhysicalDisplayId pacesetterId)
+ REQUIRES(mDisplayLock, kMainThreadContext) {
+ return mDisplays.get(pacesetterId);
+ });
+ }
+
RefreshRateSelectorPtr pacesetterSelectorPtr() const EXCLUDES(mDisplayLock) {
std::scoped_lock lock(mDisplayLock);
return pacesetterSelectorPtrLocked();
@@ -437,19 +461,17 @@
RefreshRateSelectorPtr pacesetterSelectorPtrLocked() const REQUIRES(mDisplayLock) {
ftl::FakeGuard guard(kMainThreadContext);
- return mPacesetterDisplayId
- .and_then([this](PhysicalDisplayId pacesetterId)
- REQUIRES(mDisplayLock, kMainThreadContext) {
- return mRefreshRateSelectors.get(pacesetterId);
- })
- .or_else(ftl::static_ref<RefreshRateSelectorPtr>([] { return nullptr; }))
+ return pacesetterDisplayLocked()
+ .transform([](const Display& display) { return display.selectorPtr; })
+ .or_else([] { return std::optional<RefreshRateSelectorPtr>(nullptr); })
.value();
}
- std::shared_ptr<const VsyncSchedule> getVsyncScheduleLocked(
- std::optional<PhysicalDisplayId> idOpt = std::nullopt) const REQUIRES(mDisplayLock);
- std::shared_ptr<VsyncSchedule> getVsyncScheduleLocked(
- std::optional<PhysicalDisplayId> idOpt = std::nullopt) REQUIRES(mDisplayLock) {
+ ConstVsyncSchedulePtr getVsyncScheduleLocked(
+ std::optional<PhysicalDisplayId> = std::nullopt) const REQUIRES(mDisplayLock);
+
+ VsyncSchedulePtr getVsyncScheduleLocked(std::optional<PhysicalDisplayId> idOpt = std::nullopt)
+ REQUIRES(mDisplayLock) {
return std::const_pointer_cast<VsyncSchedule>(
static_cast<const Scheduler*>(this)->getVsyncScheduleLocked(idOpt));
}
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatch.h b/services/surfaceflinger/Scheduler/VSyncDispatch.h
index 77875e3..c3a952f 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatch.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h
@@ -155,10 +155,6 @@
VSyncDispatch& operator=(const VSyncDispatch&) = delete;
};
-/*
- * Helper class to operate on registered callbacks. It is up to user of the class to ensure
- * that VsyncDispatch lifetime exceeds the lifetime of VSyncCallbackRegistation.
- */
class VSyncCallbackRegistration {
public:
VSyncCallbackRegistration(std::shared_ptr<VSyncDispatch>, VSyncDispatch::Callback,
@@ -178,9 +174,10 @@
CancelResult cancel();
private:
+ friend class VSyncCallbackRegistrationTest;
+
std::shared_ptr<VSyncDispatch> mDispatch;
- VSyncDispatch::CallbackToken mToken;
- bool mValidToken;
+ std::optional<VSyncDispatch::CallbackToken> mToken;
};
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index 26389eb..1f922f1 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -21,12 +21,16 @@
#include <android-base/stringprintf.h>
#include <ftl/concat.h>
#include <utils/Trace.h>
+#include <log/log_main.h>
#include <scheduler/TimeKeeper.h>
#include "VSyncDispatchTimerQueue.h"
#include "VSyncTracker.h"
+#undef LOG_TAG
+#define LOG_TAG "VSyncDispatch"
+
namespace android::scheduler {
using base::StringAppendF;
@@ -225,6 +229,10 @@
VSyncDispatchTimerQueue::~VSyncDispatchTimerQueue() {
std::lock_guard lock(mMutex);
cancelTimer();
+ for (auto& [_, entry] : mCallbacks) {
+ ALOGE("Forgot to unregister a callback on VSyncDispatch!");
+ entry->ensureNotRunning();
+ }
}
void VSyncDispatchTimerQueue::cancelTimer() {
@@ -438,47 +446,44 @@
VSyncDispatch::Callback callback,
std::string callbackName)
: mDispatch(std::move(dispatch)),
- mToken(mDispatch->registerCallback(std::move(callback), std::move(callbackName))),
- mValidToken(true) {}
+ mToken(mDispatch->registerCallback(std::move(callback), std::move(callbackName))) {}
VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncCallbackRegistration&& other)
- : mDispatch(std::move(other.mDispatch)),
- mToken(std::move(other.mToken)),
- mValidToken(std::move(other.mValidToken)) {
- other.mValidToken = false;
-}
+ : mDispatch(std::move(other.mDispatch)), mToken(std::exchange(other.mToken, std::nullopt)) {}
VSyncCallbackRegistration& VSyncCallbackRegistration::operator=(VSyncCallbackRegistration&& other) {
+ if (this == &other) return *this;
+ if (mToken) {
+ mDispatch->unregisterCallback(*mToken);
+ }
mDispatch = std::move(other.mDispatch);
- mToken = std::move(other.mToken);
- mValidToken = std::move(other.mValidToken);
- other.mValidToken = false;
+ mToken = std::exchange(other.mToken, std::nullopt);
return *this;
}
VSyncCallbackRegistration::~VSyncCallbackRegistration() {
- if (mValidToken) mDispatch->unregisterCallback(mToken);
+ if (mToken) mDispatch->unregisterCallback(*mToken);
}
ScheduleResult VSyncCallbackRegistration::schedule(VSyncDispatch::ScheduleTiming scheduleTiming) {
- if (!mValidToken) {
+ if (!mToken) {
return std::nullopt;
}
- return mDispatch->schedule(mToken, scheduleTiming);
+ return mDispatch->schedule(*mToken, scheduleTiming);
}
ScheduleResult VSyncCallbackRegistration::update(VSyncDispatch::ScheduleTiming scheduleTiming) {
- if (!mValidToken) {
+ if (!mToken) {
return std::nullopt;
}
- return mDispatch->update(mToken, scheduleTiming);
+ return mDispatch->update(*mToken, scheduleTiming);
}
CancelResult VSyncCallbackRegistration::cancel() {
- if (!mValidToken) {
+ if (!mToken) {
return CancelResult::Error;
}
- return mDispatch->cancel(mToken);
+ return mDispatch->cancel(*mToken);
}
} // namespace android::scheduler
diff --git a/services/surfaceflinger/ScreenCaptureOutput.cpp b/services/surfaceflinger/ScreenCaptureOutput.cpp
index a1d5cd7..b70b53d 100644
--- a/services/surfaceflinger/ScreenCaptureOutput.cpp
+++ b/services/surfaceflinger/ScreenCaptureOutput.cpp
@@ -36,6 +36,7 @@
output->setLayerFilter({args.layerStack});
output->setRenderSurface(std::make_unique<ScreenCaptureRenderSurface>(std::move(args.buffer)));
output->setDisplayBrightness(args.sdrWhitePointNits, args.displayBrightnessNits);
+ output->editState().clientTargetBrightness = args.targetBrightness;
output->setDisplayColorProfile(std::make_unique<compositionengine::impl::DisplayColorProfile>(
compositionengine::DisplayColorProfileCreationArgsBuilder()
@@ -75,7 +76,6 @@
auto clientCompositionDisplay =
compositionengine::impl::Output::generateClientCompositionDisplaySettings();
clientCompositionDisplay.clip = mRenderArea.getSourceCrop();
- clientCompositionDisplay.targetLuminanceNits = -1;
return clientCompositionDisplay;
}
diff --git a/services/surfaceflinger/ScreenCaptureOutput.h b/services/surfaceflinger/ScreenCaptureOutput.h
index 4e5a0cc..3c307b0 100644
--- a/services/surfaceflinger/ScreenCaptureOutput.h
+++ b/services/surfaceflinger/ScreenCaptureOutput.h
@@ -33,6 +33,8 @@
std::shared_ptr<renderengine::ExternalTexture> buffer;
float sdrWhitePointNits;
float displayBrightnessNits;
+ // Counterintuitively, when targetBrightness > 1.0 then dim the scene.
+ float targetBrightness;
bool regionSampling;
};
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a6f4630..172df03 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1146,17 +1146,26 @@
std::optional<PhysicalDisplayId> displayIdOpt;
{
Mutex::Autolock lock(mStateLock);
- displayIdOpt = getPhysicalDisplayIdLocked(displayToken);
+ if (displayToken) {
+ displayIdOpt = getPhysicalDisplayIdLocked(displayToken);
+ if (!displayIdOpt) {
+ ALOGW("%s: Invalid physical display token %p", __func__, displayToken.get());
+ return NAME_NOT_FOUND;
+ }
+ } else {
+ // TODO (b/277364366): Clients should be updated to pass in the display they
+ // want, rather than us picking an arbitrary one (the active display, in this
+ // case).
+ displayIdOpt = mActiveDisplayId;
+ }
}
- // TODO (b/277364366): Clients should be updated to pass in the display they
- // want, rather than us picking an arbitrary one (the pacesetter, in this
- // case).
- if (displayToken && !displayIdOpt) {
- ALOGE("%s: Invalid physical display token %p", __func__, displayToken.get());
+ const auto schedule = mScheduler->getVsyncSchedule(displayIdOpt);
+ if (!schedule) {
+ ALOGE("%s: Missing VSYNC schedule for display %s!", __func__,
+ to_string(*displayIdOpt).c_str());
return NAME_NOT_FOUND;
}
- const auto schedule = mScheduler->getVsyncSchedule(displayIdOpt);
outStats->vsyncTime = schedule->vsyncDeadlineAfter(TimePoint::now()).ns();
outStats->vsyncPeriod = schedule->period().ns();
return NO_ERROR;
@@ -2136,7 +2145,9 @@
static_cast<void>(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
{
ftl::FakeGuard guard(kMainThreadContext);
- mScheduler->getVsyncSchedule(id)->setPendingHardwareVsyncState(enabled);
+ if (auto schedule = mScheduler->getVsyncSchedule(id)) {
+ schedule->setPendingHardwareVsyncState(enabled);
+ }
}
ATRACE_FORMAT("%s (%d) for %" PRIu64 " (main thread)", whence, enabled, id.value);
@@ -2146,7 +2157,14 @@
}));
}
-auto SurfaceFlinger::getPreviousPresentFence(TimePoint frameTime, Period vsyncPeriod)
+bool SurfaceFlinger::wouldPresentEarly(TimePoint frameTime, Period vsyncPeriod) const {
+ const bool isThreeVsyncsAhead = mExpectedPresentTime - frameTime > 2 * vsyncPeriod;
+ return isThreeVsyncsAhead ||
+ getPreviousPresentFence(frameTime, vsyncPeriod)->getSignalTime() !=
+ Fence::SIGNAL_TIME_PENDING;
+}
+
+auto SurfaceFlinger::getPreviousPresentFence(TimePoint frameTime, Period vsyncPeriod) const
-> const FenceTimePtr& {
const bool isTwoVsyncsAhead = mExpectedPresentTime - frameTime > vsyncPeriod;
const size_t i = static_cast<size_t>(isTwoVsyncsAhead);
@@ -2300,16 +2318,20 @@
sp<Layer> bgColorLayer = getFactory().createEffectLayer(
LayerCreationArgs(this, nullptr, layer->name,
ISurfaceComposerClient::eFXSurfaceEffect, LayerMetadata(),
- std::make_optional(layer->parentId), true));
+ std::make_optional(layer->id), true));
mLegacyLayers[bgColorLayer->sequence] = bgColorLayer;
}
- if (!layer->hasReadyFrame()) continue;
+ const bool willReleaseBufferOnLatch = layer->willReleaseBufferOnLatch();
+ if (!layer->hasReadyFrame() && !willReleaseBufferOnLatch) continue;
auto it = mLegacyLayers.find(layer->id);
LOG_ALWAYS_FATAL_IF(it == mLegacyLayers.end(), "Couldnt find layer object for %s",
layer->getDebugString().c_str());
const bool bgColorOnly =
!layer->externalTexture && (layer->bgColorLayerId != UNASSIGNED_LAYER_ID);
+ if (willReleaseBufferOnLatch) {
+ mLayersWithBuffersRemoved.emplace(it->second);
+ }
it->second->latchBufferImpl(unused, latchTime, bgColorOnly);
mLayersWithQueuedFrames.emplace(it->second);
}
@@ -2610,21 +2632,14 @@
refreshArgs.devOptFlashDirtyRegionsDelay = std::chrono::milliseconds(mDebugFlashDelay);
}
- const auto prevVsyncTime = mExpectedPresentTime - mScheduler->getVsyncSchedule()->period();
- const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration;
-
const Period vsyncPeriod = mScheduler->getVsyncSchedule()->period();
- const bool threeVsyncsAhead = mExpectedPresentTime - frameTime > 2 * vsyncPeriod;
- // We should wait for the earliest present time if HWC doesn't support ExpectedPresentTime,
- // and the next vsync is not already taken by the previous frame.
- const bool waitForEarliestPresent =
- !getHwComposer().getComposer()->isSupported(
- Hwc2::Composer::OptionalFeature::ExpectedPresentTime) &&
- (threeVsyncsAhead ||
- mPreviousPresentFences[0].fenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING);
+ if (!getHwComposer().getComposer()->isSupported(
+ Hwc2::Composer::OptionalFeature::ExpectedPresentTime) &&
+ wouldPresentEarly(frameTime, vsyncPeriod)) {
+ const auto prevVsyncTime = mExpectedPresentTime - vsyncPeriod;
+ const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration;
- if (waitForEarliestPresent) {
refreshArgs.earliestPresentTime = prevVsyncTime - hwcMinWorkDuration;
}
@@ -2644,10 +2659,10 @@
for (auto [layer, layerFE] : layers) {
CompositionResult compositionResult{layerFE->stealCompositionResult()};
layer->onPreComposition(compositionResult.refreshStartTime);
- for (auto releaseFence : compositionResult.releaseFences) {
+ for (auto& [releaseFence, layerStack] : compositionResult.releaseFences) {
Layer* clonedFrom = layer->getClonedFrom().get();
auto owningLayer = clonedFrom ? clonedFrom : layer;
- owningLayer->onLayerDisplayed(releaseFence);
+ owningLayer->onLayerDisplayed(std::move(releaseFence), layerStack);
}
if (compositionResult.lastClientCompositionFence) {
layer->setWasClientComposed(compositionResult.lastClientCompositionFence);
@@ -2658,9 +2673,10 @@
// Send a power hint hint after presentation is finished
if (mPowerHintSessionEnabled) {
- mPowerAdvisor->setSfPresentTiming(TimePoint::fromNs(mPreviousPresentFences[0]
- .fenceTime->getSignalTime()),
- TimePoint::now());
+ const nsecs_t pastPresentTime =
+ getPreviousPresentFence(frameTime, vsyncPeriod)->getSignalTime();
+
+ mPowerAdvisor->setSfPresentTiming(TimePoint::fromNs(pastPresentTime), TimePoint::now());
mPowerAdvisor->reportActualWorkDuration();
}
@@ -2858,6 +2874,32 @@
const CompositorTiming compositorTiming(vsyncDeadline.ns(), vsyncPeriod.ns(), vsyncPhase,
presentLatency.ns());
+ display::DisplayMap<ui::LayerStack, const DisplayDevice*> layerStackToDisplay;
+ {
+ if (!mLayersWithBuffersRemoved.empty() || mNumTrustedPresentationListeners > 0) {
+ Mutex::Autolock lock(mStateLock);
+ for (const auto& [token, display] : mDisplays) {
+ layerStackToDisplay.emplace_or_replace(display->getLayerStack(), display.get());
+ }
+ }
+ }
+
+ for (auto layer : mLayersWithBuffersRemoved) {
+ std::vector<ui::LayerStack> previouslyPresentedLayerStacks =
+ std::move(layer->mPreviouslyPresentedLayerStacks);
+ layer->mPreviouslyPresentedLayerStacks.clear();
+ for (auto layerStack : previouslyPresentedLayerStacks) {
+ auto optDisplay = layerStackToDisplay.get(layerStack);
+ if (optDisplay && !optDisplay->get()->isVirtual()) {
+ auto fence = getHwComposer().getPresentFence(optDisplay->get()->getPhysicalId());
+ layer->onLayerDisplayed(ftl::yield<FenceResult>(fence).share(),
+ ui::INVALID_LAYER_STACK);
+ }
+ }
+ layer->releasePendingBuffer(presentTime.ns());
+ }
+ mLayersWithBuffersRemoved.clear();
+
for (const auto& layer: mLayersWithQueuedFrames) {
layer->onPostComposition(defaultDisplay, glCompositionDoneFenceTime, presentFenceTime,
compositorTiming);
@@ -2984,14 +3026,6 @@
}
if (mNumTrustedPresentationListeners > 0) {
- display::DisplayMap<ui::LayerStack, const DisplayDevice*> layerStackToDisplay;
- {
- Mutex::Autolock lock(mStateLock);
- for (const auto& [token, display] : mDisplays) {
- layerStackToDisplay.emplace_or_replace(display->getLayerStack(), display.get());
- }
- }
-
// We avoid any reverse traversal upwards so this shouldn't be too expensive
traverseLegacyLayers([&](Layer* layer) {
if (!layer->hasTrustedPresentationListener()) {
@@ -3699,10 +3733,10 @@
}
void SurfaceFlinger::updateInputFlinger() {
- ATRACE_CALL();
- if (!mInputFlinger) {
+ if (!mInputFlinger || (!mUpdateInputInfo && mInputWindowCommands.empty())) {
return;
}
+ ATRACE_CALL();
std::vector<WindowInfo> windowInfos;
std::vector<DisplayInfo> displayInfos;
@@ -3711,20 +3745,18 @@
mUpdateInputInfo = false;
updateWindowInfo = true;
buildWindowInfos(windowInfos, displayInfos);
- } else if (mInputWindowCommands.empty()) {
- return;
}
- std::unordered_set<Layer*> visibleLayers;
- mDrawingState.traverse([&visibleLayers](Layer* layer) {
- if (layer->isVisibleForInput()) {
- visibleLayers.insert(layer);
+ std::unordered_set<int32_t> visibleWindowIds;
+ for (WindowInfo& windowInfo : windowInfos) {
+ if (!windowInfo.inputConfig.test(WindowInfo::InputConfig::NOT_VISIBLE)) {
+ visibleWindowIds.insert(windowInfo.id);
}
- });
- bool visibleLayersChanged = false;
- if (visibleLayers != mVisibleLayers) {
- visibleLayersChanged = true;
- mVisibleLayers = std::move(visibleLayers);
+ }
+ bool visibleWindowsChanged = false;
+ if (visibleWindowIds != mVisibleWindowIds) {
+ visibleWindowsChanged = true;
+ mVisibleWindowIds = std::move(visibleWindowIds);
}
BackgroundExecutor::getInstance().sendCallbacks({[updateWindowInfo,
@@ -3733,14 +3765,14 @@
inputWindowCommands =
std::move(mInputWindowCommands),
inputFlinger = mInputFlinger, this,
- visibleLayersChanged]() {
+ visibleWindowsChanged]() {
ATRACE_NAME("BackgroundExecutor::updateInputFlinger");
if (updateWindowInfo) {
mWindowInfosListenerInvoker
->windowInfosChanged(std::move(windowInfos), std::move(displayInfos),
std::move(
inputWindowCommands.windowInfosReportedListeners),
- /* forceImmediateCall= */ visibleLayersChanged ||
+ /* forceImmediateCall= */ visibleWindowsChanged ||
!inputWindowCommands.focusRequests.empty());
} else {
// If there are listeners but no changes to input windows, call the listeners
@@ -3988,8 +4020,21 @@
}
commitOffscreenLayers();
- if (mNumClones > 0) {
- mDrawingState.traverse([&](Layer* layer) { layer->updateMirrorInfo(); });
+ if (mLayerMirrorRoots.size() > 0) {
+ std::deque<Layer*> pendingUpdates;
+ pendingUpdates.insert(pendingUpdates.end(), mLayerMirrorRoots.begin(),
+ mLayerMirrorRoots.end());
+ std::vector<Layer*> needsUpdating;
+ for (Layer* cloneRoot : mLayerMirrorRoots) {
+ pendingUpdates.pop_front();
+ if (cloneRoot->updateMirrorInfo(pendingUpdates)) {
+ } else {
+ needsUpdating.push_back(cloneRoot);
+ }
+ }
+ for (Layer* cloneRoot : needsUpdating) {
+ cloneRoot->updateMirrorInfo({});
+ }
}
}
@@ -4039,7 +4084,7 @@
}
}
- if (layer->hasReadyFrame()) {
+ if (layer->hasReadyFrame() || layer->willReleaseBufferOnLatch()) {
frameQueued = true;
mLayersWithQueuedFrames.emplace(sp<Layer>::fromExisting(layer));
} else {
@@ -4070,6 +4115,9 @@
Mutex::Autolock lock(mStateLock);
for (const auto& layer : mLayersWithQueuedFrames) {
+ if (layer->willReleaseBufferOnLatch()) {
+ mLayersWithBuffersRemoved.emplace(layer);
+ }
if (layer->latchBuffer(visibleRegions, latchTime)) {
mLayersPendingRefresh.push_back(layer);
newDataLatched = true;
@@ -4093,7 +4141,7 @@
mBootStage = BootStage::BOOTANIMATION;
}
- if (mNumClones > 0) {
+ if (mLayerMirrorRoots.size() > 0) {
mDrawingState.traverse([&](Layer* layer) { layer->updateCloneBufferInfo(); });
}
@@ -5069,7 +5117,8 @@
}
if (layer->setTransactionCompletedListeners(callbackHandles,
- layer->willPresentCurrentTransaction())) {
+ layer->willPresentCurrentTransaction() ||
+ layer->willReleaseBufferOnLatch())) {
flags |= eTraversalNeeded;
}
@@ -5183,8 +5232,9 @@
}
const auto& requestedLayerState = mLayerLifecycleManager.getLayerFromId(layer->getSequence());
- bool willPresentCurrentTransaction =
- requestedLayerState && requestedLayerState->hasReadyFrame();
+ bool willPresentCurrentTransaction = requestedLayerState &&
+ (requestedLayerState->hasReadyFrame() ||
+ requestedLayerState->willReleaseBufferOnLatch());
if (layer->setTransactionCompletedListeners(callbackHandles, willPresentCurrentTransaction))
flags |= eTraversalNeeded;
@@ -5220,7 +5270,7 @@
return result;
}
- mirrorLayer->setClonedChild(mirrorFrom->createClone());
+ mirrorLayer->setClonedChild(mirrorFrom->createClone(mirrorLayer->getSequence()));
}
outResult.layerId = mirrorLayer->sequence;
@@ -5847,8 +5897,8 @@
return layersProto;
}
- return LayerProtoFromSnapshotGenerator(mLayerSnapshotBuilder, mFrontEndDisplayInfos, {},
- traceFlags)
+ return LayerProtoFromSnapshotGenerator(mLayerSnapshotBuilder, mFrontEndDisplayInfos,
+ mLegacyLayers, traceFlags)
.generate(mLayerHierarchyBuilder.getHierarchy());
}
@@ -6892,6 +6942,32 @@
return NO_ERROR;
}
+namespace {
+
+ui::Dataspace pickBestDataspace(ui::Dataspace requestedDataspace, const DisplayDevice* display,
+ bool capturingHdrLayers, bool hintForSeamlessTransition) {
+ if (requestedDataspace != ui::Dataspace::UNKNOWN || display == nullptr) {
+ return requestedDataspace;
+ }
+
+ const auto& state = display->getCompositionDisplay()->getState();
+
+ const auto dataspaceForColorMode = ui::pickDataspaceFor(state.colorMode);
+
+ if (capturingHdrLayers && !hintForSeamlessTransition) {
+ // For now since we only support 8-bit screenshots, just use HLG and
+ // assume that 1.0 >= display max luminance. This isn't quite as future
+ // proof as PQ is, but is good enough.
+ // Consider using PQ once we support 16-bit screenshots and we're able
+ // to consistently supply metadata to image encoders.
+ return ui::Dataspace::BT2020_HLG;
+ }
+
+ return dataspaceForColorMode;
+}
+
+} // namespace
+
status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args,
const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();
@@ -6907,7 +6983,6 @@
ui::LayerStack layerStack;
ui::Size reqSize(args.width, args.height);
std::unordered_set<uint32_t> excludeLayerIds;
- ui::Dataspace dataspace;
{
Mutex::Autolock lock(mStateLock);
sp<DisplayDevice> display = getDisplayDeviceLocked(args.displayToken);
@@ -6929,17 +7004,12 @@
return NAME_NOT_FOUND;
}
}
-
- // Allow the caller to specify a dataspace regardless of the display's color mode, e.g. if
- // it wants sRGB regardless of the display's wide color mode.
- dataspace = args.dataspace == ui::Dataspace::UNKNOWN
- ? ui::pickDataspaceFor(display->getCompositionDisplay()->getState().colorMode)
- : args.dataspace;
}
RenderAreaFuture renderAreaFuture = ftl::defer([=] {
- return DisplayRenderArea::create(displayWeak, args.sourceCrop, reqSize, dataspace,
- args.useIdentityTransform, args.captureSecureLayers);
+ return DisplayRenderArea::create(displayWeak, args.sourceCrop, reqSize,
+ ui::Dataspace::UNKNOWN, args.useIdentityTransform,
+ args.hintForSeamlessTransition, args.captureSecureLayers);
});
GetLayerSnapshotsFunction getLayerSnapshots;
@@ -6965,7 +7035,6 @@
ui::LayerStack layerStack;
wp<const DisplayDevice> displayWeak;
ui::Size size;
- ui::Dataspace dataspace;
{
Mutex::Autolock lock(mStateLock);
@@ -6977,12 +7046,12 @@
displayWeak = display;
layerStack = display->getLayerStack();
size = display->getLayerStackSpaceRect().getSize();
- dataspace = ui::pickDataspaceFor(display->getCompositionDisplay()->getState().colorMode);
}
RenderAreaFuture renderAreaFuture = ftl::defer([=] {
- return DisplayRenderArea::create(displayWeak, Rect(), size, dataspace,
+ return DisplayRenderArea::create(displayWeak, Rect(), size, ui::Dataspace::UNKNOWN,
false /* useIdentityTransform */,
+ false /* hintForSeamlessTransition */,
false /* captureSecureLayers */);
});
@@ -7024,7 +7093,7 @@
sp<Layer> parent;
Rect crop(args.sourceCrop);
std::unordered_set<uint32_t> excludeLayerIds;
- ui::Dataspace dataspace;
+ ui::Dataspace dataspace = args.dataspace;
// Call this before holding mStateLock to avoid any deadlocking.
bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();
@@ -7071,12 +7140,6 @@
return NAME_NOT_FOUND;
}
}
-
- // The dataspace is depended on the color mode of display, that could use non-native mode
- // (ex. displayP3) to enhance the content, but some cases are checking native RGB in bytes,
- // and failed if display is not in native mode. This provide a way to force using native
- // colors when capture.
- dataspace = args.dataspace;
} // mStateLock
// really small crop or frameScale
@@ -7105,7 +7168,8 @@
return std::make_unique<LayerRenderArea>(*this, parent, crop, reqSize, dataspace,
childrenOnly, args.captureSecureLayers,
- layerTransform, layerBufferSize);
+ layerTransform, layerBufferSize,
+ args.hintForSeamlessTransition);
});
GetLayerSnapshotsFunction getLayerSnapshots;
if (mLayerLifecycleManagerEnabled) {
@@ -7291,29 +7355,48 @@
return ftl::yield<FenceResult>(base::unexpected(PERMISSION_DENIED)).share();
}
- captureResults.buffer = buffer->getBuffer();
- auto dataspace = renderArea->getReqDataSpace();
+ auto capturedBuffer = buffer;
+
+ auto requestedDataspace = renderArea->getReqDataSpace();
auto parent = renderArea->getParentLayer();
auto renderIntent = RenderIntent::TONE_MAP_COLORIMETRIC;
auto sdrWhitePointNits = DisplayDevice::sDefaultMaxLumiance;
auto displayBrightnessNits = DisplayDevice::sDefaultMaxLumiance;
- if (dataspace == ui::Dataspace::UNKNOWN && parent) {
+ captureResults.capturedDataspace = requestedDataspace;
+
+ {
Mutex::Autolock lock(mStateLock);
- auto display = findDisplay([layerStack = parent->getLayerStack()](const auto& display) {
- return display.getLayerStack() == layerStack;
- });
- if (!display) {
- // If the layer is not on a display, use the dataspace for the default display.
- display = getDefaultDisplayDeviceLocked();
+ const DisplayDevice* display = nullptr;
+ if (parent) {
+ display = findDisplay([layerStack = parent->getLayerStack()](const auto& display) {
+ return display.getLayerStack() == layerStack;
+ }).get();
}
- dataspace = ui::pickDataspaceFor(display->getCompositionDisplay()->getState().colorMode);
- renderIntent = display->getCompositionDisplay()->getState().renderIntent;
- sdrWhitePointNits = display->getCompositionDisplay()->getState().sdrWhitePointNits;
- displayBrightnessNits = display->getCompositionDisplay()->getState().displayBrightnessNits;
+ if (display == nullptr) {
+ display = renderArea->getDisplayDevice().get();
+ }
+
+ if (display == nullptr) {
+ display = getDefaultDisplayDeviceLocked().get();
+ }
+
+ if (display != nullptr) {
+ const auto& state = display->getCompositionDisplay()->getState();
+ captureResults.capturedDataspace =
+ pickBestDataspace(requestedDataspace, display, captureResults.capturedHdrLayers,
+ renderArea->getHintForSeamlessTransition());
+ sdrWhitePointNits = state.sdrWhitePointNits;
+ displayBrightnessNits = state.displayBrightnessNits;
+
+ if (requestedDataspace == ui::Dataspace::UNKNOWN) {
+ renderIntent = state.renderIntent;
+ }
+ }
}
- captureResults.capturedDataspace = dataspace;
+
+ captureResults.buffer = capturedBuffer->getBuffer();
ui::LayerStack layerStack{ui::DEFAULT_LAYER_STACK};
if (!layers.empty()) {
@@ -7330,9 +7413,9 @@
return layerFEs;
};
- auto present = [this, buffer = std::move(buffer), dataspace, sdrWhitePointNits,
- displayBrightnessNits, grayscale, layerFEs = copyLayerFEs(), layerStack,
- regionSampling, renderArea = std::move(renderArea),
+ auto present = [this, buffer = capturedBuffer, dataspace = captureResults.capturedDataspace,
+ sdrWhitePointNits, displayBrightnessNits, grayscale, layerFEs = copyLayerFEs(),
+ layerStack, regionSampling, renderArea = std::move(renderArea),
renderIntent]() -> FenceResult {
std::unique_ptr<compositionengine::CompositionEngine> compositionEngine =
mFactory.createCompositionEngine();
@@ -7341,6 +7424,16 @@
compositionengine::Output::ColorProfile colorProfile{.dataspace = dataspace,
.renderIntent = renderIntent};
+ float targetBrightness = 1.0f;
+ if (dataspace == ui::Dataspace::BT2020_HLG) {
+ const float maxBrightnessNits = displayBrightnessNits / sdrWhitePointNits * 203;
+ // With a low dimming ratio, don't fit the entire curve. Otherwise mixed content
+ // will appear way too bright.
+ if (maxBrightnessNits < 1000.f) {
+ targetBrightness = 1000.f / maxBrightnessNits;
+ }
+ }
+
std::shared_ptr<ScreenCaptureOutput> output = createScreenCaptureOutput(
ScreenCaptureOutputArgs{.compositionEngine = *compositionEngine,
.colorProfile = colorProfile,
@@ -7349,6 +7442,7 @@
.buffer = std::move(buffer),
.sdrWhitePointNits = sdrWhitePointNits,
.displayBrightnessNits = displayBrightnessNits,
+ .targetBrightness = targetBrightness,
.regionSampling = regionSampling});
const float colorSaturation = grayscale ? 0 : 1;
@@ -7380,12 +7474,14 @@
: ftl::yield(present()).share();
for (auto& [layer, layerFE] : layers) {
- layer->onLayerDisplayed(
- ftl::Future(presentFuture)
- .then([layerFE = std::move(layerFE)](FenceResult) {
- return layerFE->stealCompositionResult().releaseFences.back().get();
- })
- .share());
+ layer->onLayerDisplayed(ftl::Future(presentFuture)
+ .then([layerFE = std::move(layerFE)](FenceResult) {
+ return layerFE->stealCompositionResult()
+ .releaseFences.back()
+ .first.get();
+ })
+ .share(),
+ ui::INVALID_LAYER_STACK);
}
return presentFuture;
@@ -7953,7 +8049,7 @@
Mutex::Autolock lock(mStateLock);
createEffectLayer(mirrorArgs, &unused, &childMirror);
MUTEX_ALIAS(mStateLock, childMirror->mFlinger->mStateLock);
- childMirror->setClonedChild(layer->createClone());
+ childMirror->setClonedChild(layer->createClone(childMirror->getSequence()));
childMirror->reparent(mirrorDisplay.rootHandle);
}
// lock on mStateLock needs to be released before binder handle gets destroyed
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 04fcfb9..92e19c0 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -296,8 +296,7 @@
// the client can no longer modify this layer directly.
void onHandleDestroyed(BBinder* handle, sp<Layer>& layer, uint32_t layerId);
- // TODO: Remove atomic if move dtor to main thread CL lands
- std::atomic<uint32_t> mNumClones;
+ std::vector<Layer*> mLayerMirrorRoots;
TransactionCallbackInvoker& getTransactionCallbackInvoker() {
return mTransactionCallbackInvoker;
@@ -998,7 +997,9 @@
using FenceTimePtr = std::shared_ptr<FenceTime>;
- const FenceTimePtr& getPreviousPresentFence(TimePoint frameTime, Period)
+ bool wouldPresentEarly(TimePoint frameTime, Period) const REQUIRES(kMainThreadContext);
+
+ const FenceTimePtr& getPreviousPresentFence(TimePoint frameTime, Period) const
REQUIRES(kMainThreadContext);
// Blocks the thread waiting for up to graceTimeMs in case the fence is about to signal.
@@ -1193,6 +1194,7 @@
// Tracks layers that have pending frames which are candidates for being
// latched.
std::unordered_set<sp<Layer>, SpHash<Layer>> mLayersWithQueuedFrames;
+ std::unordered_set<sp<Layer>, SpHash<Layer>> mLayersWithBuffersRemoved;
// Tracks layers that need to update a display's dirty region.
std::vector<sp<Layer>> mLayersPendingRefresh;
@@ -1427,10 +1429,8 @@
display::DisplayMap<ui::LayerStack, frontend::DisplayInfo> mFrontEndDisplayInfos;
bool mFrontEndDisplayInfosChanged = false;
- // Layers visible during the last commit. This set should only be used for testing set equality
- // and membership. The pointers should not be dereferenced as it's possible the set contains
- // pointers to freed layers.
- std::unordered_set<Layer*> mVisibleLayers;
+ // WindowInfo ids visible during the last commit.
+ std::unordered_set<int32_t> mVisibleWindowIds;
};
class SurfaceComposerAIDL : public gui::BnSurfaceComposer {
diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h
index 2daea25..35c8b6c 100644
--- a/services/surfaceflinger/TransactionState.h
+++ b/services/surfaceflinger/TransactionState.h
@@ -78,8 +78,7 @@
template <typename Visitor>
void traverseStatesWithBuffers(Visitor&& visitor) const {
for (const auto& state : states) {
- if (state.state.hasBufferChanges() && state.state.hasValidBuffer() &&
- state.state.surface) {
+ if (state.state.hasBufferChanges() && state.externalTexture && state.state.surface) {
visitor(state.state);
}
}
@@ -88,8 +87,7 @@
template <typename Visitor>
void traverseStatesWithBuffersWhileTrue(Visitor&& visitor) {
for (auto state = states.begin(); state != states.end();) {
- if (state->state.hasBufferChanges() && state->state.hasValidBuffer() &&
- state->state.surface) {
+ if (state->state.hasBufferChanges() && state->externalTexture && state->state.surface) {
int result = visitor(state->state, state->externalTexture);
if (result == STOP_TRAVERSAL) return;
if (result == DELETE_AND_CONTINUE_TRAVERSAL) {
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
index a9247fe..9fac14e 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
@@ -327,7 +327,6 @@
invokeComposerHal2_4(&composer, display, outLayer);
composer.executeCommands(display);
- composer.resetCommands(display);
composer.destroyLayer(display, outLayer);
composer.destroyVirtualDisplay(display);
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
index 4304259..921cae4 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
@@ -125,9 +125,12 @@
mFdp.ConsumeIntegral<int64_t>(),
mFdp.ConsumeIntegral<int64_t>());
- layer->onLayerDisplayed(ftl::yield<FenceResult>(fence).share());
- layer->onLayerDisplayed(
- ftl::yield<FenceResult>(base::unexpected(mFdp.ConsumeIntegral<status_t>())).share());
+ layer->onLayerDisplayed(ftl::yield<FenceResult>(fence).share(),
+ ui::LayerStack::fromValue(mFdp.ConsumeIntegral<uint32_t>()));
+ layer->onLayerDisplayed(ftl::yield<FenceResult>(
+ base::unexpected(mFdp.ConsumeIntegral<status_t>()))
+ .share(),
+ ui::LayerStack::fromValue(mFdp.ConsumeIntegral<uint32_t>()));
layer->releasePendingBuffer(mFdp.ConsumeIntegral<int64_t>());
layer->onPostComposition(nullptr, fenceTime, fenceTime, compositorTiming);
@@ -174,7 +177,8 @@
{mFdp.ConsumeIntegral<int32_t>(),
mFdp.ConsumeIntegral<int32_t>()} /*reqSize*/,
mFdp.PickValueInArray(kDataspaces), mFdp.ConsumeBool(),
- mFdp.ConsumeBool(), getFuzzedTransform(), getFuzzedRect());
+ mFdp.ConsumeBool(), getFuzzedTransform(), getFuzzedRect(),
+ mFdp.ConsumeBool());
layerArea.render([]() {} /*drawLayers*/);
if (!ownsHandle) {
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
index a32750e..8061a8f 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
@@ -75,7 +75,7 @@
bool isVisible() const override { return true; }
- sp<Layer> createClone() override { return nullptr; }
+ sp<Layer> createClone(uint32_t /* mirrorRootId */) override { return nullptr; }
};
class FuzzImplVSyncTracker : public scheduler::VSyncTracker {
diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp
index 26dbc76..79886bd 100644
--- a/services/surfaceflinger/tests/LayerCallback_test.cpp
+++ b/services/surfaceflinger/tests/LayerCallback_test.cpp
@@ -1224,4 +1224,75 @@
EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
}
+TEST_F(LayerCallbackTest, SetNullBuffer) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayerWithBuffer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer, /*setBuffer=*/true,
+ /*setBackgroundColor=*/false);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ transaction.apply();
+
+ {
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::ACQUIRED,
+ ExpectedResult::PreviousBuffer::NOT_RELEASED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+ }
+
+ transaction.setBuffer(layer, nullptr);
+ transaction.addTransactionCompletedCallback(callback.function, callback.getContext());
+ transaction.apply();
+
+ {
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::ACQUIRED_NULL,
+ ExpectedResult::PreviousBuffer::RELEASED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+ }
+
+ err = fillTransaction(transaction, &callback, layer, /*setBuffer=*/true,
+ /*setBackgroundColor=*/false);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.apply();
+
+ {
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::ACQUIRED,
+ ExpectedResult::PreviousBuffer::NOT_RELEASED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+ }
+}
+
+TEST_F(LayerCallbackTest, SetNullBufferOnLayerWithoutBuffer) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayerWithBuffer());
+
+ Transaction transaction;
+ transaction.setBuffer(layer, nullptr);
+ CallbackHelper callback;
+ transaction.addTransactionCompletedCallback(callback.function, callback.getContext());
+ transaction.apply();
+
+ {
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED,
+ ExpectedResult::PreviousBuffer::NOT_RELEASED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+ }
+}
+
} // namespace android
diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
index 0b8c51e..b8068f7 100644
--- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
@@ -1636,6 +1636,65 @@
getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
}
}
+
+TEST_P(LayerRenderTypeTransactionTest, SetNullBuffer) {
+ const Rect bounds(0, 0, 32, 32);
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ sp<GraphicBuffer> buffer =
+ sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test");
+
+ ASSERT_NO_FATAL_FAILURE(TransactionUtils::fillGraphicBufferColor(buffer, bounds, Color::GREEN));
+ Transaction().setBuffer(layer, buffer).apply();
+ {
+ SCOPED_TRACE("before null buffer");
+ auto shot = getScreenCapture();
+ shot->expectColor(bounds, Color::GREEN);
+ }
+
+ Transaction().setBuffer(layer, nullptr).apply();
+ {
+ SCOPED_TRACE("null buffer removes buffer");
+ auto shot = getScreenCapture();
+ shot->expectColor(bounds, Color::BLACK);
+ }
+
+ Transaction().setBuffer(layer, buffer).apply();
+ {
+ SCOPED_TRACE("after null buffer");
+ auto shot = getScreenCapture();
+ shot->expectColor(bounds, Color::GREEN);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetNullBufferOnLayerWithoutBuffer) {
+ const Rect bounds(0, 0, 32, 32);
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ {
+ SCOPED_TRACE("starting state");
+ auto shot = getScreenCapture();
+ shot->expectColor(bounds, Color::BLACK);
+ }
+
+ Transaction().setBuffer(layer, nullptr).apply();
+ {
+ SCOPED_TRACE("null buffer has no effect");
+ auto shot = getScreenCapture();
+ shot->expectColor(bounds, Color::BLACK);
+ }
+
+ Transaction().setBuffer(layer, nullptr).apply();
+ {
+ SCOPED_TRACE("null buffer has no effect");
+ auto shot = getScreenCapture();
+ shot->expectColor(bounds, Color::BLACK);
+ }
+}
+
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/tests/tracing/Android.bp b/services/surfaceflinger/tests/tracing/Android.bp
index aa6c74e..21ebaea 100644
--- a/services/surfaceflinger/tests/tracing/Android.bp
+++ b/services/surfaceflinger/tests/tracing/Android.bp
@@ -30,7 +30,7 @@
],
test_suites: ["device-tests"],
sanitize: {
- address: false,
+ address: true,
},
srcs: [
":libsurfaceflinger_sources",
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 201d37f..55705ca 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -104,6 +104,7 @@
"SurfaceFlinger_DisplayTransactionCommitTest.cpp",
"SurfaceFlinger_ExcludeDolbyVisionTest.cpp",
"SurfaceFlinger_GetDisplayNativePrimariesTest.cpp",
+ "SurfaceFlinger_GetDisplayStatsTest.cpp",
"SurfaceFlinger_HdrOutputControlTest.cpp",
"SurfaceFlinger_HotplugTest.cpp",
"SurfaceFlinger_InitializeDisplaysTest.cpp",
@@ -128,6 +129,7 @@
"TransactionTracingTest.cpp",
"TunnelModeEnabledReporterTest.cpp",
"StrongTypingTest.cpp",
+ "VSyncCallbackRegistrationTest.cpp",
"VSyncDispatchTimerQueueTest.cpp",
"VSyncDispatchRealtimeTest.cpp",
"VsyncModulatorTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 156007b..6ca21bd 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -200,7 +200,7 @@
constexpr bool regionSampling = false;
auto renderArea = DisplayRenderArea::create(mDisplay, sourceCrop, sourceCrop.getSize(),
- ui::Dataspace::V0_SRGB, ui::Transform::ROT_0);
+ ui::Dataspace::V0_SRGB, true, true);
auto traverseLayers = [this](const LayerVector::Visitor& visitor) {
return mFlinger.traverseLayersInLayerStack(mDisplay->getLayerStack(),
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index dc76b4c..965e378 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -359,7 +359,8 @@
EXPECT_EQ(expectedChoices, actualChoices);
}
{
- // This display does not support 120 Hz, so we should choose 60 Hz despite the touch signal.
+ // The kDisplayId3 does not support 120Hz, The pacesetter display rate is chosen to be 120
+ // Hz. In this case only the display kDisplayId3 choose 60Hz as it does not support 120Hz.
mScheduler
->registerDisplay(kDisplayId3,
std::make_shared<RefreshRateSelector>(kDisplay3Modes,
@@ -371,6 +372,26 @@
expectedChoices = ftl::init::map<
const PhysicalDisplayId&,
+ DisplayModeChoice>(kDisplayId1, FrameRateMode{120_Hz, kDisplay1Mode120},
+ globalSignals)(kDisplayId2,
+ FrameRateMode{120_Hz, kDisplay2Mode120},
+ globalSignals)(kDisplayId3,
+ FrameRateMode{60_Hz,
+ kDisplay3Mode60},
+ globalSignals);
+
+ const auto actualChoices = mScheduler->chooseDisplayModes();
+ EXPECT_EQ(expectedChoices, actualChoices);
+ }
+ {
+ // We should choose 60Hz despite the touch signal as pacesetter only supports 60Hz
+ mScheduler->setPacesetterDisplay(kDisplayId3);
+ const GlobalSignals globalSignals = {.touch = true};
+ mScheduler->replaceTouchTimer(10);
+ mScheduler->setTouchStateAndIdleTimerPolicy(globalSignals);
+
+ expectedChoices = ftl::init::map<
+ const PhysicalDisplayId&,
DisplayModeChoice>(kDisplayId1, FrameRateMode{60_Hz, kDisplay1Mode60},
globalSignals)(kDisplayId2,
FrameRateMode{60_Hz, kDisplay2Mode60},
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayStatsTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayStatsTest.cpp
new file mode 100644
index 0000000..29acfaa
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayStatsTest.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2023 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 "SurfaceFlingerGetDisplayStatsTest"
+
+#include <compositionengine/Display.h>
+#include <compositionengine/mock/DisplaySurface.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <renderengine/mock/RenderEngine.h>
+#include <ui/DisplayStatInfo.h>
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/DisplayHardware/MockPowerAdvisor.h"
+#include "mock/MockTimeStats.h"
+#include "mock/system/window/MockNativeWindow.h"
+
+using namespace android;
+using namespace testing;
+
+namespace android {
+namespace {
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
+
+constexpr hal::HWDisplayId HWC_DISPLAY = FakeHwcDisplayInjector::DEFAULT_HWC_DISPLAY_ID;
+constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u);
+constexpr int DEFAULT_DISPLAY_WIDTH = 1920;
+constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
+
+class SurfaceFlingerGetDisplayStatsTest : public Test {
+public:
+ void SetUp() override;
+
+protected:
+ TestableSurfaceFlinger mFlinger;
+ renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
+ sp<DisplayDevice> mDisplay;
+ sp<compositionengine::mock::DisplaySurface> mDisplaySurface =
+ sp<compositionengine::mock::DisplaySurface>::make();
+ sp<mock::NativeWindow> mNativeWindow = sp<mock::NativeWindow>::make();
+ mock::TimeStats* mTimeStats = new mock::TimeStats();
+ Hwc2::mock::PowerAdvisor* mPowerAdvisor = nullptr;
+ Hwc2::mock::Composer* mComposer = nullptr;
+};
+
+void SurfaceFlingerGetDisplayStatsTest::SetUp() {
+ mFlinger.setupMockScheduler({.displayId = DEFAULT_DISPLAY_ID});
+ mComposer = new Hwc2::mock::Composer();
+ mPowerAdvisor = new Hwc2::mock::PowerAdvisor();
+ mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
+ mFlinger.setupTimeStats(std::shared_ptr<TimeStats>(mTimeStats));
+ mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+ mFlinger.setupPowerAdvisor(std::unique_ptr<Hwc2::PowerAdvisor>(mPowerAdvisor));
+ static constexpr bool kIsPrimary = true;
+ FakeHwcDisplayInjector(DEFAULT_DISPLAY_ID, hal::DisplayType::PHYSICAL, kIsPrimary)
+ .setPowerMode(hal::PowerMode::ON)
+ .inject(&mFlinger, mComposer);
+ auto compostionEngineDisplayArgs =
+ compositionengine::DisplayCreationArgsBuilder()
+ .setId(DEFAULT_DISPLAY_ID)
+ .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
+ .setPowerAdvisor(mPowerAdvisor)
+ .setName("injected display")
+ .build();
+ auto compositionDisplay =
+ compositionengine::impl::createDisplay(mFlinger.getCompositionEngine(),
+ std::move(compostionEngineDisplayArgs));
+ mDisplay =
+ FakeDisplayDeviceInjector(mFlinger, compositionDisplay,
+ ui::DisplayConnectionType::Internal, HWC_DISPLAY, kIsPrimary)
+ .setDisplaySurface(mDisplaySurface)
+ .setNativeWindow(mNativeWindow)
+ .setPowerMode(hal::PowerMode::ON)
+ .setRefreshRateSelector(mFlinger.scheduler()->refreshRateSelector())
+ .skipRegisterDisplay()
+ .inject();
+}
+
+// TODO (b/277364366): Clients should be updated to pass in the display they want.
+TEST_F(SurfaceFlingerGetDisplayStatsTest, nullptrSucceeds) {
+ DisplayStatInfo info;
+ status_t status = mFlinger.getDisplayStats(nullptr, &info);
+ EXPECT_EQ(status, NO_ERROR);
+}
+
+TEST_F(SurfaceFlingerGetDisplayStatsTest, explicitToken) {
+ DisplayStatInfo info;
+ status_t status = mFlinger.getDisplayStats(mDisplay->getDisplayToken().promote(), &info);
+ EXPECT_EQ(status, NO_ERROR);
+}
+
+TEST_F(SurfaceFlingerGetDisplayStatsTest, invalidToken) {
+ const String8 displayName("fakeDisplay");
+ sp<IBinder> displayToken = mFlinger.createDisplay(displayName, false);
+ DisplayStatInfo info;
+ status_t status = mFlinger.getDisplayStats(displayToken, &info);
+ EXPECT_EQ(status, NAME_NOT_FOUND);
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index f1a5fc4..3b6a987 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -65,10 +65,6 @@
auto refreshRateSelector() { return pacesetterSelectorPtr(); }
- const auto& refreshRateSelectors() const NO_THREAD_SAFETY_ANALYSIS {
- return mRefreshRateSelectors;
- }
-
void registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr) {
registerDisplay(displayId, std::move(selectorPtr),
std::make_unique<mock::VsyncController>(),
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index cfa366f..a189c00 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -56,6 +56,9 @@
#include "mock/system/window/MockNativeWindow.h"
namespace android {
+
+struct DisplayStatInfo;
+
namespace renderengine {
class RenderEngine;
@@ -545,6 +548,10 @@
return sp<DisplayDevice>::make(creationArgs);
}
+ status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* outInfo) {
+ return mFlinger->getDisplayStats(displayToken, outInfo);
+ }
+
/* ------------------------------------------------------------------------
* Read-only access to private data to assert post-conditions.
*/
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 03c4e71..dbb7c6c 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -274,6 +274,34 @@
EXPECT_EQ(nullptr, ret.get());
}
+class FakeExternalTexture : public renderengine::ExternalTexture {
+ const sp<GraphicBuffer> mEmptyBuffer = nullptr;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ uint64_t mId;
+ PixelFormat mPixelFormat;
+ uint64_t mUsage;
+
+public:
+ FakeExternalTexture(BufferData& bufferData)
+ : mWidth(bufferData.getWidth()),
+ mHeight(bufferData.getHeight()),
+ mId(bufferData.getId()),
+ mPixelFormat(bufferData.getPixelFormat()),
+ mUsage(bufferData.getUsage()) {}
+ const sp<GraphicBuffer>& getBuffer() const { return mEmptyBuffer; }
+ bool hasSameBuffer(const renderengine::ExternalTexture& other) const override {
+ return getId() == other.getId();
+ }
+ uint32_t getWidth() const override { return mWidth; }
+ uint32_t getHeight() const override { return mHeight; }
+ uint64_t getId() const override { return mId; }
+ PixelFormat getPixelFormat() const override { return mPixelFormat; }
+ uint64_t getUsage() const override { return mUsage; }
+ void remapBuffer() override {}
+ ~FakeExternalTexture() = default;
+};
+
class LatchUnsignaledTest : public TransactionApplicationTest {
public:
void TearDown() override {
@@ -346,7 +374,11 @@
std::vector<ResolvedComposerState> resolvedStates;
resolvedStates.reserve(transaction.states.size());
for (auto& state : transaction.states) {
- resolvedStates.emplace_back(std::move(state));
+ ResolvedComposerState resolvedState;
+ resolvedState.state = std::move(state.state);
+ resolvedState.externalTexture =
+ std::make_shared<FakeExternalTexture>(*resolvedState.state.bufferData);
+ resolvedStates.emplace_back(resolvedState);
}
TransactionState transactionState(transaction.frameTimelineInfo, resolvedStates,
diff --git a/services/surfaceflinger/tests/unittests/VSyncCallbackRegistrationTest.cpp b/services/surfaceflinger/tests/unittests/VSyncCallbackRegistrationTest.cpp
new file mode 100644
index 0000000..69b3861
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/VSyncCallbackRegistrationTest.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2023 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 "Scheduler/VSyncDispatch.h"
+#include "mock/MockVSyncDispatch.h"
+
+using namespace testing;
+
+namespace android::scheduler {
+
+class VSyncCallbackRegistrationTest : public Test {
+protected:
+ VSyncDispatch::Callback mCallback = [](nsecs_t, nsecs_t, nsecs_t) {};
+
+ std::shared_ptr<mock::VSyncDispatch> mVsyncDispatch = std::make_shared<mock::VSyncDispatch>();
+ VSyncDispatch::CallbackToken mCallbackToken{7};
+ std::string mCallbackName = "callback";
+
+ std::shared_ptr<mock::VSyncDispatch> mVsyncDispatch2 = std::make_shared<mock::VSyncDispatch>();
+ VSyncDispatch::CallbackToken mCallbackToken2{42};
+ std::string mCallbackName2 = "callback2";
+
+ void assertDispatch(const VSyncCallbackRegistration& registration,
+ std::shared_ptr<VSyncDispatch> dispatch) {
+ ASSERT_EQ(registration.mDispatch, dispatch);
+ }
+
+ void assertToken(const VSyncCallbackRegistration& registration,
+ const std::optional<VSyncDispatch::CallbackToken>& token) {
+ ASSERT_EQ(registration.mToken, token);
+ }
+};
+
+TEST_F(VSyncCallbackRegistrationTest, unregistersCallbackOnDestruction) {
+ // TODO (b/279581095): With ftl::Function, `_` can be replaced with
+ // `mCallback`, here and in other calls to `registerCallback, since the
+ // ftl version has an operator==, unlike std::function.
+ EXPECT_CALL(*mVsyncDispatch, registerCallback(_, mCallbackName))
+ .WillOnce(Return(mCallbackToken));
+ EXPECT_CALL(*mVsyncDispatch, unregisterCallback(mCallbackToken)).Times(1);
+
+ VSyncCallbackRegistration registration(mVsyncDispatch, mCallback, mCallbackName);
+ ASSERT_NO_FATAL_FAILURE(assertDispatch(registration, mVsyncDispatch));
+ ASSERT_NO_FATAL_FAILURE(assertToken(registration, mCallbackToken));
+}
+
+TEST_F(VSyncCallbackRegistrationTest, unregistersCallbackOnPointerMove) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mVsyncDispatch, registerCallback(_, mCallbackName))
+ .WillOnce(Return(mCallbackToken));
+ EXPECT_CALL(*mVsyncDispatch2, registerCallback(_, mCallbackName2))
+ .WillOnce(Return(mCallbackToken2));
+ EXPECT_CALL(*mVsyncDispatch2, unregisterCallback(mCallbackToken2)).Times(1);
+ EXPECT_CALL(*mVsyncDispatch, unregisterCallback(mCallbackToken)).Times(1);
+ }
+
+ auto registration =
+ std::make_unique<VSyncCallbackRegistration>(mVsyncDispatch, mCallback, mCallbackName);
+
+ auto registration2 =
+ std::make_unique<VSyncCallbackRegistration>(mVsyncDispatch2, mCallback, mCallbackName2);
+
+ registration2 = std::move(registration);
+
+ ASSERT_NO_FATAL_FAILURE(assertDispatch(*registration2.get(), mVsyncDispatch));
+ ASSERT_NO_FATAL_FAILURE(assertToken(*registration2.get(), mCallbackToken));
+}
+
+TEST_F(VSyncCallbackRegistrationTest, unregistersCallbackOnMoveOperator) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mVsyncDispatch, registerCallback(_, mCallbackName))
+ .WillOnce(Return(mCallbackToken));
+ EXPECT_CALL(*mVsyncDispatch2, registerCallback(_, mCallbackName2))
+ .WillOnce(Return(mCallbackToken2));
+ EXPECT_CALL(*mVsyncDispatch2, unregisterCallback(mCallbackToken2)).Times(1);
+ EXPECT_CALL(*mVsyncDispatch, unregisterCallback(mCallbackToken)).Times(1);
+ }
+
+ VSyncCallbackRegistration registration(mVsyncDispatch, mCallback, mCallbackName);
+
+ VSyncCallbackRegistration registration2(mVsyncDispatch2, mCallback, mCallbackName2);
+
+ registration2 = std::move(registration);
+
+ ASSERT_NO_FATAL_FAILURE(assertDispatch(registration, nullptr));
+ ASSERT_NO_FATAL_FAILURE(assertToken(registration, std::nullopt));
+
+ ASSERT_NO_FATAL_FAILURE(assertDispatch(registration2, mVsyncDispatch));
+ ASSERT_NO_FATAL_FAILURE(assertToken(registration2, mCallbackToken));
+}
+
+TEST_F(VSyncCallbackRegistrationTest, moveConstructor) {
+ EXPECT_CALL(*mVsyncDispatch, registerCallback(_, mCallbackName))
+ .WillOnce(Return(mCallbackToken));
+ EXPECT_CALL(*mVsyncDispatch, unregisterCallback(mCallbackToken)).Times(1);
+
+ VSyncCallbackRegistration registration(mVsyncDispatch, mCallback, mCallbackName);
+ VSyncCallbackRegistration registration2(std::move(registration));
+
+ ASSERT_NO_FATAL_FAILURE(assertDispatch(registration, nullptr));
+ ASSERT_NO_FATAL_FAILURE(assertToken(registration, std::nullopt));
+
+ ASSERT_NO_FATAL_FAILURE(assertDispatch(registration2, mVsyncDispatch));
+ ASSERT_NO_FATAL_FAILURE(assertToken(registration2, mCallbackToken));
+}
+
+TEST_F(VSyncCallbackRegistrationTest, moveOperatorEqualsSelf) {
+ EXPECT_CALL(*mVsyncDispatch, registerCallback(_, mCallbackName))
+ .WillOnce(Return(mCallbackToken));
+ EXPECT_CALL(*mVsyncDispatch, unregisterCallback(mCallbackToken)).Times(1);
+
+ VSyncCallbackRegistration registration(mVsyncDispatch, mCallback, mCallbackName);
+
+ // Use a reference so the compiler doesn't realize that registration is
+ // being moved to itself.
+ VSyncCallbackRegistration& registrationRef = registration;
+ registration = std::move(registrationRef);
+
+ ASSERT_NO_FATAL_FAILURE(assertDispatch(registration, mVsyncDispatch));
+ ASSERT_NO_FATAL_FAILURE(assertToken(registration, mCallbackToken));
+}
+
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 5dc3490..d3fb9fc 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -55,7 +55,6 @@
std::vector<aidl::android::hardware::graphics::composer3::Capability>());
MOCK_METHOD0(dumpDebugInfo, std::string());
MOCK_METHOD1(registerCallback, void(HWC2::ComposerCallback&));
- MOCK_METHOD1(resetCommands, void(Display));
MOCK_METHOD1(executeCommands, Error(Display));
MOCK_METHOD0(getMaxVirtualDisplayCount, uint32_t());
MOCK_METHOD4(createVirtualDisplay, Error(uint32_t, uint32_t, PixelFormat*, Display*));
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
index 0d94f4c..50e07fc 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -32,7 +32,7 @@
MOCK_CONST_METHOD0(getType, const char*());
MOCK_METHOD0(getFrameSelectionPriority, int32_t());
MOCK_CONST_METHOD0(isVisible, bool());
- MOCK_METHOD0(createClone, sp<Layer>());
+ MOCK_METHOD1(createClone, sp<Layer>(uint32_t));
MOCK_CONST_METHOD0(getFrameRateForLayerTree, FrameRate());
MOCK_CONST_METHOD0(getDefaultFrameRateCompatibility,
scheduler::LayerInfo::FrameRateCompatibility());
diff --git a/services/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp b/services/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp
index 53f3daf..971a0b9 100644
--- a/services/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp
+++ b/services/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "PowerHalControllerBenchmarks"
+#define LOG_TAG "VibratorHalControllerBenchmarks"
#include <benchmark/benchmark.h>
#include <vibratorservice/VibratorHalController.h>
@@ -183,7 +183,7 @@
return;
}
- auto duration = 6000s;
+ auto duration = 60s;
auto callback = []() {};
auto amplitude = 1.0f;