Merge "Replace security_context_t type" am: 0568338670 am: 760547e263 am: 4622dfddb5 am: b753c5a9de am: 00e163d9dc
Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/1827242
Change-Id: I5e3d62b0a300c7065399653bc0b995070fa6315e
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 8bcb1e5..4dd4f79 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,5 +1,6 @@
[Builtin Hooks]
clang_format = true
+bpfmt = true
[Builtin Hooks Options]
# Only turn on clang-format check for the following subfolders.
@@ -26,6 +27,7 @@
services/vibratorservice/
services/vr/
vulkan/
+bpfmt = -d
[Hook Scripts]
owners_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "OWNERS$"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 783a475..9a8ec32 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -244,6 +244,7 @@
{ OPT, "events/kmem/ion_heap_shrink/enable" },
{ OPT, "events/ion/ion_stat/enable" },
{ OPT, "events/gpu_mem/gpu_mem_total/enable" },
+ { OPT, "events/fastrpc/fastrpc_dma_stat/enable" },
} },
{ "thermal", "Thermal event", 0, {
{ REQ, "events/thermal/thermal_temperature/enable" },
diff --git a/cmds/cmd/Android.bp b/cmds/cmd/Android.bp
index c900a24..c3d2601 100644
--- a/cmds/cmd/Android.bp
+++ b/cmds/cmd/Android.bp
@@ -49,6 +49,7 @@
"liblog",
"libselinux",
"libbinder",
+ "packagemanager_aidl-cpp",
],
cflags: [
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index aff32c3..74dbf4b 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -100,6 +100,7 @@
"liblog",
"libutils",
"libbinderdebug",
+ "packagemanager_aidl-cpp",
],
srcs: [
"DumpstateService.cpp",
@@ -173,7 +174,6 @@
test_suites: ["device-tests"],
}
-
// =======================#
// dumpstate_test_fixture #
// =======================#
diff --git a/cmds/dumpsys/Android.bp b/cmds/dumpsys/Android.bp
index 6ab6b7f..ceb16cb 100644
--- a/cmds/dumpsys/Android.bp
+++ b/cmds/dumpsys/Android.bp
@@ -64,6 +64,10 @@
srcs: [
"main.cpp",
],
+
+ shared_libs: [
+ "packagemanager_aidl-cpp",
+ ],
}
cc_binary {
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index cfd42fe..3f7c7d6 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -528,7 +528,7 @@
void Replayer::setLayerStack(SurfaceComposerClient::Transaction& t,
layer_id id, const LayerStackChange& lsc) {
ALOGV("Layer %d: Setting LayerStack -- layer_stack=%d", id, lsc.layer_stack());
- t.setLayerStack(mLayers[id], lsc.layer_stack());
+ t.setLayerStack(mLayers[id], ui::LayerStack::fromValue(lsc.layer_stack()));
}
void Replayer::setHiddenFlag(SurfaceComposerClient::Transaction& t,
@@ -566,7 +566,7 @@
void Replayer::setDisplayLayerStack(SurfaceComposerClient::Transaction& t,
display_id id, const LayerStackChange& lsc) {
- t.setDisplayLayerStack(mDisplays[id], lsc.layer_stack());
+ t.setDisplayLayerStack(mDisplays[id], ui::LayerStack::fromValue(lsc.layer_stack()));
}
void Replayer::setDisplaySize(SurfaceComposerClient::Transaction& t,
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 164fc5d..235990a 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -231,11 +231,3 @@
src: "handheld_core_hardware.xml",
defaults: ["frameworks_native_data_etc_defaults"],
}
-
-prebuilt_etc {
- name: "android.software.app_compat_overrides.xml",
- product_specific: true,
- sub_dir: "permissions",
- src: "android.software.app_compat_overrides.xml",
- filename_from_src: true,
-}
diff --git a/include/android/input.h b/include/android/input.h
index 7642215..6d2c1b3 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -169,6 +169,9 @@
/** Drag event */
AINPUT_EVENT_TYPE_DRAG = 5,
+
+ /** TouchMode event */
+ AINPUT_EVENT_TYPE_TOUCH_MODE = 6,
};
/**
diff --git a/include/ftl/Flags.h b/include/ftl/Flags.h
index 27c8476..ae70831 100644
--- a/include/ftl/Flags.h
+++ b/include/ftl/Flags.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,79 +14,22 @@
* limitations under the License.
*/
-#include <android-base/stringprintf.h>
+#pragma once
-#include <array>
+#include <ftl/enum.h>
+#include <ftl/string.h>
+
#include <cstdint>
-#include <optional>
+#include <iterator>
#include <string>
#include <type_traits>
-#include <ftl/NamedEnum.h>
#include "utils/BitSet.h"
-#pragma once
+// TODO(b/185536303): Align with FTL style and namespace.
namespace android {
-namespace details {
-
-template <typename F>
-inline constexpr auto flag_count = sizeof(F) * __CHAR_BIT__;
-
-template <typename F, typename T, T... I>
-constexpr auto generate_flag_values(std::integer_sequence<T, I...> seq) {
- constexpr size_t count = seq.size();
-
- std::array<F, count> values{};
- for (size_t i = 0, v = 0; v < count; ++i) {
- values[v++] = static_cast<F>(T{1} << i);
- }
-
- return values;
-}
-
-template <typename F>
-inline constexpr auto flag_values = generate_flag_values<F>(
- std::make_integer_sequence<std::underlying_type_t<F>, flag_count<F>>{});
-
-template <typename F, std::size_t... I>
-constexpr auto generate_flag_names(std::index_sequence<I...>) noexcept {
- return std::array<std::optional<std::string_view>, sizeof...(I)>{
- {enum_value_name<F, flag_values<F>[I]>()...}};
-}
-
-template <typename F>
-inline constexpr auto flag_names =
- generate_flag_names<F>(std::make_index_sequence<flag_count<F>>{});
-
-// A trait for determining whether a type is specifically an enum class or not.
-template <typename T, bool = std::is_enum_v<T>>
-struct is_enum_class : std::false_type {};
-
-// By definition, an enum class is an enum that is not implicitly convertible to its underlying
-// type.
-template <typename T>
-struct is_enum_class<T, true>
- : std::bool_constant<!std::is_convertible_v<T, std::underlying_type_t<T>>> {};
-
-template <typename T>
-inline constexpr bool is_enum_class_v = is_enum_class<T>::value;
-} // namespace details
-
-template <auto V>
-constexpr auto flag_name() {
- using F = decltype(V);
- return details::enum_value_name<F, V>();
-}
-
-template <typename F>
-constexpr std::optional<std::string_view> flag_name(F flag) {
- using U = std::underlying_type_t<F>;
- auto idx = static_cast<size_t>(__builtin_ctzl(static_cast<U>(flag)));
- return details::flag_names<F>[idx];
-}
-
/* A class for handling flags defined by an enum or enum class in a type-safe way. */
template <typename F>
class Flags {
@@ -94,7 +37,7 @@
// further to avoid this restriction but in general we want to encourage the use of enums
// anyways.
static_assert(std::is_enum_v<F>, "Flags type must be an enum");
- using U = typename std::underlying_type_t<F>;
+ using U = std::underlying_type_t<F>;
public:
constexpr Flags(F f) : mFlags(static_cast<U>(f)) {}
@@ -106,11 +49,10 @@
// should force them to be explicitly constructed from their underlying types to make full use
// of the type checker.
template <typename T = U>
- constexpr Flags(T t, typename std::enable_if_t<!details::is_enum_class_v<F>, T>* = nullptr)
- : mFlags(t) {}
+ constexpr Flags(T t, std::enable_if_t<!ftl::is_scoped_enum_v<F>, T>* = nullptr) : mFlags(t) {}
+
template <typename T = U>
- explicit constexpr Flags(T t,
- typename std::enable_if_t<details::is_enum_class_v<F>, T>* = nullptr)
+ explicit constexpr Flags(T t, std::enable_if_t<ftl::is_scoped_enum_v<F>, T>* = nullptr)
: mFlags(t) {}
class Iterator {
@@ -229,16 +171,16 @@
bool first = true;
U unstringified = 0;
for (const F f : *this) {
- std::optional<std::string_view> flagString = flag_name(f);
- if (flagString) {
- appendFlag(result, flagString.value(), first);
+ if (const auto flagName = ftl::flag_name(f)) {
+ appendFlag(result, flagName.value(), first);
} else {
unstringified |= static_cast<U>(f);
}
}
if (unstringified != 0) {
- appendFlag(result, base::StringPrintf("0x%08x", unstringified), first);
+ constexpr auto radix = sizeof(U) == 1 ? ftl::Radix::kBin : ftl::Radix::kHex;
+ appendFlag(result, ftl::to_string(unstringified, radix), first);
}
if (first) {
@@ -265,15 +207,14 @@
// as flags. In order to use these, add them via a `using namespace` declaration.
namespace flag_operators {
-template <typename F, typename = std::enable_if_t<details::is_enum_class_v<F>>>
+template <typename F, typename = std::enable_if_t<ftl::is_scoped_enum_v<F>>>
inline Flags<F> operator~(F f) {
- using U = typename std::underlying_type_t<F>;
- return static_cast<F>(~static_cast<U>(f));
+ return static_cast<F>(~ftl::enum_cast(f));
}
-template <typename F, typename = std::enable_if_t<details::is_enum_class_v<F>>>
+
+template <typename F, typename = std::enable_if_t<ftl::is_scoped_enum_v<F>>>
Flags<F> operator|(F lhs, F rhs) {
- using U = typename std::underlying_type_t<F>;
- return static_cast<F>(static_cast<U>(lhs) | static_cast<U>(rhs));
+ return static_cast<F>(ftl::enum_cast(lhs) | ftl::enum_cast(rhs));
}
} // namespace flag_operators
diff --git a/include/ftl/NamedEnum.h b/include/ftl/NamedEnum.h
deleted file mode 100644
index 6e98fee..0000000
--- a/include/ftl/NamedEnum.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/stringprintf.h>
-
-#include <array>
-#include <cstdint>
-#include <optional>
-#include <string>
-
-#pragma once
-
-namespace android {
-
-namespace details {
-template <typename E, E V>
-constexpr std::optional<std::string_view> enum_value_name() {
- // Should look something like (but all on one line):
- // std::optional<std::string_view>
- // android::details::enum_value_name()
- // [E = android::test::TestEnums, V = android::test::TestEnums::ONE]
- std::string_view view = __PRETTY_FUNCTION__;
- size_t templateStart = view.rfind("[");
- size_t templateEnd = view.rfind("]");
- if (templateStart == std::string::npos || templateEnd == std::string::npos) {
- return std::nullopt;
- }
-
- // Extract the template parameters without the enclosing braces.
- // Example (cont'd): E = android::test::TestEnums, V = android::test::TestEnums::ONE
- view = view.substr(templateStart + 1, templateEnd - templateStart - 1);
- size_t valStart = view.rfind("V = ");
- if (valStart == std::string::npos) {
- return std::nullopt;
- }
-
- // Example (cont'd): V = android::test::TestEnums::ONE
- view = view.substr(valStart);
- // Check invalid enum values with cast, like V = (android::test::TestEnums)8.
- if (view.find('(') != std::string::npos) {
- return std::nullopt;
- }
- size_t nameStart = view.rfind("::");
- if (nameStart == std::string::npos) {
- return std::nullopt;
- }
-
- // Chop off the initial "::"
- nameStart += 2;
- return view.substr(nameStart);
-}
-
-template <typename E, typename T, T... I>
-constexpr auto generate_enum_values(std::integer_sequence<T, I...> seq) {
- constexpr size_t count = seq.size();
-
- std::array<E, count> values{};
- for (size_t i = 0, v = 0; v < count; ++i) {
- values[v++] = static_cast<E>(T{0} + i);
- }
-
- return values;
-}
-
-template <typename E, std::size_t N>
-inline constexpr auto enum_values =
- generate_enum_values<E>(std::make_integer_sequence<std::underlying_type_t<E>, N>{});
-
-template <typename E, std::size_t N, std::size_t... I>
-constexpr auto generate_enum_names(std::index_sequence<I...>) noexcept {
- return std::array<std::optional<std::string_view>, sizeof...(I)>{
- {enum_value_name<E, enum_values<E, N>[I]>()...}};
-}
-
-template <typename E, std::size_t N>
-inline constexpr auto enum_names = generate_enum_names<E, N>(std::make_index_sequence<N>{});
-
-} // namespace details
-
-class NamedEnum {
-public:
- // By default allowed enum value range is 0 ~ 7.
- template <typename E>
- static constexpr size_t max = 8;
-
- template <auto V>
- static constexpr auto enum_name() {
- using E = decltype(V);
- return details::enum_value_name<E, V>();
- }
-
- template <typename E>
- static constexpr std::optional<std::string_view> enum_name(E val) {
- auto idx = static_cast<size_t>(val);
- return idx < max<E> ? details::enum_names<E, max<E>>[idx] : std::nullopt;
- }
-
- // Helper function for parsing enum value to string.
- // Example : enum class TestEnums { ZERO = 0x0 };
- // NamedEnum::string(TestEnums::ZERO) returns string of "ZERO".
- // Note the default maximum enum is 8, if the enum ID to be parsed if greater than 8 like 16,
- // it should be declared to specialized the maximum enum by below:
- // template <> constexpr size_t NamedEnum::max<TestEnums> = 16;
- // If the enum class definition is sparse and contains enum values starting from a large value,
- // Do not specialize it to a large number to avoid performance issues.
- // The recommended maximum enum number to specialize is 64.
- template <typename E>
- static const std::string string(E val, const char* fallbackFormat = "%02d") {
- std::string result;
- std::optional<std::string_view> enumString = enum_name(val);
- result += enumString ? enumString.value() : base::StringPrintf(fallbackFormat, val);
- return result;
- }
-};
-
-} // namespace android
diff --git a/include/ftl/cast.h b/include/ftl/cast.h
new file mode 100644
index 0000000..ff1b58a
--- /dev/null
+++ b/include/ftl/cast.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <limits>
+#include <type_traits>
+
+#include <ftl/details/cast.h>
+
+namespace android::ftl {
+
+enum class CastSafety { kSafe, kUnderflow, kOverflow };
+
+// Returns whether static_cast<R>(v) is safe, or would result in underflow or overflow.
+//
+// static_assert(ftl::cast_safety<uint8_t>(-1) == ftl::CastSafety::kUnderflow);
+// static_assert(ftl::cast_safety<int8_t>(128u) == ftl::CastSafety::kOverflow);
+//
+// static_assert(ftl::cast_safety<uint32_t>(-.1f) == ftl::CastSafety::kUnderflow);
+// static_assert(ftl::cast_safety<int32_t>(static_cast<float>(INT32_MAX)) ==
+// ftl::CastSafety::kOverflow);
+//
+// static_assert(ftl::cast_safety<float>(-DBL_MAX) == ftl::CastSafety::kUnderflow);
+//
+template <typename R, typename T>
+constexpr CastSafety cast_safety(T v) {
+ static_assert(std::is_arithmetic_v<T>);
+ static_assert(std::is_arithmetic_v<R>);
+
+ constexpr bool kFromSigned = std::is_signed_v<T>;
+ constexpr bool kToSigned = std::is_signed_v<R>;
+
+ using details::max_exponent;
+
+ // If the R range contains the T range, then casting is always safe.
+ if constexpr ((kFromSigned == kToSigned && max_exponent<R> >= max_exponent<T>) ||
+ (!kFromSigned && kToSigned && max_exponent<R> > max_exponent<T>)) {
+ return CastSafety::kSafe;
+ }
+
+ using C = std::common_type_t<R, T>;
+
+ if constexpr (kFromSigned) {
+ using L = details::safe_limits<R, T>;
+
+ if constexpr (kToSigned) {
+ // Signed to signed.
+ if (v < L::lowest()) return CastSafety::kUnderflow;
+ return v <= L::max() ? CastSafety::kSafe : CastSafety::kOverflow;
+ } else {
+ // Signed to unsigned.
+ if (v < 0) return CastSafety::kUnderflow;
+ return static_cast<C>(v) <= static_cast<C>(L::max()) ? CastSafety::kSafe
+ : CastSafety::kOverflow;
+ }
+ } else {
+ using L = std::numeric_limits<R>;
+
+ if constexpr (kToSigned) {
+ // Unsigned to signed.
+ return static_cast<C>(v) <= static_cast<C>(L::max()) ? CastSafety::kSafe
+ : CastSafety::kOverflow;
+ } else {
+ // Unsigned to unsigned.
+ return v <= L::max() ? CastSafety::kSafe : CastSafety::kOverflow;
+ }
+ }
+}
+
+} // namespace android::ftl
diff --git a/include/ftl/details/cast.h b/include/ftl/details/cast.h
new file mode 100644
index 0000000..87b9f1e
--- /dev/null
+++ b/include/ftl/details/cast.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <limits>
+#include <type_traits>
+
+namespace android::ftl::details {
+
+// Exponent whose power of 2 is the (exclusive) upper bound of T.
+template <typename T, typename L = std::numeric_limits<T>>
+constexpr int max_exponent = std::is_floating_point_v<T> ? L::max_exponent : L::digits;
+
+// Extension of std::numeric_limits<T> that reduces the maximum for integral types T such that it
+// has an exact representation for floating-point types F. For example, the maximum int32_t value
+// is 2'147'483'647, but casting it to float commonly rounds up to 2'147'483'650.f, which cannot
+// be safely converted back lest the signed overflow invokes undefined behavior. This pitfall is
+// avoided by clearing the lower (31 - 24 =) 7 bits of precision to 2'147'483'520. Note that the
+// minimum is representable.
+template <typename T, typename F>
+struct safe_limits : std::numeric_limits<T> {
+ static constexpr T max() {
+ using Base = std::numeric_limits<T>;
+
+ if constexpr (std::is_integral_v<T> && std::is_floating_point_v<F>) {
+ // Assume the mantissa is 24 bits for float, or 53 bits for double.
+ using Float = std::numeric_limits<F>;
+ static_assert(Float::is_iec559);
+
+ // If the integer is wider than the mantissa, clear the excess bits of precision.
+ constexpr int kShift = Base::digits - Float::digits;
+ if constexpr (kShift > 0) {
+ using U = std::make_unsigned_t<T>;
+ constexpr U kOne = static_cast<U>(1);
+ return static_cast<U>(Base::max()) & ~((kOne << kShift) - kOne);
+ }
+ }
+
+ return Base::max();
+ }
+};
+
+} // namespace android::ftl::details
diff --git a/include/ftl/enum.h b/include/ftl/enum.h
new file mode 100644
index 0000000..dfe3a09
--- /dev/null
+++ b/include/ftl/enum.h
@@ -0,0 +1,299 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstddef>
+#include <limits>
+#include <optional>
+#include <string_view>
+#include <type_traits>
+#include <utility>
+
+#include <ftl/string.h>
+
+// Returns the name of enumerator E::V (i.e. "V") as std::optional<std::string_view> by parsing the
+// compiler-generated string literal for the signature of this function. The function is defined in
+// the global namespace with a short name and inferred return type to reduce bloat in the read-only
+// data segment.
+template <typename E, E V>
+constexpr auto ftl_enum() {
+ static_assert(std::is_enum_v<E>);
+
+ using R = std::optional<std::string_view>;
+ using namespace std::literals;
+
+ // The "pretty" signature has the following format:
+ //
+ // auto ftl_enum() [E = android::test::Enum, V = android::test::Enum::kValue]
+ //
+ std::string_view view = __PRETTY_FUNCTION__;
+ const auto template_begin = view.rfind('[');
+ const auto template_end = view.rfind(']');
+ if (template_begin == view.npos || template_end == view.npos) return R{};
+
+ // Extract the template parameters without the enclosing brackets. Example (cont'd):
+ //
+ // E = android::test::Enum, V = android::test::Enum::kValue
+ //
+ view = view.substr(template_begin + 1, template_end - template_begin - 1);
+ const auto value_begin = view.rfind("V = "sv);
+ if (value_begin == view.npos) return R{};
+
+ // Example (cont'd):
+ //
+ // V = android::test::Enum::kValue
+ //
+ view = view.substr(value_begin);
+ const auto name_begin = view.rfind("::"sv);
+ if (name_begin == view.npos) return R{};
+
+ // Chop off the leading "::".
+ const auto name = view.substr(name_begin + 2);
+
+ // A value that is not enumerated has the format "Enum)42".
+ return name.find(')') == view.npos ? R{name} : R{};
+}
+
+namespace android::ftl {
+
+// Trait for determining whether a type is specifically a scoped enum or not. By definition, a
+// scoped enum is one that is not implicitly convertible to its underlying type.
+//
+// TODO: Replace with std::is_scoped_enum in C++23.
+//
+template <typename T, bool = std::is_enum_v<T>>
+struct is_scoped_enum : std::false_type {};
+
+template <typename T>
+struct is_scoped_enum<T, true> : std::negation<std::is_convertible<T, std::underlying_type_t<T>>> {
+};
+
+template <typename T>
+inline constexpr bool is_scoped_enum_v = is_scoped_enum<T>::value;
+
+// Shorthand for casting an enumerator to its integral value.
+//
+// enum class E { A, B, C };
+// static_assert(ftl::enum_cast(E::B) == 1);
+//
+template <typename E>
+constexpr auto enum_cast(E v) {
+ return static_cast<std::underlying_type_t<E>>(v);
+}
+
+// Traits for retrieving an enum's range. An enum specifies its range by defining enumerators named
+// ftl_first and ftl_last. If omitted, ftl_first defaults to 0, whereas ftl_last defaults to N - 1
+// where N is the bit width of the underlying type, but only if that type is unsigned, assuming the
+// enumerators are flags. Also, note that unscoped enums must define both bounds, as casting out-of-
+// range values results in undefined behavior if the underlying type is not fixed.
+//
+// enum class E { A, B, C, F = 5, ftl_last = F };
+//
+// static_assert(ftl::enum_begin_v<E> == E::A);
+// static_assert(ftl::enum_last_v<E> == E::F);
+// static_assert(ftl::enum_size_v<E> == 6);
+//
+// enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 };
+//
+// static_assert(ftl::enum_begin_v<F> == F{0});
+// static_assert(ftl::enum_last_v<F> == F{15});
+// static_assert(ftl::enum_size_v<F> == 16);
+//
+template <typename E, typename = void>
+struct enum_begin {
+ static_assert(is_scoped_enum_v<E>, "Missing ftl_first enumerator");
+ static constexpr E value{0};
+};
+
+template <typename E>
+struct enum_begin<E, std::void_t<decltype(E::ftl_first)>> {
+ static constexpr E value = E::ftl_first;
+};
+
+template <typename E>
+inline constexpr E enum_begin_v = enum_begin<E>::value;
+
+template <typename E, typename = void>
+struct enum_end {
+ using U = std::underlying_type_t<E>;
+ static_assert(is_scoped_enum_v<E> && std::is_unsigned_v<U>, "Missing ftl_last enumerator");
+
+ static constexpr E value{std::numeric_limits<U>::digits};
+};
+
+template <typename E>
+struct enum_end<E, std::void_t<decltype(E::ftl_last)>> {
+ static constexpr E value = E{enum_cast(E::ftl_last) + 1};
+};
+
+template <typename E>
+inline constexpr E enum_end_v = enum_end<E>::value;
+
+template <typename E>
+inline constexpr E enum_last_v = E{enum_cast(enum_end_v<E>) - 1};
+
+template <typename E>
+struct enum_size {
+ static constexpr auto kBegin = enum_cast(enum_begin_v<E>);
+ static constexpr auto kEnd = enum_cast(enum_end_v<E>);
+ static_assert(kBegin < kEnd, "Invalid range");
+
+ static constexpr std::size_t value = kEnd - kBegin;
+ static_assert(value <= 64, "Excessive range size");
+};
+
+template <typename E>
+inline constexpr std::size_t enum_size_v = enum_size<E>::value;
+
+namespace details {
+
+template <auto V>
+struct Identity {
+ static constexpr auto value = V;
+};
+
+template <typename E>
+using make_enum_sequence = std::make_integer_sequence<std::underlying_type_t<E>, enum_size_v<E>>;
+
+template <typename E, template <E> class = Identity, typename = make_enum_sequence<E>>
+struct EnumRange;
+
+template <typename E, template <E> class F, typename T, T... Vs>
+struct EnumRange<E, F, std::integer_sequence<T, Vs...>> {
+ static constexpr auto kBegin = enum_cast(enum_begin_v<E>);
+ static constexpr auto kSize = enum_size_v<E>;
+
+ using R = decltype(F<E{}>::value);
+ const R values[kSize] = {F<static_cast<E>(Vs + kBegin)>::value...};
+
+ constexpr const auto* begin() const { return values; }
+ constexpr const auto* end() const { return values + kSize; }
+};
+
+template <auto V>
+struct EnumName {
+ static constexpr auto value = ftl_enum<decltype(V), V>();
+};
+
+template <auto I>
+struct FlagName {
+ using E = decltype(I);
+ using U = std::underlying_type_t<E>;
+
+ static constexpr E V{U{1} << enum_cast(I)};
+ static constexpr auto value = ftl_enum<E, V>();
+};
+
+} // namespace details
+
+// Returns an iterable over the range of an enum.
+//
+// enum class E { A, B, C, F = 5, ftl_last = F };
+//
+// std::string string;
+// for (E v : ftl::enum_range<E>()) {
+// string += ftl::enum_name(v).value_or("?");
+// }
+//
+// assert(string == "ABC??F");
+//
+template <typename E>
+constexpr auto enum_range() {
+ return details::EnumRange<E>{};
+}
+
+// Returns a stringified enumerator at compile time.
+//
+// enum class E { A, B, C };
+// static_assert(ftl::enum_name<E::B>() == "B");
+//
+template <auto V>
+constexpr std::string_view enum_name() {
+ constexpr auto kName = ftl_enum<decltype(V), V>();
+ static_assert(kName, "Unknown enumerator");
+ return *kName;
+}
+
+// Returns a stringified enumerator, possibly at compile time.
+//
+// enum class E { A, B, C, F = 5, ftl_last = F };
+//
+// static_assert(ftl::enum_name(E::C).value_or("?") == "C");
+// static_assert(ftl::enum_name(E{3}).value_or("?") == "?");
+//
+template <typename E>
+constexpr std::optional<std::string_view> enum_name(E v) {
+ const auto value = enum_cast(v);
+
+ constexpr auto kBegin = enum_cast(enum_begin_v<E>);
+ constexpr auto kLast = enum_cast(enum_last_v<E>);
+ if (value < kBegin || value > kLast) return {};
+
+ constexpr auto kRange = details::EnumRange<E, details::EnumName>{};
+ return kRange.values[value - kBegin];
+}
+
+// Returns a stringified flag enumerator, possibly at compile time.
+//
+// enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 };
+//
+// static_assert(ftl::flag_name(F::Z).value_or("?") == "Z");
+// static_assert(ftl::flag_name(F{0b111}).value_or("?") == "?");
+//
+template <typename E>
+constexpr std::optional<std::string_view> flag_name(E v) {
+ const auto value = enum_cast(v);
+
+ // TODO: Replace with std::popcount and std::countr_zero in C++20.
+ if (__builtin_popcountl(value) != 1) return {};
+
+ constexpr auto kRange = details::EnumRange<E, details::FlagName>{};
+ return kRange.values[__builtin_ctzl(value)];
+}
+
+// Returns a stringified enumerator, or its integral value if not named.
+//
+// enum class E { A, B, C, F = 5, ftl_last = F };
+//
+// assert(ftl::enum_string(E::C) == "C");
+// assert(ftl::enum_string(E{3}) == "3");
+//
+template <typename E>
+inline std::string enum_string(E v) {
+ if (const auto name = enum_name(v)) {
+ return std::string(*name);
+ }
+ return to_string(enum_cast(v));
+}
+
+// Returns a stringified flag enumerator, or its integral value if not named.
+//
+// enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 };
+//
+// assert(ftl::flag_string(F::Z) == "Z");
+// assert(ftl::flag_string(F{7}) == "0b111");
+//
+template <typename E>
+inline std::string flag_string(E v) {
+ if (const auto name = flag_name(v)) {
+ return std::string(*name);
+ }
+ constexpr auto radix = sizeof(E) == 1 ? Radix::kBin : Radix::kHex;
+ return to_string(enum_cast(v), radix);
+}
+
+} // namespace android::ftl
diff --git a/include/ftl/small_map.h b/include/ftl/small_map.h
index 84c15eb..bcaba82 100644
--- a/include/ftl/small_map.h
+++ b/include/ftl/small_map.h
@@ -19,6 +19,7 @@
#include <ftl/initializer_list.h>
#include <ftl/small_vector.h>
+#include <algorithm>
#include <functional>
#include <optional>
#include <type_traits>
@@ -28,7 +29,10 @@
// Associative container with unique, unordered keys. Unlike std::unordered_map, key-value pairs are
// stored in contiguous storage for cache efficiency. The map is allocated statically until its size
-// exceeds N, at which point mappings are relocated to dynamic memory.
+// exceeds N, at which point mappings are relocated to dynamic memory. The try_emplace operation has
+// a non-standard analogue try_replace that destructively emplaces. The API also defines an in-place
+// counterpart to insert_or_assign: emplace_or_replace. Lookup is done not via a subscript operator,
+// but immutable getters that can optionally transform the value.
//
// SmallMap<K, V, 0> unconditionally allocates on the heap.
//
@@ -43,16 +47,19 @@
// assert(!map.dynamic());
//
// assert(map.contains(123));
-// assert(map.find(42, [](const std::string& s) { return s.size(); }) == 3u);
+// assert(map.get(42, [](const std::string& s) { return s.size(); }) == 3u);
//
-// const auto opt = map.find(-1);
+// const auto opt = map.get(-1);
// assert(opt);
//
// std::string& ref = *opt;
// assert(ref.empty());
// ref = "xyz";
//
-// assert(map == SmallMap(ftl::init::map(-1, "xyz")(42, "???")(123, "abc")));
+// map.emplace_or_replace(0, "vanilla", 2u, 3u);
+// assert(map.dynamic());
+//
+// assert(map == SmallMap(ftl::init::map(-1, "xyz")(0, "nil")(42, "???")(123, "abc")));
//
template <typename K, typename V, std::size_t N>
class SmallMap final {
@@ -80,12 +87,7 @@
// The syntax for listing pairs is as follows:
//
// ftl::SmallMap map = ftl::init::map<int, std::string>(123, "abc")(-1)(42, 3u, '?');
- //
// static_assert(std::is_same_v<decltype(map), ftl::SmallMap<int, std::string, 3>>);
- // assert(map.size() == 3u);
- // assert(map.contains(-1) && map.find(-1)->get().empty());
- // assert(map.contains(42) && map.find(42)->get() == "???");
- // assert(map.contains(123) && map.find(123)->get() == "abc");
//
// The types of the key and value are deduced if the first pair contains exactly two arguments:
//
@@ -95,7 +97,7 @@
template <typename U, std::size_t... Sizes, typename... Types>
SmallMap(InitializerList<U, std::index_sequence<Sizes...>, Types...>&& list)
: map_(std::move(list)) {
- // TODO: Enforce unique keys.
+ deduplicate();
}
size_type max_size() const { return map_.max_size(); }
@@ -115,27 +117,27 @@
// Returns whether a mapping exists for the given key.
bool contains(const key_type& key) const {
- return find(key, [](const mapped_type&) {});
+ return get(key, [](const mapped_type&) {});
}
// Returns a reference to the value for the given key, or std::nullopt if the key was not found.
//
// ftl::SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C');
//
- // const auto opt = map.find('c');
+ // const auto opt = map.get('c');
// assert(opt == 'C');
//
// char d = 'd';
- // const auto ref = map.find('d').value_or(std::ref(d));
+ // const auto ref = map.get('d').value_or(std::ref(d));
// ref.get() = 'D';
// assert(d == 'D');
//
- auto find(const key_type& key) const -> std::optional<std::reference_wrapper<const mapped_type>> {
- return find(key, [](const mapped_type& v) { return std::cref(v); });
+ auto get(const key_type& key) const -> std::optional<std::reference_wrapper<const mapped_type>> {
+ return get(key, [](const mapped_type& v) { return std::cref(v); });
}
- auto find(const key_type& key) -> std::optional<std::reference_wrapper<mapped_type>> {
- return find(key, [](mapped_type& v) { return std::ref(v); });
+ auto get(const key_type& key) -> std::optional<std::reference_wrapper<mapped_type>> {
+ return get(key, [](mapped_type& v) { return std::ref(v); });
}
// Returns the result R of a unary operation F on (a constant or mutable reference to) the value
@@ -144,11 +146,11 @@
//
// ftl::SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z');
//
- // assert(map.find('c', [](char c) { return std::toupper(c); }) == 'Z');
- // assert(map.find('c', [](char& c) { c = std::toupper(c); }));
+ // assert(map.get('c', [](char c) { return std::toupper(c); }) == 'Z');
+ // assert(map.get('c', [](char& c) { c = std::toupper(c); }));
//
template <typename F, typename R = std::invoke_result_t<F, const mapped_type&>>
- auto find(const key_type& key, F f) const
+ auto get(const key_type& key, F f) const
-> std::conditional_t<std::is_void_v<R>, bool, std::optional<R>> {
for (auto& [k, v] : *this) {
if (k == key) {
@@ -165,12 +167,96 @@
}
template <typename F>
- auto find(const key_type& key, F f) {
- return std::as_const(*this).find(
+ auto get(const key_type& key, F f) {
+ return std::as_const(*this).get(
key, [&f](const mapped_type& v) { return f(const_cast<mapped_type&>(v)); });
}
+ // Returns an iterator to an existing mapping for the given key, or the end() iterator otherwise.
+ const_iterator find(const key_type& key) const { return const_cast<SmallMap&>(*this).find(key); }
+ iterator find(const key_type& key) { return find(key, begin()); }
+
+ // Inserts a mapping unless it exists. Returns an iterator to the inserted or existing mapping,
+ // and whether the mapping was inserted.
+ //
+ // On emplace, if the map reaches its static or dynamic capacity, then all iterators are
+ // invalidated. Otherwise, only the end() iterator is invalidated.
+ //
+ template <typename... Args>
+ std::pair<iterator, bool> try_emplace(const key_type& key, Args&&... args) {
+ if (const auto it = find(key); it != end()) {
+ return {it, false};
+ }
+
+ auto& ref = map_.emplace_back(std::piecewise_construct, std::forward_as_tuple(key),
+ std::forward_as_tuple(std::forward<Args>(args)...));
+ return {&ref, true};
+ }
+
+ // Replaces a mapping if it exists, and returns an iterator to it. Returns the end() iterator
+ // otherwise.
+ //
+ // The value is replaced via move constructor, so type V does not need to define copy/move
+ // assignment, e.g. its data members may be const.
+ //
+ // The arguments may directly or indirectly refer to the mapping being replaced.
+ //
+ // Iterators to the replaced mapping point to its replacement, and others remain valid.
+ //
+ template <typename... Args>
+ iterator try_replace(const key_type& key, Args&&... args) {
+ const auto it = find(key);
+ if (it == end()) return it;
+ map_.replace(it, std::piecewise_construct, std::forward_as_tuple(key),
+ std::forward_as_tuple(std::forward<Args>(args)...));
+ return it;
+ }
+
+ // In-place counterpart of std::unordered_map's insert_or_assign. Returns true on emplace, or
+ // false on replace.
+ //
+ // The value is emplaced and replaced via move constructor, so type V does not need to define
+ // copy/move assignment, e.g. its data members may be const.
+ //
+ // On emplace, if the map reaches its static or dynamic capacity, then all iterators are
+ // invalidated. Otherwise, only the end() iterator is invalidated. On replace, iterators
+ // to the replaced mapping point to its replacement, and others remain valid.
+ //
+ template <typename... Args>
+ std::pair<iterator, bool> emplace_or_replace(const key_type& key, Args&&... args) {
+ const auto [it, ok] = try_emplace(key, std::forward<Args>(args)...);
+ if (ok) return {it, ok};
+ map_.replace(it, std::piecewise_construct, std::forward_as_tuple(key),
+ std::forward_as_tuple(std::forward<Args>(args)...));
+ return {it, ok};
+ }
+
+ // Removes a mapping if it exists, and returns whether it did.
+ //
+ // The last() and end() iterators, as well as those to the erased mapping, are invalidated.
+ //
+ bool erase(const key_type& key) { return erase(key, begin()); }
+
private:
+ iterator find(const key_type& key, iterator first) {
+ return std::find_if(first, end(), [&key](const auto& pair) { return pair.first == key; });
+ }
+
+ bool erase(const key_type& key, iterator first) {
+ const auto it = find(key, first);
+ if (it == end()) return false;
+ map_.unstable_erase(it);
+ return true;
+ }
+
+ void deduplicate() {
+ for (auto it = begin(); it != end();) {
+ if (const auto key = it->first; ++it != end()) {
+ while (erase(key, it));
+ }
+ }
+ }
+
Map map_;
};
@@ -186,7 +272,7 @@
for (const auto& [k, v] : lhs) {
const auto& lv = v;
- if (!rhs.find(k, [&lv](const auto& rv) { return lv == rv; }).value_or(false)) {
+ if (!rhs.get(k, [&lv](const auto& rv) { return lv == rv; }).value_or(false)) {
return false;
}
}
diff --git a/include/ftl/small_vector.h b/include/ftl/small_vector.h
index cb0ae35..0341435 100644
--- a/include/ftl/small_vector.h
+++ b/include/ftl/small_vector.h
@@ -348,7 +348,7 @@
using Impl::pop_back;
void unstable_erase(iterator it) {
- if (it != last()) std::iter_swap(it, last());
+ if (it != last()) replace(it, std::move(back()));
pop_back();
}
diff --git a/include/ftl/string.h b/include/ftl/string.h
new file mode 100644
index 0000000..2d96b06
--- /dev/null
+++ b/include/ftl/string.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cassert>
+#include <charconv>
+#include <limits>
+#include <string>
+#include <string_view>
+#include <type_traits>
+
+namespace android::ftl {
+
+enum class Radix { kBin = 2, kDec = 10, kHex = 16 };
+
+template <typename T>
+struct to_chars_length {
+ static_assert(std::is_integral_v<T>);
+ // Maximum binary digits, plus minus sign and radix prefix.
+ static constexpr std::size_t value = std::numeric_limits<std::make_unsigned_t<T>>::digits + 3;
+};
+
+template <typename T>
+constexpr std::size_t to_chars_length_v = to_chars_length<T>::value;
+
+template <typename T = std::int64_t>
+using to_chars_buffer_t = char[to_chars_length_v<T>];
+
+// Lightweight (not allocating nor sprintf-based) alternative to std::to_string for integers, with
+// optional radix. See also ftl::to_string below.
+//
+// ftl::to_chars_buffer_t<> buffer;
+//
+// assert(ftl::to_chars(buffer, 123u) == "123");
+// assert(ftl::to_chars(buffer, -42, ftl::Radix::kBin) == "-0b101010");
+// assert(ftl::to_chars(buffer, 0xcafe, ftl::Radix::kHex) == "0xcafe");
+// assert(ftl::to_chars(buffer, '*', ftl::Radix::kHex) == "0x2a");
+//
+template <typename T, std::size_t N>
+std::string_view to_chars(char (&buffer)[N], T v, Radix radix = Radix::kDec) {
+ static_assert(N >= to_chars_length_v<T>);
+
+ auto begin = buffer + 2;
+ const auto [end, err] = std::to_chars(begin, buffer + N, v, static_cast<int>(radix));
+ assert(err == std::errc());
+
+ if (radix == Radix::kDec) {
+ // TODO: Replace with {begin, end} in C++20.
+ return {begin, static_cast<std::size_t>(end - begin)};
+ }
+
+ const auto prefix = radix == Radix::kBin ? 'b' : 'x';
+ if constexpr (std::is_unsigned_v<T>) {
+ buffer[0] = '0';
+ buffer[1] = prefix;
+ } else {
+ if (*begin == '-') {
+ *buffer = '-';
+ } else {
+ --begin;
+ }
+
+ *begin-- = prefix;
+ *begin = '0';
+ }
+
+ // TODO: Replace with {buffer, end} in C++20.
+ return {buffer, static_cast<std::size_t>(end - buffer)};
+}
+
+// Lightweight (not sprintf-based) alternative to std::to_string for integers, with optional radix.
+//
+// assert(ftl::to_string(123u) == "123");
+// assert(ftl::to_string(-42, ftl::Radix::kBin) == "-0b101010");
+// assert(ftl::to_string(0xcafe, ftl::Radix::kHex) == "0xcafe");
+// assert(ftl::to_string('*', ftl::Radix::kHex) == "0x2a");
+//
+template <typename T>
+inline std::string to_string(T v, Radix radix = Radix::kDec) {
+ to_chars_buffer_t<T> buffer;
+ return std::string(to_chars(buffer, v, radix));
+}
+
+std::string to_string(bool) = delete;
+std::string to_string(bool, Radix) = delete;
+
+} // namespace android::ftl
diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h
index a6213f3..9148fee 100644
--- a/include/input/DisplayViewport.h
+++ b/include/input/DisplayViewport.h
@@ -18,7 +18,8 @@
#define _LIBINPUT_DISPLAY_VIEWPORT_H
#include <android-base/stringprintf.h>
-#include <ftl/NamedEnum.h>
+#include <ftl/enum.h>
+#include <ftl/string.h>
#include <gui/constants.h>
#include <input/Input.h>
@@ -44,6 +45,8 @@
INTERNAL = 1,
EXTERNAL = 2,
VIRTUAL = 3,
+
+ ftl_last = VIRTUAL
};
/*
@@ -132,9 +135,8 @@
"physicalFrame=[%d, %d, %d, %d], "
"deviceSize=[%d, %d], "
"isActive=[%d]",
- NamedEnum::string(type).c_str(), displayId, uniqueId.c_str(),
- physicalPort ? StringPrintf("%" PRIu8, *physicalPort).c_str()
- : "<none>",
+ ftl::enum_string(type).c_str(), displayId, uniqueId.c_str(),
+ physicalPort ? ftl::to_string(*physicalPort).c_str() : "<none>",
orientation, logicalLeft, logicalTop, logicalRight, logicalBottom,
physicalLeft, physicalTop, physicalRight, physicalBottom, deviceWidth,
deviceHeight, isActive);
diff --git a/include/input/Input.h b/include/input/Input.h
index 4adaa5b..f170f0f 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -369,8 +369,6 @@
float getAxisValue(int32_t axis) const;
status_t setAxisValue(int32_t axis, float value);
- void scale(float globalScale);
-
// Scale the pointer coordinates according to a global scale and a
// window scale. The global scale will be applied to TOUCH/TOOL_MAJOR/MINOR
// axes, however the window scaling will not.
@@ -526,13 +524,17 @@
inline int32_t getAction() const { return mAction; }
- inline int32_t getActionMasked() const { return mAction & AMOTION_EVENT_ACTION_MASK; }
+ static int32_t getActionMasked(int32_t action) { return action & AMOTION_EVENT_ACTION_MASK; }
- inline int32_t getActionIndex() const {
- return (mAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
- >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+ inline int32_t getActionMasked() const { return getActionMasked(mAction); }
+
+ static int32_t getActionIndex(int32_t action) {
+ return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >>
+ AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
}
+ inline int32_t getActionIndex() const { return getActionIndex(mAction); }
+
inline void setAction(int32_t action) { mAction = action; }
inline int32_t getFlags() const { return mFlags; }
@@ -888,6 +890,25 @@
float mX, mY;
};
+/*
+ * Touch mode events.
+ */
+class TouchModeEvent : public InputEvent {
+public:
+ virtual ~TouchModeEvent() {}
+
+ virtual int32_t getType() const override { return AINPUT_EVENT_TYPE_TOUCH_MODE; }
+
+ inline bool isInTouchMode() const { return mIsInTouchMode; }
+
+ void initialize(int32_t id, bool isInTouchMode);
+
+ void initialize(const TouchModeEvent& from);
+
+protected:
+ bool mIsInTouchMode;
+};
+
/**
* Base class for verified events.
* Do not create a VerifiedInputEvent explicitly.
@@ -952,6 +973,7 @@
virtual FocusEvent* createFocusEvent() = 0;
virtual CaptureEvent* createCaptureEvent() = 0;
virtual DragEvent* createDragEvent() = 0;
+ virtual TouchModeEvent* createTouchModeEvent() = 0;
};
/*
@@ -968,6 +990,7 @@
virtual FocusEvent* createFocusEvent() override { return &mFocusEvent; }
virtual CaptureEvent* createCaptureEvent() override { return &mCaptureEvent; }
virtual DragEvent* createDragEvent() override { return &mDragEvent; }
+ virtual TouchModeEvent* createTouchModeEvent() override { return &mTouchModeEvent; }
private:
KeyEvent mKeyEvent;
@@ -975,6 +998,7 @@
FocusEvent mFocusEvent;
CaptureEvent mCaptureEvent;
DragEvent mDragEvent;
+ TouchModeEvent mTouchModeEvent;
};
/*
@@ -990,6 +1014,7 @@
virtual FocusEvent* createFocusEvent() override;
virtual CaptureEvent* createCaptureEvent() override;
virtual DragEvent* createDragEvent() override;
+ virtual TouchModeEvent* createTouchModeEvent() override;
void recycle(InputEvent* event);
@@ -1001,6 +1026,7 @@
std::queue<std::unique_ptr<FocusEvent>> mFocusEventPool;
std::queue<std::unique_ptr<CaptureEvent>> mCaptureEventPool;
std::queue<std::unique_ptr<DragEvent>> mDragEventPool;
+ std::queue<std::unique_ptr<TouchModeEvent>> mTouchModeEventPool;
};
/*
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 7f0324a..22aae19 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -84,6 +84,9 @@
GAME_ROTATION_VECTOR = ASENSOR_TYPE_GAME_ROTATION_VECTOR,
GYROSCOPE_UNCALIBRATED = ASENSOR_TYPE_GYROSCOPE_UNCALIBRATED,
SIGNIFICANT_MOTION = ASENSOR_TYPE_SIGNIFICANT_MOTION,
+
+ ftl_first = ACCELEROMETER,
+ ftl_last = SIGNIFICANT_MOTION
};
enum class InputDeviceSensorAccuracy : int32_t {
@@ -105,6 +108,8 @@
PLAYER_ID = 1,
RGB = 2,
MULTI_COLOR = 3,
+
+ ftl_last = MULTI_COLOR
};
struct InputDeviceSensorInfo {
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index a790b56..7632b30 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -72,6 +72,9 @@
CAPTURE,
DRAG,
TIMELINE,
+ TOUCH_MODE,
+
+ ftl_last = TOUCH_MODE
};
struct Header {
@@ -206,6 +209,15 @@
inline size_t size() const { return sizeof(Timeline); }
} timeline;
+
+ struct TouchMode {
+ int32_t eventId;
+ // The following 2 fields take up 4 bytes total
+ bool isInTouchMode;
+ uint8_t empty[3];
+
+ inline size_t size() const { return sizeof(TouchMode); }
+ } touchMode;
} __attribute__((aligned(8))) body;
bool isValid(size_t actualSize) const;
@@ -388,6 +400,15 @@
*/
status_t publishDragEvent(uint32_t seq, int32_t eventId, float x, float y, bool isExiting);
+ /* Publishes a touch mode event to the input channel.
+ *
+ * Returns OK on success.
+ * Returns WOULD_BLOCK if the channel is full.
+ * Returns DEAD_OBJECT if the channel's peer has been closed.
+ * Other errors probably indicate that the channel is broken.
+ */
+ status_t publishTouchModeEvent(uint32_t seq, int32_t eventId, bool isInTouchMode);
+
struct Finished {
uint32_t seq;
bool handled;
@@ -658,6 +679,7 @@
static void initializeFocusEvent(FocusEvent* event, const InputMessage* msg);
static void initializeCaptureEvent(CaptureEvent* event, const InputMessage* msg);
static void initializeDragEvent(DragEvent* event, const InputMessage* msg);
+ static void initializeTouchModeEvent(TouchModeEvent* event, const InputMessage* msg);
static void addSample(MotionEvent* event, const InputMessage* msg);
static bool canAddSample(const Batch& batch, const InputMessage* msg);
static ssize_t findSampleNoLaterThan(const Batch& batch, nsecs_t time);
diff --git a/include/private/surface_control_private.h b/include/private/surface_control_private.h
index 37a476e..7e6c515 100644
--- a/include/private/surface_control_private.h
+++ b/include/private/surface_control_private.h
@@ -29,8 +29,8 @@
/**
* Callback to be notified when surface stats for a specific surface control are available.
*/
-typedef void (*ASurfaceControl_SurfaceStatsListener)(void* context,
- ASurfaceControl* control, ASurfaceControlStats* stats);
+typedef void (*ASurfaceControl_SurfaceStatsListener)(void* context, int32_t id,
+ ASurfaceControlStats* stats);
/**
* Registers a callback to be invoked when surface stats from a specific surface are available.
@@ -42,7 +42,7 @@
*
* \param func The callback to be invoked when surface stats are available.
*/
-void ASurfaceControl_registerSurfaceStatsListener(ASurfaceControl* control, void* context,
+void ASurfaceControl_registerSurfaceStatsListener(ASurfaceControl* control, int32_t id, void* context,
ASurfaceControl_SurfaceStatsListener func);
/**
diff --git a/libs/battery/Android.bp b/libs/battery/Android.bp
new file mode 100644
index 0000000..c860324
--- /dev/null
+++ b/libs/battery/Android.bp
@@ -0,0 +1,37 @@
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_library {
+ name: "libbattery",
+ srcs: [
+ "LongArrayMultiStateCounter.cpp",
+ ],
+ shared_libs: [
+ "liblog",
+ ],
+ cflags: [
+ "-Werror",
+ "-Wall",
+ "-Wextra",
+ ],
+ export_include_dirs: ["."],
+}
+
+cc_test {
+ name: "libbattery_test",
+ srcs: [
+ "MultiStateCounterTest.cpp",
+ "LongArrayMultiStateCounterTest.cpp",
+ ],
+ static_libs: ["libbattery"],
+ shared_libs: [
+ "liblog",
+ ],
+ cflags: [
+ "-Werror",
+ "-Wall",
+ "-Wextra",
+ ],
+}
diff --git a/libs/battery/LongArrayMultiStateCounter.cpp b/libs/battery/LongArrayMultiStateCounter.cpp
new file mode 100644
index 0000000..125cfaf
--- /dev/null
+++ b/libs/battery/LongArrayMultiStateCounter.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ * Android BPF library - public API
+ *
+ * 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 "LongArrayMultiStateCounter.h"
+#include <log/log.h>
+
+namespace android {
+namespace battery {
+
+template <>
+bool LongArrayMultiStateCounter::delta(const std::vector<uint64_t>& previousValue,
+ const std::vector<uint64_t>& newValue,
+ std::vector<uint64_t>* outValue) const {
+ size_t size = previousValue.size();
+ if (newValue.size() != size) {
+ ALOGE("Incorrect array size: %d, should be %d", (int)newValue.size(), (int)size);
+ return false;
+ }
+
+ bool is_delta_valid = true;
+ for (int i = size - 1; i >= 0; i--) {
+ if (newValue[i] >= previousValue[i]) {
+ (*outValue)[i] = newValue[i] - previousValue[i];
+ } else {
+ (*outValue)[i] = 0;
+ is_delta_valid = false;
+ }
+ }
+ return is_delta_valid;
+}
+
+template <>
+void LongArrayMultiStateCounter::add(std::vector<uint64_t>* value1,
+ const std::vector<uint64_t>& value2, const uint64_t numerator,
+ const uint64_t denominator) const {
+ if (numerator != denominator) {
+ for (int i = value2.size() - 1; i >= 0; i--) {
+ // The caller ensures that denominator != 0
+ (*value1)[i] += value2[i] * numerator / denominator;
+ }
+ } else {
+ for (int i = value2.size() - 1; i >= 0; i--) {
+ (*value1)[i] += value2[i];
+ }
+ }
+}
+
+template <>
+std::string LongArrayMultiStateCounter::valueToString(const std::vector<uint64_t>& v) const {
+ std::stringstream s;
+ s << "{";
+ bool first = true;
+ for (uint64_t n : v) {
+ if (!first) {
+ s << ", ";
+ }
+ s << n;
+ first = false;
+ }
+ s << "}";
+ return s.str();
+}
+
+} // namespace battery
+} // namespace android
diff --git a/libs/ui/Size.cpp b/libs/battery/LongArrayMultiStateCounter.h
similarity index 63%
copy from libs/ui/Size.cpp
copy to libs/battery/LongArrayMultiStateCounter.h
index d2996d1..f3439f6 100644
--- a/libs/ui/Size.cpp
+++ b/libs/battery/LongArrayMultiStateCounter.h
@@ -1,5 +1,6 @@
/*
- * Copyright 2019 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
+ * Android BPF library - public API
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,11 +15,15 @@
* limitations under the License.
*/
-#include <ui/Size.h>
+#pragma once
-namespace android::ui {
+#include <vector>
+#include "MultiStateCounter.h"
-const Size Size::INVALID{-1, -1};
-const Size Size::EMPTY{0, 0};
+namespace android {
+namespace battery {
-} // namespace android::ui
+typedef MultiStateCounter<std::vector<uint64_t>> LongArrayMultiStateCounter;
+
+} // namespace battery
+} // namespace android
diff --git a/libs/battery/LongArrayMultiStateCounterTest.cpp b/libs/battery/LongArrayMultiStateCounterTest.cpp
new file mode 100644
index 0000000..e4e6b2a
--- /dev/null
+++ b/libs/battery/LongArrayMultiStateCounterTest.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ * Android BPF library - public API
+ *
+ * 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 <gtest/gtest.h>
+#include "LongArrayMultiStateCounter.h"
+
+namespace android {
+namespace battery {
+
+class LongArrayMultiStateCounterTest : public testing::Test {};
+
+TEST_F(LongArrayMultiStateCounterTest, stateChange) {
+ LongArrayMultiStateCounter testCounter(2, std::vector<uint64_t>(4));
+ testCounter.updateValue(std::vector<uint64_t>({0, 0, 0, 0}), 1000);
+ testCounter.setState(0, 1000);
+ testCounter.setState(1, 2000);
+ testCounter.updateValue(std::vector<uint64_t>({100, 200, 300, 400}), 3000);
+
+ // Time was split in half between the two states, so the counts will be split 50:50 too
+ EXPECT_EQ(std::vector<uint64_t>({50, 100, 150, 200}), testCounter.getCount(0));
+ EXPECT_EQ(std::vector<uint64_t>({50, 100, 150, 200}), testCounter.getCount(1));
+}
+
+TEST_F(LongArrayMultiStateCounterTest, accumulation) {
+ LongArrayMultiStateCounter testCounter(2, std::vector<uint64_t>(4));
+ testCounter.updateValue(std::vector<uint64_t>({0, 0, 0, 0}), 1000);
+ testCounter.setState(0, 1000);
+ testCounter.setState(1, 2000);
+ testCounter.updateValue(std::vector<uint64_t>({100, 200, 300, 400}), 3000);
+ testCounter.setState(0, 4000);
+ testCounter.updateValue(std::vector<uint64_t>({200, 300, 400, 500}), 8000);
+
+ // The first delta is split 50:50:
+ // 0: {50, 100, 150, 200}
+ // 1: {50, 100, 150, 200}
+ // The second delta is split 4:1
+ // 0: {80, 80, 80, 80}
+ // 1: {20, 20, 20, 20}
+ EXPECT_EQ(std::vector<uint64_t>({130, 180, 230, 280}), testCounter.getCount(0));
+ EXPECT_EQ(std::vector<uint64_t>({70, 120, 170, 220}), testCounter.getCount(1));
+}
+
+TEST_F(LongArrayMultiStateCounterTest, toString) {
+ LongArrayMultiStateCounter testCounter(2, std::vector<uint64_t>(4));
+ testCounter.updateValue(std::vector<uint64_t>({0, 0, 0, 0}), 1000);
+ testCounter.setState(0, 1000);
+ testCounter.setState(1, 2000);
+ testCounter.updateValue(std::vector<uint64_t>({100, 200, 300, 400}), 3000);
+
+ EXPECT_STREQ("[0: {50, 100, 150, 200}, 1: {50, 100, 150, 200}] updated: 3000 currentState: 1",
+ testCounter.toString().c_str());
+}
+
+} // namespace battery
+} // namespace android
diff --git a/libs/battery/MultiStateCounter.h b/libs/battery/MultiStateCounter.h
new file mode 100644
index 0000000..e1ee07c
--- /dev/null
+++ b/libs/battery/MultiStateCounter.h
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ * Android BPF library - public API
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <inttypes.h>
+#include <log/log.h>
+#include <time.h>
+#include <sstream>
+#include <string>
+
+/**
+ * An object that can track changes of some value over time, taking into account an additional
+ * dimension: the object's state. As the tracked value changes, the deltas are distributed
+ * among the object states in accordance with the time spent in those states.
+ */
+namespace android {
+namespace battery {
+
+typedef uint16_t state_t;
+
+template <class T>
+class MultiStateCounter {
+ uint16_t stateCount;
+ state_t currentState;
+ time_t lastStateChangeTimestamp;
+ T emptyValue;
+ T lastValue;
+ time_t lastUpdateTimestamp;
+ T deltaValue;
+ bool isEnabled;
+
+ struct State {
+ time_t timeInStateSinceUpdate;
+ T counter;
+ };
+
+ State* states;
+
+public:
+ MultiStateCounter(uint16_t stateCount, const T& emptyValue);
+
+ virtual ~MultiStateCounter();
+
+ void setEnabled(bool enabled, time_t timestamp);
+
+ void setState(state_t state, time_t timestamp);
+
+ void setValue(state_t state, const T& value);
+
+ void updateValue(const T& value, time_t timestamp);
+
+ void reset();
+
+ uint16_t getStateCount();
+
+ const T& getCount(state_t state);
+
+ std::string toString();
+
+private:
+ /**
+ * Subtracts previousValue from newValue and returns the result in outValue.
+ * Returns true iff the combination of previousValue and newValue is valid
+ * (newValue >= prevValue)
+ */
+ bool delta(const T& previousValue, const T& newValue, T* outValue) const;
+
+ /**
+ * Adds value2 to value1 and stores the result in value1. Denominator is
+ * guaranteed to be non-zero.
+ */
+ void add(T* value1, const T& value2, const uint64_t numerator,
+ const uint64_t denominator) const;
+
+ std::string valueToString(const T& value) const;
+};
+
+// ---------------------- MultiStateCounter Implementation -------------------------
+// Since MultiStateCounter is a template, the implementation must be inlined.
+
+template <class T>
+MultiStateCounter<T>::MultiStateCounter(uint16_t stateCount, const T& emptyValue)
+ : stateCount(stateCount),
+ currentState(0),
+ lastStateChangeTimestamp(-1),
+ emptyValue(emptyValue),
+ lastValue(emptyValue),
+ lastUpdateTimestamp(-1),
+ deltaValue(emptyValue),
+ isEnabled(true) {
+ states = new State[stateCount];
+ for (int i = 0; i < stateCount; i++) {
+ states[i].timeInStateSinceUpdate = 0;
+ states[i].counter = emptyValue;
+ }
+}
+
+template <class T>
+MultiStateCounter<T>::~MultiStateCounter() {
+ delete[] states;
+};
+
+template <class T>
+void MultiStateCounter<T>::setEnabled(bool enabled, time_t timestamp) {
+ if (enabled == isEnabled) {
+ return;
+ }
+
+ if (!enabled) {
+ // Confirm the current state for the side-effect of updating the time-in-state
+ // counter for the current state.
+ setState(currentState, timestamp);
+ }
+
+ isEnabled = enabled;
+
+ if (lastStateChangeTimestamp >= 0) {
+ lastStateChangeTimestamp = timestamp;
+ }
+}
+
+template <class T>
+void MultiStateCounter<T>::setState(state_t state, time_t timestamp) {
+ if (isEnabled && lastStateChangeTimestamp >= 0) {
+ if (timestamp >= lastStateChangeTimestamp) {
+ states[currentState].timeInStateSinceUpdate += timestamp - lastStateChangeTimestamp;
+ } else {
+ ALOGE("setState is called with an earlier timestamp: %lu, previous timestamp: %lu\n",
+ (unsigned long)timestamp, (unsigned long)lastStateChangeTimestamp);
+ // The accumulated durations have become unreliable. For example, if the timestamp
+ // sequence was 1000, 2000, 1000, 3000, if we accumulated the positive deltas,
+ // we would get 4000, which is greater than (last - first). This could lead to
+ // counts exceeding 100%.
+ for (int i = 0; i < stateCount; i++) {
+ states[i].timeInStateSinceUpdate = 0;
+ }
+ }
+ }
+ currentState = state;
+ lastStateChangeTimestamp = timestamp;
+}
+
+template <class T>
+void MultiStateCounter<T>::setValue(state_t state, const T& value) {
+ states[state].counter = value;
+}
+
+template <class T>
+void MultiStateCounter<T>::updateValue(const T& value, time_t timestamp) {
+ // If the counter is disabled, we ignore the update, except when the counter got disabled after
+ // the previous update, in which case we still need to pick up the residual delta.
+ if (isEnabled || lastUpdateTimestamp < lastStateChangeTimestamp) {
+ // Confirm the current state for the side-effect of updating the time-in-state
+ // counter for the current state.
+ setState(currentState, timestamp);
+
+ if (lastUpdateTimestamp >= 0) {
+ if (timestamp > lastUpdateTimestamp) {
+ if (delta(lastValue, value, &deltaValue)) {
+ time_t timeSinceUpdate = timestamp - lastUpdateTimestamp;
+ for (int i = 0; i < stateCount; i++) {
+ time_t timeInState = states[i].timeInStateSinceUpdate;
+ if (timeInState) {
+ add(&states[i].counter, deltaValue, timeInState, timeSinceUpdate);
+ states[i].timeInStateSinceUpdate = 0;
+ }
+ }
+ } else {
+ std::stringstream str;
+ str << "updateValue is called with a value " << valueToString(value)
+ << ", which is lower than the previous value " << valueToString(lastValue)
+ << "\n";
+ ALOGE("%s", str.str().c_str());
+ }
+ } else if (timestamp < lastUpdateTimestamp) {
+ ALOGE("updateValue is called with an earlier timestamp: %lu, previous: %lu\n",
+ (unsigned long)timestamp, (unsigned long)lastUpdateTimestamp);
+ }
+ }
+ }
+ lastValue = value;
+ lastUpdateTimestamp = timestamp;
+}
+
+template <class T>
+void MultiStateCounter<T>::reset() {
+ lastStateChangeTimestamp = -1;
+ lastUpdateTimestamp = -1;
+ for (int i = 0; i < stateCount; i++) {
+ states[i].timeInStateSinceUpdate = 0;
+ states[i].counter = emptyValue;
+ }
+}
+
+template <class T>
+uint16_t MultiStateCounter<T>::getStateCount() {
+ return stateCount;
+}
+
+template <class T>
+const T& MultiStateCounter<T>::getCount(state_t state) {
+ return states[state].counter;
+}
+
+template <class T>
+std::string MultiStateCounter<T>::toString() {
+ std::stringstream str;
+ str << "[";
+ for (int i = 0; i < stateCount; i++) {
+ if (i != 0) {
+ str << ", ";
+ }
+ str << i << ": " << valueToString(states[i].counter);
+ if (states[i].timeInStateSinceUpdate > 0) {
+ str << " timeInStateSinceUpdate: " << states[i].timeInStateSinceUpdate;
+ }
+ }
+ str << "]";
+ if (lastUpdateTimestamp >= 0) {
+ str << " updated: " << lastUpdateTimestamp;
+ }
+ if (lastStateChangeTimestamp >= 0) {
+ str << " currentState: " << currentState;
+ if (lastStateChangeTimestamp > lastUpdateTimestamp) {
+ str << " stateChanged: " << lastStateChangeTimestamp;
+ }
+ } else {
+ str << " currentState: none";
+ }
+
+ return str.str();
+}
+
+} // namespace battery
+} // namespace android
diff --git a/libs/battery/MultiStateCounterTest.cpp b/libs/battery/MultiStateCounterTest.cpp
new file mode 100644
index 0000000..319ba76
--- /dev/null
+++ b/libs/battery/MultiStateCounterTest.cpp
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ * Android BPF library - public API
+ *
+ * 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 <gtest/gtest.h>
+#include "MultiStateCounter.h"
+
+namespace android {
+namespace battery {
+
+typedef MultiStateCounter<double> DoubleMultiStateCounter;
+
+template <>
+bool DoubleMultiStateCounter::delta(const double& previousValue, const double& newValue,
+ double* outValue) const {
+ *outValue = newValue - previousValue;
+ return *outValue >= 0;
+}
+
+template <>
+void DoubleMultiStateCounter::add(double* value1, const double& value2, const uint64_t numerator,
+ const uint64_t denominator) const {
+ if (numerator != denominator) {
+ // The caller ensures that denominator != 0
+ *value1 += value2 * numerator / denominator;
+ } else {
+ *value1 += value2;
+ }
+}
+
+template <>
+std::string DoubleMultiStateCounter::valueToString(const double& v) const {
+ return std::to_string(v);
+}
+
+class MultiStateCounterTest : public testing::Test {};
+
+TEST_F(MultiStateCounterTest, constructor) {
+ DoubleMultiStateCounter testCounter(3, 0);
+ testCounter.updateValue(0, 0);
+ testCounter.setState(1, 0);
+ testCounter.updateValue(3.14, 3000);
+
+ EXPECT_DOUBLE_EQ(0, testCounter.getCount(0));
+ EXPECT_DOUBLE_EQ(3.14, testCounter.getCount(1));
+ EXPECT_DOUBLE_EQ(0, testCounter.getCount(2));
+}
+
+TEST_F(MultiStateCounterTest, stateChange) {
+ DoubleMultiStateCounter testCounter(3, 0);
+ testCounter.updateValue(0, 0);
+ testCounter.setState(1, 0);
+ testCounter.setState(2, 1000);
+ testCounter.updateValue(6.0, 3000);
+
+ EXPECT_DOUBLE_EQ(0, testCounter.getCount(0));
+ EXPECT_DOUBLE_EQ(2.0, testCounter.getCount(1));
+ EXPECT_DOUBLE_EQ(4.0, testCounter.getCount(2));
+}
+
+TEST_F(MultiStateCounterTest, setEnabled) {
+ DoubleMultiStateCounter testCounter(3, 0);
+ testCounter.updateValue(0, 0);
+ testCounter.setState(1, 0);
+ testCounter.setEnabled(false, 1000);
+ testCounter.setState(2, 2000);
+ testCounter.updateValue(6.0, 3000);
+
+ // In state 1: accumulated 1000 before disabled, that's 6.0 * 1000/3000 = 2.0
+ // In state 2: 0, since it is still disabled
+ EXPECT_DOUBLE_EQ(0, testCounter.getCount(0));
+ EXPECT_DOUBLE_EQ(2.0, testCounter.getCount(1));
+ EXPECT_DOUBLE_EQ(0, testCounter.getCount(2));
+
+ // Should have no effect since the counter is disabled
+ testCounter.setState(0, 3500);
+
+ // Should have no effect since the counter is disabled
+ testCounter.updateValue(10.0, 4000);
+
+ EXPECT_DOUBLE_EQ(0, testCounter.getCount(0));
+ EXPECT_DOUBLE_EQ(2.0, testCounter.getCount(1));
+ EXPECT_DOUBLE_EQ(0, testCounter.getCount(2));
+
+ testCounter.setState(2, 4500);
+
+ // Enable the counter to partially accumulate deltas for the current state, 2
+ testCounter.setEnabled(true, 5000);
+ testCounter.setEnabled(false, 6000);
+ testCounter.setEnabled(true, 7000);
+ testCounter.updateValue(20.0, 8000);
+
+ // The delta is 10.0 over 5000-3000=2000.
+ // Counter has been enabled in state 2 for (6000-5000)+(8000-7000) = 2000,
+ // so its share is (20.0-10.0) * 2000/(8000-4000) = 5.0
+ EXPECT_DOUBLE_EQ(0, testCounter.getCount(0));
+ EXPECT_DOUBLE_EQ(2.0, testCounter.getCount(1));
+ EXPECT_DOUBLE_EQ(5.0, testCounter.getCount(2));
+
+ testCounter.reset();
+ testCounter.setState(0, 0);
+ testCounter.updateValue(0, 0);
+ testCounter.setState(1, 2000);
+ testCounter.setEnabled(false, 3000);
+ testCounter.updateValue(200, 5000);
+
+ // 200 over 5000 = 40 per second
+ // Counter was in state 0 from 0 to 2000, so 2 sec, so the count should be 40 * 2 = 80
+ // It stayed in state 1 from 2000 to 3000, at which point the counter was disabled,
+ // so the count for state 1 should be 40 * 1 = 40.
+ // The remaining 2 seconds from 3000 to 5000 don't count because the counter was disabled.
+ EXPECT_DOUBLE_EQ(80.0, testCounter.getCount(0));
+ EXPECT_DOUBLE_EQ(40.0, testCounter.getCount(1));
+ EXPECT_DOUBLE_EQ(0, testCounter.getCount(2));
+}
+
+TEST_F(MultiStateCounterTest, reset) {
+ DoubleMultiStateCounter testCounter(3, 0);
+ testCounter.updateValue(0, 0);
+ testCounter.setState(1, 0);
+ testCounter.updateValue(2.72, 3000);
+
+ testCounter.reset();
+
+ EXPECT_DOUBLE_EQ(0, testCounter.getCount(0));
+ EXPECT_DOUBLE_EQ(0, testCounter.getCount(1));
+ EXPECT_DOUBLE_EQ(0, testCounter.getCount(2));
+
+ // Assert that we can still continue accumulating after a reset
+ testCounter.updateValue(0, 4000);
+ testCounter.updateValue(3.14, 5000);
+
+ EXPECT_DOUBLE_EQ(0, testCounter.getCount(0));
+ EXPECT_DOUBLE_EQ(3.14, testCounter.getCount(1));
+ EXPECT_DOUBLE_EQ(0, testCounter.getCount(2));
+}
+
+TEST_F(MultiStateCounterTest, timeAdjustment_setState) {
+ DoubleMultiStateCounter testCounter(3, 0);
+ testCounter.updateValue(0, 0);
+ testCounter.setState(1, 0);
+ testCounter.setState(2, 2000);
+
+ // Time moves back
+ testCounter.setState(1, 1000);
+ testCounter.updateValue(6.0, 3000);
+
+ EXPECT_DOUBLE_EQ(0, testCounter.getCount(0));
+
+ // We were in state 1 from 0 to 2000, which was erased because the time moved back.
+ // Then from 1000 to 3000, so we expect the count to be 6 * (2000/3000)
+ EXPECT_DOUBLE_EQ(4.0, testCounter.getCount(1));
+
+ // No time was effectively accumulated for state 2, because the timestamp moved back
+ // while we were in state 2.
+ EXPECT_DOUBLE_EQ(0, testCounter.getCount(2));
+}
+
+TEST_F(MultiStateCounterTest, timeAdjustment_updateValue) {
+ DoubleMultiStateCounter testCounter(1, 0);
+ testCounter.updateValue(0, 0);
+ testCounter.setState(0, 0);
+ testCounter.updateValue(6.0, 2000);
+
+ // Time moves back. The negative delta from 2000 to 1000 is ignored
+ testCounter.updateValue(8.0, 1000);
+ testCounter.updateValue(11.0, 3000);
+
+ // The total accumulated count is:
+ // 6.0 // For the period 0-2000
+ // +(11.0-8.0) // For the period 1000-3000
+ EXPECT_DOUBLE_EQ(9.0, testCounter.getCount(0));
+}
+
+TEST_F(MultiStateCounterTest, toString) {
+ DoubleMultiStateCounter testCounter(2, 0);
+
+ EXPECT_STREQ("[0: 0.000000, 1: 0.000000] currentState: none", testCounter.toString().c_str());
+
+ testCounter.updateValue(0, 0);
+ testCounter.setState(1, 0);
+ testCounter.setState(1, 2000);
+ EXPECT_STREQ("[0: 0.000000, 1: 0.000000 timeInStateSinceUpdate: 2000]"
+ " updated: 0 currentState: 1 stateChanged: 2000",
+ testCounter.toString().c_str());
+
+ testCounter.updateValue(3.14, 3000);
+
+ EXPECT_STREQ("[0: 0.000000, 1: 3.140000] updated: 3000 currentState: 1",
+ testCounter.toString().c_str());
+}
+
+} // namespace battery
+} // namespace android
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index b86a85f..06594d7 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -64,9 +64,6 @@
"PermissionCache.cpp",
"PermissionController.cpp",
]
-libbinder_no_vendor_interface_sources = [
- ":packagemanager_aidl",
-]
cc_library {
name: "libbinder",
@@ -127,7 +124,7 @@
"TextOutput.cpp",
"Utils.cpp",
":libbinder_aidl",
- ] + libbinder_no_vendor_interface_sources,
+ ],
target: {
android: {
@@ -139,7 +136,7 @@
},
},
vendor: {
- exclude_srcs: libbinder_device_interface_sources + libbinder_no_vendor_interface_sources,
+ exclude_srcs: libbinder_device_interface_sources,
},
darwin: {
enabled: false,
@@ -289,8 +286,11 @@
path: "aidl",
}
-filegroup {
+aidl_interface {
name: "packagemanager_aidl",
+ unstable: true,
+ local_include_dir: "aidl",
+ host_supported: true,
srcs: [
"aidl/android/content/pm/IPackageChangeObserver.aidl",
"aidl/android/content/pm/IPackageManagerNative.aidl",
@@ -299,7 +299,6 @@
"aidl/android/content/pm/ApexStagedEvent.aidl",
"aidl/android/content/pm/StagedApexInfo.aidl",
],
- path: "aidl",
}
aidl_interface {
diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp
index 2524c5f..5a80ad0 100644
--- a/libs/ftl/Android.bp
+++ b/libs/ftl/Android.bp
@@ -15,11 +15,13 @@
},
srcs: [
"Flags_test.cpp",
+ "cast_test.cpp",
+ "enum_test.cpp",
"future_test.cpp",
- "NamedEnum_test.cpp",
"small_map_test.cpp",
"small_vector_test.cpp",
"static_vector_test.cpp",
+ "string_test.cpp",
],
cflags: [
"-Wall",
diff --git a/libs/ftl/Flags_test.cpp b/libs/ftl/Flags_test.cpp
index 8c00b52..d241fa2 100644
--- a/libs/ftl/Flags_test.cpp
+++ b/libs/ftl/Flags_test.cpp
@@ -23,7 +23,7 @@
using namespace android::flag_operators;
-enum class TestFlags { ONE = 0x1, TWO = 0x2, THREE = 0x4 };
+enum class TestFlags : uint8_t { ONE = 0x1, TWO = 0x2, THREE = 0x4 };
TEST(Flags, Test) {
Flags<TestFlags> flags = TestFlags::ONE;
@@ -165,7 +165,7 @@
TEST(Flags, String_UnknownValues) {
auto flags = Flags<TestFlags>(0b1011);
- ASSERT_EQ(flags.string(), "ONE | TWO | 0x00000008");
+ ASSERT_EQ(flags.string(), "ONE | TWO | 0b1000");
}
TEST(FlagsIterator, IteratesOverAllFlags) {
@@ -210,18 +210,4 @@
ASSERT_EQ(++iter, flags.end());
}
-TEST(FlagNames, RuntimeFlagName) {
- TestFlags f = TestFlags::ONE;
- ASSERT_EQ(flag_name(f), "ONE");
-}
-
-TEST(FlagNames, RuntimeUnknownFlagName) {
- TestFlags f = static_cast<TestFlags>(0x8);
- ASSERT_EQ(flag_name(f), std::nullopt);
-}
-
-TEST(FlagNames, CompileTimeFlagName) {
- static_assert(flag_name<TestFlags::TWO>() == "TWO");
-}
-
-} // namespace android::test
\ No newline at end of file
+} // namespace android::test
diff --git a/libs/ftl/NamedEnum_test.cpp b/libs/ftl/NamedEnum_test.cpp
deleted file mode 100644
index dff2b8a..0000000
--- a/libs/ftl/NamedEnum_test.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gtest/gtest.h>
-#include <ftl/NamedEnum.h>
-
-namespace android {
-
-// Test enum class maximum enum value smaller than default maximum of 8.
-enum class TestEnums { ZERO = 0x0, ONE = 0x1, TWO = 0x2, THREE = 0x3, SEVEN = 0x7 };
-// Big enum contains enum values greater than default maximum of 8.
-enum class TestBigEnums { ZERO = 0x0, FIFTEEN = 0xF };
-
-// Declared to specialize the maximum enum since the enum size exceeds 8 by default.
-template <>
-constexpr size_t NamedEnum::max<TestBigEnums> = 16;
-
-namespace test {
-using android::TestBigEnums;
-using android::TestEnums;
-
-TEST(NamedEnum, RuntimeNamedEnum) {
- TestEnums e = TestEnums::ZERO;
- ASSERT_EQ(NamedEnum::enum_name(e), "ZERO");
-
- e = TestEnums::ONE;
- ASSERT_EQ(NamedEnum::enum_name(e), "ONE");
-
- e = TestEnums::THREE;
- ASSERT_EQ(NamedEnum::enum_name(e), "THREE");
-
- e = TestEnums::SEVEN;
- ASSERT_EQ(NamedEnum::enum_name(e), "SEVEN");
-}
-
-// Test big enum
-TEST(NamedEnum, RuntimeBigNamedEnum) {
- TestBigEnums e = TestBigEnums::ZERO;
- ASSERT_EQ(NamedEnum::enum_name(e), "ZERO");
-
- e = TestBigEnums::FIFTEEN;
- ASSERT_EQ(NamedEnum::enum_name(e), "FIFTEEN");
-}
-
-TEST(NamedEnum, RuntimeNamedEnumAsString) {
- TestEnums e = TestEnums::ZERO;
- ASSERT_EQ(NamedEnum::string(e), "ZERO");
-
- e = TestEnums::ONE;
- ASSERT_EQ(NamedEnum::string(e), "ONE");
-
- e = TestEnums::THREE;
- ASSERT_EQ(NamedEnum::string(e), "THREE");
-
- e = TestEnums::SEVEN;
- ASSERT_EQ(NamedEnum::string(e), "SEVEN");
-}
-
-TEST(NamedEnum, RuntimeBigNamedEnumAsString) {
- TestBigEnums e = TestBigEnums::ZERO;
- ASSERT_EQ(NamedEnum::string(e), "ZERO");
-
- e = TestBigEnums::FIFTEEN;
- ASSERT_EQ(NamedEnum::string(e), "FIFTEEN");
-}
-
-TEST(NamedEnum, RuntimeUnknownNamedEnum) {
- TestEnums e = static_cast<TestEnums>(0x5);
- ASSERT_EQ(NamedEnum::enum_name(e), std::nullopt);
- e = static_cast<TestEnums>(0x9);
- ASSERT_EQ(NamedEnum::enum_name(e), std::nullopt);
-}
-
-TEST(NamedEnum, RuntimeUnknownNamedEnumAsString) {
- TestEnums e = static_cast<TestEnums>(0x5);
- ASSERT_EQ(NamedEnum::string(e), "05");
- e = static_cast<TestEnums>(0x9);
- ASSERT_EQ(NamedEnum::string(e, "0x%08x"), "0x00000009");
-}
-
-TEST(NamedEnum, CompileTimeFlagName) {
- static_assert(NamedEnum::enum_name<TestEnums::TWO>() == "TWO");
- static_assert(NamedEnum::enum_name<TestEnums::THREE>() == "THREE");
-}
-
-} // namespace test
-
-} // namespace android
diff --git a/libs/ftl/cast_test.cpp b/libs/ftl/cast_test.cpp
new file mode 100644
index 0000000..2abcb8f
--- /dev/null
+++ b/libs/ftl/cast_test.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2021 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 <ftl/cast.h>
+#include <gtest/gtest.h>
+
+#include <cfloat>
+#include <cmath>
+#include <limits>
+
+namespace android::test {
+
+using ftl::cast_safety;
+using ftl::CastSafety;
+
+template <typename T>
+constexpr T min = std::numeric_limits<T>::lowest();
+
+template <typename T>
+constexpr T max = std::numeric_limits<T>::max();
+
+template <typename T>
+constexpr T inf = std::numeric_limits<T>::infinity();
+
+template <typename T>
+constexpr T NaN = std::numeric_limits<T>::quiet_NaN();
+
+// Keep in sync with example usage in header file.
+
+static_assert(cast_safety<uint8_t>(-1) == CastSafety::kUnderflow);
+static_assert(cast_safety<int8_t>(128u) == CastSafety::kOverflow);
+
+static_assert(cast_safety<uint32_t>(-.1f) == CastSafety::kUnderflow);
+static_assert(cast_safety<int32_t>(static_cast<float>(INT32_MAX)) == CastSafety::kOverflow);
+
+static_assert(cast_safety<float>(-DBL_MAX) == CastSafety::kUnderflow);
+
+// Unsigned to unsigned.
+
+static_assert(cast_safety<uint8_t>(0u) == CastSafety::kSafe);
+static_assert(cast_safety<uint16_t>(max<uint8_t>) == CastSafety::kSafe);
+static_assert(cast_safety<uint8_t>(static_cast<uint32_t>(max<uint8_t>)) == CastSafety::kSafe);
+
+static_assert(cast_safety<uint32_t>(max<uint64_t>) == CastSafety::kOverflow);
+static_assert(cast_safety<uint8_t>(static_cast<uint32_t>(max<uint8_t>) + 1) ==
+ CastSafety::kOverflow);
+
+// Unsigned to signed.
+
+static_assert(cast_safety<int16_t>(0u) == CastSafety::kSafe);
+static_assert(cast_safety<int16_t>(max<uint8_t>) == CastSafety::kSafe);
+static_assert(cast_safety<int16_t>(max<uint16_t>) == CastSafety::kOverflow);
+
+static_assert(cast_safety<int64_t>(static_cast<uint64_t>(max<int64_t>) - 1) == CastSafety::kSafe);
+static_assert(cast_safety<int64_t>(static_cast<uint64_t>(max<int64_t>)) == CastSafety::kSafe);
+static_assert(cast_safety<int64_t>(static_cast<uint64_t>(max<int64_t>) + 1) ==
+ CastSafety::kOverflow);
+
+// Signed to unsigned.
+
+static_assert(cast_safety<uint16_t>(0) == CastSafety::kSafe);
+static_assert(cast_safety<uint16_t>(max<int8_t>) == CastSafety::kSafe);
+static_assert(cast_safety<uint16_t>(max<int16_t>) == CastSafety::kSafe);
+
+static_assert(cast_safety<uint32_t>(-1) == CastSafety::kUnderflow);
+static_assert(cast_safety<uint32_t>(max<int64_t>) == CastSafety::kOverflow);
+
+static_assert(cast_safety<uint32_t>(static_cast<int64_t>(max<uint32_t>) - 1) == CastSafety::kSafe);
+static_assert(cast_safety<uint32_t>(static_cast<int64_t>(max<uint32_t>)) == CastSafety::kSafe);
+static_assert(cast_safety<uint32_t>(static_cast<int64_t>(max<uint32_t>) + 1) ==
+ CastSafety::kOverflow);
+
+// Signed to signed.
+
+static_assert(cast_safety<int8_t>(-129) == CastSafety::kUnderflow);
+static_assert(cast_safety<int8_t>(-128) == CastSafety::kSafe);
+static_assert(cast_safety<int8_t>(127) == CastSafety::kSafe);
+static_assert(cast_safety<int8_t>(128) == CastSafety::kOverflow);
+
+static_assert(cast_safety<int32_t>(static_cast<int64_t>(min<int32_t>)) == CastSafety::kSafe);
+static_assert(cast_safety<int32_t>(static_cast<int64_t>(max<int32_t>)) == CastSafety::kSafe);
+
+static_assert(cast_safety<int16_t>(min<int32_t>) == CastSafety::kUnderflow);
+static_assert(cast_safety<int32_t>(max<int64_t>) == CastSafety::kOverflow);
+
+// Float to float.
+
+static_assert(cast_safety<double>(max<float>) == CastSafety::kSafe);
+static_assert(cast_safety<double>(min<float>) == CastSafety::kSafe);
+
+static_assert(cast_safety<float>(min<double>) == CastSafety::kUnderflow);
+static_assert(cast_safety<float>(max<double>) == CastSafety::kOverflow);
+
+TEST(CastSafety, FloatToFloat) {
+ EXPECT_EQ(cast_safety<float>(std::nexttoward(static_cast<double>(min<float>), min<double>)),
+ CastSafety::kUnderflow);
+ EXPECT_EQ(cast_safety<float>(std::nexttoward(static_cast<double>(max<float>), max<double>)),
+ CastSafety::kOverflow);
+}
+
+// Unsigned to float.
+
+static_assert(cast_safety<float>(0u) == CastSafety::kSafe);
+static_assert(cast_safety<float>(max<uint64_t>) == CastSafety::kSafe);
+
+static_assert(cast_safety<double>(0u) == CastSafety::kSafe);
+static_assert(cast_safety<double>(max<uint64_t>) == CastSafety::kSafe);
+
+// Signed to float.
+
+static_assert(cast_safety<float>(min<int64_t>) == CastSafety::kSafe);
+static_assert(cast_safety<float>(max<int64_t>) == CastSafety::kSafe);
+
+static_assert(cast_safety<double>(min<int64_t>) == CastSafety::kSafe);
+static_assert(cast_safety<double>(max<int64_t>) == CastSafety::kSafe);
+
+// Float to unsigned.
+
+static_assert(cast_safety<uint32_t>(0.f) == CastSafety::kSafe);
+static_assert(cast_safety<uint32_t>(min<float>) == CastSafety::kUnderflow);
+static_assert(cast_safety<uint32_t>(max<float>) == CastSafety::kOverflow);
+static_assert(cast_safety<uint32_t>(-.1f) == CastSafety::kUnderflow);
+
+static_assert(cast_safety<uint16_t>(-inf<float>) == CastSafety::kUnderflow);
+static_assert(cast_safety<uint32_t>(inf<float>) == CastSafety::kOverflow);
+static_assert(cast_safety<uint64_t>(NaN<float>) == CastSafety::kOverflow);
+
+static_assert(cast_safety<uint32_t>(static_cast<float>(max<int32_t>)) == CastSafety::kSafe);
+static_assert(cast_safety<uint32_t>(static_cast<float>(max<uint32_t>)) == CastSafety::kOverflow);
+static_assert(cast_safety<uint32_t>(static_cast<double>(max<int32_t>)) == CastSafety::kSafe);
+static_assert(cast_safety<uint32_t>(static_cast<double>(max<uint32_t>)) == CastSafety::kSafe);
+
+static_assert(cast_safety<uint64_t>(0.0) == CastSafety::kSafe);
+static_assert(cast_safety<uint64_t>(min<double>) == CastSafety::kUnderflow);
+static_assert(cast_safety<uint64_t>(max<double>) == CastSafety::kOverflow);
+static_assert(cast_safety<uint64_t>(-.1) == CastSafety::kUnderflow);
+
+static_assert(cast_safety<uint64_t>(static_cast<float>(max<int64_t>)) == CastSafety::kSafe);
+static_assert(cast_safety<uint64_t>(static_cast<float>(max<uint64_t>)) == CastSafety::kOverflow);
+static_assert(cast_safety<uint64_t>(static_cast<double>(max<int64_t>)) == CastSafety::kSafe);
+static_assert(cast_safety<uint64_t>(static_cast<double>(max<uint64_t>)) == CastSafety::kOverflow);
+
+// Float to signed.
+
+static_assert(cast_safety<int32_t>(0.f) == CastSafety::kSafe);
+static_assert(cast_safety<int32_t>(min<float>) == CastSafety::kUnderflow);
+static_assert(cast_safety<int32_t>(max<float>) == CastSafety::kOverflow);
+
+static_assert(cast_safety<int16_t>(-inf<double>) == CastSafety::kUnderflow);
+static_assert(cast_safety<int32_t>(inf<double>) == CastSafety::kOverflow);
+static_assert(cast_safety<int64_t>(NaN<double>) == CastSafety::kOverflow);
+
+static_assert(cast_safety<int32_t>(static_cast<float>(min<int32_t>)) == CastSafety::kSafe);
+static_assert(cast_safety<int32_t>(static_cast<float>(max<int32_t>)) == CastSafety::kOverflow);
+static_assert(cast_safety<int32_t>(static_cast<double>(min<int32_t>)) == CastSafety::kSafe);
+static_assert(cast_safety<int32_t>(static_cast<double>(max<int32_t>)) == CastSafety::kSafe);
+
+static_assert(cast_safety<int64_t>(0.0) == CastSafety::kSafe);
+static_assert(cast_safety<int64_t>(min<double>) == CastSafety::kUnderflow);
+static_assert(cast_safety<int64_t>(max<double>) == CastSafety::kOverflow);
+
+static_assert(cast_safety<int64_t>(static_cast<float>(min<int64_t>)) == CastSafety::kSafe);
+static_assert(cast_safety<int64_t>(static_cast<float>(max<int64_t>)) == CastSafety::kOverflow);
+static_assert(cast_safety<int64_t>(static_cast<double>(min<int64_t>)) == CastSafety::kSafe);
+static_assert(cast_safety<int64_t>(static_cast<double>(max<int64_t>)) == CastSafety::kOverflow);
+
+TEST(CastSafety, FloatToSigned) {
+ constexpr int32_t kMax = ftl::details::safe_limits<int32_t, float>::max();
+ static_assert(kMax == 2'147'483'520);
+ EXPECT_EQ(kMax, static_cast<int32_t>(std::nexttowardf(max<int32_t>, 0)));
+
+ EXPECT_EQ(cast_safety<int32_t>(std::nexttowardf(min<int32_t>, 0)), CastSafety::kSafe);
+ EXPECT_EQ(cast_safety<int32_t>(std::nexttowardf(max<int32_t>, 0)), CastSafety::kSafe);
+ EXPECT_EQ(cast_safety<int64_t>(std::nexttoward(min<int64_t>, 0)), CastSafety::kSafe);
+ EXPECT_EQ(cast_safety<int64_t>(std::nexttoward(max<int64_t>, 0)), CastSafety::kSafe);
+
+ EXPECT_EQ(cast_safety<int32_t>(std::nexttowardf(min<int32_t>, min<float>)),
+ CastSafety::kUnderflow);
+ EXPECT_EQ(cast_safety<int32_t>(std::nexttowardf(max<int32_t>, max<float>)),
+ CastSafety::kOverflow);
+ EXPECT_EQ(cast_safety<int64_t>(std::nexttoward(min<int64_t>, min<double>)),
+ CastSafety::kUnderflow);
+ EXPECT_EQ(cast_safety<int64_t>(std::nexttoward(max<int64_t>, max<double>)),
+ CastSafety::kOverflow);
+}
+
+} // namespace android::test
diff --git a/libs/ftl/enum_test.cpp b/libs/ftl/enum_test.cpp
new file mode 100644
index 0000000..1fd43ab
--- /dev/null
+++ b/libs/ftl/enum_test.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2021 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 <ftl/enum.h>
+#include <gtest/gtest.h>
+
+namespace android::test {
+
+// Keep in sync with example usage in header file.
+namespace {
+
+enum class E { A, B, C, F = 5, ftl_last = F };
+
+static_assert(ftl::enum_begin_v<E> == E::A);
+static_assert(ftl::enum_last_v<E> == E::F);
+static_assert(ftl::enum_size_v<E> == 6);
+
+static_assert(ftl::enum_name<E::B>() == "B");
+static_assert(ftl::enum_name<E::ftl_last>() == "F");
+static_assert(ftl::enum_name(E::C).value_or("?") == "C");
+static_assert(ftl::enum_name(E{3}).value_or("?") == "?");
+
+enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 };
+
+static_assert(ftl::enum_begin_v<F> == F{0});
+static_assert(ftl::enum_last_v<F> == F{15});
+static_assert(ftl::enum_size_v<F> == 16);
+
+static_assert(ftl::flag_name(F::Z).value_or("?") == "Z");
+static_assert(ftl::flag_name(F{0b111}).value_or("?") == "?");
+
+// If a scoped enum is unsigned, its implicit range corresponds to its bit indices.
+enum class Flags : std::uint8_t {
+ kNone = 0,
+ kFlag1 = 0b0000'0010,
+ kFlag4 = 0b0001'0000,
+ kFlag7 = 0b1000'0000,
+ kMask = kFlag1 | kFlag4 | kFlag7,
+ kAll = 0b1111'1111
+};
+
+static_assert(ftl::enum_begin_v<Flags> == Flags{0});
+static_assert(ftl::enum_last_v<Flags> == Flags{7});
+static_assert(ftl::enum_size_v<Flags> == 8);
+
+static_assert(ftl::enum_name<Flags::kNone>() == "kNone");
+static_assert(ftl::enum_name<Flags::kFlag4>() == "kFlag4");
+static_assert(ftl::enum_name<Flags::kFlag7>() == "kFlag7");
+
+// Though not flags, the enumerators are within the implicit range of bit indices.
+enum class Planet : std::uint8_t {
+ kMercury,
+ kVenus,
+ kEarth,
+ kMars,
+ kJupiter,
+ kSaturn,
+ kUranus,
+ kNeptune
+};
+
+constexpr Planet kPluto{ftl::enum_cast(Planet::kNeptune) + 1}; // Honorable mention.
+
+static_assert(ftl::enum_begin_v<Planet> == Planet::kMercury);
+static_assert(ftl::enum_last_v<Planet> == Planet::kNeptune);
+static_assert(ftl::enum_size_v<Planet> == 8);
+
+static_assert(ftl::enum_name<Planet::kMercury>() == "kMercury");
+static_assert(ftl::enum_name<Planet::kSaturn>() == "kSaturn");
+
+// Unscoped enum must define explicit range, even if the underlying type is fixed.
+enum Temperature : int {
+ kRoom = 20,
+ kFridge = 4,
+ kFreezer = -18,
+
+ ftl_first = kFreezer,
+ ftl_last = kRoom
+};
+
+static_assert(ftl::enum_begin_v<Temperature> == kFreezer);
+static_assert(ftl::enum_last_v<Temperature> == kRoom);
+static_assert(ftl::enum_size_v<Temperature> == 39);
+
+static_assert(ftl::enum_name<kFreezer>() == "kFreezer");
+static_assert(ftl::enum_name<kFridge>() == "kFridge");
+static_assert(ftl::enum_name<kRoom>() == "kRoom");
+
+} // namespace
+
+TEST(Enum, Range) {
+ std::string string;
+ for (E v : ftl::enum_range<E>()) {
+ string += ftl::enum_name(v).value_or("?");
+ }
+ EXPECT_EQ(string, "ABC??F");
+}
+
+TEST(Enum, Name) {
+ {
+ EXPECT_EQ(ftl::flag_name(Flags::kFlag1), "kFlag1");
+ EXPECT_EQ(ftl::flag_name(Flags::kFlag7), "kFlag7");
+
+ EXPECT_EQ(ftl::flag_name(Flags::kNone), std::nullopt);
+ EXPECT_EQ(ftl::flag_name(Flags::kMask), std::nullopt);
+ EXPECT_EQ(ftl::flag_name(Flags::kAll), std::nullopt);
+ }
+ {
+ EXPECT_EQ(ftl::enum_name(Planet::kEarth), "kEarth");
+ EXPECT_EQ(ftl::enum_name(Planet::kNeptune), "kNeptune");
+
+ EXPECT_EQ(ftl::enum_name(kPluto), std::nullopt);
+ }
+ {
+ EXPECT_EQ(ftl::enum_name(kRoom), "kRoom");
+ EXPECT_EQ(ftl::enum_name(kFridge), "kFridge");
+ EXPECT_EQ(ftl::enum_name(kFreezer), "kFreezer");
+
+ EXPECT_EQ(ftl::enum_name(static_cast<Temperature>(-30)), std::nullopt);
+ EXPECT_EQ(ftl::enum_name(static_cast<Temperature>(0)), std::nullopt);
+ EXPECT_EQ(ftl::enum_name(static_cast<Temperature>(100)), std::nullopt);
+ }
+}
+
+TEST(Enum, String) {
+ {
+ EXPECT_EQ(ftl::flag_string(Flags::kFlag1), "kFlag1");
+ EXPECT_EQ(ftl::flag_string(Flags::kFlag7), "kFlag7");
+
+ EXPECT_EQ(ftl::flag_string(Flags::kNone), "0b0");
+ EXPECT_EQ(ftl::flag_string(Flags::kMask), "0b10010010");
+ EXPECT_EQ(ftl::flag_string(Flags::kAll), "0b11111111");
+ }
+ {
+ EXPECT_EQ(ftl::enum_string(Planet::kEarth), "kEarth");
+ EXPECT_EQ(ftl::enum_string(Planet::kNeptune), "kNeptune");
+
+ EXPECT_EQ(ftl::enum_string(kPluto), "8");
+ }
+ {
+ EXPECT_EQ(ftl::enum_string(kRoom), "kRoom");
+ EXPECT_EQ(ftl::enum_string(kFridge), "kFridge");
+ EXPECT_EQ(ftl::enum_string(kFreezer), "kFreezer");
+
+ EXPECT_EQ(ftl::enum_string(static_cast<Temperature>(-30)), "-30");
+ EXPECT_EQ(ftl::enum_string(static_cast<Temperature>(0)), "0");
+ EXPECT_EQ(ftl::enum_string(static_cast<Temperature>(100)), "100");
+ }
+}
+
+} // namespace android::test
diff --git a/libs/ftl/small_map_test.cpp b/libs/ftl/small_map_test.cpp
index 323b9f9..2e81022 100644
--- a/libs/ftl/small_map_test.cpp
+++ b/libs/ftl/small_map_test.cpp
@@ -18,6 +18,9 @@
#include <gtest/gtest.h>
#include <cctype>
+#include <string>
+
+using namespace std::string_literals;
namespace android::test {
@@ -35,16 +38,19 @@
EXPECT_TRUE(map.contains(123));
- EXPECT_EQ(map.find(42, [](const std::string& s) { return s.size(); }), 3u);
+ EXPECT_EQ(map.get(42, [](const std::string& s) { return s.size(); }), 3u);
- const auto opt = map.find(-1);
+ const auto opt = map.get(-1);
ASSERT_TRUE(opt);
std::string& ref = *opt;
EXPECT_TRUE(ref.empty());
ref = "xyz";
- EXPECT_EQ(map, SmallMap(ftl::init::map(-1, "xyz")(42, "???")(123, "abc")));
+ map.emplace_or_replace(0, "vanilla", 2u, 3u);
+ EXPECT_TRUE(map.dynamic());
+
+ EXPECT_EQ(map, SmallMap(ftl::init::map(-1, "xyz")(0, "nil")(42, "???")(123, "abc")));
}
TEST(SmallMap, Construct) {
@@ -90,42 +96,253 @@
}
}
+TEST(SmallMap, UniqueKeys) {
+ {
+ // Duplicate mappings are discarded.
+ const SmallMap map = ftl::init::map<int, float>(1)(2)(3)(2)(3)(1)(3)(2)(1);
+
+ EXPECT_EQ(map.size(), 3u);
+ EXPECT_EQ(map.max_size(), 9u);
+
+ using Map = decltype(map);
+ EXPECT_EQ(map, Map(ftl::init::map(1, 0.f)(2, 0.f)(3, 0.f)));
+ }
+ {
+ // Duplicate mappings may be reordered.
+ const SmallMap map = ftl::init::map('a', 'A')(
+ 'b', 'B')('b')('b')('c', 'C')('a')('d')('c')('e', 'E')('d', 'D')('a')('f', 'F');
+
+ EXPECT_EQ(map.size(), 6u);
+ EXPECT_EQ(map.max_size(), 12u);
+
+ using Map = decltype(map);
+ EXPECT_EQ(map, Map(ftl::init::map('a', 'A')('b', 'B')('c', 'C')('d', 'D')('e', 'E')('f', 'F')));
+ }
+}
+
TEST(SmallMap, Find) {
{
// Constant reference.
- const ftl::SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C');
+ const SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C');
- const auto opt = map.find('b');
+ const auto opt = map.get('b');
EXPECT_EQ(opt, 'B');
const char d = 'D';
- const auto ref = map.find('d').value_or(std::cref(d));
+ const auto ref = map.get('d').value_or(std::cref(d));
EXPECT_EQ(ref.get(), 'D');
}
{
// Mutable reference.
- ftl::SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C');
+ SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C');
- const auto opt = map.find('c');
+ const auto opt = map.get('c');
EXPECT_EQ(opt, 'C');
char d = 'd';
- const auto ref = map.find('d').value_or(std::ref(d));
+ const auto ref = map.get('d').value_or(std::ref(d));
ref.get() = 'D';
EXPECT_EQ(d, 'D');
}
{
// Constant unary operation.
- const ftl::SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z');
- EXPECT_EQ(map.find('c', [](char c) { return std::toupper(c); }), 'Z');
+ const SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z');
+ EXPECT_EQ(map.get('c', [](char c) { return std::toupper(c); }), 'Z');
}
{
// Mutable unary operation.
- ftl::SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z');
- EXPECT_TRUE(map.find('c', [](char& c) { c = std::toupper(c); }));
+ SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z');
+ EXPECT_TRUE(map.get('c', [](char& c) { c = std::toupper(c); }));
EXPECT_EQ(map, SmallMap(ftl::init::map('c', 'Z')('b', 'y')('a', 'x')));
}
}
+TEST(SmallMap, TryEmplace) {
+ SmallMap<int, std::string, 3> map;
+ using Pair = decltype(map)::value_type;
+
+ {
+ const auto [it, ok] = map.try_emplace(123, "abc");
+ ASSERT_TRUE(ok);
+ EXPECT_EQ(*it, Pair(123, "abc"s));
+ }
+ {
+ const auto [it, ok] = map.try_emplace(42, 3u, '?');
+ ASSERT_TRUE(ok);
+ EXPECT_EQ(*it, Pair(42, "???"s));
+ }
+ {
+ const auto [it, ok] = map.try_emplace(-1);
+ ASSERT_TRUE(ok);
+ EXPECT_EQ(*it, Pair(-1, std::string()));
+ EXPECT_FALSE(map.dynamic());
+ }
+ {
+ // Insertion fails if mapping exists.
+ const auto [it, ok] = map.try_emplace(42, "!!!");
+ EXPECT_FALSE(ok);
+ EXPECT_EQ(*it, Pair(42, "???"));
+ EXPECT_FALSE(map.dynamic());
+ }
+ {
+ // Insertion at capacity promotes the map.
+ const auto [it, ok] = map.try_emplace(999, "xyz");
+ ASSERT_TRUE(ok);
+ EXPECT_EQ(*it, Pair(999, "xyz"));
+ EXPECT_TRUE(map.dynamic());
+ }
+
+ EXPECT_EQ(map, SmallMap(ftl::init::map(-1, ""s)(42, "???"s)(123, "abc"s)(999, "xyz"s)));
+}
+
+namespace {
+
+// The mapped type does not require a copy/move assignment operator.
+struct String {
+ template <typename... Args>
+ String(Args... args) : str(args...) {}
+ const std::string str;
+
+ bool operator==(const String& other) const { return other.str == str; }
+};
+
+} // namespace
+
+TEST(SmallMap, TryReplace) {
+ SmallMap<int, String, 3> map = ftl::init::map(1, "a")(2, "B");
+ using Pair = decltype(map)::value_type;
+
+ {
+ // Replacing fails unless mapping exists.
+ const auto it = map.try_replace(3, "c");
+ EXPECT_EQ(it, map.end());
+ }
+ {
+ // Replacement arguments can refer to the replaced mapping.
+ const auto ref = map.get(2, [](const auto& s) { return s.str[0]; });
+ ASSERT_TRUE(ref);
+
+ // Construct std::string from one character.
+ const auto it = map.try_replace(2, 1u, static_cast<char>(std::tolower(*ref)));
+ ASSERT_NE(it, map.end());
+ EXPECT_EQ(*it, Pair(2, "b"));
+ }
+
+ EXPECT_FALSE(map.dynamic());
+ EXPECT_TRUE(map.try_emplace(3, "abc").second);
+ EXPECT_TRUE(map.try_emplace(4, "d").second);
+ EXPECT_TRUE(map.dynamic());
+
+ {
+ // Replacing fails unless mapping exists.
+ const auto it = map.try_replace(5, "e");
+ EXPECT_EQ(it, map.end());
+ }
+ {
+ // Replacement arguments can refer to the replaced mapping.
+ const auto ref = map.get(3);
+ ASSERT_TRUE(ref);
+
+ // Construct std::string from substring.
+ const auto it = map.try_replace(3, ref->get().str, 2u, 1u);
+ ASSERT_NE(it, map.end());
+ EXPECT_EQ(*it, Pair(3, "c"));
+ }
+
+ EXPECT_EQ(map, SmallMap(ftl::init::map(4, "d"s)(3, "c"s)(2, "b"s)(1, "a"s)));
+}
+
+TEST(SmallMap, EmplaceOrReplace) {
+ SmallMap<int, String, 3> map = ftl::init::map(1, "a")(2, "B");
+ using Pair = decltype(map)::value_type;
+
+ {
+ // New mapping is emplaced.
+ const auto [it, emplace] = map.emplace_or_replace(3, "c");
+ EXPECT_TRUE(emplace);
+ EXPECT_EQ(*it, Pair(3, "c"));
+ }
+ {
+ // Replacement arguments can refer to the replaced mapping.
+ const auto ref = map.get(2, [](const auto& s) { return s.str[0]; });
+ ASSERT_TRUE(ref);
+
+ // Construct std::string from one character.
+ const auto [it, emplace] = map.emplace_or_replace(2, 1u, static_cast<char>(std::tolower(*ref)));
+ EXPECT_FALSE(emplace);
+ EXPECT_EQ(*it, Pair(2, "b"));
+ }
+
+ EXPECT_FALSE(map.dynamic());
+ EXPECT_FALSE(map.emplace_or_replace(3, "abc").second); // Replace.
+ EXPECT_TRUE(map.emplace_or_replace(4, "d").second); // Emplace.
+ EXPECT_TRUE(map.dynamic());
+
+ {
+ // New mapping is emplaced.
+ const auto [it, emplace] = map.emplace_or_replace(5, "e");
+ EXPECT_TRUE(emplace);
+ EXPECT_EQ(*it, Pair(5, "e"));
+ }
+ {
+ // Replacement arguments can refer to the replaced mapping.
+ const auto ref = map.get(3);
+ ASSERT_TRUE(ref);
+
+ // Construct std::string from substring.
+ const auto [it, emplace] = map.emplace_or_replace(3, ref->get().str, 2u, 1u);
+ EXPECT_FALSE(emplace);
+ EXPECT_EQ(*it, Pair(3, "c"));
+ }
+
+ EXPECT_EQ(map, SmallMap(ftl::init::map(5, "e"s)(4, "d"s)(3, "c"s)(2, "b"s)(1, "a"s)));
+}
+
+TEST(SmallMap, Erase) {
+ {
+ SmallMap map = ftl::init::map(1, '1')(2, '2')(3, '3')(4, '4');
+ EXPECT_FALSE(map.dynamic());
+
+ EXPECT_FALSE(map.erase(0)); // Key not found.
+
+ EXPECT_TRUE(map.erase(2));
+ EXPECT_EQ(map, SmallMap(ftl::init::map(1, '1')(3, '3')(4, '4')));
+
+ EXPECT_TRUE(map.erase(1));
+ EXPECT_EQ(map, SmallMap(ftl::init::map(3, '3')(4, '4')));
+
+ EXPECT_TRUE(map.erase(4));
+ EXPECT_EQ(map, SmallMap(ftl::init::map(3, '3')));
+
+ EXPECT_TRUE(map.erase(3));
+ EXPECT_FALSE(map.erase(3)); // Key not found.
+
+ EXPECT_TRUE(map.empty());
+ EXPECT_FALSE(map.dynamic());
+ }
+ {
+ SmallMap map = ftl::init::map(1, '1')(2, '2')(3, '3');
+ map.try_emplace(4, '4');
+ EXPECT_TRUE(map.dynamic());
+
+ EXPECT_FALSE(map.erase(0)); // Key not found.
+
+ EXPECT_TRUE(map.erase(2));
+ EXPECT_EQ(map, SmallMap(ftl::init::map(1, '1')(3, '3')(4, '4')));
+
+ EXPECT_TRUE(map.erase(1));
+ EXPECT_EQ(map, SmallMap(ftl::init::map(3, '3')(4, '4')));
+
+ EXPECT_TRUE(map.erase(4));
+ EXPECT_EQ(map, SmallMap(ftl::init::map(3, '3')));
+
+ EXPECT_TRUE(map.erase(3));
+ EXPECT_FALSE(map.erase(3)); // Key not found.
+
+ EXPECT_TRUE(map.empty());
+ EXPECT_TRUE(map.dynamic());
+ }
+}
+
} // namespace android::test
diff --git a/libs/ftl/string_test.cpp b/libs/ftl/string_test.cpp
new file mode 100644
index 0000000..f3d85c8
--- /dev/null
+++ b/libs/ftl/string_test.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2021 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 <ftl/string.h>
+#include <gtest/gtest.h>
+
+#include <algorithm>
+#include <cstdint>
+#include <iterator>
+#include <limits>
+#include <sstream>
+#include <type_traits>
+
+namespace android::test {
+
+// Keep in sync with example usage in header file.
+TEST(String, ToChars) {
+ ftl::to_chars_buffer_t<> buffer;
+
+ EXPECT_EQ(ftl::to_chars(buffer, 123u), "123");
+ EXPECT_EQ(ftl::to_chars(buffer, -42, ftl::Radix::kBin), "-0b101010");
+ EXPECT_EQ(ftl::to_chars(buffer, 0xcafe, ftl::Radix::kHex), "0xcafe");
+ EXPECT_EQ(ftl::to_chars(buffer, '*', ftl::Radix::kHex), "0x2a");
+}
+
+namespace {
+
+template <typename F, typename T>
+void ToCharsTest() {
+ constexpr auto kRadix = F::kRadix;
+
+ using Limits = std::numeric_limits<T>;
+ constexpr auto kMin = Limits::min();
+ constexpr auto kMax = Limits::max();
+ constexpr auto kNeg = static_cast<T>(-42);
+ constexpr auto kPos = static_cast<T>(123);
+
+ ftl::to_chars_buffer_t<T> buffer;
+
+ EXPECT_EQ(ftl::to_chars(buffer, kMin, kRadix), F{}(kMin));
+ EXPECT_EQ(ftl::to_chars(buffer, kMax, kRadix), F{}(kMax));
+ EXPECT_EQ(ftl::to_chars(buffer, kNeg, kRadix), F{}(kNeg));
+ EXPECT_EQ(ftl::to_chars(buffer, kPos, kRadix), F{}(kPos));
+}
+
+template <typename...>
+struct Types {};
+
+template <typename F, typename Types>
+struct ToCharsTests;
+
+template <typename F, typename T, typename... Ts>
+struct ToCharsTests<F, Types<T, Ts...>> {
+ static void test() {
+ ToCharsTest<F, T>();
+ ToCharsTests<F, Types<Ts...>>::test();
+ }
+};
+
+template <typename F>
+struct ToCharsTests<F, Types<>> {
+ static void test() {}
+};
+
+template <typename T, typename U = std::make_unsigned_t<T>>
+U to_unsigned(std::ostream& stream, T v) {
+ if (std::is_same_v<T, U>) return v;
+
+ if (v < 0) {
+ stream << '-';
+ return std::numeric_limits<U>::max() - static_cast<U>(v) + 1;
+ } else {
+ return static_cast<U>(v);
+ }
+}
+
+struct Bin {
+ static constexpr auto kRadix = ftl::Radix::kBin;
+
+ template <typename T>
+ std::string operator()(T v) const {
+ std::ostringstream stream;
+ auto u = to_unsigned(stream, v);
+ stream << "0b";
+
+ if (u == 0) {
+ stream << 0;
+ } else {
+ std::ostringstream digits;
+ do {
+ digits << (u & 1);
+ } while (u >>= 1);
+
+ const auto str = digits.str();
+ std::copy(str.rbegin(), str.rend(), std::ostream_iterator<char>(stream));
+ }
+
+ return stream.str();
+ }
+};
+
+struct Dec {
+ static constexpr auto kRadix = ftl::Radix::kDec;
+
+ template <typename T>
+ std::string operator()(T v) const {
+ return std::to_string(v);
+ }
+};
+
+struct Hex {
+ static constexpr auto kRadix = ftl::Radix::kHex;
+
+ template <typename T>
+ std::string operator()(T v) const {
+ std::ostringstream stream;
+ const auto u = to_unsigned(stream, v);
+ stream << "0x" << std::hex << std::nouppercase;
+ stream << (sizeof(T) == 1 ? static_cast<unsigned>(u) : u);
+ return stream.str();
+ }
+};
+
+using IntegerTypes =
+ Types<char, unsigned char, signed char, std::uint8_t, std::uint16_t, std::uint32_t,
+ std::uint64_t, std::int8_t, std::int16_t, std::int32_t, std::int64_t>;
+
+} // namespace
+
+TEST(String, ToCharsBin) {
+ ToCharsTests<Bin, IntegerTypes>::test();
+
+ {
+ const std::uint8_t x = 0b1111'1111;
+ ftl::to_chars_buffer_t<decltype(x)> buffer;
+ EXPECT_EQ(ftl::to_chars(buffer, x, ftl::Radix::kBin), "0b11111111");
+ }
+ {
+ const std::int16_t x = -0b1000'0000'0000'0000;
+ ftl::to_chars_buffer_t<decltype(x)> buffer;
+ EXPECT_EQ(ftl::to_chars(buffer, x, ftl::Radix::kBin), "-0b1000000000000000");
+ }
+}
+
+TEST(String, ToCharsDec) {
+ ToCharsTests<Dec, IntegerTypes>::test();
+
+ {
+ const std::uint32_t x = UINT32_MAX;
+ ftl::to_chars_buffer_t<decltype(x)> buffer;
+ EXPECT_EQ(ftl::to_chars(buffer, x), "4294967295");
+ }
+ {
+ const std::int32_t x = INT32_MIN;
+ ftl::to_chars_buffer_t<decltype(x)> buffer;
+ EXPECT_EQ(ftl::to_chars(buffer, x), "-2147483648");
+ }
+}
+
+TEST(String, ToCharsHex) {
+ ToCharsTests<Hex, IntegerTypes>::test();
+
+ {
+ const std::uint16_t x = 0xfade;
+ ftl::to_chars_buffer_t<decltype(x)> buffer;
+ EXPECT_EQ(ftl::to_chars(buffer, x, ftl::Radix::kHex), "0xfade");
+ }
+ {
+ ftl::to_chars_buffer_t<> buffer;
+ EXPECT_EQ(ftl::to_chars(buffer, INT64_MIN, ftl::Radix::kHex), "-0x8000000000000000");
+ }
+}
+
+} // namespace android::test
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 326da3a..2d1f5a1 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -65,11 +65,13 @@
host_supported: true,
srcs: [
":guiconstants_aidl",
+ "android/gui/DisplayInfo.aidl",
"android/gui/FocusRequest.aidl",
"android/gui/InputApplicationInfo.aidl",
"android/gui/IWindowInfosListener.aidl",
"android/gui/IWindowInfosReportedListener.aidl",
"android/gui/WindowInfo.aidl",
+ "DisplayInfo.cpp",
"WindowInfo.cpp",
],
@@ -90,7 +92,7 @@
],
aidl: {
- export_aidl_headers: true
+ export_aidl_headers: true,
},
include_dirs: [
@@ -135,8 +137,8 @@
],
aidl: {
- export_aidl_headers: true
- }
+ export_aidl_headers: true,
+ },
}
cc_library_shared {
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index d1f57b0..379b090 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -508,21 +508,7 @@
}
}
- auto mergeTransaction =
- [&t, currentFrameNumber = bufferItem.mFrameNumber](
- std::tuple<uint64_t, SurfaceComposerClient::Transaction> pendingTransaction) {
- auto& [targetFrameNumber, transaction] = pendingTransaction;
- if (currentFrameNumber < targetFrameNumber) {
- return false;
- }
- t->merge(std::move(transaction));
- return true;
- };
-
- mPendingTransactions.erase(std::remove_if(mPendingTransactions.begin(),
- mPendingTransactions.end(), mergeTransaction),
- mPendingTransactions.end());
-
+ mergePendingTransactions(t, bufferItem.mFrameNumber);
if (applyTransaction) {
t->setApplyToken(mApplyToken).apply();
}
@@ -726,6 +712,32 @@
}
}
+void BLASTBufferQueue::applyPendingTransactions(uint64_t frameNumber) {
+ std::lock_guard _lock{mMutex};
+
+ SurfaceComposerClient::Transaction t;
+ mergePendingTransactions(&t, frameNumber);
+ t.setApplyToken(mApplyToken).apply();
+}
+
+void BLASTBufferQueue::mergePendingTransactions(SurfaceComposerClient::Transaction* t,
+ uint64_t frameNumber) {
+ auto mergeTransaction =
+ [&t, currentFrameNumber = frameNumber](
+ std::tuple<uint64_t, SurfaceComposerClient::Transaction> pendingTransaction) {
+ auto& [targetFrameNumber, transaction] = pendingTransaction;
+ if (currentFrameNumber < targetFrameNumber) {
+ return false;
+ }
+ t->merge(std::move(transaction));
+ return true;
+ };
+
+ mPendingTransactions.erase(std::remove_if(mPendingTransactions.begin(),
+ mPendingTransactions.end(), mergeTransaction),
+ mPendingTransactions.end());
+}
+
// Maintains a single worker thread per process that services a list of runnables.
class AsyncWorker : public Singleton<AsyncWorker> {
private:
@@ -856,4 +868,9 @@
}
}
+uint64_t BLASTBufferQueue::getLastAcquiredFrameNum() {
+ std::unique_lock _lock{mMutex};
+ return mLastAcquiredFrameNumber;
+}
+
} // namespace android
diff --git a/libs/gui/DisplayInfo.cpp b/libs/gui/DisplayInfo.cpp
new file mode 100644
index 0000000..52d9540
--- /dev/null
+++ b/libs/gui/DisplayInfo.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2021 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.
+ */
+
+#define LOG_TAG "DisplayInfo"
+
+#include <binder/Parcel.h>
+#include <gui/DisplayInfo.h>
+#include <private/gui/ParcelUtils.h>
+
+#include <log/log.h>
+
+namespace android::gui {
+
+// --- DisplayInfo ---
+
+status_t DisplayInfo::readFromParcel(const android::Parcel* parcel) {
+ if (parcel == nullptr) {
+ ALOGE("%s: Null parcel", __func__);
+ return BAD_VALUE;
+ }
+
+ float dsdx, dtdx, tx, dtdy, dsdy, ty;
+ SAFE_PARCEL(parcel->readInt32, &displayId);
+ SAFE_PARCEL(parcel->readInt32, &logicalWidth);
+ SAFE_PARCEL(parcel->readInt32, &logicalHeight);
+ SAFE_PARCEL(parcel->readFloat, &dsdx);
+ SAFE_PARCEL(parcel->readFloat, &dtdx);
+ SAFE_PARCEL(parcel->readFloat, &tx);
+ SAFE_PARCEL(parcel->readFloat, &dtdy);
+ SAFE_PARCEL(parcel->readFloat, &dsdy);
+ SAFE_PARCEL(parcel->readFloat, &ty);
+
+ transform.set({dsdx, dtdx, tx, dtdy, dsdy, ty, 0, 0, 1});
+
+ return OK;
+}
+
+status_t DisplayInfo::writeToParcel(android::Parcel* parcel) const {
+ if (parcel == nullptr) {
+ ALOGE("%s: Null parcel", __func__);
+ return BAD_VALUE;
+ }
+
+ SAFE_PARCEL(parcel->writeInt32, displayId);
+ SAFE_PARCEL(parcel->writeInt32, logicalWidth);
+ SAFE_PARCEL(parcel->writeInt32, logicalHeight);
+ SAFE_PARCEL(parcel->writeFloat, transform.dsdx());
+ SAFE_PARCEL(parcel->writeFloat, transform.dtdx());
+ SAFE_PARCEL(parcel->writeFloat, transform.tx());
+ SAFE_PARCEL(parcel->writeFloat, transform.dtdy());
+ SAFE_PARCEL(parcel->writeFloat, transform.dsdy());
+ SAFE_PARCEL(parcel->writeFloat, transform.ty());
+
+ return OK;
+}
+
+} // namespace android::gui
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 2a980bd..3bf6306 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -124,11 +124,11 @@
return remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY, data, &reply);
}
- status_t captureDisplay(uint64_t displayOrLayerStack,
+ status_t captureDisplay(DisplayId displayId,
const sp<IScreenCaptureListener>& captureListener) override {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- SAFE_PARCEL(data.writeUint64, displayOrLayerStack);
+ SAFE_PARCEL(data.writeUint64, displayId.value);
SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(captureListener));
return remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY_BY_ID, data, &reply);
@@ -282,9 +282,14 @@
NO_ERROR) {
std::vector<uint64_t> rawIds;
if (reply.readUint64Vector(&rawIds) == NO_ERROR) {
- std::vector<PhysicalDisplayId> displayIds(rawIds.size());
- std::transform(rawIds.begin(), rawIds.end(), displayIds.begin(),
- [](uint64_t rawId) { return PhysicalDisplayId(rawId); });
+ std::vector<PhysicalDisplayId> displayIds;
+ displayIds.reserve(rawIds.size());
+
+ for (const uint64_t rawId : rawIds) {
+ if (const auto id = DisplayId::fromValue<PhysicalDisplayId>(rawId)) {
+ displayIds.push_back(*id);
+ }
+ }
return displayIds;
}
}
@@ -1344,12 +1349,15 @@
}
case CAPTURE_DISPLAY_BY_ID: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- uint64_t displayOrLayerStack = 0;
+ uint64_t value;
+ SAFE_PARCEL(data.readUint64, &value);
+ const auto id = DisplayId::fromValue(value);
+ if (!id) return BAD_VALUE;
+
sp<IScreenCaptureListener> captureListener;
- SAFE_PARCEL(data.readUint64, &displayOrLayerStack);
SAFE_PARCEL(data.readStrongBinder, &captureListener);
- return captureDisplay(displayOrLayerStack, captureListener);
+ return captureDisplay(*id, captureListener);
}
case CAPTURE_LAYERS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
@@ -1416,9 +1424,9 @@
}
case GET_PHYSICAL_DISPLAY_TOKEN: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- PhysicalDisplayId displayId(data.readUint64());
- sp<IBinder> display = getPhysicalDisplayToken(displayId);
- reply->writeStrongBinder(display);
+ const auto id = DisplayId::fromValue<PhysicalDisplayId>(data.readUint64());
+ if (!id) return BAD_VALUE;
+ reply->writeStrongBinder(getPhysicalDisplayToken(*id));
return NO_ERROR;
}
case GET_DISPLAY_STATE: {
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 8a7a871..1fd9d13 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -41,7 +41,6 @@
z(0),
w(0),
h(0),
- layerStack(0),
alpha(0),
flags(0),
mask(0),
@@ -86,7 +85,7 @@
SAFE_PARCEL(output.writeInt32, z);
SAFE_PARCEL(output.writeUint32, w);
SAFE_PARCEL(output.writeUint32, h);
- SAFE_PARCEL(output.writeUint32, layerStack);
+ SAFE_PARCEL(output.writeUint32, layerStack.id);
SAFE_PARCEL(output.writeFloat, alpha);
SAFE_PARCEL(output.writeUint32, flags);
SAFE_PARCEL(output.writeUint32, mask);
@@ -188,7 +187,7 @@
SAFE_PARCEL(input.readInt32, &z);
SAFE_PARCEL(input.readUint32, &w);
SAFE_PARCEL(input.readUint32, &h);
- SAFE_PARCEL(input.readUint32, &layerStack);
+ SAFE_PARCEL(input.readUint32, &layerStack.id);
SAFE_PARCEL(input.readFloat, &alpha);
SAFE_PARCEL(input.readUint32, &flags);
@@ -316,21 +315,14 @@
return state.read(input);
}
-DisplayState::DisplayState()
- : what(0),
- layerStack(0),
- flags(0),
- layerStackSpaceRect(Rect::EMPTY_RECT),
- orientedDisplaySpaceRect(Rect::EMPTY_RECT),
- width(0),
- height(0) {}
+DisplayState::DisplayState() = default;
status_t DisplayState::write(Parcel& output) const {
SAFE_PARCEL(output.writeStrongBinder, token);
SAFE_PARCEL(output.writeStrongBinder, IInterface::asBinder(surface));
SAFE_PARCEL(output.writeUint32, what);
- SAFE_PARCEL(output.writeUint32, layerStack);
SAFE_PARCEL(output.writeUint32, flags);
+ SAFE_PARCEL(output.writeUint32, layerStack.id);
SAFE_PARCEL(output.writeUint32, toRotationInt(orientation));
SAFE_PARCEL(output.write, layerStackSpaceRect);
SAFE_PARCEL(output.write, orientedDisplaySpaceRect);
@@ -346,8 +338,8 @@
surface = interface_cast<IGraphicBufferProducer>(tmpBinder);
SAFE_PARCEL(input.readUint32, &what);
- SAFE_PARCEL(input.readUint32, &layerStack);
SAFE_PARCEL(input.readUint32, &flags);
+ SAFE_PARCEL(input.readUint32, &layerStack.id);
uint32_t tmpUint = 0;
SAFE_PARCEL(input.readUint32, &tmpUint);
orientation = ui::toRotation(tmpUint);
@@ -563,10 +555,13 @@
what |= eDestinationFrameChanged;
destinationFrame = other.destinationFrame;
}
+ if (other.what & eProducerDisconnect) {
+ what |= eProducerDisconnect;
+ }
if ((other.what & what) != other.what) {
ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
- "other.what=0x%" PRIu64 " what=0x%" PRIu64,
- other.what, what);
+ "other.what=0x%" PRIX64 " what=0x%" PRIX64 " unmerged flags=0x%" PRIX64,
+ other.what, what, (other.what & what) ^ other.what);
}
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index a2037ac..1bca6f9 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1108,7 +1108,7 @@
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayerStack(
- const sp<SurfaceControl>& sc, uint32_t layerStack) {
+ const sp<SurfaceControl>& sc, ui::LayerStack layerStack) {
layer_state_t* s = getLayerState(sc);
if (!s) {
mStatus = BAD_INDEX;
@@ -1773,7 +1773,7 @@
}
void SurfaceComposerClient::Transaction::setDisplayLayerStack(const sp<IBinder>& token,
- uint32_t layerStack) {
+ ui::LayerStack layerStack) {
DisplayState& s(getDisplayState(token));
s.layerStack = layerStack;
s.what |= DisplayState::eLayerStackChanged;
@@ -2197,12 +2197,12 @@
return s->captureDisplay(captureArgs, captureListener);
}
-status_t ScreenshotClient::captureDisplay(uint64_t displayOrLayerStack,
+status_t ScreenshotClient::captureDisplay(DisplayId displayId,
const sp<IScreenCaptureListener>& captureListener) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == nullptr) return NO_INIT;
- return s->captureDisplay(displayOrLayerStack, captureListener);
+ return s->captureDisplay(displayId, captureListener);
}
status_t ScreenshotClient::captureLayers(const LayerCaptureArgs& captureArgs,
diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp
index b2ef7aa..5f3a726 100644
--- a/libs/gui/WindowInfo.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -54,12 +54,11 @@
info.frameLeft == frameLeft && info.frameTop == frameTop &&
info.frameRight == frameRight && info.frameBottom == frameBottom &&
info.surfaceInset == surfaceInset && info.globalScaleFactor == globalScaleFactor &&
- info.transform == transform && info.displayOrientation == displayOrientation &&
- info.displayWidth == displayWidth && info.displayHeight == displayHeight &&
- info.touchableRegion.hasSameRects(touchableRegion) && info.visible == visible &&
- info.trustedOverlay == trustedOverlay && info.focusable == focusable &&
- info.touchOcclusionMode == touchOcclusionMode && info.hasWallpaper == hasWallpaper &&
- info.paused == paused && info.ownerPid == ownerPid && info.ownerUid == ownerUid &&
+ info.transform == transform && info.touchableRegion.hasSameRects(touchableRegion) &&
+ info.visible == visible && info.trustedOverlay == trustedOverlay &&
+ info.focusable == focusable && info.touchOcclusionMode == touchOcclusionMode &&
+ info.hasWallpaper == hasWallpaper && info.paused == paused &&
+ info.ownerPid == ownerPid && info.ownerUid == ownerUid &&
info.packageName == packageName && info.inputFeatures == inputFeatures &&
info.displayId == displayId && info.portalToDisplayId == portalToDisplayId &&
info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop &&
@@ -97,9 +96,6 @@
parcel->writeFloat(transform.dtdy()) ?:
parcel->writeFloat(transform.dsdy()) ?:
parcel->writeFloat(transform.ty()) ?:
- parcel->writeUint32(displayOrientation) ?:
- parcel->writeInt32(displayWidth) ?:
- parcel->writeInt32(displayHeight) ?:
parcel->writeBool(visible) ?:
parcel->writeBool(focusable) ?:
parcel->writeBool(hasWallpaper) ?:
@@ -155,9 +151,6 @@
parcel->readFloat(&dtdy) ?:
parcel->readFloat(&dsdy) ?:
parcel->readFloat(&ty) ?:
- parcel->readUint32(&displayOrientation) ?:
- parcel->readInt32(&displayWidth) ?:
- parcel->readInt32(&displayHeight) ?:
parcel->readBool(&visible) ?:
parcel->readBool(&focusable) ?:
parcel->readBool(&hasWallpaper) ?:
diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp
index c00a438..c32b9ab 100644
--- a/libs/gui/WindowInfosListenerReporter.cpp
+++ b/libs/gui/WindowInfosListenerReporter.cpp
@@ -19,6 +19,7 @@
namespace android {
+using gui::DisplayInfo;
using gui::IWindowInfosReportedListener;
using gui::WindowInfo;
using gui::WindowInfosListener;
@@ -65,7 +66,7 @@
}
binder::Status WindowInfosListenerReporter::onWindowInfosChanged(
- const std::vector<WindowInfo>& windowInfos,
+ const std::vector<WindowInfo>& windowInfos, const std::vector<DisplayInfo>& displayInfos,
const sp<IWindowInfosReportedListener>& windowInfosReportedListener) {
std::unordered_set<sp<WindowInfosListener>, ISurfaceComposer::SpHash<WindowInfosListener>>
windowInfosListeners;
@@ -78,7 +79,7 @@
}
for (auto listener : windowInfosListeners) {
- listener->onWindowInfosChanged(windowInfos);
+ listener->onWindowInfosChanged(windowInfos, displayInfos);
}
if (windowInfosReportedListener) {
diff --git a/libs/ui/Size.cpp b/libs/gui/android/gui/DisplayInfo.aidl
similarity index 67%
rename from libs/ui/Size.cpp
rename to libs/gui/android/gui/DisplayInfo.aidl
index d2996d1..30c0885 100644
--- a/libs/ui/Size.cpp
+++ b/libs/gui/android/gui/DisplayInfo.aidl
@@ -1,11 +1,11 @@
/*
- * Copyright 2019 The Android Open Source Project
+ * Copyright 2021, 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
+ * 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,
@@ -14,11 +14,6 @@
* limitations under the License.
*/
-#include <ui/Size.h>
+package android.gui;
-namespace android::ui {
-
-const Size Size::INVALID{-1, -1};
-const Size Size::EMPTY{0, 0};
-
-} // namespace android::ui
+parcelable DisplayInfo cpp_header "gui/DisplayInfo.h";
diff --git a/libs/gui/android/gui/IWindowInfosListener.aidl b/libs/gui/android/gui/IWindowInfosListener.aidl
index d4553ca..a5b2762 100644
--- a/libs/gui/android/gui/IWindowInfosListener.aidl
+++ b/libs/gui/android/gui/IWindowInfosListener.aidl
@@ -16,11 +16,12 @@
package android.gui;
+import android.gui.DisplayInfo;
import android.gui.IWindowInfosReportedListener;
import android.gui.WindowInfo;
/** @hide */
oneway interface IWindowInfosListener
{
- void onWindowInfosChanged(in WindowInfo[] windowInfos, in @nullable IWindowInfosReportedListener windowInfosReportedListener);
+ void onWindowInfosChanged(in WindowInfo[] windowInfos, in DisplayInfo[] displayInfos, in @nullable IWindowInfosReportedListener windowInfosReportedListener);
}
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 6c5b2aa..1f517f6 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -94,12 +94,12 @@
uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount);
void setNextTransaction(SurfaceComposerClient::Transaction *t);
void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber);
+ void applyPendingTransactions(uint64_t frameNumber);
void setTransactionCompleteCallback(uint64_t frameNumber,
std::function<void(int64_t)>&& transactionCompleteCallback);
void update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, int32_t format,
SurfaceComposerClient::Transaction* outTransaction = nullptr);
- void flushShadowQueue() {}
status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless);
status_t setFrameTimelineInfo(const FrameTimelineInfo& info);
@@ -107,6 +107,7 @@
void setSidebandStream(const sp<NativeHandle>& stream);
uint32_t getLastTransformHint() const;
+ uint64_t getLastAcquiredFrameNum();
virtual ~BLASTBufferQueue();
@@ -125,6 +126,8 @@
bool rejectBuffer(const BufferItem& item) REQUIRES(mMutex);
bool maxBuffersAcquired(bool includeExtraAcquire) const REQUIRES(mMutex);
static PixelFormat convertBufferFormat(PixelFormat& format);
+ void mergePendingTransactions(SurfaceComposerClient::Transaction* t, uint64_t frameNumber)
+ REQUIRES(mMutex);
std::string mName;
// Represents the queued buffer count from buffer queue,
diff --git a/libs/gui/include/gui/DisplayInfo.h b/libs/gui/include/gui/DisplayInfo.h
new file mode 100644
index 0000000..74f33a2
--- /dev/null
+++ b/libs/gui/include/gui/DisplayInfo.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <gui/constants.h>
+#include <ui/Transform.h>
+
+namespace android::gui {
+
+/*
+ * Describes information about a display that can have windows in it.
+ *
+ * This should only be used by InputFlinger to support raw coordinates in logical display space.
+ */
+struct DisplayInfo : public Parcelable {
+ int32_t displayId = ADISPLAY_ID_NONE;
+
+ // Logical display dimensions.
+ int32_t logicalWidth = 0;
+ int32_t logicalHeight = 0;
+
+ // The display transform. This takes display coordinates to logical display coordinates.
+ ui::Transform transform;
+
+ status_t writeToParcel(android::Parcel*) const override;
+
+ status_t readFromParcel(const android::Parcel*) override;
+};
+
+} // namespace android::gui
\ No newline at end of file
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index ad7bcb7..b7cd082 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -116,6 +116,11 @@
using EventRegistrationFlags = Flags<EventRegistration>;
+ template <typename T>
+ struct SpHash {
+ size_t operator()(const sp<T>& k) const { return std::hash<T*>()(k.get()); }
+ };
+
/*
* Create a connection with SurfaceFlinger.
*/
@@ -239,24 +244,17 @@
* The subregion can be optionally rotated. It will also be scaled to
* match the size of the output buffer.
*/
- virtual status_t captureDisplay(const DisplayCaptureArgs& args,
- const sp<IScreenCaptureListener>& captureListener) = 0;
+ virtual status_t captureDisplay(const DisplayCaptureArgs&,
+ const sp<IScreenCaptureListener>&) = 0;
- virtual status_t captureDisplay(uint64_t displayOrLayerStack,
- const sp<IScreenCaptureListener>& captureListener) = 0;
-
- template <class AA>
- struct SpHash {
- size_t operator()(const sp<AA>& k) const { return std::hash<AA*>()(k.get()); }
- };
+ virtual status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&) = 0;
/**
* Capture a subtree of the layer hierarchy, potentially ignoring the root node.
* This requires READ_FRAME_BUFFER permission. This function will fail if there
* is a secure window on screen
*/
- virtual status_t captureLayers(const LayerCaptureArgs& args,
- const sp<IScreenCaptureListener>& captureListener) = 0;
+ virtual status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&) = 0;
/* Clears the frame statistics for animations.
*
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 8dc8b9a..f14127c 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -35,6 +35,7 @@
#include <math/vec3.h>
#include <ui/BlurRegion.h>
#include <ui/GraphicTypes.h>
+#include <ui/LayerStack.h>
#include <ui/Rect.h>
#include <ui/Region.h>
#include <ui/Rotation.h>
@@ -143,7 +144,7 @@
int32_t z;
uint32_t w;
uint32_t h;
- uint32_t layerStack;
+ ui::LayerStack layerStack = ui::DEFAULT_LAYER_STACK;
float alpha;
uint32_t flags;
uint32_t mask;
@@ -267,11 +268,12 @@
DisplayState();
void merge(const DisplayState& other);
- uint32_t what;
+ uint32_t what = 0;
+ uint32_t flags = 0;
sp<IBinder> token;
sp<IGraphicBufferProducer> surface;
- uint32_t layerStack;
- uint32_t flags;
+
+ ui::LayerStack layerStack = ui::DEFAULT_LAYER_STACK;
// These states define how layers are projected onto the physical display.
//
@@ -285,10 +287,11 @@
// will be additionally rotated by 90 degrees around the origin clockwise and translated by (W,
// 0).
ui::Rotation orientation = ui::ROTATION_0;
- Rect layerStackSpaceRect;
- Rect orientedDisplaySpaceRect;
+ Rect layerStackSpaceRect = Rect::EMPTY_RECT;
+ Rect orientedDisplaySpaceRect = Rect::EMPTY_RECT;
- uint32_t width, height;
+ uint32_t width = 0;
+ uint32_t height = 0;
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 0f8a32b..baa6878 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -456,7 +456,7 @@
int backgroundBlurRadius);
Transaction& setBlurRegions(const sp<SurfaceControl>& sc,
const std::vector<BlurRegion>& regions);
- Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack);
+ Transaction& setLayerStack(const sp<SurfaceControl>&, ui::LayerStack);
Transaction& setMetadata(const sp<SurfaceControl>& sc, uint32_t key, const Parcel& p);
/// Reparents the current layer to the new parent handle. The new parent must not be null.
@@ -566,7 +566,7 @@
status_t setDisplaySurface(const sp<IBinder>& token,
const sp<IGraphicBufferProducer>& bufferProducer);
- void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack);
+ void setDisplayLayerStack(const sp<IBinder>& token, ui::LayerStack);
void setDisplayFlags(const sp<IBinder>& token, uint32_t flags);
@@ -638,12 +638,9 @@
class ScreenshotClient {
public:
- static status_t captureDisplay(const DisplayCaptureArgs& captureArgs,
- const sp<IScreenCaptureListener>& captureListener);
- static status_t captureDisplay(uint64_t displayOrLayerStack,
- const sp<IScreenCaptureListener>& captureListener);
- static status_t captureLayers(const LayerCaptureArgs& captureArgs,
- const sp<IScreenCaptureListener>& captureListener);
+ static status_t captureDisplay(const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&);
+ static status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&);
+ static status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&);
};
// ---------------------------------------------------------------------------
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index f090c63..54a372c 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -71,8 +71,9 @@
SLIPPERY = 0x20000000,
LAYOUT_ATTACHED_IN_DECOR = 0x40000000,
DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000,
- }; // Window types from WindowManager.LayoutParams
+ };
+ // Window types from WindowManager.LayoutParams
enum class Type : int32_t {
UNKNOWN = 0,
FIRST_APPLICATION_WINDOW = 1,
@@ -87,43 +88,55 @@
APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3,
APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4,
LAST_SUB_WINDOW = 1999,
- FIRST_SYSTEM_WINDOW = 2000,
- STATUS_BAR = FIRST_SYSTEM_WINDOW,
- SEARCH_BAR = FIRST_SYSTEM_WINDOW + 1,
- PHONE = FIRST_SYSTEM_WINDOW + 2,
- SYSTEM_ALERT = FIRST_SYSTEM_WINDOW + 3,
- KEYGUARD = FIRST_SYSTEM_WINDOW + 4,
- TOAST = FIRST_SYSTEM_WINDOW + 5,
- SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 6,
- PRIORITY_PHONE = FIRST_SYSTEM_WINDOW + 7,
- SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW + 8,
- KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW + 9,
- SYSTEM_ERROR = FIRST_SYSTEM_WINDOW + 10,
- INPUT_METHOD = FIRST_SYSTEM_WINDOW + 11,
- INPUT_METHOD_DIALOG = FIRST_SYSTEM_WINDOW + 12,
- WALLPAPER = FIRST_SYSTEM_WINDOW + 13,
- STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW + 14,
- SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 15,
- DRAG = FIRST_SYSTEM_WINDOW + 16,
- STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW + 17,
- POINTER = FIRST_SYSTEM_WINDOW + 18,
- NAVIGATION_BAR = FIRST_SYSTEM_WINDOW + 19,
- VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW + 20,
- BOOT_PROGRESS = FIRST_SYSTEM_WINDOW + 21,
- INPUT_CONSUMER = FIRST_SYSTEM_WINDOW + 22,
- NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW + 24,
- MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 27,
- ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW + 32,
- DOCK_DIVIDER = FIRST_SYSTEM_WINDOW + 34,
- ACCESSIBILITY_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 39,
- NOTIFICATION_SHADE = FIRST_SYSTEM_WINDOW + 40,
+
+#define FIRST_SYSTEM_WINDOW_ 2000
+
+ STATUS_BAR = FIRST_SYSTEM_WINDOW_,
+ SEARCH_BAR = FIRST_SYSTEM_WINDOW_ + 1,
+ PHONE = FIRST_SYSTEM_WINDOW_ + 2,
+ SYSTEM_ALERT = FIRST_SYSTEM_WINDOW_ + 3,
+ KEYGUARD = FIRST_SYSTEM_WINDOW_ + 4,
+ TOAST = FIRST_SYSTEM_WINDOW_ + 5,
+ SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW_ + 6,
+ PRIORITY_PHONE = FIRST_SYSTEM_WINDOW_ + 7,
+ SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW_ + 8,
+ KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW_ + 9,
+ SYSTEM_ERROR = FIRST_SYSTEM_WINDOW_ + 10,
+ INPUT_METHOD = FIRST_SYSTEM_WINDOW_ + 11,
+ INPUT_METHOD_DIALOG = FIRST_SYSTEM_WINDOW_ + 12,
+ WALLPAPER = FIRST_SYSTEM_WINDOW_ + 13,
+ STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW_ + 14,
+ SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW_ + 15,
+ DRAG = FIRST_SYSTEM_WINDOW_ + 16,
+ STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW_ + 17,
+ POINTER = FIRST_SYSTEM_WINDOW_ + 18,
+ NAVIGATION_BAR = FIRST_SYSTEM_WINDOW_ + 19,
+ VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW_ + 20,
+ BOOT_PROGRESS = FIRST_SYSTEM_WINDOW_ + 21,
+ INPUT_CONSUMER = FIRST_SYSTEM_WINDOW_ + 22,
+ NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW_ + 24,
+ MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW_ + 27,
+ ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW_ + 32,
+ DOCK_DIVIDER = FIRST_SYSTEM_WINDOW_ + 34,
+ ACCESSIBILITY_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW_ + 39,
+ NOTIFICATION_SHADE = FIRST_SYSTEM_WINDOW_ + 40,
+
+ FIRST_SYSTEM_WINDOW = FIRST_SYSTEM_WINDOW_,
LAST_SYSTEM_WINDOW = 2999,
+
+#undef FIRST_SYSTEM_WINDOW_
+
+ // Small range to limit LUT size.
+ ftl_first = FIRST_SYSTEM_WINDOW,
+ ftl_last = FIRST_SYSTEM_WINDOW + 15
};
- enum class Feature {
- DISABLE_TOUCH_PAD_GESTURES = 0x00000001,
- NO_INPUT_CHANNEL = 0x00000002,
- DISABLE_USER_ACTIVITY = 0x00000004,
+ enum class Feature : uint32_t {
+ DISABLE_TOUCH_PAD_GESTURES = 1u << 0,
+ NO_INPUT_CHANNEL = 1u << 1,
+ DISABLE_USER_ACTIVITY = 1u << 2,
+ DROP_INPUT = 1u << 3,
+ DROP_INPUT_IF_OBSCURED = 1u << 4,
};
/* These values are filled in by the WM and passed through SurfaceFlinger
@@ -168,13 +181,6 @@
// Transform applied to individual windows.
ui::Transform transform;
- // Display orientation as ui::Transform::RotationFlags. Used for compatibility raw coordinates.
- uint32_t displayOrientation = ui::Transform::ROT_0;
-
- // Display size in its natural rotation. Used to rotate raw coordinates for compatibility.
- int32_t displayWidth = 0;
- int32_t displayHeight = 0;
-
/*
* This is filled in by the WM relative to the frame and then translated
* to absolute coordinates by SurfaceFlinger once the frame is computed.
@@ -265,4 +271,4 @@
WindowInfo mInfo;
};
-} // namespace android::gui
\ No newline at end of file
+} // namespace android::gui
diff --git a/libs/gui/include/gui/WindowInfosListener.h b/libs/gui/include/gui/WindowInfosListener.h
index 8a70b9b..a18a498 100644
--- a/libs/gui/include/gui/WindowInfosListener.h
+++ b/libs/gui/include/gui/WindowInfosListener.h
@@ -16,6 +16,7 @@
#pragma once
+#include <gui/DisplayInfo.h>
#include <gui/WindowInfo.h>
#include <utils/RefBase.h>
@@ -23,6 +24,7 @@
class WindowInfosListener : public virtual RefBase {
public:
- virtual void onWindowInfosChanged(const std::vector<WindowInfo>& /*windowInfos*/) = 0;
+ virtual void onWindowInfosChanged(const std::vector<WindowInfo>&,
+ const std::vector<DisplayInfo>&) = 0;
};
} // namespace android::gui
\ No newline at end of file
diff --git a/libs/gui/include/gui/WindowInfosListenerReporter.h b/libs/gui/include/gui/WindowInfosListenerReporter.h
index 7cb96e0..157a804 100644
--- a/libs/gui/include/gui/WindowInfosListenerReporter.h
+++ b/libs/gui/include/gui/WindowInfosListenerReporter.h
@@ -21,7 +21,6 @@
#include <binder/IBinder.h>
#include <gui/ISurfaceComposer.h>
#include <gui/WindowInfosListener.h>
-#include <utils/Mutex.h>
#include <unordered_set>
namespace android {
@@ -30,7 +29,8 @@
class WindowInfosListenerReporter : public gui::BnWindowInfosListener {
public:
static sp<WindowInfosListenerReporter> getInstance();
- binder::Status onWindowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos,
+ binder::Status onWindowInfosChanged(const std::vector<gui::WindowInfo>&,
+ const std::vector<gui::DisplayInfo>&,
const sp<gui::IWindowInfosReportedListener>&) override;
status_t addWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener,
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 3d26c3d..6dd1073 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -27,6 +27,7 @@
"BufferQueue_test.cpp",
"CpuConsumer_test.cpp",
"EndToEndNativeInputTest.cpp",
+ "DisplayInfo_test.cpp",
"DisplayedContentSampling_test.cpp",
"FillBuffer.cpp",
"GLTest.cpp",
@@ -62,7 +63,7 @@
"libinput",
"libui",
"libutils",
- "libnativewindow"
+ "libnativewindow",
],
header_libs: ["libsurfaceflinger_headers"],
@@ -117,7 +118,7 @@
"libgui",
"libui",
"libutils",
- "libbufferhubqueue", // TODO(b/70046255): Remove these once BufferHub is integrated into libgui.
+ "libbufferhubqueue", // TODO(b/70046255): Remove these once BufferHub is integrated into libgui.
"libpdx_default_transport",
],
@@ -146,5 +147,5 @@
"liblog",
"libui",
"libutils",
- ]
+ ],
}
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 9082d27..26d902d 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -128,7 +128,7 @@
mDisplayToken = mClient->getInternalDisplayToken();
ASSERT_NE(nullptr, mDisplayToken.get());
Transaction t;
- t.setDisplayLayerStack(mDisplayToken, 0);
+ t.setDisplayLayerStack(mDisplayToken, ui::DEFAULT_LAYER_STACK);
t.apply();
t.clear();
@@ -142,7 +142,7 @@
mDisplayHeight, PIXEL_FORMAT_RGBA_8888,
ISurfaceComposerClient::eFXSurfaceBufferState,
/*parent*/ nullptr);
- t.setLayerStack(mSurfaceControl, 0)
+ t.setLayerStack(mSurfaceControl, ui::DEFAULT_LAYER_STACK)
.setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max())
.show(mSurfaceControl)
.setDataspace(mSurfaceControl, ui::Dataspace::V0_SRGB)
@@ -490,7 +490,7 @@
ISurfaceComposerClient::eFXSurfaceEffect);
ASSERT_NE(nullptr, bg.get());
Transaction t;
- t.setLayerStack(bg, 0)
+ t.setLayerStack(bg, ui::DEFAULT_LAYER_STACK)
.setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight))
.setColor(bg, half3{0, 0, 0})
.setLayer(bg, 0)
@@ -545,7 +545,7 @@
ISurfaceComposerClient::eFXSurfaceEffect);
ASSERT_NE(nullptr, bg.get());
Transaction t;
- t.setLayerStack(bg, 0)
+ t.setLayerStack(bg, ui::DEFAULT_LAYER_STACK)
.setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight))
.setColor(bg, half3{0, 0, 0})
.setLayer(bg, 0)
@@ -612,7 +612,7 @@
ISurfaceComposerClient::eFXSurfaceEffect);
ASSERT_NE(nullptr, bg.get());
Transaction t;
- t.setLayerStack(bg, 0)
+ t.setLayerStack(bg, ui::DEFAULT_LAYER_STACK)
.setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight))
.setColor(bg, half3{0, 0, 0})
.setLayer(bg, 0)
@@ -733,7 +733,7 @@
ISurfaceComposerClient::eFXSurfaceBufferState);
ASSERT_NE(nullptr, bgSurface.get());
Transaction t;
- t.setLayerStack(bgSurface, 0)
+ t.setLayerStack(bgSurface, ui::DEFAULT_LAYER_STACK)
.show(bgSurface)
.setDataspace(bgSurface, ui::Dataspace::V0_SRGB)
.setLayer(bgSurface, std::numeric_limits<int32_t>::max() - 1)
diff --git a/libs/gui/tests/DisplayInfo_test.cpp b/libs/gui/tests/DisplayInfo_test.cpp
new file mode 100644
index 0000000..df3329c
--- /dev/null
+++ b/libs/gui/tests/DisplayInfo_test.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021 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 <gtest/gtest.h>
+
+#include <binder/Parcel.h>
+
+#include <gui/DisplayInfo.h>
+
+namespace android {
+
+using gui::DisplayInfo;
+
+namespace test {
+
+TEST(DisplayInfo, Parcelling) {
+ DisplayInfo info;
+ info.displayId = 42;
+ info.logicalWidth = 99;
+ info.logicalHeight = 78;
+ info.transform.set({0.4, -1, 100, 0.5, 0, 40, 0, 0, 1});
+
+ Parcel p;
+ info.writeToParcel(&p);
+ p.setDataPosition(0);
+
+ DisplayInfo info2;
+ info2.readFromParcel(&p);
+ ASSERT_EQ(info.displayId, info2.displayId);
+ ASSERT_EQ(info.logicalWidth, info2.logicalWidth);
+ ASSERT_EQ(info.logicalHeight, info2.logicalHeight);
+ ASSERT_EQ(info.transform, info2.transform);
+}
+
+} // namespace test
+} // namespace android
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index a02970c..d1ad478 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -752,21 +752,19 @@
}
status_t setActiveColorMode(const sp<IBinder>& /*display*/,
ColorMode /*colorMode*/) override { return NO_ERROR; }
- status_t captureDisplay(const DisplayCaptureArgs& /* captureArgs */,
- const sp<IScreenCaptureListener>& /* captureListener */) override {
- return NO_ERROR;
- }
void setAutoLowLatencyMode(const sp<IBinder>& /*display*/, bool /*on*/) override {}
void setGameContentType(const sp<IBinder>& /*display*/, bool /*on*/) override {}
- status_t captureDisplay(uint64_t /*displayOrLayerStack*/,
- const sp<IScreenCaptureListener>& /* captureListener */) override {
+
+ status_t captureDisplay(const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&) override {
return NO_ERROR;
}
- virtual status_t captureLayers(
- const LayerCaptureArgs& /* captureArgs */,
- const sp<IScreenCaptureListener>& /* captureListener */) override {
+ status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&) override {
return NO_ERROR;
}
+ status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&) override {
+ return NO_ERROR;
+ }
+
status_t clearAnimationFrameStats() override { return NO_ERROR; }
status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override {
return NO_ERROR;
diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp
index a4f436c..dcdf76f 100644
--- a/libs/gui/tests/WindowInfo_test.cpp
+++ b/libs/gui/tests/WindowInfo_test.cpp
@@ -60,9 +60,6 @@
i.globalScaleFactor = 0.3;
i.alpha = 0.7;
i.transform.set({0.4, -1, 100, 0.5, 0, 40, 0, 0, 1});
- i.displayOrientation = ui::Transform::ROT_0;
- i.displayWidth = 1000;
- i.displayHeight = 2000;
i.visible = false;
i.focusable = false;
i.hasWallpaper = false;
@@ -100,8 +97,6 @@
ASSERT_EQ(i.globalScaleFactor, i2.globalScaleFactor);
ASSERT_EQ(i.alpha, i2.alpha);
ASSERT_EQ(i.transform, i2.transform);
- ASSERT_EQ(i.displayWidth, i2.displayWidth);
- ASSERT_EQ(i.displayHeight, i2.displayHeight);
ASSERT_EQ(i.visible, i2.visible);
ASSERT_EQ(i.focusable, i2.focusable);
ASSERT_EQ(i.hasWallpaper, i2.hasWallpaper);
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 35209f7..037849e 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -170,6 +170,9 @@
case AINPUT_EVENT_TYPE_DRAG: {
return "DRAG";
}
+ case AINPUT_EVENT_TYPE_TOUCH_MODE: {
+ return "TOUCH_MODE";
+ }
}
return "UNKNOWN";
}
@@ -330,10 +333,6 @@
scaleAxisValue(*this, AMOTION_EVENT_AXIS_RELATIVE_Y, windowYScale);
}
-void PointerCoords::scale(float globalScaleFactor) {
- scale(globalScaleFactor, globalScaleFactor, globalScaleFactor);
-}
-
void PointerCoords::applyOffset(float xOffset, float yOffset) {
setAxisValue(AMOTION_EVENT_AXIS_X, getX() + xOffset);
setAxisValue(AMOTION_EVENT_AXIS_Y, getY() + yOffset);
@@ -835,9 +834,9 @@
case AMOTION_EVENT_ACTION_OUTSIDE:
return "OUTSIDE";
case AMOTION_EVENT_ACTION_POINTER_DOWN:
- return "POINTER_DOWN";
+ return StringPrintf("POINTER_DOWN(%" PRId32 ")", MotionEvent::getActionIndex(action));
case AMOTION_EVENT_ACTION_POINTER_UP:
- return "POINTER_UP";
+ return StringPrintf("POINTER_UP(%" PRId32 ")", MotionEvent::getActionIndex(action));
case AMOTION_EVENT_ACTION_HOVER_MOVE:
return "HOVER_MOVE";
case AMOTION_EVENT_ACTION_SCROLL:
@@ -899,6 +898,19 @@
mY = from.mY;
}
+// --- TouchModeEvent ---
+
+void TouchModeEvent::initialize(int32_t id, bool isInTouchMode) {
+ InputEvent::initialize(id, ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID, AINPUT_SOURCE_UNKNOWN,
+ ADISPLAY_ID_NONE, INVALID_HMAC);
+ mIsInTouchMode = isInTouchMode;
+}
+
+void TouchModeEvent::initialize(const TouchModeEvent& from) {
+ InputEvent::initialize(from);
+ mIsInTouchMode = from.mIsInTouchMode;
+}
+
// --- PooledInputEventFactory ---
PooledInputEventFactory::PooledInputEventFactory(size_t maxPoolSize) :
@@ -953,6 +965,15 @@
return event;
}
+TouchModeEvent* PooledInputEventFactory::createTouchModeEvent() {
+ if (mTouchModeEventPool.empty()) {
+ return new TouchModeEvent();
+ }
+ TouchModeEvent* event = mTouchModeEventPool.front().release();
+ mTouchModeEventPool.pop();
+ return event;
+}
+
void PooledInputEventFactory::recycle(InputEvent* event) {
switch (event->getType()) {
case AINPUT_EVENT_TYPE_KEY:
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 220c8e1..69ae9a0 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -21,7 +21,7 @@
#include <ctype.h>
#include <android-base/stringprintf.h>
-#include <ftl/NamedEnum.h>
+#include <ftl/enum.h>
#include <input/InputDevice.h>
#include <input/InputEventLabels.h>
@@ -228,7 +228,7 @@
void InputDeviceInfo::addSensorInfo(const InputDeviceSensorInfo& info) {
if (mSensors.find(info.type) != mSensors.end()) {
ALOGW("Sensor type %s already exists, will be replaced by new sensor added.",
- NamedEnum::string(info.type).c_str());
+ ftl::enum_string(info.type).c_str());
}
mSensors.insert_or_assign(info.type, info);
}
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index ea8b9a7..91ab008 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -30,10 +30,10 @@
#include <android-base/stringprintf.h>
#include <binder/Parcel.h>
#include <cutils/properties.h>
+#include <ftl/enum.h>
#include <log/log.h>
#include <utils/Trace.h>
-#include <ftl/NamedEnum.h>
#include <input/InputTransport.h>
using android::base::StringPrintf;
@@ -116,6 +116,7 @@
case Type::FOCUS:
case Type::CAPTURE:
case Type::DRAG:
+ case Type::TOUCH_MODE:
return true;
case Type::TIMELINE: {
const nsecs_t gpuCompletedTime =
@@ -151,6 +152,8 @@
return sizeof(Header) + body.drag.size();
case Type::TIMELINE:
return sizeof(Header) + body.timeline.size();
+ case Type::TOUCH_MODE:
+ return sizeof(Header) + body.touchMode.size();
}
return sizeof(Header);
}
@@ -293,6 +296,10 @@
msg->body.timeline.graphicsTimeline = body.timeline.graphicsTimeline;
break;
}
+ case InputMessage::Type::TOUCH_MODE: {
+ msg->body.touchMode.eventId = body.touchMode.eventId;
+ msg->body.touchMode.isInTouchMode = body.touchMode.isInTouchMode;
+ }
}
}
@@ -665,6 +672,22 @@
return mChannel->sendMessage(&msg);
}
+status_t InputPublisher::publishTouchModeEvent(uint32_t seq, int32_t eventId, bool isInTouchMode) {
+ if (ATRACE_ENABLED()) {
+ std::string message =
+ StringPrintf("publishTouchModeEvent(inputChannel=%s, isInTouchMode=%s)",
+ mChannel->getName().c_str(), toString(isInTouchMode));
+ ATRACE_NAME(message.c_str());
+ }
+
+ InputMessage msg;
+ msg.header.type = InputMessage::Type::TOUCH_MODE;
+ msg.header.seq = seq;
+ msg.body.touchMode.eventId = eventId;
+ msg.body.touchMode.isInTouchMode = isInTouchMode;
+ return mChannel->sendMessage(&msg);
+}
+
android::base::Result<InputPublisher::ConsumerResponse> InputPublisher::receiveConsumerResponse() {
if (DEBUG_TRANSPORT_ACTIONS) {
ALOGD("channel '%s' publisher ~ %s", mChannel->getName().c_str(), __func__);
@@ -691,7 +714,7 @@
}
ALOGE("channel '%s' publisher ~ Received unexpected %s message from consumer",
- mChannel->getName().c_str(), NamedEnum::string(msg.header.type).c_str());
+ mChannel->getName().c_str(), ftl::enum_string(msg.header.type).c_str());
return android::base::Error(UNKNOWN_ERROR);
}
@@ -833,7 +856,7 @@
case InputMessage::Type::TIMELINE: {
LOG_ALWAYS_FATAL("Consumed a %s message, which should never be seen by "
"InputConsumer!",
- NamedEnum::string(mMsg.header.type).c_str());
+ ftl::enum_string(mMsg.header.type).c_str());
break;
}
@@ -866,6 +889,16 @@
*outEvent = dragEvent;
break;
}
+
+ case InputMessage::Type::TOUCH_MODE: {
+ TouchModeEvent* touchModeEvent = factory->createTouchModeEvent();
+ if (!touchModeEvent) return NO_MEMORY;
+
+ initializeTouchModeEvent(touchModeEvent, &mMsg);
+ *outSeq = mMsg.header.seq;
+ *outEvent = touchModeEvent;
+ break;
+ }
}
}
return OK;
@@ -1370,6 +1403,10 @@
msg->body.motion.eventTime, pointerCount, pointerProperties, pointerCoords);
}
+void InputConsumer::initializeTouchModeEvent(TouchModeEvent* event, const InputMessage* msg) {
+ event->initialize(msg->body.touchMode.eventId, msg->body.touchMode.isInTouchMode);
+}
+
void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) {
uint32_t pointerCount = msg->body.motion.pointerCount;
PointerCoords pointerCoords[pointerCount];
@@ -1412,14 +1449,14 @@
out = out + "mChannel = " + mChannel->getName() + "\n";
out = out + "mMsgDeferred: " + toString(mMsgDeferred) + "\n";
if (mMsgDeferred) {
- out = out + "mMsg : " + NamedEnum::string(mMsg.header.type) + "\n";
+ out = out + "mMsg : " + ftl::enum_string(mMsg.header.type) + "\n";
}
out += "Batches:\n";
for (const Batch& batch : mBatches) {
out += " Batch:\n";
for (const InputMessage& msg : batch.samples) {
out += android::base::StringPrintf(" Message %" PRIu32 ": %s ", msg.header.seq,
- NamedEnum::string(msg.header.type).c_str());
+ ftl::enum_string(msg.header.type).c_str());
switch (msg.header.type) {
case InputMessage::Type::KEY: {
out += android::base::StringPrintf("action=%s keycode=%" PRId32,
@@ -1476,6 +1513,11 @@
presentTime);
break;
}
+ case InputMessage::Type::TOUCH_MODE: {
+ out += android::base::StringPrintf("isInTouchMode=%s",
+ toString(msg.body.touchMode.isInTouchMode));
+ break;
+ }
}
out += "\n";
}
diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp
index c365ab0..7c25cda 100644
--- a/libs/input/KeyLayoutMap.cpp
+++ b/libs/input/KeyLayoutMap.cpp
@@ -16,10 +16,8 @@
#define LOG_TAG "KeyLayoutMap"
-#include <stdlib.h>
-
#include <android/keycodes.h>
-#include <ftl/NamedEnum.h>
+#include <ftl/enum.h>
#include <input/InputEventLabels.h>
#include <input/KeyLayoutMap.h>
#include <input/Keyboard.h>
@@ -28,6 +26,10 @@
#include <utils/Timers.h>
#include <utils/Tokenizer.h>
+#include <cstdlib>
+#include <string_view>
+#include <unordered_map>
+
// Enables debug output for the parser.
#define DEBUG_PARSER 0
@@ -39,36 +41,38 @@
namespace android {
+namespace {
-static const char* WHITESPACE = " \t\r";
+constexpr const char* WHITESPACE = " \t\r";
-#define SENSOR_ENTRY(type) NamedEnum::string(type), type
-static const std::unordered_map<std::string, InputDeviceSensorType> SENSOR_LIST =
- {{SENSOR_ENTRY(InputDeviceSensorType::ACCELEROMETER)},
- {SENSOR_ENTRY(InputDeviceSensorType::MAGNETIC_FIELD)},
- {SENSOR_ENTRY(InputDeviceSensorType::ORIENTATION)},
- {SENSOR_ENTRY(InputDeviceSensorType::GYROSCOPE)},
- {SENSOR_ENTRY(InputDeviceSensorType::LIGHT)},
- {SENSOR_ENTRY(InputDeviceSensorType::PRESSURE)},
- {SENSOR_ENTRY(InputDeviceSensorType::TEMPERATURE)},
- {SENSOR_ENTRY(InputDeviceSensorType::PROXIMITY)},
- {SENSOR_ENTRY(InputDeviceSensorType::GRAVITY)},
- {SENSOR_ENTRY(InputDeviceSensorType::LINEAR_ACCELERATION)},
- {SENSOR_ENTRY(InputDeviceSensorType::ROTATION_VECTOR)},
- {SENSOR_ENTRY(InputDeviceSensorType::RELATIVE_HUMIDITY)},
- {SENSOR_ENTRY(InputDeviceSensorType::AMBIENT_TEMPERATURE)},
- {SENSOR_ENTRY(InputDeviceSensorType::MAGNETIC_FIELD_UNCALIBRATED)},
- {SENSOR_ENTRY(InputDeviceSensorType::GAME_ROTATION_VECTOR)},
- {SENSOR_ENTRY(InputDeviceSensorType::GYROSCOPE_UNCALIBRATED)},
- {SENSOR_ENTRY(InputDeviceSensorType::SIGNIFICANT_MOTION)}};
-
-// --- KeyLayoutMap ---
-
-KeyLayoutMap::KeyLayoutMap() {
+template <InputDeviceSensorType S>
+constexpr auto sensorPair() {
+ return std::make_pair(ftl::enum_name<S>(), S);
}
-KeyLayoutMap::~KeyLayoutMap() {
-}
+static const std::unordered_map<std::string_view, InputDeviceSensorType> SENSOR_LIST =
+ {sensorPair<InputDeviceSensorType::ACCELEROMETER>(),
+ sensorPair<InputDeviceSensorType::MAGNETIC_FIELD>(),
+ sensorPair<InputDeviceSensorType::ORIENTATION>(),
+ sensorPair<InputDeviceSensorType::GYROSCOPE>(),
+ sensorPair<InputDeviceSensorType::LIGHT>(),
+ sensorPair<InputDeviceSensorType::PRESSURE>(),
+ sensorPair<InputDeviceSensorType::TEMPERATURE>(),
+ sensorPair<InputDeviceSensorType::PROXIMITY>(),
+ sensorPair<InputDeviceSensorType::GRAVITY>(),
+ sensorPair<InputDeviceSensorType::LINEAR_ACCELERATION>(),
+ sensorPair<InputDeviceSensorType::ROTATION_VECTOR>(),
+ sensorPair<InputDeviceSensorType::RELATIVE_HUMIDITY>(),
+ sensorPair<InputDeviceSensorType::AMBIENT_TEMPERATURE>(),
+ sensorPair<InputDeviceSensorType::MAGNETIC_FIELD_UNCALIBRATED>(),
+ sensorPair<InputDeviceSensorType::GAME_ROTATION_VECTOR>(),
+ sensorPair<InputDeviceSensorType::GYROSCOPE_UNCALIBRATED>(),
+ sensorPair<InputDeviceSensorType::SIGNIFICANT_MOTION>()};
+
+} // namespace
+
+KeyLayoutMap::KeyLayoutMap() = default;
+KeyLayoutMap::~KeyLayoutMap() = default;
base::Result<std::shared_ptr<KeyLayoutMap>> KeyLayoutMap::loadContents(const std::string& filename,
const char* contents) {
@@ -160,8 +164,8 @@
const Sensor& sensor = it->second;
#if DEBUG_MAPPING
- ALOGD("mapSensor: absCode=%d, sensorType=0x%0x, sensorDataIndex=0x%x.", absCode,
- NamedEnum::string(sensor.sensorType), sensor.sensorDataIndex);
+ ALOGD("mapSensor: absCode=%d, sensorType=%s, sensorDataIndex=0x%x.", absCode,
+ ftl::enum_string(sensor.sensorType).c_str(), sensor.sensorDataIndex);
#endif
return std::make_pair(sensor.sensorType, sensor.sensorDataIndex);
}
@@ -513,7 +517,7 @@
}
static std::optional<InputDeviceSensorType> getSensorType(const char* token) {
- auto it = SENSOR_LIST.find(std::string(token));
+ auto it = SENSOR_LIST.find(token);
if (it == SENSOR_LIST.end()) {
return std::nullopt;
}
@@ -581,8 +585,8 @@
int32_t sensorDataIndex = indexOpt.value();
#if DEBUG_PARSER
- ALOGD("Parsed sensor: abs code=%d, sensorType=%d, sensorDataIndex=%d.", code,
- NamedEnum::string(sensorType).c_str(), sensorDataIndex);
+ ALOGD("Parsed sensor: abs code=%d, sensorType=%s, sensorDataIndex=%d.", code,
+ ftl::enum_string(sensorType).c_str(), sensorDataIndex);
#endif
Sensor sensor;
@@ -591,4 +595,5 @@
map.emplace(code, sensor);
return NO_ERROR;
}
-};
+
+} // namespace android
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 5d1f2c3..8db5bf1 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -56,6 +56,7 @@
void PublishAndConsumeFocusEvent();
void PublishAndConsumeCaptureEvent();
void PublishAndConsumeDragEvent();
+ void PublishAndConsumeTouchModeEvent();
};
TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) {
@@ -413,6 +414,46 @@
<< "finished signal's consume time should be greater than publish time";
}
+void InputPublisherAndConsumerTest::PublishAndConsumeTouchModeEvent() {
+ status_t status;
+
+ constexpr uint32_t seq = 15;
+ int32_t eventId = InputEvent::nextId();
+ constexpr bool touchModeEnabled = true;
+ const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ status = mPublisher->publishTouchModeEvent(seq, eventId, touchModeEnabled);
+ ASSERT_EQ(OK, status) << "publisher publishTouchModeEvent should return OK";
+
+ uint32_t consumeSeq;
+ InputEvent* event;
+ status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
+ ASSERT_EQ(OK, status) << "consumer consume should return OK";
+
+ ASSERT_TRUE(event != nullptr) << "consumer should have returned non-NULL event";
+ ASSERT_EQ(AINPUT_EVENT_TYPE_TOUCH_MODE, event->getType())
+ << "consumer should have returned a touch mode event";
+
+ const TouchModeEvent& touchModeEvent = static_cast<const TouchModeEvent&>(*event);
+ EXPECT_EQ(seq, consumeSeq);
+ EXPECT_EQ(eventId, touchModeEvent.getId());
+ EXPECT_EQ(touchModeEnabled, touchModeEvent.isInTouchMode());
+
+ status = mConsumer->sendFinishedSignal(seq, true);
+ ASSERT_EQ(OK, status) << "consumer sendFinishedSignal should return OK";
+
+ Result<InputPublisher::ConsumerResponse> result = mPublisher->receiveConsumerResponse();
+ ASSERT_TRUE(result.ok()) << "receiveConsumerResponse should return OK";
+ ASSERT_TRUE(std::holds_alternative<InputPublisher::Finished>(*result));
+ const InputPublisher::Finished& finish = std::get<InputPublisher::Finished>(*result);
+ ASSERT_EQ(seq, finish.seq)
+ << "receiveConsumerResponse should have returned the original sequence number";
+ ASSERT_TRUE(finish.handled)
+ << "receiveConsumerResponse should have set handled to consumer's reply";
+ ASSERT_GE(finish.consumeTime, publishTime)
+ << "finished signal's consume time should be greater than publish time";
+}
+
TEST_F(InputPublisherAndConsumerTest, SendTimeline) {
const int32_t inputEventId = 20;
std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
@@ -449,6 +490,10 @@
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeDragEvent());
}
+TEST_F(InputPublisherAndConsumerTest, PublishTouchModeEvent_EndToEnd) {
+ ASSERT_NO_FATAL_FAILURE(PublishAndConsumeTouchModeEvent());
+}
+
TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenSequenceNumberIsZero_ReturnsError) {
status_t status;
const size_t pointerCount = 1;
@@ -520,6 +565,7 @@
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeDragEvent());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
+ ASSERT_NO_FATAL_FAILURE(PublishAndConsumeTouchModeEvent());
}
} // namespace android
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 59fed1f..18289a5 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -102,6 +102,10 @@
CHECK_OFFSET(InputMessage::Body::Timeline, eventId, 0);
CHECK_OFFSET(InputMessage::Body::Timeline, empty, 4);
CHECK_OFFSET(InputMessage::Body::Timeline, graphicsTimeline, 8);
+
+ CHECK_OFFSET(InputMessage::Body::TouchMode, eventId, 0);
+ CHECK_OFFSET(InputMessage::Body::TouchMode, isInTouchMode, 4);
+ CHECK_OFFSET(InputMessage::Body::TouchMode, empty, 5);
}
void TestHeaderSize() {
@@ -123,6 +127,7 @@
static_assert(sizeof(InputMessage::Body::Focus) == 8);
static_assert(sizeof(InputMessage::Body::Capture) == 8);
static_assert(sizeof(InputMessage::Body::Drag) == 16);
+ static_assert(sizeof(InputMessage::Body::TouchMode) == 8);
// Timeline
static_assert(GraphicsTimeline::SIZE == 2);
static_assert(sizeof(InputMessage::Body::Timeline) == 24);
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index 2dd6c4f..ba71960 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -192,6 +192,7 @@
// Only poke DisplayManagerGlobal to unregister if we previously registered
// callbacks.
if (gChoreographers.ptrs.empty() && gChoreographers.registeredToDisplayManager) {
+ gChoreographers.registeredToDisplayManager = false;
JNIEnv* env = getJniEnv();
if (env == nullptr) {
ALOGW("JNI environment is unavailable, skipping choreographer cleanup");
@@ -305,8 +306,9 @@
// Fortunately, these events are small so sending packets across the
// socket should be atomic across processes.
DisplayEventReceiver::Event event;
- event.header = DisplayEventReceiver::Event::Header{DisplayEventReceiver::DISPLAY_EVENT_NULL,
- PhysicalDisplayId(0), systemTime()};
+ event.header =
+ DisplayEventReceiver::Event::Header{DisplayEventReceiver::DISPLAY_EVENT_NULL,
+ PhysicalDisplayId::fromPort(0), systemTime()};
injectEvent(event);
}
}
diff --git a/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h b/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h
index 6eaa84e..bac44c9 100644
--- a/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h
+++ b/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h
@@ -272,10 +272,11 @@
status_t attachToContext(uint32_t tex);
sp<GraphicBuffer> dequeueBuffer(int* outSlotid, android_dataspace* outDataspace,
- float* outTransformMatrix, bool* outQueueEmpty,
+ float* outTransformMatrix, uint32_t* outTransform,
+ bool* outQueueEmpty,
SurfaceTexture_createReleaseFence createFence,
SurfaceTexture_fenceWait fenceWait,
- void* fencePassThroughHandle);
+ void* fencePassThroughHandle, ARect* currentCrop);
/**
* takeConsumerOwnership attaches a SurfaceTexture that is currently in the
diff --git a/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h
index 85fe42f..e85009c 100644
--- a/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h
+++ b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h
@@ -84,10 +84,11 @@
*/
AHardwareBuffer* ASurfaceTexture_dequeueBuffer(ASurfaceTexture* st, int* outSlotid,
android_dataspace* outDataspace,
- float* outTransformMatrix, bool* outNewContent,
+ float* outTransformMatrix, uint32_t* outTransform,
+ bool* outNewContent,
ASurfaceTexture_createReleaseFence createFence,
ASurfaceTexture_fenceWait fenceWait,
- void* fencePassThroughHandle);
+ void* fencePassThroughHandle, ARect* currentCrop);
} // namespace android
diff --git a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp
index 62db6d0..3535e67 100644
--- a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp
+++ b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp
@@ -464,10 +464,11 @@
}
sp<GraphicBuffer> SurfaceTexture::dequeueBuffer(int* outSlotid, android_dataspace* outDataspace,
- float* outTransformMatrix, bool* outQueueEmpty,
+ float* outTransformMatrix, uint32_t* outTransform,
+ bool* outQueueEmpty,
SurfaceTexture_createReleaseFence createFence,
SurfaceTexture_fenceWait fenceWait,
- void* fencePassThroughHandle) {
+ void* fencePassThroughHandle, ARect* currentCrop) {
Mutex::Autolock _l(mMutex);
sp<GraphicBuffer> buffer;
@@ -484,6 +485,8 @@
buffer = mImageConsumer.dequeueBuffer(outSlotid, outDataspace, outQueueEmpty, *this,
createFence, fenceWait, fencePassThroughHandle);
memcpy(outTransformMatrix, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
+ *outTransform = mCurrentTransform;
+ *currentCrop = mCurrentCrop;
return buffer;
}
diff --git a/libs/nativedisplay/surfacetexture/surface_texture.cpp b/libs/nativedisplay/surfacetexture/surface_texture.cpp
index c214ab7..cc0a12d 100644
--- a/libs/nativedisplay/surfacetexture/surface_texture.cpp
+++ b/libs/nativedisplay/surfacetexture/surface_texture.cpp
@@ -194,15 +194,18 @@
AHardwareBuffer* ASurfaceTexture_dequeueBuffer(ASurfaceTexture* st, int* outSlotid,
android_dataspace* outDataspace,
- float* outTransformMatrix, bool* outNewContent,
+ float* outTransformMatrix, uint32_t* outTransform,
+ bool* outNewContent,
ASurfaceTexture_createReleaseFence createFence,
- ASurfaceTexture_fenceWait fenceWait, void* handle) {
+ ASurfaceTexture_fenceWait fenceWait, void* handle,
+ ARect* currentCrop) {
sp<GraphicBuffer> buffer;
*outNewContent = false;
bool queueEmpty;
do {
buffer = st->consumer->dequeueBuffer(outSlotid, outDataspace, outTransformMatrix,
- &queueEmpty, createFence, fenceWait, handle);
+ outTransform, &queueEmpty, createFence, fenceWait,
+ handle, currentCrop);
if (!queueEmpty) {
*outNewContent = true;
}
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index d93a84c..d5e7cb2 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -556,6 +556,7 @@
int32_t* _Nonnull outBytesPerPixel,
int32_t* _Nonnull outBytesPerStride) __INTRODUCED_IN(29);
+
/**
* Get the system wide unique id for an AHardwareBuffer.
*
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 7f01135..0bc2b5d 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -1089,10 +1089,13 @@
/**
* Retrieves an identifier for the next frame to be queued by this window.
*
- * \return the next frame id.
+ * Frame ids start at 1 and are incremented on each new frame until the underlying surface changes,
+ * in which case the frame id is reset to 1.
+ *
+ * \return the next frame id (0 being uninitialized).
*/
-static inline int64_t ANativeWindow_getNextFrameId(ANativeWindow* window) {
- int64_t value;
+static inline uint64_t ANativeWindow_getNextFrameId(ANativeWindow* window) {
+ uint64_t value;
window->perform(window, NATIVE_WINDOW_GET_NEXT_FRAME_ID, &value);
return value;
}
diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
index 0c5a851..2174df5 100644
--- a/libs/renderengine/RenderEngine.cpp
+++ b/libs/renderengine/RenderEngine.cpp
@@ -95,5 +95,16 @@
"output buffer not gpu writeable");
}
+std::future<RenderEngineResult> RenderEngine::drawLayers(
+ const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
+ base::unique_fd&& bufferFence) {
+ const auto resultPromise = std::make_shared<std::promise<RenderEngineResult>>();
+ std::future<RenderEngineResult> resultFuture = resultPromise->get_future();
+ drawLayersInternal(std::move(resultPromise), display, layers, buffer, useFramebufferCache,
+ std::move(bufferFence));
+ return resultFuture;
+}
+
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 467f848..2375cb7 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -1078,15 +1078,16 @@
return image;
}
-status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
- const std::vector<const LayerSettings*>& layers,
- const std::shared_ptr<ExternalTexture>& buffer,
- const bool useFramebufferCache, base::unique_fd&& bufferFence,
- base::unique_fd* drawFence) {
+void GLESRenderEngine::drawLayersInternal(
+ const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+ const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
+ base::unique_fd&& bufferFence) {
ATRACE_CALL();
if (layers.empty()) {
ALOGV("Drawing empty layer stack");
- return NO_ERROR;
+ resultPromise->set_value({NO_ERROR, base::unique_fd()});
+ return;
}
if (bufferFence.get() >= 0) {
@@ -1100,7 +1101,8 @@
if (buffer == nullptr) {
ALOGE("No output buffer provided. Aborting GPU composition.");
- return BAD_VALUE;
+ resultPromise->set_value({BAD_VALUE, base::unique_fd()});
+ return;
}
validateOutputBufferUsage(buffer->getBuffer());
@@ -1128,7 +1130,8 @@
ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
buffer->getBuffer()->handle);
checkErrors();
- return fbo->getStatus();
+ resultPromise->set_value({fbo->getStatus(), base::unique_fd()});
+ return;
}
setViewportAndProjection(display.physicalDisplay, display.clip);
} else {
@@ -1139,7 +1142,8 @@
ALOGE("Failed to prepare blur filter! Aborting GPU composition for buffer (%p).",
buffer->getBuffer()->handle);
checkErrors();
- return status;
+ resultPromise->set_value({status, base::unique_fd()});
+ return;
}
}
@@ -1156,10 +1160,6 @@
const mat4 projectionMatrix =
ui::Transform(display.orientation).asMatrix4() * mState.projectionMatrix;
- if (!display.clearRegion.isEmpty()) {
- glDisable(GL_BLEND);
- fillRegionWithColor(display.clearRegion, 0.0, 0.0, 0.0, 1.0);
- }
Mesh mesh = Mesh::Builder()
.setPrimitive(Mesh::TRIANGLE_FAN)
@@ -1176,7 +1176,8 @@
ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).",
buffer->getBuffer()->handle);
checkErrors("Can't render first blur pass");
- return status;
+ resultPromise->set_value({status, base::unique_fd()});
+ return;
}
if (blurLayers.size() == 0) {
@@ -1198,7 +1199,8 @@
ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
buffer->getBuffer()->handle);
checkErrors("Can't bind native framebuffer");
- return status;
+ resultPromise->set_value({status, base::unique_fd()});
+ return;
}
status = mBlurFilter->render(blurLayersSize > 1);
@@ -1206,7 +1208,8 @@
ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).",
buffer->getBuffer()->handle);
checkErrors("Can't render blur filter");
- return status;
+ resultPromise->set_value({status, base::unique_fd()});
+ return;
}
}
@@ -1293,30 +1296,31 @@
}
}
- if (drawFence != nullptr) {
- *drawFence = flush();
- }
+ base::unique_fd drawFence = flush();
+
// If flush failed or we don't support native fences, we need to force the
// gl command stream to be executed.
- if (drawFence == nullptr || drawFence->get() < 0) {
+ if (drawFence.get() < 0) {
bool success = finish();
if (!success) {
ALOGE("Failed to flush RenderEngine commands");
checkErrors();
// Chances are, something illegal happened (either the caller passed
// us bad parameters, or we messed up our shader generation).
- return INVALID_OPERATION;
+ resultPromise->set_value({INVALID_OPERATION, std::move(drawFence)});
+ return;
}
mLastDrawFence = nullptr;
} else {
// The caller takes ownership of drawFence, so we need to duplicate the
// fd here.
- mLastDrawFence = new Fence(dup(drawFence->get()));
+ mLastDrawFence = new Fence(dup(drawFence.get()));
}
mPriorResourcesCleaned = false;
checkErrors();
- return NO_ERROR;
+ resultPromise->set_value({NO_ERROR, std::move(drawFence)});
+ return;
}
void GLESRenderEngine::setViewportAndProjection(Rect viewport, Rect clip) {
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 14627ce..c4adfdf 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -63,11 +63,6 @@
bool isProtected() const override { return mInProtectedContext; }
bool supportsProtectedContent() const override;
void useProtectedContext(bool useProtectedContext) override;
- status_t drawLayers(const DisplaySettings& display,
- const std::vector<const LayerSettings*>& layers,
- const std::shared_ptr<ExternalTexture>& buffer,
- const bool useFramebufferCache, base::unique_fd&& bufferFence,
- base::unique_fd* drawFence) override;
void cleanupPostRender() override;
int getContextPriority() override;
bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; }
@@ -107,6 +102,11 @@
EXCLUDES(mRenderingMutex);
void unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) EXCLUDES(mRenderingMutex);
bool canSkipPostRenderCleanup() const override;
+ void drawLayersInternal(const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+ const DisplaySettings& display,
+ const std::vector<const LayerSettings*>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer,
+ const bool useFramebufferCache, base::unique_fd&& bufferFence) override;
private:
friend class BindNativeBufferAsFramebuffer;
diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h
index 53fa622..d395d06 100644
--- a/libs/renderengine/include/renderengine/DisplaySettings.h
+++ b/libs/renderengine/include/renderengine/DisplaySettings.h
@@ -51,10 +51,6 @@
// dataspace, in non-linear space.
mat4 colorTransform = mat4();
- // Region that will be cleared to (0, 0, 0, 1) prior to rendering.
- // This is specified in layer-stack space.
- Region clearRegion = Region::INVALID_REGION;
-
// An additional orientation flag to be applied after clipping the output.
// By way of example, this may be used for supporting fullscreen screenshot
// capture of a device in landscape while the buffer is in portrait
@@ -68,8 +64,7 @@
static inline bool operator==(const DisplaySettings& lhs, const DisplaySettings& rhs) {
return lhs.physicalDisplay == rhs.physicalDisplay && lhs.clip == rhs.clip &&
lhs.maxLuminance == rhs.maxLuminance && lhs.outputDataspace == rhs.outputDataspace &&
- lhs.colorTransform == rhs.colorTransform &&
- lhs.clearRegion.hasSameRects(rhs.clearRegion) && lhs.orientation == rhs.orientation;
+ lhs.colorTransform == rhs.colorTransform && lhs.orientation == rhs.orientation;
}
// Defining PrintTo helps with Google Tests.
@@ -84,9 +79,6 @@
PrintTo(settings.outputDataspace, os);
*os << "\n .colorTransform = " << settings.colorTransform;
*os << "\n .clearRegion = ";
- PrintTo(settings.clearRegion, os);
- *os << "\n .orientation = " << settings.orientation;
- *os << "\n}";
}
} // namespace renderengine
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 967cf5d..701c1f2 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -68,6 +68,7 @@
class Mesh;
class Texture;
struct RenderEngineCreationArgs;
+struct RenderEngineResult;
namespace threaded {
class RenderEngineThreaded;
@@ -156,17 +157,12 @@
// parameter does nothing.
// @param bufferFence Fence signalling that the buffer is ready to be drawn
// to.
- // @param drawFence A pointer to a fence, which will fire when the buffer
- // has been drawn to and is ready to be examined. The fence will be
- // initialized by this method. The caller will be responsible for owning the
- // fence.
- // @return An error code indicating whether drawing was successful. For
- // now, this always returns NO_ERROR.
- virtual status_t drawLayers(const DisplaySettings& display,
- const std::vector<const LayerSettings*>& layers,
- const std::shared_ptr<ExternalTexture>& buffer,
- const bool useFramebufferCache, base::unique_fd&& bufferFence,
- base::unique_fd* drawFence) = 0;
+ // @return A future object of RenderEngineResult struct indicating whether
+ // drawing was successful in async mode.
+ virtual std::future<RenderEngineResult> drawLayers(
+ const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
+ base::unique_fd&& bufferFence);
// Clean-up method that should be called on the main thread after the
// drawFence returned by drawLayers fires. This method will free up
@@ -232,6 +228,12 @@
friend class threaded::RenderEngineThreaded;
friend class RenderEngineTest_cleanupPostRender_cleansUpOnce_Test;
const RenderEngineType mRenderEngineType;
+
+ virtual void drawLayersInternal(
+ const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+ const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
+ base::unique_fd&& bufferFence) = 0;
};
struct RenderEngineCreationArgs {
@@ -318,6 +320,13 @@
RenderEngine::RenderEngineType::SKIA_GL_THREADED;
};
+struct RenderEngineResult {
+ // status indicates if drawing is successful
+ status_t status;
+ // drawFence will fire when the buffer has been drawn to and is ready to be examined.
+ base::unique_fd drawFence;
+};
+
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index 0be3ba6..a7e6809 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -47,10 +47,15 @@
MOCK_METHOD1(useProtectedContext, void(bool));
MOCK_METHOD0(cleanupPostRender, void());
MOCK_CONST_METHOD0(canSkipPostRenderCleanup, bool());
- MOCK_METHOD6(drawLayers,
- status_t(const DisplaySettings&, const std::vector<const LayerSettings*>&,
- const std::shared_ptr<ExternalTexture>&, const bool, base::unique_fd&&,
- base::unique_fd*));
+ MOCK_METHOD5(drawLayers,
+ std::future<RenderEngineResult>(const DisplaySettings&,
+ const std::vector<const LayerSettings*>&,
+ const std::shared_ptr<ExternalTexture>&,
+ const bool, base::unique_fd&&));
+ MOCK_METHOD6(drawLayersInternal,
+ void(const std::shared_ptr<std::promise<RenderEngineResult>>&&,
+ const DisplaySettings&, const std::vector<const LayerSettings*>&,
+ const std::shared_ptr<ExternalTexture>&, const bool, base::unique_fd&&));
MOCK_METHOD0(cleanFramebufferCache, void());
MOCK_METHOD0(getContextPriority, int());
MOCK_METHOD0(supportsBackgroundBlur, bool());
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index ae8f238..c4fa1bb 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -96,24 +96,26 @@
};
auto layers = std::vector<const LayerSettings*>{&layer, &caster};
- // When sourceDataspace matches dest, the general shadow fragment shader doesn't
- // have color correction added.
- // independently, when it is not srgb, the *vertex* shader has color correction added.
- // This may be a bug, but the shader still needs to be cached as it is triggered
- // during youtube pip.
- for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) {
- layer.sourceDataspace = dataspace;
- // The 2nd matrix, which has different scales for x and y, will
- // generate the slower (more general case) shadow shader
- for (auto transform : {mat4(), kScaleAndTranslate, kFlip}) {
- layer.geometry.positionTransform = transform;
- caster.geometry.positionTransform = transform;
- for (bool translucent : {false, true}){
- layer.shadow.casterIsTranslucent = translucent;
- renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
- base::unique_fd(), nullptr);
- }
- }
+ // Four combinations of settings are used (two transforms here, and drawShadowLayers is
+ // called with two different destination data spaces) They're all rounded rect.
+ // Three of these are cache misses that generate new shaders.
+ // The first combination generates a short and simple shadow shader.
+ // The second combination, flip transform, generates two shaders. The first appears to involve
+ // gaussian_fp. The second is a long and general purpose shadow shader with a device space
+ // transformation stage.
+ // The third combination is a cache hit, nothing new.
+ // The fourth combination, flip transform with a non-SRGB destination dataspace, is new.
+ // It is unique in that nearly everything is done in the vertex shader, and that vertex shader
+ // requires color correction. This is triggered differently from every other instance of color
+ // correction. All other instances are triggered when src and dst dataspaces differ, while
+ // this one is triggered by the destination being non-srgb. Apparently since the third
+ // combination is a cache hit, this color correction is only added when the vertex shader is
+ // doing something non-trivial.
+ for (auto transform : {mat4(), kFlip}) {
+ layer.geometry.positionTransform = transform;
+ caster.geometry.positionTransform = transform;
+ renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
+ base::unique_fd());
}
}
@@ -151,7 +153,7 @@
for (auto alpha : {half(.2f), half(1.0f)}) {
layer.alpha = alpha;
renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
- base::unique_fd(), nullptr);
+ base::unique_fd());
}
}
}
@@ -180,7 +182,7 @@
for (float roundedCornersRadius : {0.0f, 50.f}) {
layer.geometry.roundedCornersRadius = roundedCornersRadius;
renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
- base::unique_fd(), nullptr);
+ base::unique_fd());
}
}
}
@@ -204,7 +206,7 @@
for (int radius : {9, 60}) {
layer.backgroundBlurRadius = radius;
renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
- base::unique_fd(), nullptr);
+ base::unique_fd());
}
}
@@ -251,7 +253,7 @@
for (float alpha : {0.5f, 1.f}) {
layer.alpha = alpha,
renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
- base::unique_fd(), nullptr);
+ base::unique_fd());
}
}
}
@@ -288,8 +290,7 @@
};
auto layers = std::vector<const LayerSettings*>{&layer};
- renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
- base::unique_fd(), nullptr);
+ renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd());
}
static void drawHolePunchLayer(SkiaRenderEngine* renderengine, const DisplaySettings& display,
@@ -317,8 +318,7 @@
};
auto layers = std::vector<const LayerSettings*>{&layer};
- renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
- base::unique_fd(), nullptr);
+ renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd());
}
//
@@ -381,6 +381,7 @@
ExternalTexture::Usage::WRITEABLE);
drawHolePunchLayer(renderengine, display, dstTexture);
drawSolidLayers(renderengine, display, dstTexture);
+
drawShadowLayers(renderengine, display, srcTexture);
drawShadowLayers(renderengine, p3Display, srcTexture);
@@ -388,7 +389,10 @@
drawBlurLayers(renderengine, display, dstTexture);
}
- // should be the same as AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+ // The majority of skia shaders needed by RenderEngine are related to sampling images.
+ // These need to be generated with various source textures.
+ // Make a list of applicable sources.
+ // GRALLOC_USAGE_HW_TEXTURE should be the same as AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE.
const int64_t usageExternal = GRALLOC_USAGE_HW_TEXTURE;
sp<GraphicBuffer> externalBuffer =
new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888,
@@ -396,24 +400,24 @@
const auto externalTexture =
std::make_shared<ExternalTexture>(externalBuffer, *renderengine,
ExternalTexture::Usage::READABLE);
+ std::vector<const std::shared_ptr<ExternalTexture>> textures =
+ {srcTexture, externalTexture};
- // Another external texture with a different pixel format triggers useIsOpaqueWorkaround
+ // Another external texture with a different pixel format triggers useIsOpaqueWorkaround.
+ // It doesn't have to be f16, but it can't be the usual 8888.
sp<GraphicBuffer> f16ExternalBuffer =
new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_FP16,
1, usageExternal, "primeShaderCache_external_f16");
- const auto f16ExternalTexture =
+ // The F16 texture may not be usable on all devices, so check first that it was created.
+ status_t error = f16ExternalBuffer->initCheck();
+ if (!error) {
+ const auto f16ExternalTexture =
std::make_shared<ExternalTexture>(f16ExternalBuffer, *renderengine,
ExternalTexture::Usage::READABLE);
+ textures.push_back(f16ExternalTexture);
+ }
- // The majority of shaders are related to sampling images.
- // These need to be generated with various source textures
- // The F16 texture may not be usable on all devices, so check first that it was created with
- // the requested usage bit.
- auto textures = {srcTexture, externalTexture};
- auto texturesWithF16 = {srcTexture, externalTexture, f16ExternalTexture};
- bool canUsef16 = f16ExternalBuffer->getUsage() & GRALLOC_USAGE_HW_TEXTURE;
-
- for (auto texture : canUsef16 ? texturesWithF16 : textures) {
+ for (auto texture : textures) {
drawImageLayers(renderengine, display, dstTexture, texture);
// Draw layers for b/185569240.
drawClippedLayers(renderengine, display, dstTexture, texture);
@@ -421,6 +425,16 @@
drawPIPImageLayer(renderengine, display, dstTexture, externalTexture);
+ // draw one final layer synchronously to force GL submit
+ LayerSettings layer{
+ .source = PixelSource{.solidColor = half3(0.f, 0.f, 0.f)},
+ };
+ auto layers = std::vector<const LayerSettings*>{&layer};
+ // call get() to make it synchronous
+ renderengine
+ ->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd())
+ .get();
+
const nsecs_t timeAfter = systemTime();
const float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6;
const int shadersCompiled = renderengine->reportShadersCompiled();
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index e42b5b9..cb686a6 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -727,22 +727,24 @@
return roundedRect;
}
-status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display,
- const std::vector<const LayerSettings*>& layers,
- const std::shared_ptr<ExternalTexture>& buffer,
- const bool /*useFramebufferCache*/,
- base::unique_fd&& bufferFence, base::unique_fd* drawFence) {
+void SkiaGLRenderEngine::drawLayersInternal(
+ const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+ const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer, const bool /*useFramebufferCache*/,
+ base::unique_fd&& bufferFence) {
ATRACE_NAME("SkiaGL::drawLayers");
std::lock_guard<std::mutex> lock(mRenderingMutex);
if (layers.empty()) {
ALOGV("Drawing empty layer stack");
- return NO_ERROR;
+ resultPromise->set_value({NO_ERROR, base::unique_fd()});
+ return;
}
if (buffer == nullptr) {
ALOGE("No output buffer provided. Aborting GPU composition.");
- return BAD_VALUE;
+ resultPromise->set_value({BAD_VALUE, base::unique_fd()});
+ return;
}
validateOutputBufferUsage(buffer->getBuffer());
@@ -774,7 +776,8 @@
SkCanvas* dstCanvas = mCapture->tryCapture(dstSurface.get());
if (dstCanvas == nullptr) {
ALOGE("Cannot acquire canvas from Skia.");
- return BAD_VALUE;
+ resultPromise->set_value({BAD_VALUE, base::unique_fd()});
+ return;
}
// setup color filter if necessary
@@ -821,28 +824,6 @@
canvas->clear(SK_ColorTRANSPARENT);
initCanvas(canvas, display);
- // TODO: clearRegion was required for SurfaceView when a buffer is not yet available but the
- // view is still on-screen. The clear region could be re-specified as a black color layer,
- // however.
- if (!display.clearRegion.isEmpty()) {
- ATRACE_NAME("ClearRegion");
- size_t numRects = 0;
- Rect const* rects = display.clearRegion.getArray(&numRects);
- SkIRect skRects[numRects];
- for (int i = 0; i < numRects; ++i) {
- skRects[i] =
- SkIRect::MakeLTRB(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom);
- }
- SkRegion clearRegion;
- SkPaint paint;
- sk_sp<SkShader> shader =
- SkShaders::Color(SkColor4f{.fR = 0., .fG = 0., .fB = 0., .fA = 1.0},
- toSkColorSpace(dstDataspace));
- paint.setShader(shader);
- clearRegion.setRects(skRects, numRects);
- canvas->drawRegion(clearRegion, paint);
- }
-
for (const auto& layer : layers) {
ATRACE_FORMAT("DrawLayer: %s", layer->name.c_str());
@@ -1131,13 +1112,11 @@
activeSurface->flush();
}
- if (drawFence != nullptr) {
- *drawFence = flush();
- }
+ base::unique_fd drawFence = flush();
// If flush failed or we don't support native fences, we need to force the
// gl command stream to be executed.
- bool requireSync = drawFence == nullptr || drawFence->get() < 0;
+ bool requireSync = drawFence.get() < 0;
if (requireSync) {
ATRACE_BEGIN("Submit(sync=true)");
} else {
@@ -1149,11 +1128,13 @@
ALOGE("Failed to flush RenderEngine commands");
// Chances are, something illegal happened (either the caller passed
// us bad parameters, or we messed up our shader generation).
- return INVALID_OPERATION;
+ resultPromise->set_value({INVALID_OPERATION, std::move(drawFence)});
+ return;
}
// checkErrors();
- return NO_ERROR;
+ resultPromise->set_value({NO_ERROR, std::move(drawFence)});
+ return;
}
inline SkRect SkiaGLRenderEngine::getSkRect(const FloatRect& rect) {
@@ -1164,6 +1145,73 @@
return SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom);
}
+/**
+ * Verifies that common, simple bounds + clip combinations can be converted into
+ * a single RRect draw call returning true if possible. If true the radii parameter
+ * will be filled with the correct radii values that combined with bounds param will
+ * produce the insected roundRect. If false, the returned state of the radii param is undefined.
+ */
+static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop,
+ const SkRect& insetCrop, float cornerRadius,
+ SkVector radii[4]) {
+ const bool leftEqual = bounds.fLeft == crop.fLeft;
+ const bool topEqual = bounds.fTop == crop.fTop;
+ const bool rightEqual = bounds.fRight == crop.fRight;
+ const bool bottomEqual = bounds.fBottom == crop.fBottom;
+
+ // In the event that the corners of the bounds only partially align with the crop we
+ // need to ensure that the resulting shape can still be represented as a round rect.
+ // In particular the round rect implementation will scale the value of all corner radii
+ // if the sum of the radius along any edge is greater than the length of that edge.
+ // See https://www.w3.org/TR/css-backgrounds-3/#corner-overlap
+ const bool requiredWidth = bounds.width() > (cornerRadius * 2);
+ const bool requiredHeight = bounds.height() > (cornerRadius * 2);
+ if (!requiredWidth || !requiredHeight) {
+ return false;
+ }
+
+ // Check each cropped corner to ensure that it exactly matches the crop or its corner is
+ // contained within the cropped shape and does not need rounded.
+ // compute the UpperLeft corner radius
+ if (leftEqual && topEqual) {
+ radii[0].set(cornerRadius, cornerRadius);
+ } else if ((leftEqual && bounds.fTop >= insetCrop.fTop) ||
+ (topEqual && bounds.fLeft >= insetCrop.fLeft)) {
+ radii[0].set(0, 0);
+ } else {
+ return false;
+ }
+ // compute the UpperRight corner radius
+ if (rightEqual && topEqual) {
+ radii[1].set(cornerRadius, cornerRadius);
+ } else if ((rightEqual && bounds.fTop >= insetCrop.fTop) ||
+ (topEqual && bounds.fRight <= insetCrop.fRight)) {
+ radii[1].set(0, 0);
+ } else {
+ return false;
+ }
+ // compute the BottomRight corner radius
+ if (rightEqual && bottomEqual) {
+ radii[2].set(cornerRadius, cornerRadius);
+ } else if ((rightEqual && bounds.fBottom <= insetCrop.fBottom) ||
+ (bottomEqual && bounds.fRight <= insetCrop.fRight)) {
+ radii[2].set(0, 0);
+ } else {
+ return false;
+ }
+ // compute the BottomLeft corner radius
+ if (leftEqual && bottomEqual) {
+ radii[3].set(cornerRadius, cornerRadius);
+ } else if ((leftEqual && bounds.fBottom <= insetCrop.fBottom) ||
+ (bottomEqual && bounds.fLeft >= insetCrop.fLeft)) {
+ radii[3].set(0, 0);
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
inline std::pair<SkRRect, SkRRect> SkiaGLRenderEngine::getBoundsAndClip(const FloatRect& boundsRect,
const FloatRect& cropRect,
const float cornerRadius) {
@@ -1181,66 +1229,20 @@
// converting them to a single RRect draw. It is possible there are other cases
// that can be converted.
if (crop.contains(bounds)) {
- bool intersectionIsRoundRect = true;
- // check each cropped corner to ensure that it exactly matches the crop or is full
- SkVector radii[4];
-
const auto insetCrop = crop.makeInset(cornerRadius, cornerRadius);
-
- const bool leftEqual = bounds.fLeft == crop.fLeft;
- const bool topEqual = bounds.fTop == crop.fTop;
- const bool rightEqual = bounds.fRight == crop.fRight;
- const bool bottomEqual = bounds.fBottom == crop.fBottom;
-
- // compute the UpperLeft corner radius
- if (leftEqual && topEqual) {
- radii[0].set(cornerRadius, cornerRadius);
- } else if ((leftEqual && bounds.fTop >= insetCrop.fTop) ||
- (topEqual && bounds.fLeft >= insetCrop.fLeft) ||
- insetCrop.contains(bounds.fLeft, bounds.fTop)) {
- radii[0].set(0, 0);
- } else {
- intersectionIsRoundRect = false;
- }
- // compute the UpperRight corner radius
- if (rightEqual && topEqual) {
- radii[1].set(cornerRadius, cornerRadius);
- } else if ((rightEqual && bounds.fTop >= insetCrop.fTop) ||
- (topEqual && bounds.fRight <= insetCrop.fRight) ||
- insetCrop.contains(bounds.fRight, bounds.fTop)) {
- radii[1].set(0, 0);
- } else {
- intersectionIsRoundRect = false;
- }
- // compute the BottomRight corner radius
- if (rightEqual && bottomEqual) {
- radii[2].set(cornerRadius, cornerRadius);
- } else if ((rightEqual && bounds.fBottom <= insetCrop.fBottom) ||
- (bottomEqual && bounds.fRight <= insetCrop.fRight) ||
- insetCrop.contains(bounds.fRight, bounds.fBottom)) {
- radii[2].set(0, 0);
- } else {
- intersectionIsRoundRect = false;
- }
- // compute the BottomLeft corner radius
- if (leftEqual && bottomEqual) {
- radii[3].set(cornerRadius, cornerRadius);
- } else if ((leftEqual && bounds.fBottom <= insetCrop.fBottom) ||
- (bottomEqual && bounds.fLeft >= insetCrop.fLeft) ||
- insetCrop.contains(bounds.fLeft, bounds.fBottom)) {
- radii[3].set(0, 0);
- } else {
- intersectionIsRoundRect = false;
+ if (insetCrop.contains(bounds)) {
+ return {SkRRect::MakeRect(bounds), clip}; // clip is empty - no rounding required
}
- if (intersectionIsRoundRect) {
+ SkVector radii[4];
+ if (intersectionIsRoundRect(bounds, crop, insetCrop, cornerRadius, radii)) {
SkRRect intersectionBounds;
intersectionBounds.setRectRadii(bounds, radii);
return {intersectionBounds, clip};
}
}
- // we didn't it any of our fast paths so set the clip to the cropRect
+ // we didn't hit any of our fast paths so set the clip to the cropRect
clip.setRectXY(crop, cornerRadius, cornerRadius);
}
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index e1162f5..e010c35 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -54,11 +54,6 @@
~SkiaGLRenderEngine() override EXCLUDES(mRenderingMutex);
std::future<void> primeCache() override;
- status_t drawLayers(const DisplaySettings& display,
- const std::vector<const LayerSettings*>& layers,
- const std::shared_ptr<ExternalTexture>& buffer,
- const bool useFramebufferCache, base::unique_fd&& bufferFence,
- base::unique_fd* drawFence) override;
void cleanupPostRender() override;
void cleanFramebufferCache() override{};
int getContextPriority() override;
@@ -77,6 +72,11 @@
void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) override;
void unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) override;
bool canSkipPostRenderCleanup() const override;
+ void drawLayersInternal(const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+ const DisplaySettings& display,
+ const std::vector<const LayerSettings*>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer,
+ const bool useFramebufferCache, base::unique_fd&& bufferFence) override;
private:
static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h
index 7cd9eca..f61653b 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -44,14 +44,6 @@
virtual void deleteTextures(size_t /*count*/, uint32_t const* /*names*/) override{};
virtual bool isProtected() const override { return false; } // mInProtectedContext; }
virtual bool supportsProtectedContent() const override { return false; };
- virtual status_t drawLayers(const DisplaySettings& /*display*/,
- const std::vector<const LayerSettings*>& /*layers*/,
- const std::shared_ptr<ExternalTexture>& /*buffer*/,
- const bool /*useFramebufferCache*/,
- base::unique_fd&& /*bufferFence*/,
- base::unique_fd* /*drawFence*/) override {
- return 0;
- };
virtual int getContextPriority() override { return 0; }
virtual void assertShadersCompiled(int numShaders) {}
virtual int reportShadersCompiled() { return 0; }
@@ -60,6 +52,14 @@
virtual void mapExternalTextureBuffer(const sp<GraphicBuffer>& /*buffer*/,
bool /*isRenderable*/) override = 0;
virtual void unmapExternalTextureBuffer(const sp<GraphicBuffer>& /*buffer*/) override = 0;
+
+ virtual void drawLayersInternal(
+ const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+ const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
+ base::unique_fd&& bufferFence) override {
+ resultPromise->set_value({NO_ERROR, base::unique_fd()});
+ };
};
} // namespace skia
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp
index 7c5bee9..6af6195 100644
--- a/libs/renderengine/skia/filters/BlurFilter.cpp
+++ b/libs/renderengine/skia/filters/BlurFilter.cpp
@@ -39,15 +39,15 @@
uniform float2 in_maxSizeXY;
half4 main(float2 xy) {
- half4 c = sample(input, xy);
- c += sample(input, float2( clamp( in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
- clamp(in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
- c += sample(input, float2( clamp( in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
- clamp(-in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
- c += sample(input, float2( clamp( -in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
- clamp(in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
- c += sample(input, float2( clamp( -in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
- clamp(-in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
+ half4 c = input.eval(xy);
+ c += input.eval(float2(clamp( in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
+ clamp( in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
+ c += input.eval(float2(clamp( in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
+ clamp(-in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
+ c += input.eval(float2(clamp(-in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
+ clamp( in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
+ c += input.eval(float2(clamp(-in_blurOffset.x + xy.x, 0, in_maxSizeXY.x),
+ clamp(-in_blurOffset.y + xy.y, 0, in_maxSizeXY.y)));
return half4(c.rgb * 0.2, 1.0);
}
@@ -65,7 +65,7 @@
uniform float mixFactor;
half4 main(float2 xy) {
- return half4(mix(sample(originalInput, xy), sample(blurredInput, xy), mixFactor));
+ return half4(mix(originalInput.eval(xy), blurredInput.eval(xy), mixFactor));
}
)");
diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp
index fc45af9..dc5fe17 100644
--- a/libs/renderengine/skia/filters/LinearEffect.cpp
+++ b/libs/renderengine/skia/filters/LinearEffect.cpp
@@ -391,7 +391,7 @@
shader.append(R"(
uniform shader input;
half4 main(float2 xy) {
- float4 c = float4(sample(input, xy));
+ float4 c = float4(input.eval(xy));
)");
if (undoPremultipliedAlpha) {
shader.append(R"(
diff --git a/libs/renderengine/skia/filters/StretchShaderFactory.cpp b/libs/renderengine/skia/filters/StretchShaderFactory.cpp
index 4ac5c40..c262e35 100644
--- a/libs/renderengine/skia/filters/StretchShaderFactory.cpp
+++ b/libs/renderengine/skia/filters/StretchShaderFactory.cpp
@@ -184,7 +184,7 @@
);
coord.x = (outU - uScrollX) * viewportWidth;
coord.y = (outV - uScrollY) * viewportHeight;
- return sample(uContentTexture, coord);
+ return uContentTexture.eval(coord);
})");
const float INTERPOLATION_STRENGTH_VALUE = 0.7f;
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 33e3773..694bda6 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -419,17 +419,16 @@
void invokeDraw(renderengine::DisplaySettings settings,
std::vector<const renderengine::LayerSettings*> layers) {
- base::unique_fd fence;
- status_t status =
- mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), &fence);
-
- int fd = fence.release();
- if (fd >= 0) {
- sync_wait(fd, -1);
- close(fd);
- }
+ std::future<renderengine::RenderEngineResult> result =
+ mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd());
+ ASSERT_TRUE(result.valid());
+ auto [status, fence] = result.get();
ASSERT_EQ(NO_ERROR, status);
+ if (fence.ok()) {
+ sync_wait(fence.get(), -1);
+ }
+
if (layers.size() > 0 && mGLESRE != nullptr) {
ASSERT_TRUE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getBuffer()->getId()));
}
@@ -524,10 +523,6 @@
void fillGreenColorBufferThenClearRegion();
- void clearLeftRegion();
-
- void clearRegion();
-
template <typename SourceVariant>
void drawShadow(const renderengine::LayerSettings& castingLayer,
const renderengine::ShadowSettings& shadow, const ubyte4& casterColor,
@@ -1195,28 +1190,6 @@
expectBufferColor(fullscreenRect(), 128, 0, 0, 128, 1);
}
-void RenderEngineTest::clearLeftRegion() {
- renderengine::DisplaySettings settings;
- settings.physicalDisplay = fullscreenRect();
- // Here logical space is 4x4
- settings.clip = Rect(4, 4);
- settings.clearRegion = Region(Rect(2, 4));
- std::vector<const renderengine::LayerSettings*> layers;
- // fake layer, without bounds should not render anything
- renderengine::LayerSettings layer;
- layers.push_back(&layer);
- invokeDraw(settings, layers);
-}
-
-void RenderEngineTest::clearRegion() {
- // Reuse mBuffer
- clearLeftRegion();
- expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT), 0, 0, 0, 255);
- expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, 0, DEFAULT_DISPLAY_WIDTH,
- DEFAULT_DISPLAY_HEIGHT),
- 0, 0, 0, 0);
-}
-
template <typename SourceVariant>
void RenderEngineTest::drawShadow(const renderengine::LayerSettings& castingLayer,
const renderengine::ShadowSettings& shadow,
@@ -1338,30 +1311,13 @@
layer.geometry.boundaries = fullscreenRect().toFloatRect();
BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layers.push_back(&layer);
- base::unique_fd fence;
- status_t status = mRE->drawLayers(settings, layers, nullptr, true, base::unique_fd(), &fence);
+ std::future<renderengine::RenderEngineResult> result =
+ mRE->drawLayers(settings, layers, nullptr, true, base::unique_fd());
+ ASSERT_TRUE(result.valid());
+ auto [status, fence] = result.get();
ASSERT_EQ(BAD_VALUE, status);
-}
-
-TEST_P(RenderEngineTest, drawLayers_nullOutputFence) {
- initializeRenderEngine();
-
- renderengine::DisplaySettings settings;
- settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
- settings.physicalDisplay = fullscreenRect();
- settings.clip = fullscreenRect();
-
- std::vector<const renderengine::LayerSettings*> layers;
- renderengine::LayerSettings layer;
- layer.geometry.boundaries = fullscreenRect().toFloatRect();
- BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
- layer.alpha = 1.0;
- layers.push_back(&layer);
-
- status_t status = mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), nullptr);
- ASSERT_EQ(NO_ERROR, status);
- expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
+ ASSERT_FALSE(fence.ok());
}
TEST_P(RenderEngineTest, drawLayers_doesNotCacheFramebuffer) {
@@ -1386,8 +1342,16 @@
layer.alpha = 1.0;
layers.push_back(&layer);
- status_t status = mRE->drawLayers(settings, layers, mBuffer, false, base::unique_fd(), nullptr);
+ std::future<renderengine::RenderEngineResult> result =
+ mRE->drawLayers(settings, layers, mBuffer, false, base::unique_fd());
+ ASSERT_TRUE(result.valid());
+ auto [status, fence] = result.get();
+
ASSERT_EQ(NO_ERROR, status);
+ if (fence.ok()) {
+ sync_wait(fence.get(), -1);
+ }
+
ASSERT_FALSE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getBuffer()->getId()));
expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
}
@@ -1647,11 +1611,6 @@
fillBufferWithoutPremultiplyAlpha();
}
-TEST_P(RenderEngineTest, drawLayers_clearRegion) {
- initializeRenderEngine();
- clearRegion();
-}
-
TEST_P(RenderEngineTest, drawLayers_fillShadow_castsWithoutCasterLayer) {
initializeRenderEngine();
@@ -1791,15 +1750,21 @@
layer.alpha = 1.0;
layers.push_back(&layer);
- base::unique_fd fenceOne;
- mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), &fenceOne);
- base::unique_fd fenceTwo;
- mRE->drawLayers(settings, layers, mBuffer, true, std::move(fenceOne), &fenceTwo);
+ std::future<renderengine::RenderEngineResult> resultOne =
+ mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd());
+ ASSERT_TRUE(resultOne.valid());
+ auto [statusOne, fenceOne] = resultOne.get();
+ ASSERT_EQ(NO_ERROR, statusOne);
- const int fd = fenceTwo.get();
- if (fd >= 0) {
- sync_wait(fd, -1);
+ std::future<renderengine::RenderEngineResult> resultTwo =
+ mRE->drawLayers(settings, layers, mBuffer, true, std::move(fenceOne));
+ ASSERT_TRUE(resultTwo.valid());
+ auto [statusTwo, fenceTwo] = resultTwo.get();
+ ASSERT_EQ(NO_ERROR, statusTwo);
+ if (fenceTwo.ok()) {
+ sync_wait(fenceTwo.get(), -1);
}
+
// Only cleanup the first time.
EXPECT_FALSE(mRE->canSkipPostRenderCleanup());
mRE->cleanupPostRender();
@@ -1900,6 +1865,40 @@
expectBufferColor(Point(0, (DEFAULT_DISPLAY_HEIGHT / 2) - 1), 0, 255, 0, 255);
}
+TEST_P(RenderEngineTest, testRoundedCornersParentCropSmallBounds) {
+ initializeRenderEngine();
+
+ renderengine::DisplaySettings settings;
+ settings.physicalDisplay = fullscreenRect();
+ settings.clip = fullscreenRect();
+ settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+
+ std::vector<const renderengine::LayerSettings*> layers;
+
+ renderengine::LayerSettings redLayer;
+ redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+ redLayer.geometry.boundaries = FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH, 32);
+ redLayer.geometry.roundedCornersRadius = 64;
+ redLayer.geometry.roundedCornersCrop = FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH, 128);
+ // Red background.
+ redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f);
+ redLayer.alpha = 1.0f;
+
+ layers.push_back(&redLayer);
+ invokeDraw(settings, layers);
+
+ // Due to roundedCornersRadius, the top corners are untouched.
+ expectBufferColor(Point(0, 0), 0, 0, 0, 0);
+ expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH - 1, 0), 0, 0, 0, 0);
+
+ // ensure that the entire height of the red layer was clipped by the rounded corners crop.
+ expectBufferColor(Point(0, 31), 0, 0, 0, 0);
+ expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH - 1, 31), 0, 0, 0, 0);
+
+ // the bottom middle should be red
+ expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH / 2, 31), 255, 0, 0, 255);
+}
+
TEST_P(RenderEngineTest, testClear) {
initializeRenderEngine();
diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
index 830f463..99250c1 100644
--- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp
+++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
@@ -169,6 +169,7 @@
status_t result = mThreadedRE->supportsBackgroundBlur();
ASSERT_EQ(true, result);
}
+
TEST_F(RenderEngineThreadedTest, drawLayers) {
renderengine::DisplaySettings settings;
std::vector<const renderengine::LayerSettings*> layers;
@@ -177,17 +178,22 @@
renderengine::ExternalTexture::Usage::READABLE |
renderengine::ExternalTexture::Usage::WRITEABLE);
base::unique_fd bufferFence;
- base::unique_fd drawFence;
- EXPECT_CALL(*mRenderEngine, drawLayers)
- .WillOnce([](const renderengine::DisplaySettings&,
- const std::vector<const renderengine::LayerSettings*>&,
- const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd&&, base::unique_fd*) -> status_t { return NO_ERROR; });
+ EXPECT_CALL(*mRenderEngine, drawLayersInternal)
+ .WillOnce([&](const std::shared_ptr<std::promise<renderengine::RenderEngineResult>>&&
+ resultPromise,
+ const renderengine::DisplaySettings&,
+ const std::vector<const renderengine::LayerSettings*>&,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&) -> void {
+ resultPromise->set_value({NO_ERROR, base::unique_fd()});
+ });
- status_t result = mThreadedRE->drawLayers(settings, layers, buffer, false,
- std::move(bufferFence), &drawFence);
- ASSERT_EQ(NO_ERROR, result);
+ std::future<renderengine::RenderEngineResult> result =
+ mThreadedRE->drawLayers(settings, layers, buffer, false, std::move(bufferFence));
+ ASSERT_TRUE(result.valid());
+ auto [status, _] = result.get();
+ ASSERT_EQ(NO_ERROR, status);
}
} // namespace android
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index 8e666d5..a549672 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -292,7 +292,7 @@
{
std::lock_guard lock(mThreadMutex);
mFunctionCalls.push([=](renderengine::RenderEngine& instance) {
- ATRACE_NAME("REThreaded::unmapExternalTextureBuffer");
+ ATRACE_NAME("REThreaded::cleanupPostRender");
instance.cleanupPostRender();
});
}
@@ -304,27 +304,33 @@
return mRenderEngine->canSkipPostRenderCleanup();
}
-status_t RenderEngineThreaded::drawLayers(const DisplaySettings& display,
- const std::vector<const LayerSettings*>& layers,
- const std::shared_ptr<ExternalTexture>& buffer,
- const bool useFramebufferCache,
- base::unique_fd&& bufferFence,
- base::unique_fd* drawFence) {
+void RenderEngineThreaded::drawLayersInternal(
+ const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+ const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
+ base::unique_fd&& bufferFence) {
+ resultPromise->set_value({NO_ERROR, base::unique_fd()});
+ return;
+}
+
+std::future<RenderEngineResult> RenderEngineThreaded::drawLayers(
+ const DisplaySettings& display, const std::vector<const LayerSettings*>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
+ base::unique_fd&& bufferFence) {
ATRACE_CALL();
- std::promise<status_t> resultPromise;
- std::future<status_t> resultFuture = resultPromise.get_future();
+ const auto resultPromise = std::make_shared<std::promise<RenderEngineResult>>();
+ std::future<RenderEngineResult> resultFuture = resultPromise->get_future();
{
std::lock_guard lock(mThreadMutex);
- mFunctionCalls.push([&resultPromise, &display, &layers, &buffer, useFramebufferCache,
- &bufferFence, &drawFence](renderengine::RenderEngine& instance) {
+ mFunctionCalls.push([resultPromise, &display, &layers, &buffer, useFramebufferCache,
+ &bufferFence](renderengine::RenderEngine& instance) {
ATRACE_NAME("REThreaded::drawLayers");
- status_t status = instance.drawLayers(display, layers, buffer, useFramebufferCache,
- std::move(bufferFence), drawFence);
- resultPromise.set_value(status);
+ instance.drawLayersInternal(std::move(resultPromise), display, layers, buffer,
+ useFramebufferCache, std::move(bufferFence));
});
}
mCondition.notify_one();
- return resultFuture.get();
+ return resultFuture;
}
void RenderEngineThreaded::cleanFramebufferCache() {
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index b197df7..2303caa 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -56,11 +56,11 @@
void useProtectedContext(bool useProtectedContext) override;
void cleanupPostRender() override;
- status_t drawLayers(const DisplaySettings& display,
- const std::vector<const LayerSettings*>& layers,
- const std::shared_ptr<ExternalTexture>& buffer,
- const bool useFramebufferCache, base::unique_fd&& bufferFence,
- base::unique_fd* drawFence) override;
+ std::future<RenderEngineResult> drawLayers(const DisplaySettings& display,
+ const std::vector<const LayerSettings*>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer,
+ const bool useFramebufferCache,
+ base::unique_fd&& bufferFence) override;
void cleanFramebufferCache() override;
int getContextPriority() override;
@@ -71,6 +71,11 @@
void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) override;
void unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) override;
bool canSkipPostRenderCleanup() const override;
+ void drawLayersInternal(const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+ const DisplaySettings& display,
+ const std::vector<const LayerSettings*>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer,
+ const bool useFramebufferCache, base::unique_fd&& bufferFence) override;
private:
void threadMain(CreateInstanceFactory factory);
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index eed58c5..ba5a64f 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -137,7 +137,6 @@
"HdrCapabilities.cpp",
"PixelFormat.cpp",
"PublicFormat.cpp",
- "Size.cpp",
"StaticDisplayInfo.cpp",
],
diff --git a/libs/ui/include/ui/DisplayId.h b/libs/ui/include/ui/DisplayId.h
index f196ab9..9120972 100644
--- a/libs/ui/include/ui/DisplayId.h
+++ b/libs/ui/include/ui/DisplayId.h
@@ -38,12 +38,22 @@
uint64_t value;
+ // For deserialization.
+ static constexpr std::optional<DisplayId> fromValue(uint64_t);
+
+ // As above, but also upcast to Id.
+ template <typename Id>
+ static constexpr std::optional<Id> fromValue(uint64_t value) {
+ if (const auto id = Id::tryCast(DisplayId(value))) {
+ return id;
+ }
+ return {};
+ }
+
protected:
explicit constexpr DisplayId(uint64_t id) : value(id) {}
};
-static_assert(sizeof(DisplayId) == sizeof(uint64_t));
-
inline bool operator==(DisplayId lhs, DisplayId rhs) {
return lhs.value == rhs.value;
}
@@ -80,11 +90,8 @@
// TODO(b/162612135) Remove default constructor
PhysicalDisplayId() = default;
- // TODO(b/162612135) Remove constructor
- explicit constexpr PhysicalDisplayId(uint64_t id) : DisplayId(id) {}
constexpr uint16_t getManufacturerId() const { return static_cast<uint16_t>(value >> 40); }
-
constexpr uint8_t getPort() const { return static_cast<uint8_t>(value); }
private:
@@ -96,10 +103,9 @@
explicit constexpr PhysicalDisplayId(DisplayId other) : DisplayId(other) {}
};
-static_assert(sizeof(PhysicalDisplayId) == sizeof(uint64_t));
-
struct VirtualDisplayId : DisplayId {
using BaseId = uint32_t;
+
// Flag indicating that this virtual display is backed by the GPU.
static constexpr uint64_t FLAG_GPU = 1ULL << 61;
@@ -163,10 +169,23 @@
explicit constexpr HalDisplayId(DisplayId other) : DisplayId(other) {}
};
+constexpr std::optional<DisplayId> DisplayId::fromValue(uint64_t value) {
+ if (const auto id = fromValue<PhysicalDisplayId>(value)) {
+ return id;
+ }
+ if (const auto id = fromValue<VirtualDisplayId>(value)) {
+ return id;
+ }
+ return {};
+}
+
+static_assert(sizeof(DisplayId) == sizeof(uint64_t));
+static_assert(sizeof(HalDisplayId) == sizeof(uint64_t));
static_assert(sizeof(VirtualDisplayId) == sizeof(uint64_t));
+
+static_assert(sizeof(PhysicalDisplayId) == sizeof(uint64_t));
static_assert(sizeof(HalVirtualDisplayId) == sizeof(uint64_t));
static_assert(sizeof(GpuVirtualDisplayId) == sizeof(uint64_t));
-static_assert(sizeof(HalDisplayId) == sizeof(uint64_t));
} // namespace android
diff --git a/libs/ui/include/ui/DisplayState.h b/libs/ui/include/ui/DisplayState.h
index 70a0d50..98ee356 100644
--- a/libs/ui/include/ui/DisplayState.h
+++ b/libs/ui/include/ui/DisplayState.h
@@ -16,21 +16,18 @@
#pragma once
+#include <ui/LayerStack.h>
#include <ui/Rotation.h>
#include <ui/Size.h>
-#include <cstdint>
#include <type_traits>
namespace android::ui {
-using LayerStack = uint32_t;
-constexpr LayerStack NO_LAYER_STACK = static_cast<LayerStack>(-1);
-
// Transactional state of physical or virtual display. Note that libgui defines
// android::DisplayState as a superset of android::ui::DisplayState.
struct DisplayState {
- LayerStack layerStack = NO_LAYER_STACK;
+ LayerStack layerStack;
Rotation orientation = ROTATION_0;
Size layerStackSpaceRect;
};
diff --git a/libs/ui/include/ui/LayerStack.h b/libs/ui/include/ui/LayerStack.h
new file mode 100644
index 0000000..d6ffeb7
--- /dev/null
+++ b/libs/ui/include/ui/LayerStack.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+#include <ftl/cast.h>
+#include <ftl/string.h>
+#include <log/log.h>
+
+namespace android::ui {
+
+// A LayerStack identifies a Z-ordered group of layers. A layer can only be associated to a single
+// LayerStack, but a LayerStack can be associated to multiple displays, mirroring the same content.
+struct LayerStack {
+ uint32_t id = UINT32_MAX;
+
+ template <typename T>
+ static constexpr LayerStack fromValue(T v) {
+ if (ftl::cast_safety<uint32_t>(v) == ftl::CastSafety::kSafe) {
+ return {static_cast<uint32_t>(v)};
+ }
+
+ ALOGW("Invalid layer stack %s", ftl::to_string(v).c_str());
+ return {};
+ }
+};
+
+constexpr LayerStack INVALID_LAYER_STACK;
+constexpr LayerStack DEFAULT_LAYER_STACK{0u};
+
+inline bool operator==(LayerStack lhs, LayerStack rhs) {
+ return lhs.id == rhs.id;
+}
+
+inline bool operator!=(LayerStack lhs, LayerStack rhs) {
+ return !(lhs == rhs);
+}
+
+inline bool operator>(LayerStack lhs, LayerStack rhs) {
+ return lhs.id > rhs.id;
+}
+
+// A LayerFilter determines if a layer is included for output to a display.
+struct LayerFilter {
+ LayerStack layerStack;
+
+ // True if the layer is only output to internal displays, i.e. excluded from screenshots, screen
+ // recordings, and mirroring to virtual or external displays. Used for display cutout overlays.
+ bool toInternalDisplay = false;
+
+ // Returns true if the input filter can be output to this filter.
+ bool includes(LayerFilter other) const {
+ // The layer stacks must match.
+ if (other.layerStack == INVALID_LAYER_STACK || other.layerStack != layerStack) {
+ return false;
+ }
+
+ // The output must be to an internal display if the input filter has that constraint.
+ return !other.toInternalDisplay || toInternalDisplay;
+ }
+};
+
+} // namespace android::ui
diff --git a/libs/ui/include/ui/Size.h b/libs/ui/include/ui/Size.h
index f1e8252..ecc192d 100644
--- a/libs/ui/include/ui/Size.h
+++ b/libs/ui/include/ui/Size.h
@@ -23,103 +23,70 @@
#include <type_traits>
#include <utility>
-namespace android {
-namespace ui {
+namespace android::ui {
-// Forward declare a few things.
-struct Size;
-bool operator==(const Size& lhs, const Size& rhs);
-
-/**
- * A simple value type representing a two-dimensional size
- */
+// A simple value type representing a two-dimensional size.
struct Size {
- int32_t width;
- int32_t height;
+ int32_t width = -1;
+ int32_t height = -1;
- // Special values
- static const Size INVALID;
- static const Size EMPTY;
+ constexpr Size() = default;
- // ------------------------------------------------------------------------
- // Construction
- // ------------------------------------------------------------------------
-
- Size() : Size(INVALID) {}
template <typename T>
- Size(T&& w, T&& h)
- : width(Size::clamp<int32_t, T>(std::forward<T>(w))),
- height(Size::clamp<int32_t, T>(std::forward<T>(h))) {}
-
- // ------------------------------------------------------------------------
- // Accessors
- // ------------------------------------------------------------------------
+ constexpr Size(T w, T h) : width(clamp<int32_t>(w)), height(clamp<int32_t>(h)) {}
int32_t getWidth() const { return width; }
int32_t getHeight() const { return height; }
- template <typename T>
- void setWidth(T&& v) {
- width = Size::clamp<int32_t, T>(std::forward<T>(v));
- }
- template <typename T>
- void setHeight(T&& v) {
- height = Size::clamp<int32_t, T>(std::forward<T>(v));
- }
-
- // ------------------------------------------------------------------------
- // Assignment
- // ------------------------------------------------------------------------
-
- void set(const Size& size) { *this = size; }
- template <typename T>
- void set(T&& w, T&& h) {
- set(Size(std::forward<T>(w), std::forward<T>(h)));
- }
-
- // Sets the value to INVALID
- void makeInvalid() { set(INVALID); }
-
- // Sets the value to EMPTY
- void clear() { set(EMPTY); }
-
- // ------------------------------------------------------------------------
- // Semantic checks
- // ------------------------------------------------------------------------
-
// Valid means non-negative width and height
bool isValid() const { return width >= 0 && height >= 0; }
// Empty means zero width and height
- bool isEmpty() const { return *this == EMPTY; }
+ bool isEmpty() const;
- // ------------------------------------------------------------------------
- // Clamp Helpers
- // ------------------------------------------------------------------------
-
- // Note: We use only features available in C++11 here for compatibility with
- // external targets which include this file directly or indirectly and which
- // themselves use C++11.
-
- // C++11 compatible replacement for std::remove_cv_reference_t [C++20]
template <typename T>
- using remove_cv_reference_t =
- typename std::remove_cv<typename std::remove_reference<T>::type>::type;
+ void setWidth(T v) {
+ width = clamp<int32_t>(v);
+ }
+
+ template <typename T>
+ void setHeight(T v) {
+ height = clamp<int32_t>(v);
+ }
+
+ void set(Size size) { *this = size; }
+
+ template <typename T>
+ void set(T w, T h) {
+ set(Size(w, h));
+ }
+
+ // Sets the value to kInvalidSize
+ void makeInvalid();
+
+ // Sets the value to kEmptySize
+ void clear();
+
+ // TODO: Replace with std::remove_cvref_t in C++20.
+ template <typename T>
+ using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
// Takes a value of type FromType, and ensures it can be represented as a value of type ToType,
// clamping the input value to the output range if necessary.
template <typename ToType, typename FromType>
- static Size::remove_cv_reference_t<ToType>
- clamp(typename std::enable_if<
- std::numeric_limits<Size::remove_cv_reference_t<ToType>>::is_specialized &&
- std::numeric_limits<Size::remove_cv_reference_t<FromType>>::is_specialized,
- FromType>::type v) {
- using BareToType = remove_cv_reference_t<ToType>;
- using BareFromType = remove_cv_reference_t<FromType>;
- static constexpr auto toHighest = std::numeric_limits<BareToType>::max();
- static constexpr auto toLowest = std::numeric_limits<BareToType>::lowest();
- static constexpr auto fromHighest = std::numeric_limits<BareFromType>::max();
- static constexpr auto fromLowest = std::numeric_limits<BareFromType>::lowest();
+ static constexpr remove_cvref_t<ToType> clamp(FromType v) {
+ using BareToType = remove_cvref_t<ToType>;
+ using ToLimits = std::numeric_limits<BareToType>;
+
+ using BareFromType = remove_cvref_t<FromType>;
+ using FromLimits = std::numeric_limits<BareFromType>;
+
+ static_assert(ToLimits::is_specialized && FromLimits::is_specialized);
+
+ constexpr auto toHighest = ToLimits::max();
+ constexpr auto toLowest = ToLimits::lowest();
+ constexpr auto fromHighest = FromLimits::max();
+ constexpr auto fromLowest = FromLimits::lowest();
// Get the closest representation of [toLowest, toHighest] in type
// FromType to use to clamp the input value before conversion.
@@ -127,37 +94,35 @@
// std::common_type<...> is used to get a value-preserving type for the
// top end of the range.
using CommonHighestType = std::common_type_t<BareToType, BareFromType>;
+ using CommonLimits = std::numeric_limits<CommonHighestType>;
// std::make_signed<std::common_type<...>> is used to get a
// value-preserving type for the bottom end of the range, except this is
// a bit trickier for non-integer types like float.
- using CommonLowestType =
- std::conditional_t<std::numeric_limits<CommonHighestType>::is_integer,
- std::make_signed_t<std::conditional_t<
- std::numeric_limits<CommonHighestType>::is_integer,
- CommonHighestType, int /* not used */>>,
- CommonHighestType>;
+ using CommonLowestType = std::conditional_t<
+ CommonLimits::is_integer,
+ std::make_signed_t<std::conditional_t<CommonLimits::is_integer, CommonHighestType,
+ int /* not used */>>,
+ CommonHighestType>;
// We can then compute the clamp range in a way that can be later
// trivially converted to either the 'from' or 'to' types, and be
- // representabile in either.
- static constexpr auto commonClampHighest =
- std::min(static_cast<CommonHighestType>(fromHighest),
- static_cast<CommonHighestType>(toHighest));
- static constexpr auto commonClampLowest =
- std::max(static_cast<CommonLowestType>(fromLowest),
- static_cast<CommonLowestType>(toLowest));
+ // representable in either.
+ constexpr auto commonClampHighest = std::min(static_cast<CommonHighestType>(fromHighest),
+ static_cast<CommonHighestType>(toHighest));
+ constexpr auto commonClampLowest = std::max(static_cast<CommonLowestType>(fromLowest),
+ static_cast<CommonLowestType>(toLowest));
- static constexpr auto fromClampHighest = static_cast<BareFromType>(commonClampHighest);
- static constexpr auto fromClampLowest = static_cast<BareFromType>(commonClampLowest);
+ constexpr auto fromClampHighest = static_cast<BareFromType>(commonClampHighest);
+ constexpr auto fromClampLowest = static_cast<BareFromType>(commonClampLowest);
// A clamp is needed only if the range we are clamping to is not the
// same as the range of the input.
- static constexpr bool isClampNeeded =
+ constexpr bool isClampNeeded =
(fromLowest != fromClampLowest) || (fromHighest != fromClampHighest);
// If a clamp is not needed, the conversion is just a trivial cast.
- if (!isClampNeeded) {
+ if constexpr (!isClampNeeded) {
return static_cast<BareToType>(v);
}
@@ -170,34 +135,46 @@
// Otherwise clamping is done by using the already computed endpoints
// for each type.
- return (v <= fromClampLowest)
- ? toClampLowest
- : ((v >= fromClampHighest) ? toClampHighest : static_cast<BareToType>(v));
+ if (v <= fromClampLowest) {
+ return toClampLowest;
+ }
+
+ return v >= fromClampHighest ? toClampHighest : static_cast<BareToType>(v);
}
};
-// ------------------------------------------------------------------------
-// Comparisons
-// ------------------------------------------------------------------------
+constexpr Size kInvalidSize;
+constexpr Size kEmptySize{0, 0};
-inline bool operator==(const Size& lhs, const Size& rhs) {
+inline void Size::makeInvalid() {
+ set(kInvalidSize);
+}
+
+inline void Size::clear() {
+ set(kEmptySize);
+}
+
+inline bool operator==(Size lhs, Size rhs) {
return lhs.width == rhs.width && lhs.height == rhs.height;
}
-inline bool operator!=(const Size& lhs, const Size& rhs) {
- return !operator==(lhs, rhs);
+inline bool Size::isEmpty() const {
+ return *this == kEmptySize;
}
-inline bool operator<(const Size& lhs, const Size& rhs) {
+inline bool operator!=(Size lhs, Size rhs) {
+ return !(lhs == rhs);
+}
+
+inline bool operator<(Size lhs, Size rhs) {
// Orders by increasing width, then height.
if (lhs.width != rhs.width) return lhs.width < rhs.width;
return lhs.height < rhs.height;
}
// Defining PrintTo helps with Google Tests.
-static inline void PrintTo(const Size& size, ::std::ostream* os) {
- *os << "Size(" << size.width << ", " << size.height << ")";
+inline void PrintTo(Size size, std::ostream* stream) {
+ *stream << "Size(" << size.width << ", " << size.height << ')';
}
-} // namespace ui
-} // namespace android
+} // namespace android::ui
diff --git a/libs/ui/tests/DisplayId_test.cpp b/libs/ui/tests/DisplayId_test.cpp
index 1d908b8..8ddee7e 100644
--- a/libs/ui/tests/DisplayId_test.cpp
+++ b/libs/ui/tests/DisplayId_test.cpp
@@ -32,6 +32,9 @@
EXPECT_FALSE(GpuVirtualDisplayId::tryCast(id));
EXPECT_TRUE(PhysicalDisplayId::tryCast(id));
EXPECT_TRUE(HalDisplayId::tryCast(id));
+
+ EXPECT_EQ(id, DisplayId::fromValue(id.value));
+ EXPECT_EQ(id, DisplayId::fromValue<PhysicalDisplayId>(id.value));
}
TEST(DisplayIdTest, createPhysicalIdFromPort) {
@@ -43,6 +46,9 @@
EXPECT_FALSE(GpuVirtualDisplayId::tryCast(id));
EXPECT_TRUE(PhysicalDisplayId::tryCast(id));
EXPECT_TRUE(HalDisplayId::tryCast(id));
+
+ EXPECT_EQ(id, DisplayId::fromValue(id.value));
+ EXPECT_EQ(id, DisplayId::fromValue<PhysicalDisplayId>(id.value));
}
TEST(DisplayIdTest, createGpuVirtualId) {
@@ -52,6 +58,9 @@
EXPECT_FALSE(HalVirtualDisplayId::tryCast(id));
EXPECT_FALSE(PhysicalDisplayId::tryCast(id));
EXPECT_FALSE(HalDisplayId::tryCast(id));
+
+ EXPECT_EQ(id, DisplayId::fromValue(id.value));
+ EXPECT_EQ(id, DisplayId::fromValue<GpuVirtualDisplayId>(id.value));
}
TEST(DisplayIdTest, createHalVirtualId) {
@@ -61,6 +70,9 @@
EXPECT_FALSE(GpuVirtualDisplayId::tryCast(id));
EXPECT_FALSE(PhysicalDisplayId::tryCast(id));
EXPECT_TRUE(HalDisplayId::tryCast(id));
+
+ EXPECT_EQ(id, DisplayId::fromValue(id.value));
+ EXPECT_EQ(id, DisplayId::fromValue<HalVirtualDisplayId>(id.value));
}
} // namespace android::ui
diff --git a/libs/ui/tests/Size_test.cpp b/libs/ui/tests/Size_test.cpp
index 5f75aea..acef47f 100644
--- a/libs/ui/tests/Size_test.cpp
+++ b/libs/ui/tests/Size_test.cpp
@@ -93,9 +93,8 @@
}
{
- const auto& s = Size::INVALID;
- EXPECT_FALSE(s.isValid());
- EXPECT_FALSE(s.isEmpty());
+ EXPECT_FALSE(kInvalidSize.isValid());
+ EXPECT_FALSE(kInvalidSize.isEmpty());
}
{
@@ -112,9 +111,8 @@
}
{
- const auto& s = Size::EMPTY;
- EXPECT_TRUE(s.isValid());
- EXPECT_TRUE(s.isEmpty());
+ EXPECT_TRUE(kEmptySize.isValid());
+ EXPECT_TRUE(kEmptySize.isEmpty());
}
{
diff --git a/services/automotive/display/AutomotiveDisplayProxyService.cpp b/services/automotive/display/AutomotiveDisplayProxyService.cpp
index d6fc695..d205231 100644
--- a/services/automotive/display/AutomotiveDisplayProxyService.cpp
+++ b/services/automotive/display/AutomotiveDisplayProxyService.cpp
@@ -34,7 +34,10 @@
sp<IBinder> displayToken = nullptr;
sp<SurfaceControl> surfaceControl = nullptr;
if (it == mDisplays.end()) {
- displayToken = SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId(id));
+ if (const auto displayId = DisplayId::fromValue<PhysicalDisplayId>(id)) {
+ displayToken = SurfaceComposerClient::getPhysicalDisplayToken(*displayId);
+ }
+
if (displayToken == nullptr) {
ALOGE("Given display id, 0x%lX, is invalid.", (unsigned long)id);
return nullptr;
@@ -157,7 +160,11 @@
HwDisplayConfig activeConfig;
HwDisplayState activeState;
- auto displayToken = SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId(id));
+ sp<IBinder> displayToken;
+ if (const auto displayId = DisplayId::fromValue<PhysicalDisplayId>(id)) {
+ displayToken = SurfaceComposerClient::getPhysicalDisplayToken(*displayId);
+ }
+
if (displayToken == nullptr) {
ALOGE("Given display id, 0x%lX, is invalid.", (unsigned long)id);
} else {
diff --git a/services/inputflinger/InputReaderBase.cpp b/services/inputflinger/InputReaderBase.cpp
index 05ef489..a864cf8 100644
--- a/services/inputflinger/InputReaderBase.cpp
+++ b/services/inputflinger/InputReaderBase.cpp
@@ -19,12 +19,12 @@
//#define LOG_NDEBUG 0
#include "InputReaderBase.h"
-#include <ftl/NamedEnum.h>
#include "input/DisplayViewport.h"
#include "input/Input.h"
-#include <android/log.h>
#include <android-base/stringprintf.h>
+#include <android/log.h>
+#include <ftl/enum.h>
#define INDENT " "
#define INDENT2 " "
@@ -117,7 +117,7 @@
}
if (count > 1) {
ALOGW("Found %zu viewports with type %s, but expected 1 at most", count,
- NamedEnum::string(type).c_str());
+ ftl::enum_string(type).c_str());
}
return result;
}
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index 82b4fe4..571c126 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -176,10 +176,11 @@
}
return StringPrintf("KeyEvent(deviceId=%d, eventTime=%" PRIu64
", source=0x%08x, displayId=%" PRId32 ", action=%s, "
- "flags=0x%08x, keyCode=%d, scanCode=%d, metaState=0x%08x, "
+ "flags=0x%08x, keyCode=%s(%d), scanCode=%d, metaState=0x%08x, "
"repeatCount=%d), policyFlags=0x%08x",
deviceId, eventTime, source, displayId, KeyEvent::actionToString(action),
- flags, keyCode, scanCode, metaState, repeatCount, policyFlags);
+ flags, KeyEvent::getLabel(keyCode), keyCode, scanCode, metaState,
+ repeatCount, policyFlags);
}
void KeyEntry::recycle() {
@@ -191,6 +192,18 @@
interceptKeyWakeupTime = 0;
}
+// --- TouchModeEntry ---
+
+TouchModeEntry::TouchModeEntry(int32_t id, nsecs_t eventTime, bool inTouchMode)
+ : EventEntry(id, Type::TOUCH_MODE_CHANGED, eventTime, POLICY_FLAG_PASS_TO_USER),
+ inTouchMode(inTouchMode) {}
+
+TouchModeEntry::~TouchModeEntry() {}
+
+std::string TouchModeEntry::getDescription() const {
+ return StringPrintf("TouchModeEvent(inTouchMode=%s)", inTouchMode ? "true" : "false");
+}
+
// --- MotionEntry ---
MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source,
@@ -318,16 +331,4 @@
return seq;
}
-// --- CommandEntry ---
-
-CommandEntry::CommandEntry(Command command)
- : command(command),
- eventTime(0),
- keyEntry(nullptr),
- userActivityEventType(0),
- seq(0),
- handled(false) {}
-
-CommandEntry::~CommandEntry() {}
-
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index ffe3bb6..5365a78 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -39,6 +39,9 @@
SENSOR,
POINTER_CAPTURE_CHANGED,
DRAG,
+ TOUCH_MODE_CHANGED,
+
+ ftl_last = TOUCH_MODE_CHANGED
};
int32_t id;
@@ -185,7 +188,7 @@
float xOffset, float yOffset);
std::string getDescription() const override;
- virtual ~MotionEntry();
+ ~MotionEntry() override;
};
struct SensorEntry : EventEntry {
@@ -207,6 +210,15 @@
~SensorEntry() override;
};
+struct TouchModeEntry : EventEntry {
+ bool inTouchMode;
+
+ TouchModeEntry(int32_t id, nsecs_t eventTime, bool inTouchMode);
+ std::string getDescription() const override;
+
+ ~TouchModeEntry() override;
+};
+
// Tracks the progress of dispatching a particular event to a particular connection.
struct DispatchEntry {
const uint32_t seq; // unique sequence number, never 0
@@ -245,55 +257,6 @@
VerifiedKeyEvent verifiedKeyEventFromKeyEntry(const KeyEntry& entry);
VerifiedMotionEvent verifiedMotionEventFromMotionEntry(const MotionEntry& entry);
-class InputDispatcher;
-// A command entry captures state and behavior for an action to be performed in the
-// dispatch loop after the initial processing has taken place. It is essentially
-// a kind of continuation used to postpone sensitive policy interactions to a point
-// in the dispatch loop where it is safe to release the lock (generally after finishing
-// the critical parts of the dispatch cycle).
-//
-// The special thing about commands is that they can voluntarily release and reacquire
-// the dispatcher lock at will. Initially when the command starts running, the
-// dispatcher lock is held. However, if the command needs to call into the policy to
-// do some work, it can release the lock, do the work, then reacquire the lock again
-// before returning.
-//
-// This mechanism is a bit clunky but it helps to preserve the invariant that the dispatch
-// never calls into the policy while holding its lock.
-//
-// Commands are implicitly 'LockedInterruptible'.
-struct CommandEntry;
-typedef std::function<void(InputDispatcher&, CommandEntry*)> Command;
-
-class Connection;
-struct CommandEntry {
- explicit CommandEntry(Command command);
- ~CommandEntry();
-
- Command command;
-
- // parameters for the command (usage varies by command)
- sp<Connection> connection;
- nsecs_t eventTime;
- std::shared_ptr<KeyEntry> keyEntry;
- std::shared_ptr<SensorEntry> sensorEntry;
- std::shared_ptr<InputApplicationHandle> inputApplicationHandle;
- std::string reason;
- int32_t userActivityEventType;
- uint32_t seq;
- bool handled;
- sp<IBinder> connectionToken;
- sp<IBinder> oldToken;
- sp<IBinder> newToken;
- std::string obscuringPackage;
- PointerCaptureRequest pointerCaptureRequest;
- int32_t pid;
- nsecs_t consumeTime; // time when the event was consumed by InputConsumer
- int32_t displayId;
- float x;
- float y;
-};
-
} // namespace android::inputdispatcher
#endif // _UI_INPUT_INPUTDISPATCHER_ENTRY_H
diff --git a/services/inputflinger/dispatcher/FocusResolver.cpp b/services/inputflinger/dispatcher/FocusResolver.cpp
index 4a75773..600f02b 100644
--- a/services/inputflinger/dispatcher/FocusResolver.cpp
+++ b/services/inputflinger/dispatcher/FocusResolver.cpp
@@ -27,7 +27,7 @@
#include <android-base/stringprintf.h>
#include <binder/Binder.h>
-#include <ftl/NamedEnum.h>
+#include <ftl/enum.h>
#include <gui/WindowInfo.h>
#include <log/log.h>
@@ -65,7 +65,7 @@
if (result == Focusability::OK) {
return std::nullopt;
}
- removeFocusReason = NamedEnum::string(result);
+ removeFocusReason = ftl::enum_string(result);
}
// We don't have a focused window or the currently focused window is no longer focusable. Check
@@ -79,7 +79,7 @@
if (result == Focusability::OK) {
return updateFocusedWindow(displayId,
"Window became focusable. Previous reason: " +
- NamedEnum::string(previousResult),
+ ftl::enum_string(previousResult),
requestedFocus, request->windowName);
}
}
@@ -116,7 +116,7 @@
request.token, request.windowName);
}
ALOGW("setFocusedWindow %s on display %" PRId32 " ignored, reason: %s",
- request.windowName.c_str(), displayId, NamedEnum::string(result).c_str());
+ request.windowName.c_str(), displayId, ftl::enum_string(result).c_str());
return std::nullopt;
}
@@ -134,7 +134,7 @@
// The requested window is not currently focusable. Wait for the window to become focusable
// but remove focus from the current window so that input events can go into a pending queue
// and be sent to the window when it becomes focused.
- return updateFocusedWindow(displayId, "Waiting for window because " + NamedEnum::string(result),
+ return updateFocusedWindow(displayId, "Waiting for window because " + ftl::enum_string(result),
nullptr);
}
@@ -212,7 +212,7 @@
for (const auto& [displayId, request] : mFocusRequestByDisplay) {
auto it = mLastFocusResultByDisplay.find(displayId);
std::string result =
- it != mLastFocusResultByDisplay.end() ? NamedEnum::string(it->second) : "";
+ it != mLastFocusResultByDisplay.end() ? ftl::enum_string(it->second) : "";
dump += base::StringPrintf(INDENT2 "displayId=%" PRId32 ", name='%s' result='%s'\n",
displayId, request.windowName.c_str(), result.c_str());
}
diff --git a/services/inputflinger/dispatcher/FocusResolver.h b/services/inputflinger/dispatcher/FocusResolver.h
index 1d6cd9a..6d11a77 100644
--- a/services/inputflinger/dispatcher/FocusResolver.h
+++ b/services/inputflinger/dispatcher/FocusResolver.h
@@ -77,6 +77,8 @@
NO_WINDOW,
NOT_FOCUSABLE,
NOT_VISIBLE,
+
+ ftl_last = NOT_VISIBLE
};
// Checks if the window token can be focused on a display. The token can be focused if there is
@@ -113,4 +115,4 @@
std::optional<android::gui::FocusRequest> getFocusRequest(int32_t displayId);
};
-} // namespace android::inputdispatcher
\ No newline at end of file
+} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 4a7860a..da3e237 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -19,34 +19,6 @@
#define LOG_NDEBUG 1
-// Log detailed debug messages about each inbound event notification to the dispatcher.
-#define DEBUG_INBOUND_EVENT_DETAILS 0
-
-// Log detailed debug messages about each outbound event processed by the dispatcher.
-#define DEBUG_OUTBOUND_EVENT_DETAILS 0
-
-// Log debug messages about the dispatch cycle.
-#define DEBUG_DISPATCH_CYCLE 0
-
-// Log debug messages about channel creation
-#define DEBUG_CHANNEL_CREATION 0
-
-// Log debug messages about input event injection.
-#define DEBUG_INJECTION 0
-
-// Log debug messages about input focus tracking.
-static constexpr bool DEBUG_FOCUS = false;
-
-// Log debug messages about touch occlusion
-// STOPSHIP(b/169067926): Set to false
-static constexpr bool DEBUG_TOUCH_OCCLUSION = true;
-
-// Log debug messages about the app switch latency optimization.
-#define DEBUG_APP_SWITCH 0
-
-// Log debug messages about hover events.
-#define DEBUG_HOVER 0
-
#include <InputFlingerProperties.sysprop.h>
#include <android-base/chrono_utils.h>
#include <android-base/properties.h>
@@ -55,6 +27,7 @@
#include <binder/Binder.h>
#include <binder/IServiceManager.h>
#include <com/android/internal/compat/IPlatformCompatNative.h>
+#include <ftl/enum.h>
#include <gui/SurfaceComposerClient.h>
#include <input/InputDevice.h>
#include <log/log.h>
@@ -82,6 +55,7 @@
using android::base::HwTimeoutMultiplier;
using android::base::Result;
using android::base::StringPrintf;
+using android::gui::DisplayInfo;
using android::gui::FocusRequest;
using android::gui::TouchOcclusionMode;
using android::gui::WindowInfo;
@@ -94,9 +68,50 @@
namespace android::inputdispatcher {
+namespace {
+
+// Log detailed debug messages about each inbound event notification to the dispatcher.
+constexpr bool DEBUG_INBOUND_EVENT_DETAILS = false;
+
+// Log detailed debug messages about each outbound event processed by the dispatcher.
+constexpr bool DEBUG_OUTBOUND_EVENT_DETAILS = false;
+
+// Log debug messages about the dispatch cycle.
+constexpr bool DEBUG_DISPATCH_CYCLE = false;
+
+// Log debug messages about channel creation
+constexpr bool DEBUG_CHANNEL_CREATION = false;
+
+// Log debug messages about input event injection.
+constexpr bool DEBUG_INJECTION = false;
+
+// Log debug messages about input focus tracking.
+constexpr bool DEBUG_FOCUS = false;
+
+// Log debug messages about touch occlusion
+// STOPSHIP(b/169067926): Set to false
+constexpr bool DEBUG_TOUCH_OCCLUSION = true;
+
+// Log debug messages about the app switch latency optimization.
+constexpr bool DEBUG_APP_SWITCH = false;
+
+// Log debug messages about hover events.
+constexpr bool DEBUG_HOVER = false;
+
+// Temporarily releases a held mutex for the lifetime of the instance.
+// Named to match std::scoped_lock
+class scoped_unlock {
+public:
+ explicit scoped_unlock(std::mutex& mutex) : mMutex(mutex) { mMutex.unlock(); }
+ ~scoped_unlock() { mMutex.lock(); }
+
+private:
+ std::mutex& mMutex;
+};
+
// When per-window-input-rotation is enabled, InputFlinger works in the un-rotated display
// coordinates and SurfaceFlinger includes the display rotation in the input window transforms.
-static bool isPerWindowInputRotationEnabled() {
+bool isPerWindowInputRotationEnabled() {
static const bool PER_WINDOW_INPUT_ROTATION =
sysprop::InputFlingerProperties::per_window_input_rotation().value_or(false);
@@ -136,27 +151,27 @@
constexpr int LOGTAG_INPUT_INTERACTION = 62000;
constexpr int LOGTAG_INPUT_FOCUS = 62001;
-static inline nsecs_t now() {
+inline nsecs_t now() {
return systemTime(SYSTEM_TIME_MONOTONIC);
}
-static inline const char* toString(bool value) {
+inline const char* toString(bool value) {
return value ? "true" : "false";
}
-static inline const std::string toString(sp<IBinder> binder) {
+inline const std::string toString(const sp<IBinder>& binder) {
if (binder == nullptr) {
return "<null>";
}
return StringPrintf("%p", binder.get());
}
-static inline int32_t getMotionEventActionPointerIndex(int32_t action) {
+inline int32_t getMotionEventActionPointerIndex(int32_t action) {
return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >>
AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
}
-static bool isValidKeyAction(int32_t action) {
+bool isValidKeyAction(int32_t action) {
switch (action) {
case AKEY_EVENT_ACTION_DOWN:
case AKEY_EVENT_ACTION_UP:
@@ -166,7 +181,7 @@
}
}
-static bool validateKeyEvent(int32_t action) {
+bool validateKeyEvent(int32_t action) {
if (!isValidKeyAction(action)) {
ALOGE("Key event has invalid action code 0x%x", action);
return false;
@@ -174,7 +189,7 @@
return true;
}
-static bool isValidMotionAction(int32_t action, int32_t actionButton, int32_t pointerCount) {
+bool isValidMotionAction(int32_t action, int32_t actionButton, int32_t pointerCount) {
switch (action & AMOTION_EVENT_ACTION_MASK) {
case AMOTION_EVENT_ACTION_DOWN:
case AMOTION_EVENT_ACTION_UP:
@@ -199,12 +214,12 @@
}
}
-static int64_t millis(std::chrono::nanoseconds t) {
+int64_t millis(std::chrono::nanoseconds t) {
return std::chrono::duration_cast<std::chrono::milliseconds>(t).count();
}
-static bool validateMotionEvent(int32_t action, int32_t actionButton, size_t pointerCount,
- const PointerProperties* pointerProperties) {
+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;
@@ -231,7 +246,7 @@
return true;
}
-static std::string dumpRegion(const Region& region) {
+std::string dumpRegion(const Region& region) {
if (region.isEmpty()) {
return "<empty>";
}
@@ -252,7 +267,7 @@
return dump;
}
-static std::string dumpQueue(const std::deque<DispatchEntry*>& queue, nsecs_t currentTime) {
+std::string dumpQueue(const std::deque<DispatchEntry*>& queue, nsecs_t currentTime) {
constexpr size_t maxEntries = 50; // max events to print
constexpr size_t skipBegin = maxEntries / 2;
const size_t skipEnd = queue.size() - maxEntries / 2;
@@ -291,12 +306,12 @@
* Also useful when the entries are sp<>. If an entry is not found, nullptr is returned.
*/
template <typename K, typename V>
-static V getValueByKey(const std::unordered_map<K, V>& map, K key) {
+V getValueByKey(const std::unordered_map<K, V>& map, K key) {
auto it = map.find(key);
return it != map.end() ? it->second : V{};
}
-static bool haveSameToken(const sp<WindowInfoHandle>& first, const sp<WindowInfoHandle>& second) {
+bool haveSameToken(const sp<WindowInfoHandle>& first, const sp<WindowInfoHandle>& second) {
if (first == second) {
return true;
}
@@ -308,7 +323,7 @@
return first->getToken() == second->getToken();
}
-static bool haveSameApplicationToken(const WindowInfo* first, const WindowInfo* second) {
+bool haveSameApplicationToken(const WindowInfo* first, const WindowInfo* second) {
if (first == nullptr || second == nullptr) {
return false;
}
@@ -316,13 +331,13 @@
first->applicationInfo.token == second->applicationInfo.token;
}
-static bool isStaleEvent(nsecs_t currentTime, const EventEntry& entry) {
+bool isStaleEvent(nsecs_t currentTime, const EventEntry& entry) {
return currentTime - entry.eventTime >= STALE_EVENT_TIMEOUT;
}
-static std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inputTarget,
- std::shared_ptr<EventEntry> eventEntry,
- int32_t inputTargetFlags) {
+std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inputTarget,
+ std::shared_ptr<EventEntry> eventEntry,
+ int32_t inputTargetFlags) {
if (eventEntry->type == EventEntry::Type::MOTION) {
const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*eventEntry);
if ((motionEntry.source & AINPUT_SOURCE_CLASS_JOYSTICK) ||
@@ -399,9 +414,9 @@
return dispatchEntry;
}
-static void addGestureMonitors(const std::vector<Monitor>& monitors,
- std::vector<TouchedMonitor>& outTouchedMonitors, float xOffset = 0,
- float yOffset = 0) {
+void addGestureMonitors(const std::vector<Monitor>& monitors,
+ std::vector<TouchedMonitor>& outTouchedMonitors, float xOffset = 0,
+ float yOffset = 0) {
if (monitors.empty()) {
return;
}
@@ -411,9 +426,8 @@
}
}
-static status_t openInputChannelPair(const std::string& name,
- std::shared_ptr<InputChannel>& serverChannel,
- std::unique_ptr<InputChannel>& clientChannel) {
+status_t openInputChannelPair(const std::string& name, std::shared_ptr<InputChannel>& serverChannel,
+ std::unique_ptr<InputChannel>& clientChannel) {
std::unique_ptr<InputChannel> uniqueServerChannel;
status_t result = InputChannel::openInputChannelPair(name, uniqueServerChannel, clientChannel);
@@ -422,7 +436,7 @@
}
template <typename T>
-static bool sharedPointersEqual(const std::shared_ptr<T>& lhs, const std::shared_ptr<T>& rhs) {
+bool sharedPointersEqual(const std::shared_ptr<T>& lhs, const std::shared_ptr<T>& rhs) {
if (lhs == nullptr && rhs == nullptr) {
return true;
}
@@ -432,7 +446,7 @@
return *lhs == *rhs;
}
-static sp<IPlatformCompatNative> getCompatService() {
+sp<IPlatformCompatNative> getCompatService() {
sp<IBinder> service(defaultServiceManager()->getService(String16("platform_compat_native")));
if (service == nullptr) {
ALOGE("Failed to link to compat service");
@@ -441,7 +455,7 @@
return interface_cast<IPlatformCompatNative>(service);
}
-static KeyEvent createKeyEvent(const KeyEntry& entry) {
+KeyEvent createKeyEvent(const KeyEntry& entry) {
KeyEvent event;
event.initialize(entry.id, entry.deviceId, entry.source, entry.displayId, INVALID_HMAC,
entry.action, entry.flags, entry.keyCode, entry.scanCode, entry.metaState,
@@ -449,7 +463,7 @@
return event;
}
-static std::optional<int32_t> findMonitorPidByToken(
+std::optional<int32_t> findMonitorPidByToken(
const std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay,
const sp<IBinder>& token) {
for (const auto& it : monitorsByDisplay) {
@@ -463,7 +477,7 @@
return std::nullopt;
}
-static bool shouldReportMetricsForConnection(const Connection& connection) {
+bool shouldReportMetricsForConnection(const Connection& connection) {
// Do not keep track of gesture monitors. They receive every event and would disproportionately
// affect the statistics.
if (connection.monitor) {
@@ -476,8 +490,7 @@
return true;
}
-static bool shouldReportFinishedEvent(const DispatchEntry& dispatchEntry,
- const Connection& connection) {
+bool shouldReportFinishedEvent(const DispatchEntry& dispatchEntry, const Connection& connection) {
const EventEntry& eventEntry = *dispatchEntry.eventEntry;
const int32_t& inputEventId = eventEntry.id;
if (inputEventId != dispatchEntry.resolvedEventId) {
@@ -513,6 +526,22 @@
return true;
}
+/**
+ * Connection is responsive if it has no events in the waitQueue that are older than the
+ * current time.
+ */
+bool isConnectionResponsive(const Connection& connection) {
+ const nsecs_t currentTime = now();
+ for (const DispatchEntry* entry : connection.waitQueue) {
+ if (entry->timeoutTime < currentTime) {
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
// --- InputDispatcher ---
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
@@ -545,17 +574,17 @@
}
InputDispatcher::~InputDispatcher() {
- { // acquire lock
- std::scoped_lock _l(mLock);
+ std::scoped_lock _l(mLock);
- resetKeyRepeatLocked();
- releasePendingEventLocked();
- drainInboundQueueLocked();
- }
+ resetKeyRepeatLocked();
+ releasePendingEventLocked();
+ drainInboundQueueLocked();
+ mCommandQueue.clear();
while (!mConnectionsByToken.empty()) {
sp<Connection> connection = mConnectionsByToken.begin()->second;
- removeInputChannel(connection->inputChannel->getConnectionToken());
+ removeInputChannelLocked(connection->inputChannel->getConnectionToken(),
+ false /* notify */);
}
}
@@ -595,7 +624,7 @@
// Run all pending commands if there are any.
// If any commands were run then force the next poll to wake up immediately.
- if (runCommandsLockedInterruptible()) {
+ if (runCommandsLockedInterruptable()) {
nextWakeupTime = LONG_LONG_MIN;
}
@@ -798,6 +827,14 @@
break;
}
+ case EventEntry::Type::TOUCH_MODE_CHANGED: {
+ const auto typedEntry = std::static_pointer_cast<TouchModeEntry>(mPendingEvent);
+ dispatchTouchModeChangeLocked(currentTime, typedEntry);
+ done = true;
+ dropReason = DropReason::NOT_DROPPED; // touch mode events are never dropped
+ break;
+ }
+
case EventEntry::Type::POINTER_CAPTURE_CHANGED: {
const auto typedEntry =
std::static_pointer_cast<PointerCaptureChangedEntry>(mPendingEvent);
@@ -910,8 +947,7 @@
}
// Alternatively, maybe there's a gesture monitor that could handle this event
- std::vector<TouchedMonitor> gestureMonitors =
- findTouchedGestureMonitorsLocked(displayId, {});
+ std::vector<TouchedMonitor> gestureMonitors = findTouchedGestureMonitorsLocked(displayId);
for (TouchedMonitor& gestureMonitor : gestureMonitors) {
sp<Connection> connection =
getConnectionLocked(gestureMonitor.monitor.inputChannel->getConnectionToken());
@@ -956,9 +992,9 @@
mAppSwitchSawKeyDown = true;
} else if (keyEntry.action == AKEY_EVENT_ACTION_UP) {
if (mAppSwitchSawKeyDown) {
-#if DEBUG_APP_SWITCH
- ALOGD("App switch is pending!");
-#endif
+ if (DEBUG_APP_SWITCH) {
+ ALOGD("App switch is pending!");
+ }
mAppSwitchDueTime = keyEntry.eventTime + APP_SWITCH_TIMEOUT;
mAppSwitchSawKeyDown = false;
needWake = true;
@@ -979,6 +1015,7 @@
LOG_ALWAYS_FATAL("Focus events should be inserted using enqueueFocusEventLocked");
break;
}
+ case EventEntry::Type::TOUCH_MODE_CHANGED:
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET:
case EventEntry::Type::SENSOR:
@@ -1005,11 +1042,9 @@
sp<WindowInfoHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, int32_t x,
int32_t y, TouchState* touchState,
bool addOutsideTargets,
- bool addPortalWindows,
bool ignoreDragWindow) {
- if ((addPortalWindows || addOutsideTargets) && touchState == nullptr) {
- LOG_ALWAYS_FATAL(
- "Must provide a valid touch state if adding portal windows or outside targets");
+ if (addOutsideTargets && touchState == nullptr) {
+ LOG_ALWAYS_FATAL("Must provide a valid touch state if adding outside targets");
}
// Traverse windows from front to back to find touched window.
const std::vector<sp<WindowInfoHandle>>& windowHandles = getWindowHandlesLocked(displayId);
@@ -1026,16 +1061,6 @@
bool isTouchModal = !flags.test(WindowInfo::Flag::NOT_FOCUSABLE) &&
!flags.test(WindowInfo::Flag::NOT_TOUCH_MODAL);
if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
- int32_t portalToDisplayId = windowInfo->portalToDisplayId;
- if (portalToDisplayId != ADISPLAY_ID_NONE &&
- portalToDisplayId != displayId) {
- if (addPortalWindows) {
- // For the monitoring channels of the display.
- touchState->addPortalWindow(windowHandle);
- }
- return findTouchedWindowAtLocked(portalToDisplayId, x, y, touchState,
- addOutsideTargets, addPortalWindows);
- }
// Found window.
return windowHandle;
}
@@ -1053,17 +1078,11 @@
}
std::vector<TouchedMonitor> InputDispatcher::findTouchedGestureMonitorsLocked(
- int32_t displayId, const std::vector<sp<WindowInfoHandle>>& portalWindows) const {
+ int32_t displayId) const {
std::vector<TouchedMonitor> touchedMonitors;
std::vector<Monitor> monitors = getValueByKey(mGestureMonitorsByDisplay, displayId);
addGestureMonitors(monitors, touchedMonitors);
- for (const sp<WindowInfoHandle>& portalWindow : portalWindows) {
- const WindowInfo* windowInfo = portalWindow->getInfo();
- monitors = getValueByKey(mGestureMonitorsByDisplay, windowInfo->portalToDisplayId);
- addGestureMonitors(monitors, touchedMonitors, -windowInfo->frameLeft,
- -windowInfo->frameTop);
- }
return touchedMonitors;
}
@@ -1071,9 +1090,9 @@
const char* reason;
switch (dropReason) {
case DropReason::POLICY:
-#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("Dropped event because policy consumed it.");
-#endif
+ if (DEBUG_INBOUND_EVENT_DETAILS) {
+ ALOGD("Dropped event because policy consumed it.");
+ }
reason = "inbound event was dropped because the policy consumed it";
break;
case DropReason::DISABLED:
@@ -1131,9 +1150,10 @@
break;
}
case EventEntry::Type::FOCUS:
+ case EventEntry::Type::TOUCH_MODE_CHANGED:
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET: {
- LOG_ALWAYS_FATAL("Should not drop %s events", NamedEnum::string(entry.type).c_str());
+ LOG_ALWAYS_FATAL("Should not drop %s events", ftl::enum_string(entry.type).c_str());
break;
}
}
@@ -1157,37 +1177,35 @@
void InputDispatcher::resetPendingAppSwitchLocked(bool handled) {
mAppSwitchDueTime = LONG_LONG_MAX;
-#if DEBUG_APP_SWITCH
- if (handled) {
- ALOGD("App switch has arrived.");
- } else {
- ALOGD("App switch was abandoned.");
+ if (DEBUG_APP_SWITCH) {
+ if (handled) {
+ ALOGD("App switch has arrived.");
+ } else {
+ ALOGD("App switch was abandoned.");
+ }
}
-#endif
}
bool InputDispatcher::haveCommandsLocked() const {
return !mCommandQueue.empty();
}
-bool InputDispatcher::runCommandsLockedInterruptible() {
+bool InputDispatcher::runCommandsLockedInterruptable() {
if (mCommandQueue.empty()) {
return false;
}
do {
- std::unique_ptr<CommandEntry> commandEntry = std::move(mCommandQueue.front());
+ auto command = std::move(mCommandQueue.front());
mCommandQueue.pop_front();
- Command command = commandEntry->command;
- command(*this, commandEntry.get()); // commands are implicitly 'LockedInterruptible'
-
- commandEntry->connection.clear();
+ // Commands are run with the lock held, but may release and re-acquire the lock from within.
+ command();
} while (!mCommandQueue.empty());
return true;
}
-void InputDispatcher::postCommandLocked(std::unique_ptr<CommandEntry> commandEntry) {
- mCommandQueue.push_back(std::move(commandEntry));
+void InputDispatcher::postCommandLocked(Command&& command) {
+ mCommandQueue.push_back(command);
}
void InputDispatcher::drainInboundQueueLocked() {
@@ -1209,9 +1227,9 @@
void InputDispatcher::releaseInboundEventLocked(std::shared_ptr<EventEntry> entry) {
InjectionState* injectionState = entry->injectionState;
if (injectionState && injectionState->injectionResult == InputEventInjectionResult::PENDING) {
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("Injected inbound event was dropped.");
-#endif
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("Injected inbound event was dropped.");
+ }
setInjectionResult(*entry, InputEventInjectionResult::FAILED);
}
if (entry == mNextUnblockedEvent) {
@@ -1246,27 +1264,28 @@
bool InputDispatcher::dispatchConfigurationChangedLocked(nsecs_t currentTime,
const ConfigurationChangedEntry& entry) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("dispatchConfigurationChanged - eventTime=%" PRId64, entry.eventTime);
-#endif
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("dispatchConfigurationChanged - eventTime=%" PRId64, entry.eventTime);
+ }
// Reset key repeating in case a keyboard device was added or removed or something.
resetKeyRepeatLocked();
// Enqueue a command to run outside the lock to tell the policy that the configuration changed.
- std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
- &InputDispatcher::doNotifyConfigurationChangedLockedInterruptible);
- commandEntry->eventTime = entry.eventTime;
- postCommandLocked(std::move(commandEntry));
+ auto command = [this, eventTime = entry.eventTime]() REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy->notifyConfigurationChanged(eventTime);
+ };
+ postCommandLocked(std::move(command));
return true;
}
bool InputDispatcher::dispatchDeviceResetLocked(nsecs_t currentTime,
const DeviceResetEntry& entry) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("dispatchDeviceReset - eventTime=%" PRId64 ", deviceId=%d", entry.eventTime,
- entry.deviceId);
-#endif
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("dispatchDeviceReset - eventTime=%" PRId64 ", deviceId=%d", entry.eventTime,
+ entry.deviceId);
+ }
// Reset key repeating in case a keyboard device was disabled or enabled.
if (mKeyRepeatState.lastKeyEntry && mKeyRepeatState.lastKeyEntry->deviceId == entry.deviceId) {
@@ -1390,6 +1409,43 @@
dropReason = DropReason::NOT_DROPPED;
}
+void InputDispatcher::dispatchTouchModeChangeLocked(nsecs_t currentTime,
+ const std::shared_ptr<TouchModeEntry>& entry) {
+ const std::vector<sp<WindowInfoHandle>>& windowHandles =
+ getWindowHandlesLocked(mFocusedDisplayId);
+ if (windowHandles.empty()) {
+ return;
+ }
+ const std::vector<InputTarget> inputTargets =
+ getInputTargetsFromWindowHandlesLocked(windowHandles);
+ if (inputTargets.empty()) {
+ return;
+ }
+ entry->dispatchInProgress = true;
+ dispatchEventLocked(currentTime, entry, inputTargets);
+}
+
+std::vector<InputTarget> InputDispatcher::getInputTargetsFromWindowHandlesLocked(
+ const std::vector<sp<WindowInfoHandle>>& windowHandles) const {
+ std::vector<InputTarget> inputTargets;
+ for (const sp<WindowInfoHandle>& handle : windowHandles) {
+ // TODO(b/193718270): Due to performance concerns, consider notifying visible windows only.
+ const sp<IBinder>& token = handle->getToken();
+ if (token == nullptr) {
+ continue;
+ }
+ std::shared_ptr<InputChannel> channel = getInputChannelLocked(token);
+ if (channel == nullptr) {
+ continue; // Window has gone away
+ }
+ InputTarget target;
+ target.inputChannel = channel;
+ target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
+ inputTargets.push_back(target);
+ }
+ return inputTargets;
+}
+
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, std::shared_ptr<KeyEntry> entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
// Preprocessing.
@@ -1421,9 +1477,9 @@
} else if (entry->action == AKEY_EVENT_ACTION_UP && mKeyRepeatState.lastKeyEntry &&
mKeyRepeatState.lastKeyEntry->deviceId != entry->deviceId) {
// The key on device 'deviceId' is still down, do not stop key repeat
-#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("deviceId=%d got KEY_UP as stale", entry->deviceId);
-#endif
+ if (DEBUG_INBOUND_EVENT_DETAILS) {
+ ALOGD("deviceId=%d got KEY_UP as stale", entry->deviceId);
+ }
} else if (!entry->syntheticRepeat) {
resetKeyRepeatLocked();
}
@@ -1454,13 +1510,13 @@
// Give the policy a chance to intercept the key.
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
- std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
- &InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
sp<IBinder> focusedWindowToken =
mFocusResolver.getFocusedWindowToken(getTargetDisplayId(*entry));
- commandEntry->connectionToken = focusedWindowToken;
- commandEntry->keyEntry = entry;
- postCommandLocked(std::move(commandEntry));
+
+ auto command = [this, focusedWindowToken, entry]() REQUIRES(mLock) {
+ doInterceptKeyBeforeDispatchingCommand(focusedWindowToken, *entry);
+ };
+ postCommandLocked(std::move(command));
return false; // wait for the command to run
} else {
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
@@ -1502,47 +1558,42 @@
}
void InputDispatcher::logOutboundKeyDetails(const char* prefix, const KeyEntry& entry) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 ", "
- "policyFlags=0x%x, action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, "
- "metaState=0x%x, repeatCount=%d, downTime=%" PRId64,
- prefix, entry.eventTime, entry.deviceId, entry.source, entry.displayId, entry.policyFlags,
- entry.action, entry.flags, entry.keyCode, entry.scanCode, entry.metaState,
- entry.repeatCount, entry.downTime);
-#endif
-}
-
-void InputDispatcher::doNotifySensorLockedInterruptible(CommandEntry* commandEntry) {
- mLock.unlock();
-
- const std::shared_ptr<SensorEntry>& entry = commandEntry->sensorEntry;
- if (entry->accuracyChanged) {
- mPolicy->notifySensorAccuracy(entry->deviceId, entry->sensorType, entry->accuracy);
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 ", "
+ "policyFlags=0x%x, action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, "
+ "metaState=0x%x, repeatCount=%d, downTime=%" PRId64,
+ prefix, entry.eventTime, entry.deviceId, entry.source, entry.displayId,
+ entry.policyFlags, entry.action, entry.flags, entry.keyCode, entry.scanCode,
+ entry.metaState, entry.repeatCount, entry.downTime);
}
- mPolicy->notifySensorEvent(entry->deviceId, entry->sensorType, entry->accuracy,
- entry->hwTimestamp, entry->values);
- mLock.lock();
}
-void InputDispatcher::dispatchSensorLocked(nsecs_t currentTime, std::shared_ptr<SensorEntry> entry,
+void InputDispatcher::dispatchSensorLocked(nsecs_t currentTime,
+ const std::shared_ptr<SensorEntry>& entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("notifySensorEvent eventTime=%" PRId64 ", hwTimestamp=%" PRId64 ", deviceId=%d, "
- "source=0x%x, sensorType=%s",
- entry->eventTime, entry->hwTimestamp, entry->deviceId, entry->source,
- NamedEnum::string(entry->sensorType).c_str());
-#endif
- std::unique_ptr<CommandEntry> commandEntry =
- std::make_unique<CommandEntry>(&InputDispatcher::doNotifySensorLockedInterruptible);
- commandEntry->sensorEntry = entry;
- postCommandLocked(std::move(commandEntry));
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("notifySensorEvent eventTime=%" PRId64 ", hwTimestamp=%" PRId64 ", deviceId=%d, "
+ "source=0x%x, sensorType=%s",
+ entry->eventTime, entry->hwTimestamp, entry->deviceId, entry->source,
+ ftl::enum_string(entry->sensorType).c_str());
+ }
+ auto command = [this, entry]() REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+
+ if (entry->accuracyChanged) {
+ mPolicy->notifySensorAccuracy(entry->deviceId, entry->sensorType, entry->accuracy);
+ }
+ mPolicy->notifySensorEvent(entry->deviceId, entry->sensorType, entry->accuracy,
+ entry->hwTimestamp, entry->values);
+ };
+ postCommandLocked(std::move(command));
}
bool InputDispatcher::flushSensor(int deviceId, InputDeviceSensorType sensorType) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("flushSensor deviceId=%d, sensorType=%s", deviceId,
- NamedEnum::string(sensorType).c_str());
-#endif
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("flushSensor deviceId=%d, sensorType=%s", deviceId,
+ ftl::enum_string(sensorType).c_str());
+ }
{ // acquire lock
std::scoped_lock _l(mLock);
@@ -1613,23 +1664,6 @@
// Add monitor channels from event's or focused display.
addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry));
- if (isPointerEvent) {
- std::unordered_map<int32_t, TouchState>::iterator it =
- mTouchStatesByDisplay.find(entry->displayId);
- if (it != mTouchStatesByDisplay.end()) {
- const TouchState& state = it->second;
- if (!state.portalWindows.empty()) {
- // The event has gone through these portal windows, so we add monitoring targets of
- // the corresponding displays as well.
- for (size_t i = 0; i < state.portalWindows.size(); i++) {
- const WindowInfo* windowInfo = state.portalWindows[i]->getInfo();
- addGlobalMonitoringTargetsLocked(inputTargets, windowInfo->portalToDisplayId,
- -windowInfo->frameLeft, -windowInfo->frameTop);
- }
- }
- }
- }
-
// Dispatch the motion.
if (conflictingPointerActions) {
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
@@ -1670,42 +1704,43 @@
}
void InputDispatcher::logOutboundMotionDetails(const char* prefix, const MotionEntry& entry) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32
- ", policyFlags=0x%x, "
- "action=0x%x, actionButton=0x%x, flags=0x%x, "
- "metaState=0x%x, buttonState=0x%x,"
- "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64,
- prefix, entry.eventTime, entry.deviceId, entry.source, entry.displayId, entry.policyFlags,
- entry.action, entry.actionButton, entry.flags, entry.metaState, entry.buttonState,
- entry.edgeFlags, entry.xPrecision, entry.yPrecision, entry.downTime);
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32
+ ", policyFlags=0x%x, "
+ "action=%s, actionButton=0x%x, flags=0x%x, "
+ "metaState=0x%x, buttonState=0x%x,"
+ "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64,
+ prefix, entry.eventTime, entry.deviceId, entry.source, entry.displayId,
+ entry.policyFlags, MotionEvent::actionToString(entry.action).c_str(),
+ entry.actionButton, entry.flags, entry.metaState, entry.buttonState, entry.edgeFlags,
+ entry.xPrecision, entry.yPrecision, entry.downTime);
- for (uint32_t i = 0; i < entry.pointerCount; i++) {
- ALOGD(" Pointer %d: id=%d, toolType=%d, "
- "x=%f, y=%f, pressure=%f, size=%f, "
- "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, "
- "orientation=%f",
- i, entry.pointerProperties[i].id, entry.pointerProperties[i].toolType,
- entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
- entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
- entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
- entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
- entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
- entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
- entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
- entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
- entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
+ for (uint32_t i = 0; i < entry.pointerCount; i++) {
+ ALOGD(" Pointer %d: id=%d, toolType=%d, "
+ "x=%f, y=%f, pressure=%f, size=%f, "
+ "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, "
+ "orientation=%f",
+ i, entry.pointerProperties[i].id, entry.pointerProperties[i].toolType,
+ entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
+ entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
+ entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
+ entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
+ entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
+ entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
+ entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
+ entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
+ entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
+ }
}
-#endif
}
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
std::shared_ptr<EventEntry> eventEntry,
const std::vector<InputTarget>& inputTargets) {
ATRACE_CALL();
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("dispatchEventToCurrentInputTargets");
-#endif
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("dispatchEventToCurrentInputTargets");
+ }
updateInteractionTokensLocked(*eventEntry, inputTargets);
@@ -1773,11 +1808,12 @@
}
case EventEntry::Type::POINTER_CAPTURE_CHANGED:
case EventEntry::Type::FOCUS:
+ case EventEntry::Type::TOUCH_MODE_CHANGED:
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET:
case EventEntry::Type::SENSOR:
case EventEntry::Type::DRAG: {
- ALOGE("%s events do not have a target display", NamedEnum::string(entry.type).c_str());
+ ALOGE("%s events do not have a target display", ftl::enum_string(entry.type).c_str());
return ADISPLAY_ID_NONE;
}
}
@@ -1829,7 +1865,12 @@
if (focusedWindowHandle == nullptr && focusedApplicationHandle == nullptr) {
ALOGI("Dropping %s event because there is no focused window or focused application in "
"display %" PRId32 ".",
- NamedEnum::string(entry.type).c_str(), displayId);
+ ftl::enum_string(entry.type).c_str(), displayId);
+ return InputEventInjectionResult::FAILED;
+ }
+
+ // Drop key events if requested by input feature
+ if (focusedWindowHandle != nullptr && shouldDropInput(entry, focusedWindowHandle)) {
return InputEventInjectionResult::FAILED;
}
@@ -1854,7 +1895,7 @@
} else if (currentTime > *mNoFocusedWindowTimeoutTime) {
// Already raised ANR. Drop the event
ALOGE("Dropping %s event because there is no focused window",
- NamedEnum::string(entry.type).c_str());
+ ftl::enum_string(entry.type).c_str());
return InputEventInjectionResult::FAILED;
} else {
// Still waiting for the focused window
@@ -2017,12 +2058,11 @@
y = int32_t(entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y));
}
bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN;
- newTouchedWindowHandle =
- findTouchedWindowAtLocked(displayId, x, y, &tempTouchState,
- isDown /*addOutsideTargets*/, true /*addPortalWindows*/);
+ newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, &tempTouchState,
+ isDown /*addOutsideTargets*/);
std::vector<TouchedMonitor> newGestureMonitors = isDown
- ? findTouchedGestureMonitorsLocked(displayId, tempTouchState.portalWindows)
+ ? findTouchedGestureMonitorsLocked(displayId)
: std::vector<TouchedMonitor>{};
// Figure out whether splitting will be allowed for this window.
@@ -2070,7 +2110,7 @@
ALOGD("%s", log.c_str());
}
}
- onUntrustedTouchLocked(occlusionInfo.obscuringPackage);
+ sendUntrustedTouchCommandLocked(occlusionInfo.obscuringPackage);
if (mBlockUntrustedTouchesMode == BlockUntrustedTouchesMode::BLOCK) {
ALOGW("Dropping untrusted touch event due to %s/%d",
occlusionInfo.obscuringPackage.c_str(), occlusionInfo.obscuringUid);
@@ -2079,6 +2119,11 @@
}
}
+ // Drop touch events if requested by input feature
+ if (newTouchedWindowHandle != nullptr && shouldDropInput(entry, newTouchedWindowHandle)) {
+ newTouchedWindowHandle = nullptr;
+ }
+
// Also don't send the new touch event to unresponsive gesture monitors
newGestureMonitors = selectResponsiveMonitorsLocked(newGestureMonitors);
@@ -2144,6 +2189,13 @@
sp<WindowInfoHandle> oldTouchedWindowHandle =
tempTouchState.getFirstForegroundWindowHandle();
newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, &tempTouchState);
+
+ // Drop touch events if requested by input feature
+ if (newTouchedWindowHandle != nullptr &&
+ shouldDropInput(entry, newTouchedWindowHandle)) {
+ newTouchedWindowHandle = nullptr;
+ }
+
if (oldTouchedWindowHandle != newTouchedWindowHandle &&
oldTouchedWindowHandle != nullptr && newTouchedWindowHandle != nullptr) {
if (DEBUG_FOCUS) {
@@ -2187,10 +2239,10 @@
if (mLastHoverWindowHandle != nullptr &&
(maskedAction != AMOTION_EVENT_ACTION_HOVER_EXIT ||
mLastHoverWindowHandle != newTouchedWindowHandle)) {
-#if DEBUG_HOVER
- ALOGD("Sending hover exit event to window %s.",
- mLastHoverWindowHandle->getName().c_str());
-#endif
+ if (DEBUG_HOVER) {
+ ALOGD("Sending hover exit event to window %s.",
+ mLastHoverWindowHandle->getName().c_str());
+ }
tempTouchState.addOrUpdateWindow(mLastHoverWindowHandle,
InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0));
}
@@ -2200,10 +2252,10 @@
if (newHoverWindowHandle != nullptr &&
(maskedAction != AMOTION_EVENT_ACTION_HOVER_ENTER ||
newHoverWindowHandle != newTouchedWindowHandle)) {
-#if DEBUG_HOVER
- ALOGD("Sending hover enter event to window %s.",
- newHoverWindowHandle->getName().c_str());
-#endif
+ if (DEBUG_HOVER) {
+ ALOGD("Sending hover enter event to window %s.",
+ newHoverWindowHandle->getName().c_str());
+ }
tempTouchState.addOrUpdateWindow(newHoverWindowHandle,
InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER,
BitSet32(0));
@@ -2393,13 +2445,12 @@
void InputDispatcher::finishDragAndDrop(int32_t displayId, float x, float y) {
const sp<WindowInfoHandle> dropWindow =
findTouchedWindowAtLocked(displayId, x, y, nullptr /*touchState*/,
- false /*addOutsideTargets*/, false /*addPortalWindows*/,
- true /*ignoreDragWindow*/);
+ false /*addOutsideTargets*/, true /*ignoreDragWindow*/);
if (dropWindow) {
vec2 local = dropWindow->getInfo()->transform.transform(x, y);
- notifyDropWindowLocked(dropWindow->getToken(), local.x, local.y);
+ sendDropWindowCommandLocked(dropWindow->getToken(), local.x, local.y);
} else {
- notifyDropWindowLocked(nullptr, 0, 0);
+ sendDropWindowCommandLocked(nullptr, 0, 0);
}
mDragState.reset();
}
@@ -2428,8 +2479,7 @@
const sp<WindowInfoHandle> hoverWindowHandle =
findTouchedWindowAtLocked(entry.displayId, x, y, nullptr /*touchState*/,
- false /*addOutsideTargets*/, false /*addPortalWindows*/,
- true /*ignoreDragWindow*/);
+ false /*addOutsideTargets*/, true /*ignoreDragWindow*/);
// enqueue drag exit if needed.
if (hoverWindowHandle != mDragState->dragHoverWindowHandle &&
!haveSameToken(hoverWindowHandle, mDragState->dragHoverWindowHandle)) {
@@ -2446,7 +2496,7 @@
} else if (maskedAction == AMOTION_EVENT_ACTION_UP) {
finishDragAndDrop(entry.displayId, x, y);
} else if (maskedAction == AMOTION_EVENT_ACTION_CANCEL) {
- notifyDropWindowLocked(nullptr, 0, 0);
+ sendDropWindowCommandLocked(nullptr, 0, 0);
mDragState.reset();
}
}
@@ -2474,9 +2524,15 @@
inputTarget.inputChannel = inputChannel;
inputTarget.flags = targetFlags;
inputTarget.globalScaleFactor = windowInfo->globalScaleFactor;
- inputTarget.displayOrientation = windowInfo->displayOrientation;
- inputTarget.displaySize =
- int2(windowHandle->getInfo()->displayWidth, windowHandle->getInfo()->displayHeight);
+ const auto& displayInfoIt = mDisplayInfos.find(windowInfo->displayId);
+ if (displayInfoIt != mDisplayInfos.end()) {
+ const auto& displayInfo = displayInfoIt->second;
+ inputTarget.displayOrientation = displayInfo.transform.getOrientation();
+ inputTarget.displaySize = int2(displayInfo.logicalWidth, displayInfo.logicalHeight);
+ } else {
+ ALOGI_IF(isPerWindowInputRotationEnabled(),
+ "DisplayInfo not found for window on display: %d", windowInfo->displayId);
+ }
inputTargets.push_back(inputTarget);
it = inputTargets.end() - 1;
}
@@ -2645,8 +2701,7 @@
"frame=[%" PRId32 ",%" PRId32 "][%" PRId32 ",%" PRId32
"], touchableRegion=%s, window={%s}, flags={%s}, inputFeatures={%s}, "
"hasToken=%s, applicationInfo.name=%s, applicationInfo.token=%s\n",
- (isTouchedWindow) ? "[TOUCHED] " : "",
- NamedEnum::string(info->type, "%" PRId32).c_str(),
+ isTouchedWindow ? "[TOUCHED] " : "", ftl::enum_string(info->type).c_str(),
info->packageName.c_str(), info->ownerUid, info->id,
toString(info->touchOcclusionMode).c_str(), info->alpha, info->frameLeft,
info->frameTop, info->frameRight, info->frameBottom,
@@ -2734,9 +2789,9 @@
if (focusedWindowHandle != nullptr) {
const WindowInfo* info = focusedWindowHandle->getInfo();
if (info->inputFeatures.test(WindowInfo::Feature::DISABLE_USER_ACTIVITY)) {
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("Not poking user activity: disabled by window '%s'.", info->name.c_str());
-#endif
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("Not poking user activity: disabled by window '%s'.", info->name.c_str());
+ }
return;
}
}
@@ -2762,6 +2817,10 @@
eventType = USER_ACTIVITY_EVENT_BUTTON;
break;
}
+ case EventEntry::Type::TOUCH_MODE_CHANGED: {
+ break;
+ }
+
case EventEntry::Type::FOCUS:
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET:
@@ -2769,17 +2828,17 @@
case EventEntry::Type::POINTER_CAPTURE_CHANGED:
case EventEntry::Type::DRAG: {
LOG_ALWAYS_FATAL("%s events are not user activity",
- NamedEnum::string(eventEntry.type).c_str());
+ ftl::enum_string(eventEntry.type).c_str());
break;
}
}
- std::unique_ptr<CommandEntry> commandEntry =
- std::make_unique<CommandEntry>(&InputDispatcher::doPokeUserActivityLockedInterruptible);
- commandEntry->eventTime = eventEntry.eventTime;
- commandEntry->userActivityEventType = eventType;
- commandEntry->displayId = displayId;
- postCommandLocked(std::move(commandEntry));
+ auto command = [this, eventTime = eventEntry.eventTime, eventType, displayId]()
+ REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy->pokeUserActivity(eventTime, eventType, displayId);
+ };
+ postCommandLocked(std::move(command));
}
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
@@ -2792,21 +2851,21 @@
connection->getInputChannelName().c_str(), eventEntry->id);
ATRACE_NAME(message.c_str());
}
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, "
- "globalScaleFactor=%f, pointerIds=0x%x %s",
- connection->getInputChannelName().c_str(), inputTarget.flags,
- inputTarget.globalScaleFactor, inputTarget.pointerIds.value,
- inputTarget.getPointerInfoString().c_str());
-#endif
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, "
+ "globalScaleFactor=%f, pointerIds=0x%x %s",
+ connection->getInputChannelName().c_str(), inputTarget.flags,
+ inputTarget.globalScaleFactor, inputTarget.pointerIds.value,
+ inputTarget.getPointerInfoString().c_str());
+ }
// Skip this event if the connection status is not normal.
// We don't want to enqueue additional outbound events if the connection is broken.
if (connection->status != Connection::STATUS_NORMAL) {
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ Dropping event because the channel status is %s",
- connection->getInputChannelName().c_str(), connection->getStatusLabel());
-#endif
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("channel '%s' ~ Dropping event because the channel status is %s",
+ connection->getInputChannelName().c_str(), connection->getStatusLabel());
+ }
return;
}
@@ -2814,7 +2873,7 @@
if (inputTarget.flags & InputTarget::FLAG_SPLIT) {
LOG_ALWAYS_FATAL_IF(eventEntry->type != EventEntry::Type::MOTION,
"Entry type %s should not have FLAG_SPLIT",
- NamedEnum::string(eventEntry->type).c_str());
+ ftl::enum_string(eventEntry->type).c_str());
const MotionEntry& originalMotionEntry = static_cast<const MotionEntry&>(*eventEntry);
if (inputTarget.pointerIds.count() != originalMotionEntry.pointerCount) {
@@ -2905,10 +2964,11 @@
if (!connection->inputState.trackKey(keyEntry, dispatchEntry->resolvedAction,
dispatchEntry->resolvedFlags)) {
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event",
- connection->getInputChannelName().c_str());
-#endif
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key "
+ "event",
+ connection->getInputChannelName().c_str());
+ }
return; // skip the inconsistent event
}
break;
@@ -2938,11 +2998,11 @@
if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE &&
!connection->inputState.isHovering(motionEntry.deviceId, motionEntry.source,
motionEntry.displayId)) {
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter "
- "event",
- connection->getInputChannelName().c_str());
-#endif
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover "
+ "enter event",
+ connection->getInputChannelName().c_str());
+ }
// We keep the 'resolvedEventId' here equal to the original 'motionEntry.id' because
// this is a one-to-one event conversion.
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
@@ -2958,11 +3018,11 @@
if (!connection->inputState.trackMotion(motionEntry, dispatchEntry->resolvedAction,
dispatchEntry->resolvedFlags)) {
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion "
- "event",
- connection->getInputChannelName().c_str());
-#endif
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion "
+ "event",
+ connection->getInputChannelName().c_str());
+ }
return; // skip the inconsistent event
}
@@ -2989,6 +3049,7 @@
break;
}
case EventEntry::Type::FOCUS:
+ case EventEntry::Type::TOUCH_MODE_CHANGED:
case EventEntry::Type::POINTER_CAPTURE_CHANGED:
case EventEntry::Type::DRAG: {
break;
@@ -3000,7 +3061,7 @@
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET: {
LOG_ALWAYS_FATAL("%s events should not go to apps",
- NamedEnum::string(newEntry.type).c_str());
+ ftl::enum_string(newEntry.type).c_str());
break;
}
}
@@ -3094,10 +3155,11 @@
return;
}
- std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
- &InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible);
- commandEntry->newToken = token;
- postCommandLocked(std::move(commandEntry));
+ auto command = [this, token]() REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy->onPointerDownOutsideFocus(token);
+ };
+ postCommandLocked(std::move(command));
}
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
@@ -3107,9 +3169,9 @@
connection->getInputChannelName().c_str());
ATRACE_NAME(message.c_str());
}
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ startDispatchCycle", connection->getInputChannelName().c_str());
-#endif
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("channel '%s' ~ startDispatchCycle", connection->getInputChannelName().c_str());
+ }
while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.empty()) {
DispatchEntry* dispatchEntry = connection->outboundQueue.front();
@@ -3206,6 +3268,16 @@
break;
}
+ case EventEntry::Type::TOUCH_MODE_CHANGED: {
+ const TouchModeEntry& touchModeEntry =
+ static_cast<const TouchModeEntry&>(eventEntry);
+ status = connection->inputPublisher
+ .publishTouchModeEvent(dispatchEntry->seq, touchModeEntry.id,
+ touchModeEntry.inTouchMode);
+
+ break;
+ }
+
case EventEntry::Type::POINTER_CAPTURE_CHANGED: {
const auto& captureEntry =
static_cast<const PointerCaptureChangedEntry&>(eventEntry);
@@ -3228,7 +3300,7 @@
case EventEntry::Type::DEVICE_RESET:
case EventEntry::Type::SENSOR: {
LOG_ALWAYS_FATAL("Should never start dispatch cycles for %s events",
- NamedEnum::string(eventEntry.type).c_str());
+ ftl::enum_string(eventEntry.type).c_str());
return;
}
}
@@ -3247,11 +3319,11 @@
} else {
// Pipe is full and we are waiting for the app to finish process some events
// before sending more events to it.
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ Could not publish event because the pipe is full, "
- "waiting for the application to catch up",
- connection->getInputChannelName().c_str());
-#endif
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("channel '%s' ~ Could not publish event because the pipe is full, "
+ "waiting for the application to catch up",
+ connection->getInputChannelName().c_str());
+ }
}
} else {
ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, "
@@ -3318,10 +3390,10 @@
void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection, uint32_t seq,
bool handled, nsecs_t consumeTime) {
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s",
- connection->getInputChannelName().c_str(), seq, toString(handled));
-#endif
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s",
+ connection->getInputChannelName().c_str(), seq, toString(handled));
+ }
if (connection->status == Connection::STATUS_BROKEN ||
connection->status == Connection::STATUS_ZOMBIE) {
@@ -3329,16 +3401,19 @@
}
// Notify other system components and prepare to start the next dispatch cycle.
- onDispatchCycleFinishedLocked(currentTime, connection, seq, handled, consumeTime);
+ auto command = [this, currentTime, connection, seq, handled, consumeTime]() REQUIRES(mLock) {
+ doDispatchCycleFinishedCommand(currentTime, connection, seq, handled, consumeTime);
+ };
+ postCommandLocked(std::move(command));
}
void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection,
bool notify) {
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ abortBrokenDispatchCycle - notify=%s",
- connection->getInputChannelName().c_str(), toString(notify));
-#endif
+ if (DEBUG_DISPATCH_CYCLE) {
+ ALOGD("channel '%s' ~ abortBrokenDispatchCycle - notify=%s",
+ connection->getInputChannelName().c_str(), toString(notify));
+ }
// Clear the dispatch queues.
drainDispatchQueue(connection->outboundQueue);
@@ -3353,7 +3428,15 @@
if (notify) {
// Notify other system components.
- onDispatchCycleBrokenLocked(currentTime, connection);
+ ALOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!",
+ connection->getInputChannelName().c_str());
+
+ auto command = [this, connection]() REQUIRES(mLock) {
+ if (connection->status == Connection::STATUS_ZOMBIE) return;
+ scoped_unlock unlock(mLock);
+ mPolicy->notifyInputChannelBroken(connection->inputChannel->getConnectionToken());
+ };
+ postCommandLocked(std::move(command));
}
}
}
@@ -3420,7 +3503,7 @@
gotOne = true;
}
if (gotOne) {
- runCommandsLockedInterruptible();
+ runCommandsLockedInterruptable();
if (status == WOULD_BLOCK) {
return 1;
}
@@ -3497,12 +3580,12 @@
if (cancelationEvents.empty()) {
return;
}
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("channel '%s' ~ Synthesized %zu cancelation events to bring channel back in sync "
- "with reality: %s, mode=%d.",
- connection->getInputChannelName().c_str(), cancelationEvents.size(), options.reason,
- options.mode);
-#endif
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("channel '%s' ~ Synthesized %zu cancelation events to bring channel back in sync "
+ "with reality: %s, mode=%d.",
+ connection->getInputChannelName().c_str(), cancelationEvents.size(), options.reason,
+ options.mode);
+ }
InputTarget target;
sp<WindowInfoHandle> windowHandle =
@@ -3529,17 +3612,18 @@
break;
}
case EventEntry::Type::FOCUS:
+ case EventEntry::Type::TOUCH_MODE_CHANGED:
case EventEntry::Type::POINTER_CAPTURE_CHANGED:
case EventEntry::Type::DRAG: {
LOG_ALWAYS_FATAL("Canceling %s events is not supported",
- NamedEnum::string(cancelationEventEntry->type).c_str());
+ ftl::enum_string(cancelationEventEntry->type).c_str());
break;
}
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET:
case EventEntry::Type::SENSOR: {
LOG_ALWAYS_FATAL("%s event should not be found inside Connections's queue",
- NamedEnum::string(cancelationEventEntry->type).c_str());
+ ftl::enum_string(cancelationEventEntry->type).c_str());
break;
}
}
@@ -3566,10 +3650,10 @@
return;
}
-#if DEBUG_OUTBOUND_EVENT_DETAILS
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
ALOGD("channel '%s' ~ Synthesized %zu down events to ensure consistent event stream.",
connection->getInputChannelName().c_str(), downEvents.size());
-#endif
+ }
InputTarget target;
sp<WindowInfoHandle> windowHandle =
@@ -3592,13 +3676,14 @@
case EventEntry::Type::KEY:
case EventEntry::Type::FOCUS:
+ case EventEntry::Type::TOUCH_MODE_CHANGED:
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET:
case EventEntry::Type::POINTER_CAPTURE_CHANGED:
case EventEntry::Type::SENSOR:
case EventEntry::Type::DRAG: {
LOG_ALWAYS_FATAL("%s event should not be found inside Connections's queue",
- NamedEnum::string(downEventEntry->type).c_str());
+ ftl::enum_string(downEventEntry->type).c_str());
break;
}
}
@@ -3712,9 +3797,9 @@
}
void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
-#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("notifyConfigurationChanged - eventTime=%" PRId64, args->eventTime);
-#endif
+ if (DEBUG_INBOUND_EVENT_DETAILS) {
+ ALOGD("notifyConfigurationChanged - eventTime=%" PRId64, args->eventTime);
+ }
bool needWake;
{ // acquire lock
@@ -3768,14 +3853,14 @@
}
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
-#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("notifyKey - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32
- "policyFlags=0x%x, action=0x%x, "
- "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%" PRId64,
- args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags,
- args->action, args->flags, args->keyCode, args->scanCode, args->metaState,
- args->downTime);
-#endif
+ if (DEBUG_INBOUND_EVENT_DETAILS) {
+ ALOGD("notifyKey - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32
+ "policyFlags=0x%x, action=0x%x, "
+ "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%" PRId64,
+ args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags,
+ args->action, args->flags, args->keyCode, args->scanCode, args->metaState,
+ args->downTime);
+ }
if (!validateKeyEvent(args->action)) {
return;
}
@@ -3846,33 +3931,33 @@
}
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
-#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("notifyMotion - id=%" PRIx32 " eventTime=%" PRId64 ", deviceId=%d, source=0x%x, "
- "displayId=%" PRId32 ", policyFlags=0x%x, "
- "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, "
- "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, xCursorPosition=%f, "
- "yCursorPosition=%f, downTime=%" PRId64,
- args->id, args->eventTime, args->deviceId, args->source, args->displayId,
- args->policyFlags, args->action, args->actionButton, args->flags, args->metaState,
- args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision,
- args->xCursorPosition, args->yCursorPosition, args->downTime);
- for (uint32_t i = 0; i < args->pointerCount; i++) {
- ALOGD(" Pointer %d: id=%d, toolType=%d, "
- "x=%f, y=%f, pressure=%f, size=%f, "
- "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, "
- "orientation=%f",
- i, args->pointerProperties[i].id, args->pointerProperties[i].toolType,
- args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
- args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
- args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
- args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
- args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
- args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
- args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
- args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
- args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
+ if (DEBUG_INBOUND_EVENT_DETAILS) {
+ ALOGD("notifyMotion - id=%" PRIx32 " eventTime=%" PRId64 ", deviceId=%d, source=0x%x, "
+ "displayId=%" PRId32 ", policyFlags=0x%x, "
+ "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, "
+ "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, xCursorPosition=%f, "
+ "yCursorPosition=%f, downTime=%" PRId64,
+ args->id, args->eventTime, args->deviceId, args->source, args->displayId,
+ args->policyFlags, args->action, args->actionButton, args->flags, args->metaState,
+ args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision,
+ args->xCursorPosition, args->yCursorPosition, args->downTime);
+ for (uint32_t i = 0; i < args->pointerCount; i++) {
+ ALOGD(" Pointer %d: id=%d, toolType=%d, "
+ "x=%f, y=%f, pressure=%f, size=%f, "
+ "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, "
+ "orientation=%f",
+ i, args->pointerProperties[i].id, args->pointerProperties[i].toolType,
+ args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
+ args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
+ args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
+ args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
+ args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
+ args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
+ args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
+ args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
+ args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
+ }
}
-#endif
if (!validateMotionEvent(args->action, args->actionButton, args->pointerCount,
args->pointerProperties)) {
return;
@@ -3925,6 +4010,13 @@
args->downTime, args->pointerCount,
args->pointerProperties, args->pointerCoords, 0, 0);
+ if (args->id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID &&
+ IdGenerator::getSource(args->id) == IdGenerator::Source::INPUT_READER &&
+ !mInputFilterEnabled) {
+ const bool isDown = args->action == AMOTION_EVENT_ACTION_DOWN;
+ mLatencyTracker.trackListener(args->id, isDown, args->eventTime, args->readTime);
+ }
+
needWake = enqueueInboundEventLocked(std::move(newEntry));
mLock.unlock();
} // release lock
@@ -3935,12 +4027,12 @@
}
void InputDispatcher::notifySensor(const NotifySensorArgs* args) {
-#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("notifySensor - id=%" PRIx32 " eventTime=%" PRId64 ", deviceId=%d, source=0x%x, "
- " sensorType=%s",
- args->id, args->eventTime, args->deviceId, args->source,
- NamedEnum::string(args->sensorType).c_str());
-#endif
+ if (DEBUG_INBOUND_EVENT_DETAILS) {
+ ALOGD("notifySensor - id=%" PRIx32 " eventTime=%" PRId64 ", deviceId=%d, source=0x%x, "
+ " sensorType=%s",
+ args->id, args->eventTime, args->deviceId, args->source,
+ ftl::enum_string(args->sensorType).c_str());
+ }
bool needWake;
{ // acquire lock
@@ -3963,10 +4055,10 @@
}
void InputDispatcher::notifyVibratorState(const NotifyVibratorStateArgs* args) {
-#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("notifyVibratorState - eventTime=%" PRId64 ", device=%d, isOn=%d", args->eventTime,
- args->deviceId, args->isOn);
-#endif
+ if (DEBUG_INBOUND_EVENT_DETAILS) {
+ ALOGD("notifyVibratorState - eventTime=%" PRId64 ", device=%d, isOn=%d", args->eventTime,
+ args->deviceId, args->isOn);
+ }
mPolicy->notifyVibratorState(args->deviceId, args->isOn);
}
@@ -3975,11 +4067,11 @@
}
void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) {
-#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("notifySwitch - eventTime=%" PRId64 ", policyFlags=0x%x, switchValues=0x%08x, "
- "switchMask=0x%08x",
- args->eventTime, args->policyFlags, args->switchValues, args->switchMask);
-#endif
+ if (DEBUG_INBOUND_EVENT_DETAILS) {
+ ALOGD("notifySwitch - eventTime=%" PRId64 ", policyFlags=0x%x, switchValues=0x%08x, "
+ "switchMask=0x%08x",
+ args->eventTime, args->policyFlags, args->switchValues, args->switchMask);
+ }
uint32_t policyFlags = args->policyFlags;
policyFlags |= POLICY_FLAG_TRUSTED;
@@ -3987,10 +4079,10 @@
}
void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
-#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("notifyDeviceReset - eventTime=%" PRId64 ", deviceId=%d", args->eventTime,
- args->deviceId);
-#endif
+ if (DEBUG_INBOUND_EVENT_DETAILS) {
+ ALOGD("notifyDeviceReset - eventTime=%" PRId64 ", deviceId=%d", args->eventTime,
+ args->deviceId);
+ }
bool needWake;
{ // acquire lock
@@ -4007,10 +4099,10 @@
}
void InputDispatcher::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
-#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("notifyPointerCaptureChanged - eventTime=%" PRId64 ", enabled=%s", args->eventTime,
- args->request.enable ? "true" : "false");
-#endif
+ if (DEBUG_INBOUND_EVENT_DETAILS) {
+ ALOGD("notifyPointerCaptureChanged - eventTime=%" PRId64 ", enabled=%s", args->eventTime,
+ args->request.enable ? "true" : "false");
+ }
bool needWake;
{ // acquire lock
@@ -4028,11 +4120,11 @@
InputEventInjectionResult InputDispatcher::injectInputEvent(
const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
InputEventInjectionSync syncMode, std::chrono::milliseconds timeout, uint32_t policyFlags) {
-#if DEBUG_INBOUND_EVENT_DETAILS
- ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, "
- "syncMode=%d, timeout=%lld, policyFlags=0x%08x",
- event->getType(), injectorPid, injectorUid, syncMode, timeout.count(), policyFlags);
-#endif
+ if (DEBUG_INBOUND_EVENT_DETAILS) {
+ ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, "
+ "syncMode=%d, timeout=%lld, policyFlags=0x%08x",
+ event->getType(), injectorPid, injectorUid, syncMode, timeout.count(), policyFlags);
+ }
nsecs_t endTime = now() + std::chrono::duration_cast<std::chrono::nanoseconds>(timeout).count();
policyFlags |= POLICY_FLAG_INJECTED;
@@ -4210,10 +4302,10 @@
nsecs_t remainingTimeout = endTime - now();
if (remainingTimeout <= 0) {
-#if DEBUG_INJECTION
- ALOGD("injectInputEvent - Timed out waiting for injection result "
- "to become available.");
-#endif
+ if (DEBUG_INJECTION) {
+ ALOGD("injectInputEvent - Timed out waiting for injection result "
+ "to become available.");
+ }
injectionResult = InputEventInjectionResult::TIMED_OUT;
break;
}
@@ -4224,16 +4316,16 @@
if (injectionResult == InputEventInjectionResult::SUCCEEDED &&
syncMode == InputEventInjectionSync::WAIT_FOR_FINISHED) {
while (injectionState->pendingForegroundDispatches != 0) {
-#if DEBUG_INJECTION
- ALOGD("injectInputEvent - Waiting for %d pending foreground dispatches.",
- injectionState->pendingForegroundDispatches);
-#endif
+ if (DEBUG_INJECTION) {
+ ALOGD("injectInputEvent - Waiting for %d pending foreground dispatches.",
+ injectionState->pendingForegroundDispatches);
+ }
nsecs_t remainingTimeout = endTime - now();
if (remainingTimeout <= 0) {
-#if DEBUG_INJECTION
- ALOGD("injectInputEvent - Timed out waiting for pending foreground "
- "dispatches to finish.");
-#endif
+ if (DEBUG_INJECTION) {
+ ALOGD("injectInputEvent - Timed out waiting for pending foreground "
+ "dispatches to finish.");
+ }
injectionResult = InputEventInjectionResult::TIMED_OUT;
break;
}
@@ -4246,10 +4338,10 @@
injectionState->release();
} // release lock
-#if DEBUG_INJECTION
- ALOGD("injectInputEvent - Finished with result %d. injectorPid=%d, injectorUid=%d",
- injectionResult, injectorPid, injectorUid);
-#endif
+ if (DEBUG_INJECTION) {
+ ALOGD("injectInputEvent - Finished with result %d. injectorPid=%d, injectorUid=%d",
+ injectionResult, injectorPid, injectorUid);
+ }
return injectionResult;
}
@@ -4296,11 +4388,11 @@
InputEventInjectionResult injectionResult) {
InjectionState* injectionState = entry.injectionState;
if (injectionState) {
-#if DEBUG_INJECTION
- ALOGD("Setting input event injection result to %d. "
- "injectorPid=%d, injectorUid=%d",
- injectionResult, injectionState->injectorPid, injectionState->injectorUid);
-#endif
+ if (DEBUG_INJECTION) {
+ ALOGD("Setting input event injection result to %d. "
+ "injectorPid=%d, injectorUid=%d",
+ injectionResult, injectionState->injectorPid, injectionState->injectorUid);
+ }
if (injectionState->injectionIsAsync && !(entry.policyFlags & POLICY_FLAG_FILTERED)) {
// Log the outcome since the injector did not wait for the injection result.
@@ -4460,8 +4552,7 @@
std::vector<sp<WindowInfoHandle>> newHandles;
for (const sp<WindowInfoHandle>& handle : windowInfoHandles) {
const WindowInfo* info = handle->getInfo();
- if ((getInputChannelLocked(handle->getToken()) == nullptr &&
- info->portalToDisplayId == ADISPLAY_ID_NONE)) {
+ if (getInputChannelLocked(handle->getToken()) == nullptr) {
const bool noInputChannel =
info->inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL);
const bool canReceiveInput = !info->flags.test(WindowInfo::Flag::NOT_TOUCHABLE) ||
@@ -4495,6 +4586,7 @@
void InputDispatcher::setInputWindows(
const std::unordered_map<int32_t, std::vector<sp<WindowInfoHandle>>>& handlesPerDisplay) {
+ // TODO(b/198444055): Remove setInputWindows from InputDispatcher.
{ // acquire lock
std::scoped_lock _l(mLock);
for (const auto& [displayId, handles] : handlesPerDisplay) {
@@ -4575,6 +4667,18 @@
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
"touched window was removed");
synthesizeCancelationEventsForInputChannelLocked(touchedInputChannel, options);
+ // Since we are about to drop the touch, cancel the events for the wallpaper as
+ // well.
+ if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND &&
+ touchedWindow.windowHandle->getInfo()->hasWallpaper) {
+ sp<WindowInfoHandle> wallpaper = state.getWallpaperWindow();
+ if (wallpaper != nullptr) {
+ sp<Connection> wallpaperConnection =
+ getConnectionLocked(wallpaper->getToken());
+ synthesizeCancelationEventsForConnectionLocked(wallpaperConnection,
+ options);
+ }
+ }
}
state.windows.erase(state.windows.begin() + i);
} else {
@@ -4706,7 +4810,7 @@
// Find new focused window and validate
sp<IBinder> newFocusedWindowToken = mFocusResolver.getFocusedWindowToken(displayId);
- notifyFocusChangedLocked(oldFocusedWindowToken, newFocusedWindowToken);
+ sendFocusChangedCommandLocked(oldFocusedWindowToken, newFocusedWindowToken);
if (newFocusedWindowToken == nullptr) {
ALOGW("Focused display #%" PRId32 " does not have a focused window.", displayId);
@@ -4785,6 +4889,7 @@
void InputDispatcher::setInTouchMode(bool inTouchMode) {
std::scoped_lock lock(mLock);
mInTouchMode = inTouchMode;
+ // TODO(b/193718270): Fire TouchModeEvent here.
}
void InputDispatcher::setMaximumObscuringOpacityForTouch(float opacity) {
@@ -5003,14 +5108,6 @@
} else {
dump += INDENT3 "Windows: <none>\n";
}
- if (!state.portalWindows.empty()) {
- dump += INDENT3 "Portal windows:\n";
- for (size_t i = 0; i < state.portalWindows.size(); i++) {
- const sp<WindowInfoHandle> portalWindowHandle = state.portalWindows[i];
- dump += StringPrintf(INDENT4 "%zu: name='%s'\n", i,
- portalWindowHandle->getName().c_str());
- }
- }
}
} else {
dump += INDENT "TouchStates: <no displays touched>\n";
@@ -5022,9 +5119,17 @@
}
if (!mWindowHandlesByDisplay.empty()) {
- for (auto& it : mWindowHandlesByDisplay) {
- const std::vector<sp<WindowInfoHandle>> windowHandles = it.second;
- dump += StringPrintf(INDENT "Display: %" PRId32 "\n", it.first);
+ for (const auto& [displayId, windowHandles] : mWindowHandlesByDisplay) {
+ dump += StringPrintf(INDENT "Display: %" PRId32 "\n", displayId);
+ if (const auto& it = mDisplayInfos.find(displayId); it != mDisplayInfos.end()) {
+ const auto& displayInfo = it->second;
+ dump += StringPrintf(INDENT2 "logicalSize=%dx%d\n", displayInfo.logicalWidth,
+ displayInfo.logicalHeight);
+ displayInfo.transform.dump(dump, "transform", INDENT4);
+ } else {
+ dump += INDENT2 "No DisplayInfo found!\n";
+ }
+
if (!windowHandles.empty()) {
dump += INDENT2 "Windows:\n";
for (size_t i = 0; i < windowHandles.size(); i++) {
@@ -5032,7 +5137,7 @@
const WindowInfo* windowInfo = windowHandle->getInfo();
dump += StringPrintf(INDENT3 "%zu: name='%s', id=%" PRId32 ", displayId=%d, "
- "portalToDisplayId=%d, paused=%s, focusable=%s, "
+ "paused=%s, focusable=%s, "
"hasWallpaper=%s, visible=%s, alpha=%.2f, "
"flags=%s, type=%s, "
"frame=[%d,%d][%d,%d], globalScale=%f, "
@@ -5040,13 +5145,12 @@
"applicationInfo.token=%s, "
"touchableRegion=",
i, windowInfo->name.c_str(), windowInfo->id,
- windowInfo->displayId, windowInfo->portalToDisplayId,
- toString(windowInfo->paused),
+ windowInfo->displayId, toString(windowInfo->paused),
toString(windowInfo->focusable),
toString(windowInfo->hasWallpaper),
toString(windowInfo->visible), windowInfo->alpha,
windowInfo->flags.string().c_str(),
- NamedEnum::string(windowInfo->type).c_str(),
+ ftl::enum_string(windowInfo->type).c_str(),
windowInfo->frameLeft, windowInfo->frameTop,
windowInfo->frameRight, windowInfo->frameBottom,
windowInfo->globalScaleFactor,
@@ -5057,13 +5161,12 @@
windowInfo->inputFeatures.string().c_str());
dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%" PRId64
"ms, trustedOverlay=%s, hasToken=%s, "
- "touchOcclusionMode=%s, displayOrientation=%d\n",
+ "touchOcclusionMode=%s\n",
windowInfo->ownerPid, windowInfo->ownerUid,
millis(windowInfo->dispatchingTimeout),
toString(windowInfo->trustedOverlay),
toString(windowInfo->token != nullptr),
- toString(windowInfo->touchOcclusionMode).c_str(),
- windowInfo->displayOrientation);
+ toString(windowInfo->touchOcclusionMode).c_str());
windowInfo->transform.dump(dump, "transform", INDENT4);
}
} else {
@@ -5138,6 +5241,12 @@
dump += INDENT "ReplacedKeys: <empty>\n";
}
+ if (!mCommandQueue.empty()) {
+ dump += StringPrintf(INDENT "CommandQueue: size=%zu\n", mCommandQueue.size());
+ } else {
+ dump += INDENT "CommandQueue: <empty>\n";
+ }
+
if (!mConnectionsByToken.empty()) {
dump += INDENT "Connections:\n";
for (const auto& [token, connection] : mConnectionsByToken) {
@@ -5204,9 +5313,9 @@
};
Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(const std::string& name) {
-#if DEBUG_CHANNEL_CREATION
- ALOGD("channel '%s' ~ createInputChannel", name.c_str());
-#endif
+ if (DEBUG_CHANNEL_CREATION) {
+ ALOGD("channel '%s' ~ createInputChannel", name.c_str());
+ }
std::unique_ptr<InputChannel> serverChannel;
std::unique_ptr<InputChannel> clientChannel;
@@ -5486,46 +5595,92 @@
mConnectionsByToken.erase(connection->inputChannel->getConnectionToken());
}
-void InputDispatcher::onDispatchCycleFinishedLocked(nsecs_t currentTime,
- const sp<Connection>& connection, uint32_t seq,
- bool handled, nsecs_t consumeTime) {
- std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
- &InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
- commandEntry->connection = connection;
- commandEntry->eventTime = currentTime;
- commandEntry->seq = seq;
- commandEntry->handled = handled;
- commandEntry->consumeTime = consumeTime;
- postCommandLocked(std::move(commandEntry));
+void InputDispatcher::doDispatchCycleFinishedCommand(nsecs_t finishTime,
+ const sp<Connection>& connection, uint32_t seq,
+ bool handled, nsecs_t consumeTime) {
+ // Handle post-event policy actions.
+ std::deque<DispatchEntry*>::iterator dispatchEntryIt = connection->findWaitQueueEntry(seq);
+ if (dispatchEntryIt == connection->waitQueue.end()) {
+ return;
+ }
+ DispatchEntry* dispatchEntry = *dispatchEntryIt;
+ const nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
+ if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
+ ALOGI("%s spent %" PRId64 "ms processing %s", connection->getWindowName().c_str(),
+ ns2ms(eventDuration), dispatchEntry->eventEntry->getDescription().c_str());
+ }
+ if (shouldReportFinishedEvent(*dispatchEntry, *connection)) {
+ mLatencyTracker.trackFinishedEvent(dispatchEntry->eventEntry->id,
+ connection->inputChannel->getConnectionToken(),
+ dispatchEntry->deliveryTime, consumeTime, finishTime);
+ }
+
+ bool restartEvent;
+ if (dispatchEntry->eventEntry->type == EventEntry::Type::KEY) {
+ KeyEntry& keyEntry = static_cast<KeyEntry&>(*(dispatchEntry->eventEntry));
+ restartEvent =
+ afterKeyEventLockedInterruptable(connection, dispatchEntry, keyEntry, handled);
+ } else if (dispatchEntry->eventEntry->type == EventEntry::Type::MOTION) {
+ MotionEntry& motionEntry = static_cast<MotionEntry&>(*(dispatchEntry->eventEntry));
+ restartEvent = afterMotionEventLockedInterruptable(connection, dispatchEntry, motionEntry,
+ handled);
+ } else {
+ restartEvent = false;
+ }
+
+ // Dequeue the event and start the next cycle.
+ // Because the lock might have been released, it is possible that the
+ // contents of the wait queue to have been drained, so we need to double-check
+ // a few things.
+ dispatchEntryIt = connection->findWaitQueueEntry(seq);
+ if (dispatchEntryIt != connection->waitQueue.end()) {
+ dispatchEntry = *dispatchEntryIt;
+ connection->waitQueue.erase(dispatchEntryIt);
+ const sp<IBinder>& connectionToken = connection->inputChannel->getConnectionToken();
+ mAnrTracker.erase(dispatchEntry->timeoutTime, connectionToken);
+ if (!connection->responsive) {
+ connection->responsive = isConnectionResponsive(*connection);
+ if (connection->responsive) {
+ // The connection was unresponsive, and now it's responsive.
+ processConnectionResponsiveLocked(*connection);
+ }
+ }
+ traceWaitQueueLength(*connection);
+ if (restartEvent && connection->status == Connection::STATUS_NORMAL) {
+ connection->outboundQueue.push_front(dispatchEntry);
+ traceOutboundQueueLength(*connection);
+ } else {
+ releaseDispatchEntry(dispatchEntry);
+ }
+ }
+
+ // Start the next dispatch cycle for this connection.
+ startDispatchCycleLocked(now(), connection);
}
-void InputDispatcher::onDispatchCycleBrokenLocked(nsecs_t currentTime,
- const sp<Connection>& connection) {
- ALOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!",
- connection->getInputChannelName().c_str());
-
- std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
- &InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible);
- commandEntry->connection = connection;
- postCommandLocked(std::move(commandEntry));
+void InputDispatcher::sendFocusChangedCommandLocked(const sp<IBinder>& oldToken,
+ const sp<IBinder>& newToken) {
+ auto command = [this, oldToken, newToken]() REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy->notifyFocusChanged(oldToken, newToken);
+ };
+ postCommandLocked(std::move(command));
}
-void InputDispatcher::notifyFocusChangedLocked(const sp<IBinder>& oldToken,
- const sp<IBinder>& newToken) {
- std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
- &InputDispatcher::doNotifyFocusChangedLockedInterruptible);
- commandEntry->oldToken = oldToken;
- commandEntry->newToken = newToken;
- postCommandLocked(std::move(commandEntry));
+void InputDispatcher::sendDropWindowCommandLocked(const sp<IBinder>& token, float x, float y) {
+ auto command = [this, token, x, y]() REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy->notifyDropWindow(token, x, y);
+ };
+ postCommandLocked(std::move(command));
}
-void InputDispatcher::notifyDropWindowLocked(const sp<IBinder>& token, float x, float y) {
- std::unique_ptr<CommandEntry> commandEntry =
- std::make_unique<CommandEntry>(&InputDispatcher::doNotifyDropWindowLockedInterruptible);
- commandEntry->newToken = token;
- commandEntry->x = x;
- commandEntry->y = y;
- postCommandLocked(std::move(commandEntry));
+void InputDispatcher::sendUntrustedTouchCommandLocked(const std::string& obscuringPackage) {
+ auto command = [this, obscuringPackage]() REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy->notifyUntrustedTouch(obscuringPackage);
+ };
+ postCommandLocked(std::move(command));
}
void InputDispatcher::onAnrLocked(const sp<Connection>& connection) {
@@ -5568,17 +5723,11 @@
StringPrintf("%s does not have a focused window", application->getName().c_str());
updateLastAnrStateLocked(*application, reason);
- std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
- &InputDispatcher::doNotifyNoFocusedWindowAnrLockedInterruptible);
- commandEntry->inputApplicationHandle = std::move(application);
- postCommandLocked(std::move(commandEntry));
-}
-
-void InputDispatcher::onUntrustedTouchLocked(const std::string& obscuringPackage) {
- std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
- &InputDispatcher::doNotifyUntrustedTouchLockedInterruptible);
- commandEntry->obscuringPackage = obscuringPackage;
- postCommandLocked(std::move(commandEntry));
+ auto command = [this, application = std::move(application)]() REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy->notifyNoFocusedWindowAnr(application);
+ };
+ postCommandLocked(std::move(command));
}
void InputDispatcher::updateLastAnrStateLocked(const sp<WindowInfoHandle>& window,
@@ -5609,109 +5758,24 @@
dumpDispatchStateLocked(mLastAnrState);
}
-void InputDispatcher::doNotifyConfigurationChangedLockedInterruptible(CommandEntry* commandEntry) {
- mLock.unlock();
-
- mPolicy->notifyConfigurationChanged(commandEntry->eventTime);
-
- mLock.lock();
-}
-
-void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry) {
- sp<Connection> connection = commandEntry->connection;
-
- if (connection->status != Connection::STATUS_ZOMBIE) {
- mLock.unlock();
-
- mPolicy->notifyInputChannelBroken(connection->inputChannel->getConnectionToken());
-
- mLock.lock();
- }
-}
-
-void InputDispatcher::doNotifyFocusChangedLockedInterruptible(CommandEntry* commandEntry) {
- sp<IBinder> oldToken = commandEntry->oldToken;
- sp<IBinder> newToken = commandEntry->newToken;
- mLock.unlock();
- mPolicy->notifyFocusChanged(oldToken, newToken);
- mLock.lock();
-}
-
-void InputDispatcher::doNotifyDropWindowLockedInterruptible(CommandEntry* commandEntry) {
- sp<IBinder> newToken = commandEntry->newToken;
- mLock.unlock();
- mPolicy->notifyDropWindow(newToken, commandEntry->x, commandEntry->y);
- mLock.lock();
-}
-
-void InputDispatcher::doNotifyNoFocusedWindowAnrLockedInterruptible(CommandEntry* commandEntry) {
- mLock.unlock();
-
- mPolicy->notifyNoFocusedWindowAnr(commandEntry->inputApplicationHandle);
-
- mLock.lock();
-}
-
-void InputDispatcher::doNotifyWindowUnresponsiveLockedInterruptible(CommandEntry* commandEntry) {
- mLock.unlock();
-
- mPolicy->notifyWindowUnresponsive(commandEntry->connectionToken, commandEntry->reason);
-
- mLock.lock();
-}
-
-void InputDispatcher::doNotifyMonitorUnresponsiveLockedInterruptible(CommandEntry* commandEntry) {
- mLock.unlock();
-
- mPolicy->notifyMonitorUnresponsive(commandEntry->pid, commandEntry->reason);
-
- mLock.lock();
-}
-
-void InputDispatcher::doNotifyWindowResponsiveLockedInterruptible(CommandEntry* commandEntry) {
- mLock.unlock();
-
- mPolicy->notifyWindowResponsive(commandEntry->connectionToken);
-
- mLock.lock();
-}
-
-void InputDispatcher::doNotifyMonitorResponsiveLockedInterruptible(CommandEntry* commandEntry) {
- mLock.unlock();
-
- mPolicy->notifyMonitorResponsive(commandEntry->pid);
-
- mLock.lock();
-}
-
-void InputDispatcher::doNotifyUntrustedTouchLockedInterruptible(CommandEntry* commandEntry) {
- mLock.unlock();
-
- mPolicy->notifyUntrustedTouch(commandEntry->obscuringPackage);
-
- mLock.lock();
-}
-
-void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
- CommandEntry* commandEntry) {
- KeyEntry& entry = *(commandEntry->keyEntry);
- KeyEvent event = createKeyEvent(entry);
-
- mLock.unlock();
-
- android::base::Timer t;
- const sp<IBinder>& token = commandEntry->connectionToken;
- nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(token, &event, entry.policyFlags);
- if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
- ALOGW("Excessive delay in interceptKeyBeforeDispatching; took %s ms",
- std::to_string(t.duration().count()).c_str());
- }
-
- mLock.lock();
+void InputDispatcher::doInterceptKeyBeforeDispatchingCommand(const sp<IBinder>& focusedWindowToken,
+ KeyEntry& entry) {
+ const KeyEvent event = createKeyEvent(entry);
+ nsecs_t delay = 0;
+ { // release lock
+ scoped_unlock unlock(mLock);
+ android::base::Timer t;
+ delay = mPolicy->interceptKeyBeforeDispatching(focusedWindowToken, &event,
+ entry.policyFlags);
+ if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
+ ALOGW("Excessive delay in interceptKeyBeforeDispatching; took %s ms",
+ std::to_string(t.duration().count()).c_str());
+ }
+ } // acquire lock
if (delay < 0) {
entry.interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP;
- } else if (!delay) {
+ } else if (delay == 0) {
entry.interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
} else {
entry.interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER;
@@ -5719,122 +5783,37 @@
}
}
-void InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry) {
- mLock.unlock();
- mPolicy->onPointerDownOutsideFocus(commandEntry->newToken);
- mLock.lock();
-}
-
-/**
- * Connection is responsive if it has no events in the waitQueue that are older than the
- * current time.
- */
-static bool isConnectionResponsive(const Connection& connection) {
- const nsecs_t currentTime = now();
- for (const DispatchEntry* entry : connection.waitQueue) {
- if (entry->timeoutTime < currentTime) {
- return false;
- }
- }
- return true;
-}
-
-void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) {
- sp<Connection> connection = commandEntry->connection;
- const nsecs_t finishTime = commandEntry->eventTime;
- uint32_t seq = commandEntry->seq;
- const bool handled = commandEntry->handled;
-
- // Handle post-event policy actions.
- std::deque<DispatchEntry*>::iterator dispatchEntryIt = connection->findWaitQueueEntry(seq);
- if (dispatchEntryIt == connection->waitQueue.end()) {
- return;
- }
- DispatchEntry* dispatchEntry = *dispatchEntryIt;
- const nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
- if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
- ALOGI("%s spent %" PRId64 "ms processing %s", connection->getWindowName().c_str(),
- ns2ms(eventDuration), dispatchEntry->eventEntry->getDescription().c_str());
- }
- if (shouldReportFinishedEvent(*dispatchEntry, *connection)) {
- mLatencyTracker.trackFinishedEvent(dispatchEntry->eventEntry->id,
- connection->inputChannel->getConnectionToken(),
- dispatchEntry->deliveryTime, commandEntry->consumeTime,
- finishTime);
- }
-
- bool restartEvent;
- if (dispatchEntry->eventEntry->type == EventEntry::Type::KEY) {
- KeyEntry& keyEntry = static_cast<KeyEntry&>(*(dispatchEntry->eventEntry));
- restartEvent =
- afterKeyEventLockedInterruptible(connection, dispatchEntry, keyEntry, handled);
- } else if (dispatchEntry->eventEntry->type == EventEntry::Type::MOTION) {
- MotionEntry& motionEntry = static_cast<MotionEntry&>(*(dispatchEntry->eventEntry));
- restartEvent = afterMotionEventLockedInterruptible(connection, dispatchEntry, motionEntry,
- handled);
- } else {
- restartEvent = false;
- }
-
- // Dequeue the event and start the next cycle.
- // Because the lock might have been released, it is possible that the
- // contents of the wait queue to have been drained, so we need to double-check
- // a few things.
- dispatchEntryIt = connection->findWaitQueueEntry(seq);
- if (dispatchEntryIt != connection->waitQueue.end()) {
- dispatchEntry = *dispatchEntryIt;
- connection->waitQueue.erase(dispatchEntryIt);
- const sp<IBinder>& connectionToken = connection->inputChannel->getConnectionToken();
- mAnrTracker.erase(dispatchEntry->timeoutTime, connectionToken);
- if (!connection->responsive) {
- connection->responsive = isConnectionResponsive(*connection);
- if (connection->responsive) {
- // The connection was unresponsive, and now it's responsive.
- processConnectionResponsiveLocked(*connection);
- }
- }
- traceWaitQueueLength(*connection);
- if (restartEvent && connection->status == Connection::STATUS_NORMAL) {
- connection->outboundQueue.push_front(dispatchEntry);
- traceOutboundQueueLength(*connection);
- } else {
- releaseDispatchEntry(dispatchEntry);
- }
- }
-
- // Start the next dispatch cycle for this connection.
- startDispatchCycleLocked(now(), connection);
-}
-
void InputDispatcher::sendMonitorUnresponsiveCommandLocked(int32_t pid, std::string reason) {
- std::unique_ptr<CommandEntry> monitorUnresponsiveCommand = std::make_unique<CommandEntry>(
- &InputDispatcher::doNotifyMonitorUnresponsiveLockedInterruptible);
- monitorUnresponsiveCommand->pid = pid;
- monitorUnresponsiveCommand->reason = std::move(reason);
- postCommandLocked(std::move(monitorUnresponsiveCommand));
+ auto command = [this, pid, reason = std::move(reason)]() REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy->notifyMonitorUnresponsive(pid, reason);
+ };
+ postCommandLocked(std::move(command));
}
-void InputDispatcher::sendWindowUnresponsiveCommandLocked(sp<IBinder> connectionToken,
+void InputDispatcher::sendWindowUnresponsiveCommandLocked(const sp<IBinder>& token,
std::string reason) {
- std::unique_ptr<CommandEntry> windowUnresponsiveCommand = std::make_unique<CommandEntry>(
- &InputDispatcher::doNotifyWindowUnresponsiveLockedInterruptible);
- windowUnresponsiveCommand->connectionToken = std::move(connectionToken);
- windowUnresponsiveCommand->reason = std::move(reason);
- postCommandLocked(std::move(windowUnresponsiveCommand));
+ auto command = [this, token, reason = std::move(reason)]() REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy->notifyWindowUnresponsive(token, reason);
+ };
+ postCommandLocked(std::move(command));
}
void InputDispatcher::sendMonitorResponsiveCommandLocked(int32_t pid) {
- std::unique_ptr<CommandEntry> monitorResponsiveCommand = std::make_unique<CommandEntry>(
- &InputDispatcher::doNotifyMonitorResponsiveLockedInterruptible);
- monitorResponsiveCommand->pid = pid;
- postCommandLocked(std::move(monitorResponsiveCommand));
+ auto command = [this, pid]() REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy->notifyMonitorResponsive(pid);
+ };
+ postCommandLocked(std::move(command));
}
-void InputDispatcher::sendWindowResponsiveCommandLocked(sp<IBinder> connectionToken) {
- std::unique_ptr<CommandEntry> windowResponsiveCommand = std::make_unique<CommandEntry>(
- &InputDispatcher::doNotifyWindowResponsiveLockedInterruptible);
- windowResponsiveCommand->connectionToken = std::move(connectionToken);
- postCommandLocked(std::move(windowResponsiveCommand));
+void InputDispatcher::sendWindowResponsiveCommandLocked(const sp<IBinder>& connectionToken) {
+ auto command = [this, connectionToken]() REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy->notifyWindowResponsive(connectionToken);
+ };
+ postCommandLocked(std::move(command));
}
/**
@@ -5882,7 +5861,7 @@
sendWindowResponsiveCommandLocked(connectionToken);
}
-bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& connection,
+bool InputDispatcher::afterKeyEventLockedInterruptable(const sp<Connection>& connection,
DispatchEntry* dispatchEntry,
KeyEntry& keyEntry, bool handled) {
if (keyEntry.flags & AKEY_EVENT_FLAG_FALLBACK) {
@@ -5907,11 +5886,12 @@
// then cancel the associated fallback key, if any.
if (fallbackKeyCode != -1) {
// Dispatch the unhandled key to the policy with the cancel flag.
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("Unhandled key event: Asking policy to cancel fallback action. "
- "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
- keyEntry.keyCode, keyEntry.action, keyEntry.repeatCount, keyEntry.policyFlags);
-#endif
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("Unhandled key event: Asking policy to cancel fallback action. "
+ "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
+ keyEntry.keyCode, keyEntry.action, keyEntry.repeatCount,
+ keyEntry.policyFlags);
+ }
KeyEvent event = createKeyEvent(keyEntry);
event.setFlags(event.getFlags() | AKEY_EVENT_FLAG_CANCELED);
@@ -5939,21 +5919,21 @@
// Then ask the policy what to do with it.
bool initialDown = keyEntry.action == AKEY_EVENT_ACTION_DOWN && keyEntry.repeatCount == 0;
if (fallbackKeyCode == -1 && !initialDown) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("Unhandled key event: Skipping unhandled key event processing "
- "since this is not an initial down. "
- "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
- originalKeyCode, keyEntry.action, keyEntry.repeatCount, keyEntry.policyFlags);
-#endif
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("Unhandled key event: Skipping unhandled key event processing "
+ "since this is not an initial down. "
+ "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
+ originalKeyCode, keyEntry.action, keyEntry.repeatCount, keyEntry.policyFlags);
+ }
return false;
}
// Dispatch the unhandled key to the policy.
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("Unhandled key event: Asking policy to perform fallback action. "
- "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
- keyEntry.keyCode, keyEntry.action, keyEntry.repeatCount, keyEntry.policyFlags);
-#endif
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("Unhandled key event: Asking policy to perform fallback action. "
+ "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
+ keyEntry.keyCode, keyEntry.action, keyEntry.repeatCount, keyEntry.policyFlags);
+ }
KeyEvent event = createKeyEvent(keyEntry);
mLock.unlock();
@@ -5987,19 +5967,19 @@
// longer dispatch a fallback key to the application.
if (fallbackKeyCode != AKEYCODE_UNKNOWN &&
(!fallback || fallbackKeyCode != event.getKeyCode())) {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- if (fallback) {
- ALOGD("Unhandled key event: Policy requested to send key %d"
- "as a fallback for %d, but on the DOWN it had requested "
- "to send %d instead. Fallback canceled.",
- event.getKeyCode(), originalKeyCode, fallbackKeyCode);
- } else {
- ALOGD("Unhandled key event: Policy did not request fallback for %d, "
- "but on the DOWN it had requested to send %d. "
- "Fallback canceled.",
- originalKeyCode, fallbackKeyCode);
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ if (fallback) {
+ ALOGD("Unhandled key event: Policy requested to send key %d"
+ "as a fallback for %d, but on the DOWN it had requested "
+ "to send %d instead. Fallback canceled.",
+ event.getKeyCode(), originalKeyCode, fallbackKeyCode);
+ } else {
+ ALOGD("Unhandled key event: Policy did not request fallback for %d, "
+ "but on the DOWN it had requested to send %d. "
+ "Fallback canceled.",
+ originalKeyCode, fallbackKeyCode);
+ }
}
-#endif
CancelationOptions options(CancelationOptions::CANCEL_FALLBACK_EVENTS,
"canceling fallback, policy no longer desires it");
@@ -6013,18 +5993,18 @@
}
}
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- {
- std::string msg;
- const KeyedVector<int32_t, int32_t>& fallbackKeys =
- connection->inputState.getFallbackKeys();
- for (size_t i = 0; i < fallbackKeys.size(); i++) {
- msg += StringPrintf(", %d->%d", fallbackKeys.keyAt(i), fallbackKeys.valueAt(i));
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ {
+ std::string msg;
+ const KeyedVector<int32_t, int32_t>& fallbackKeys =
+ connection->inputState.getFallbackKeys();
+ for (size_t i = 0; i < fallbackKeys.size(); i++) {
+ msg += StringPrintf(", %d->%d", fallbackKeys.keyAt(i), fallbackKeys.valueAt(i));
+ }
+ ALOGD("Unhandled key event: %zu currently tracked fallback keys%s.",
+ fallbackKeys.size(), msg.c_str());
}
- ALOGD("Unhandled key event: %zu currently tracked fallback keys%s.",
- fallbackKeys.size(), msg.c_str());
}
-#endif
if (fallback) {
// Restart the dispatch cycle using the fallback key.
@@ -6040,16 +6020,16 @@
keyEntry.downTime = event.getDownTime();
keyEntry.syntheticRepeat = false;
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("Unhandled key event: Dispatching fallback key. "
- "originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x",
- originalKeyCode, fallbackKeyCode, keyEntry.metaState);
-#endif
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("Unhandled key event: Dispatching fallback key. "
+ "originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x",
+ originalKeyCode, fallbackKeyCode, keyEntry.metaState);
+ }
return true; // restart the event
} else {
-#if DEBUG_OUTBOUND_EVENT_DETAILS
- ALOGD("Unhandled key event: No fallback key.");
-#endif
+ if (DEBUG_OUTBOUND_EVENT_DETAILS) {
+ ALOGD("Unhandled key event: No fallback key.");
+ }
// Report the key as unhandled, since there is no fallback key.
mReporter->reportUnhandledKey(keyEntry.id);
@@ -6058,21 +6038,12 @@
return false;
}
-bool InputDispatcher::afterMotionEventLockedInterruptible(const sp<Connection>& connection,
+bool InputDispatcher::afterMotionEventLockedInterruptable(const sp<Connection>& connection,
DispatchEntry* dispatchEntry,
MotionEntry& motionEntry, bool handled) {
return false;
}
-void InputDispatcher::doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) {
- mLock.unlock();
-
- mPolicy->pokeUserActivity(commandEntry->eventTime, commandEntry->userActivityEventType,
- commandEntry->displayId);
-
- mLock.lock();
-}
-
void InputDispatcher::traceInboundQueueLengthLocked() {
if (ATRACE_ENABLED()) {
ATRACE_INT("iq", mInboundQueue.size());
@@ -6184,7 +6155,7 @@
disablePointerCaptureForcedLocked();
if (mFocusedDisplayId == changes.displayId) {
- notifyFocusChangedLocked(changes.oldFocus, changes.newFocus);
+ sendFocusChangedCommandLocked(changes.oldFocus, changes.newFocus);
}
}
@@ -6216,22 +6187,14 @@
mInboundQueue.push_front(std::move(entry));
}
-void InputDispatcher::setPointerCaptureLocked(bool enabled) {
- mCurrentPointerCaptureRequest.enable = enabled;
+void InputDispatcher::setPointerCaptureLocked(bool enable) {
+ mCurrentPointerCaptureRequest.enable = enable;
mCurrentPointerCaptureRequest.seq++;
- std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
- &InputDispatcher::doSetPointerCaptureLockedInterruptible);
- commandEntry->pointerCaptureRequest = mCurrentPointerCaptureRequest;
- postCommandLocked(std::move(commandEntry));
-}
-
-void InputDispatcher::doSetPointerCaptureLockedInterruptible(
- android::inputdispatcher::CommandEntry* commandEntry) {
- mLock.unlock();
-
- mPolicy->setPointerCapture(commandEntry->pointerCaptureRequest);
-
- mLock.lock();
+ auto command = [this, request = mCurrentPointerCaptureRequest]() REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy->setPointerCapture(request);
+ };
+ postCommandLocked(std::move(command));
}
void InputDispatcher::displayRemoved(int32_t displayId) {
@@ -6249,16 +6212,44 @@
mLooper->wake();
}
-void InputDispatcher::onWindowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos) {
+void InputDispatcher::onWindowInfosChanged(const std::vector<WindowInfo>& windowInfos,
+ const std::vector<DisplayInfo>& displayInfos) {
// The listener sends the windows as a flattened array. Separate the windows by display for
// more convenient parsing.
std::unordered_map<int32_t, std::vector<sp<WindowInfoHandle>>> handlesPerDisplay;
-
for (const auto& info : windowInfos) {
handlesPerDisplay.emplace(info.displayId, std::vector<sp<WindowInfoHandle>>());
handlesPerDisplay[info.displayId].push_back(new WindowInfoHandle(info));
}
- setInputWindows(handlesPerDisplay);
+
+ { // acquire lock
+ std::scoped_lock _l(mLock);
+ mDisplayInfos.clear();
+ for (const auto& displayInfo : displayInfos) {
+ mDisplayInfos.emplace(displayInfo.displayId, displayInfo);
+ }
+
+ for (const auto& [displayId, handles] : handlesPerDisplay) {
+ setInputWindowsLocked(handles, displayId);
+ }
+ }
+ // Wake up poll loop since it may need to make new input dispatching choices.
+ mLooper->wake();
+}
+
+bool InputDispatcher::shouldDropInput(
+ const EventEntry& entry, const sp<android::gui::WindowInfoHandle>& windowHandle) const {
+ if (windowHandle->getInfo()->inputFeatures.test(WindowInfo::Feature::DROP_INPUT) ||
+ (windowHandle->getInfo()->inputFeatures.test(WindowInfo::Feature::DROP_INPUT_IF_OBSCURED) &&
+ isWindowObscuredLocked(windowHandle))) {
+ ALOGW("Dropping %s event targeting %s as requested by input feature %s on display "
+ "%" PRId32 ".",
+ ftl::enum_string(entry.type).c_str(), windowHandle->getName().c_str(),
+ windowHandle->getInfo()->inputFeatures.string().c_str(),
+ windowHandle->getInfo()->displayId);
+ return true;
+ }
+ return false;
}
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index db559df..4f6d0d2 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -143,7 +143,8 @@
void displayRemoved(int32_t displayId) override;
- void onWindowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos) override;
+ void onWindowInfosChanged(const std::vector<gui::WindowInfo>&,
+ const std::vector<gui::DisplayInfo>&) override;
private:
enum class DropReason {
@@ -171,7 +172,26 @@
std::shared_ptr<EventEntry> mPendingEvent GUARDED_BY(mLock);
std::deque<std::shared_ptr<EventEntry>> mInboundQueue GUARDED_BY(mLock);
std::deque<std::shared_ptr<EventEntry>> mRecentQueue GUARDED_BY(mLock);
- std::deque<std::unique_ptr<CommandEntry>> mCommandQueue GUARDED_BY(mLock);
+
+ // A command entry captures state and behavior for an action to be performed in the
+ // dispatch loop after the initial processing has taken place. It is essentially
+ // a kind of continuation used to postpone sensitive policy interactions to a point
+ // in the dispatch loop where it is safe to release the lock (generally after finishing
+ // the critical parts of the dispatch cycle).
+ //
+ // The special thing about commands is that they can voluntarily release and reacquire
+ // the dispatcher lock at will. Initially when the command starts running, the
+ // dispatcher lock is held. However, if the command needs to call into the policy to
+ // do some work, it can release the lock, do the work, then reacquire the lock again
+ // before returning.
+ //
+ // This mechanism is a bit clunky but it helps to preserve the invariant that the dispatch
+ // never calls into the policy while holding its lock.
+ //
+ // Commands are called with the lock held, but they can release and re-acquire the lock from
+ // within.
+ using Command = std::function<void()>;
+ std::deque<Command> mCommandQueue GUARDED_BY(mLock);
DropReason mLastDropReason GUARDED_BY(mLock);
@@ -215,7 +235,6 @@
sp<android::gui::WindowInfoHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x,
int32_t y, TouchState* touchState,
bool addOutsideTargets = false,
- bool addPortalWindows = false,
bool ignoreDragWindow = false)
REQUIRES(mLock);
@@ -296,8 +315,8 @@
// Deferred command processing.
bool haveCommandsLocked() const REQUIRES(mLock);
- bool runCommandsLockedInterruptible() REQUIRES(mLock);
- void postCommandLocked(std::unique_ptr<CommandEntry> commandEntry) REQUIRES(mLock);
+ bool runCommandsLockedInterruptable() REQUIRES(mLock);
+ void postCommandLocked(Command&& command) REQUIRES(mLock);
nsecs_t processAnrsLocked() REQUIRES(mLock);
std::chrono::nanoseconds getDispatchingTimeoutLocked(const sp<IBinder>& token) REQUIRES(mLock);
@@ -319,8 +338,10 @@
float mMaximumObscuringOpacityForTouch GUARDED_BY(mLock);
android::os::BlockUntrustedTouchesMode mBlockUntrustedTouchesMode GUARDED_BY(mLock);
- std::unordered_map<int32_t, std::vector<sp<android::gui::WindowInfoHandle>>>
+ std::unordered_map<int32_t /*displayId*/, std::vector<sp<android::gui::WindowInfoHandle>>>
mWindowHandlesByDisplay GUARDED_BY(mLock);
+ std::unordered_map<int32_t /*displayId*/, android::gui::DisplayInfo> mDisplayInfos
+ GUARDED_BY(mLock);
void setInputWindowsLocked(
const std::vector<sp<android::gui::WindowInfoHandle>>& inputWindowHandles,
int32_t displayId) REQUIRES(mLock);
@@ -343,6 +364,12 @@
bool hasResponsiveConnectionLocked(android::gui::WindowInfoHandle& windowHandle) const
REQUIRES(mLock);
+ // Gets all the input targets (with their respective input channels) from the window handles
+ // passed as argument.
+ std::vector<InputTarget> getInputTargetsFromWindowHandlesLocked(
+ const std::vector<sp<android::gui::WindowInfoHandle>>& windowHandles) const
+ REQUIRES(mLock);
+
/*
* Validate and update InputWindowHandles for a given display.
*/
@@ -405,9 +432,12 @@
void dispatchPointerCaptureChangedLocked(
nsecs_t currentTime, const std::shared_ptr<PointerCaptureChangedEntry>& entry,
DropReason& dropReason) REQUIRES(mLock);
+ void dispatchTouchModeChangeLocked(nsecs_t currentTime,
+ const std::shared_ptr<TouchModeEntry>& entry)
+ REQUIRES(mLock);
void dispatchEventLocked(nsecs_t currentTime, std::shared_ptr<EventEntry> entry,
const std::vector<InputTarget>& inputTargets) REQUIRES(mLock);
- void dispatchSensorLocked(nsecs_t currentTime, std::shared_ptr<SensorEntry> entry,
+ void dispatchSensorLocked(nsecs_t currentTime, const std::shared_ptr<SensorEntry>& entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) REQUIRES(mLock);
void dispatchDragLocked(nsecs_t currentTime, std::shared_ptr<DragEntry> entry) REQUIRES(mLock);
void logOutboundKeyDetails(const char* prefix, const KeyEntry& entry);
@@ -454,24 +484,11 @@
*/
void processConnectionResponsiveLocked(const Connection& connection) REQUIRES(mLock);
- /**
- * Post `doNotifyMonitorUnresponsiveLockedInterruptible` command.
- */
void sendMonitorUnresponsiveCommandLocked(int32_t pid, std::string reason) REQUIRES(mLock);
- /**
- * Post `doNotifyWindowUnresponsiveLockedInterruptible` command.
- */
- void sendWindowUnresponsiveCommandLocked(sp<IBinder> connectionToken, std::string reason)
+ void sendWindowUnresponsiveCommandLocked(const sp<IBinder>& connectionToken, std::string reason)
REQUIRES(mLock);
- /**
- * Post `doNotifyMonitorResponsiveLockedInterruptible` command.
- */
void sendMonitorResponsiveCommandLocked(int32_t pid) REQUIRES(mLock);
- /**
- * Post `doNotifyWindowResponsiveLockedInterruptible` command.
- */
- void sendWindowResponsiveCommandLocked(sp<IBinder> connectionToken) REQUIRES(mLock);
-
+ void sendWindowResponsiveCommandLocked(const sp<IBinder>& connectionToken) REQUIRES(mLock);
// Optimization: AnrTracker is used to quickly find which connection is due for a timeout next.
// AnrTracker must be kept in-sync with all responsive connection.waitQueues.
@@ -499,9 +516,7 @@
android::os::InputEventInjectionResult findTouchedWindowTargetsLocked(
nsecs_t currentTime, const MotionEntry& entry, std::vector<InputTarget>& inputTargets,
nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) REQUIRES(mLock);
- std::vector<TouchedMonitor> findTouchedGestureMonitorsLocked(
- int32_t displayId,
- const std::vector<sp<android::gui::WindowInfoHandle>>& portalWindows) const
+ std::vector<TouchedMonitor> findTouchedGestureMonitorsLocked(int32_t displayId) const
REQUIRES(mLock);
std::vector<TouchedMonitor> selectResponsiveMonitorsLocked(
const std::vector<TouchedMonitor>& gestureMonitors) const REQUIRES(mLock);
@@ -542,6 +557,10 @@
std::string getApplicationWindowLabel(const InputApplicationHandle* applicationHandle,
const sp<android::gui::WindowInfoHandle>& windowHandle);
+ bool shouldDropInput(const EventEntry& entry,
+ const sp<android::gui::WindowInfoHandle>& windowHandle) const
+ REQUIRES(mLock);
+
// Manage the dispatch cycle for a single connection.
// These methods are deliberately not Interruptible because doing all of the work
// with the mutex held makes it easier to ensure that connection invariants are maintained.
@@ -607,53 +626,30 @@
REQUIRES(mLock);
// Interesting events that we might like to log or tell the framework about.
- void onDispatchCycleFinishedLocked(nsecs_t currentTime, const sp<Connection>& connection,
- uint32_t seq, bool handled, nsecs_t consumeTime)
+ void doDispatchCycleFinishedCommand(nsecs_t finishTime, const sp<Connection>& connection,
+ uint32_t seq, bool handled, nsecs_t consumeTime)
REQUIRES(mLock);
- void onDispatchCycleBrokenLocked(nsecs_t currentTime, const sp<Connection>& connection)
- REQUIRES(mLock);
+ void doInterceptKeyBeforeDispatchingCommand(const sp<IBinder>& focusedWindowToken,
+ KeyEntry& entry) REQUIRES(mLock);
void onFocusChangedLocked(const FocusResolver::FocusChanges& changes) REQUIRES(mLock);
- void notifyFocusChangedLocked(const sp<IBinder>& oldFocus, const sp<IBinder>& newFocus)
+ void sendFocusChangedCommandLocked(const sp<IBinder>& oldToken, const sp<IBinder>& newToken)
REQUIRES(mLock);
- void notifyDropWindowLocked(const sp<IBinder>& token, float x, float y) REQUIRES(mLock);
+ void sendDropWindowCommandLocked(const sp<IBinder>& token, float x, float y) REQUIRES(mLock);
+ void sendUntrustedTouchCommandLocked(const std::string& obscuringPackage) REQUIRES(mLock);
void onAnrLocked(const sp<Connection>& connection) REQUIRES(mLock);
void onAnrLocked(std::shared_ptr<InputApplicationHandle> application) REQUIRES(mLock);
- void onUntrustedTouchLocked(const std::string& obscuringPackage) REQUIRES(mLock);
void updateLastAnrStateLocked(const sp<android::gui::WindowInfoHandle>& window,
const std::string& reason) REQUIRES(mLock);
void updateLastAnrStateLocked(const InputApplicationHandle& application,
const std::string& reason) REQUIRES(mLock);
void updateLastAnrStateLocked(const std::string& windowLabel, const std::string& reason)
REQUIRES(mLock);
-
- // Outbound policy interactions.
- void doNotifyConfigurationChangedLockedInterruptible(CommandEntry* commandEntry)
- REQUIRES(mLock);
- void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- void doNotifyFocusChangedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- void doNotifyDropWindowLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
-
- // ANR-related callbacks - start
- void doNotifyNoFocusedWindowAnrLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- void doNotifyWindowUnresponsiveLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- void doNotifyMonitorUnresponsiveLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- void doNotifyWindowResponsiveLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- void doNotifyMonitorResponsiveLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- // ANR-related callbacks - end
- void doNotifySensorLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- void doNotifyUntrustedTouchLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry)
- REQUIRES(mLock);
- void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- void doSetPointerCaptureLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- bool afterKeyEventLockedInterruptible(const sp<Connection>& connection,
+ bool afterKeyEventLockedInterruptable(const sp<Connection>& connection,
DispatchEntry* dispatchEntry, KeyEntry& keyEntry,
bool handled) REQUIRES(mLock);
- bool afterMotionEventLockedInterruptible(const sp<Connection>& connection,
+ bool afterMotionEventLockedInterruptable(const sp<Connection>& connection,
DispatchEntry* dispatchEntry, MotionEntry& motionEntry,
bool handled) REQUIRES(mLock);
- void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
- void doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
// Find touched state and touched window by token.
std::pair<TouchState*, TouchedWindow*> findTouchStateAndWindowLocked(const sp<IBinder>& token)
diff --git a/services/inputflinger/dispatcher/LatencyTracker.cpp b/services/inputflinger/dispatcher/LatencyTracker.cpp
index d634dcd..52f189c 100644
--- a/services/inputflinger/dispatcher/LatencyTracker.cpp
+++ b/services/inputflinger/dispatcher/LatencyTracker.cpp
@@ -50,13 +50,12 @@
* key-value pair. Equivalent to the imaginary std api std::multimap::erase(key, value).
*/
template <typename K, typename V>
-static void eraseByKeyAndValue(std::multimap<K, V>& map, K key, V value) {
- auto iterpair = map.equal_range(key);
-
- for (auto it = iterpair.first; it != iterpair.second; ++it) {
+static void eraseByValue(std::multimap<K, V>& map, const V& value) {
+ for (auto it = map.begin(); it != map.end();) {
if (it->second == value) {
- map.erase(it);
- break;
+ it = map.erase(it);
+ } else {
+ it++;
}
}
}
@@ -76,9 +75,7 @@
// confuse us by reporting the rest of the timeline for one of them. This should happen
// rarely, so we won't lose much data
mTimelines.erase(it);
- // In case we have another input event with a different id and at the same eventTime,
- // only erase this specific inputEventId.
- eraseByKeyAndValue(mEventTimes, eventTime, inputEventId);
+ eraseByValue(mEventTimes, inputEventId);
return;
}
mTimelines.emplace(inputEventId, InputEventTimeline(isDown, eventTime, readTime));
@@ -90,7 +87,8 @@
nsecs_t finishTime) {
const auto it = mTimelines.find(inputEventId);
if (it == mTimelines.end()) {
- // It's possible that an app sends a bad (or late)'Finish' signal, since it's free to do
+ // This could happen if we erased this event when duplicate events were detected. It's
+ // also possible that an app sent a bad (or late) 'Finish' signal, since it's free to do
// anything in its process. Just drop the report and move on.
return;
}
@@ -120,7 +118,8 @@
std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline) {
const auto it = mTimelines.find(inputEventId);
if (it == mTimelines.end()) {
- // It's possible that an app sends a bad (or late) 'Timeline' signal, since it's free to do
+ // This could happen if we erased this event when duplicate events were detected. It's
+ // also possible that an app sent a bad (or late) 'Timeline' signal, since it's free to do
// anything in its process. Just drop the report and move on.
return;
}
@@ -166,14 +165,6 @@
}
}
-void LatencyTracker::reportNow() {
- for (const auto& [inputEventId, timeline] : mTimelines) {
- mTimelineProcessor->processTimeline(timeline);
- }
- mTimelines.clear();
- mEventTimes.clear();
-}
-
std::string LatencyTracker::dump(const char* prefix) {
return StringPrintf("%sLatencyTracker:\n", prefix) +
StringPrintf("%s mTimelines.size() = %zu\n", prefix, mTimelines.size()) +
diff --git a/services/inputflinger/dispatcher/LatencyTracker.h b/services/inputflinger/dispatcher/LatencyTracker.h
index 289b8ed..4b0c618 100644
--- a/services/inputflinger/dispatcher/LatencyTracker.h
+++ b/services/inputflinger/dispatcher/LatencyTracker.h
@@ -43,6 +43,12 @@
LatencyTracker(InputEventTimelineProcessor* processor);
/**
* Start keeping track of an event identified by inputEventId. This must be called first.
+ * If duplicate events are encountered (events that have the same eventId), none of them will be
+ * tracked. This is because there is not enough information to correctly track them. The api's
+ * 'trackFinishedEvent' and 'trackGraphicsLatency' only contain the inputEventId, and not the
+ * eventTime. Even if eventTime was provided, there would still be a possibility of having
+ * duplicate events that happen to have the same eventTime and inputEventId. Therefore, we
+ * must drop all duplicate data.
*/
void trackListener(int32_t inputEventId, bool isDown, nsecs_t eventTime, nsecs_t readTime);
void trackFinishedEvent(int32_t inputEventId, const sp<IBinder>& connectionToken,
@@ -50,14 +56,6 @@
void trackGraphicsLatency(int32_t inputEventId, const sp<IBinder>& connectionToken,
std::array<nsecs_t, GraphicsTimeline::SIZE> timeline);
- /**
- * Report all collected events immediately, even if some of them are currently incomplete
- * and may receive 'trackFinishedEvent' or 'trackGraphicsLatency' calls in the future.
- * This is useful for tests. Otherwise, tests would have to inject additional "future" events,
- * which is not convenient.
- */
- void reportNow();
-
std::string dump(const char* prefix);
private:
diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp
index 20b6ead..4a50a68 100644
--- a/services/inputflinger/dispatcher/TouchState.cpp
+++ b/services/inputflinger/dispatcher/TouchState.cpp
@@ -37,7 +37,6 @@
source = 0;
displayId = ADISPLAY_ID_NONE;
windows.clear();
- portalWindows.clear();
gestureMonitors.clear();
}
@@ -48,7 +47,6 @@
source = other.source;
displayId = other.displayId;
windows = other.windows;
- portalWindows = other.portalWindows;
gestureMonitors = other.gestureMonitors;
}
@@ -77,16 +75,6 @@
windows.push_back(touchedWindow);
}
-void TouchState::addPortalWindow(const sp<android::gui::WindowInfoHandle>& windowHandle) {
- size_t numWindows = portalWindows.size();
- for (size_t i = 0; i < numWindows; i++) {
- if (portalWindows[i] == windowHandle) {
- return;
- }
- }
- portalWindows.push_back(windowHandle);
-}
-
void TouchState::addGestureMonitors(const std::vector<TouchedMonitor>& newMonitors) {
const size_t newSize = gestureMonitors.size() + newMonitors.size();
gestureMonitors.reserve(newSize);
@@ -119,7 +107,6 @@
void TouchState::filterNonMonitors() {
windows.clear();
- portalWindows.clear();
}
sp<WindowInfoHandle> TouchState::getFirstForegroundWindowHandle() const {
@@ -147,4 +134,14 @@
return haveSlipperyForegroundWindow;
}
+sp<WindowInfoHandle> TouchState::getWallpaperWindow() const {
+ for (size_t i = 0; i < windows.size(); i++) {
+ const TouchedWindow& window = windows[i];
+ if (window.windowHandle->getInfo()->type == WindowInfo::Type::WALLPAPER) {
+ return window.windowHandle;
+ }
+ }
+ return nullptr;
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h
index a4e52b0..7dcf55d 100644
--- a/services/inputflinger/dispatcher/TouchState.h
+++ b/services/inputflinger/dispatcher/TouchState.h
@@ -36,11 +36,6 @@
int32_t displayId; // id to the display that currently has a touch, others are rejected
std::vector<TouchedWindow> windows;
- // This collects the portal windows that the touch has gone through. Each portal window
- // targets a display (embedded display for most cases). With this info, we can add the
- // monitoring channels of the displays touched.
- std::vector<sp<android::gui::WindowInfoHandle>> portalWindows;
-
std::vector<TouchedMonitor> gestureMonitors;
TouchState();
@@ -56,6 +51,7 @@
void filterNonMonitors();
sp<android::gui::WindowInfoHandle> getFirstForegroundWindowHandle() const;
bool isSlippery() const;
+ sp<android::gui::WindowInfoHandle> getWallpaperWindow() const;
};
} // namespace inputdispatcher
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index a7dccf0..b74f304 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -202,6 +202,7 @@
* InputDispatcher is the source of truth of Pointer Capture.
*/
virtual void requestPointerCapture(const sp<IBinder>& windowToken, bool enabled) = 0;
+
/* Flush input device motion sensor.
*
* Returns true on success.
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 68d5e7c..d10f8b6 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -40,6 +40,7 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <cutils/properties.h>
+#include <ftl/enum.h>
#include <input/KeyCharacterMap.h>
#include <input/KeyLayoutMap.h>
#include <input/VirtualKeyMap.h>
@@ -263,7 +264,7 @@
*/
static std::vector<std::filesystem::path> findSysfsNodes(const std::filesystem::path& sysfsRoot,
SysfsClass clazz) {
- std::string nodeStr = NamedEnum::string(clazz);
+ std::string nodeStr = ftl::enum_string(clazz);
std::for_each(nodeStr.begin(), nodeStr.end(),
[](char& c) { c = std::tolower(static_cast<unsigned char>(c)); });
std::vector<std::filesystem::path> nodes;
@@ -1209,6 +1210,15 @@
return false;
}
+bool EventHub::hasKeyCode(int32_t deviceId, int32_t keyCode) const {
+ std::scoped_lock _l(mLock);
+ Device* device = getDeviceLocked(deviceId);
+ if (device != nullptr) {
+ return device->hasKeycodeLocked(keyCode);
+ }
+ return false;
+}
+
bool EventHub::hasLed(int32_t deviceId, int32_t led) const {
std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 1e9ec54..36344b5 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -559,7 +559,13 @@
}
void InputDevice::updateMetaState(int32_t keyCode) {
- for_each_mapper([keyCode](InputMapper& mapper) { mapper.updateMetaState(keyCode); });
+ first_in_mappers<bool>([keyCode](InputMapper& mapper) {
+ if (sourcesMatchMask(mapper.getSources(), AINPUT_SOURCE_KEYBOARD) &&
+ mapper.updateMetaState(keyCode)) {
+ return std::make_optional(true);
+ }
+ return std::optional<bool>();
+ });
}
void InputDevice::bumpGeneration() {
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 5120860..86d4c26 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -561,6 +561,7 @@
}
if (device->isIgnored()) {
+ ALOGW("Ignoring toggleCapsLock for ignored deviceId %" PRId32 ".", deviceId);
return;
}
diff --git a/services/inputflinger/reader/controller/PeripheralController.cpp b/services/inputflinger/reader/controller/PeripheralController.cpp
index 9c8a29a..a693496 100644
--- a/services/inputflinger/reader/controller/PeripheralController.cpp
+++ b/services/inputflinger/reader/controller/PeripheralController.cpp
@@ -17,9 +17,9 @@
#include <locale>
#include <regex>
-#include "../Macros.h"
+#include <ftl/enum.h>
-#include <ftl/NamedEnum.h>
+#include "../Macros.h"
#include "PeripheralController.h"
// Log detailed debug messages about input device lights.
@@ -286,7 +286,7 @@
for (const auto& [lightId, light] : mLights) {
dump += StringPrintf(INDENT4 "Id: %d", lightId);
dump += StringPrintf(INDENT4 "Name: %s", light->name.c_str());
- dump += StringPrintf(INDENT4 "Type: %s", NamedEnum::string(light->type).c_str());
+ dump += StringPrintf(INDENT4 "Type: %s", ftl::enum_string(light->type).c_str());
light->dump(dump);
}
}
@@ -487,7 +487,7 @@
auto& light = it->second;
if (DEBUG_LIGHT_DETAILS) {
ALOGD("setLightColor lightId %d type %s color 0x%x", lightId,
- NamedEnum::string(light->type).c_str(), color);
+ ftl::enum_string(light->type).c_str(), color);
}
return light->setLightColor(color);
}
@@ -501,7 +501,7 @@
std::optional<int32_t> color = light->getLightColor();
if (DEBUG_LIGHT_DETAILS) {
ALOGD("getLightColor lightId %d type %s color 0x%x", lightId,
- NamedEnum::string(light->type).c_str(), color.value_or(0));
+ ftl::enum_string(light->type).c_str(), color.value_or(0));
}
return color;
}
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 3c3f88e..1f96294 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -146,6 +146,8 @@
enum class SysfsClass : uint32_t {
POWER_SUPPLY = 0,
LEDS = 1,
+
+ ftl_last = LEDS
};
enum class LightColor : uint32_t {
@@ -312,6 +314,7 @@
uint8_t* outFlags) const = 0;
virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const = 0;
+ virtual bool hasKeyCode(int32_t deviceId, int32_t keyCode) const = 0;
/* LED related functions expect Android LED constants, not scan codes or HID usages */
virtual bool hasLed(int32_t deviceId, int32_t led) const = 0;
@@ -489,6 +492,7 @@
std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) override final;
bool hasScanCode(int32_t deviceId, int32_t scanCode) const override final;
+ bool hasKeyCode(int32_t deviceId, int32_t keyCode) const override final;
bool hasLed(int32_t deviceId, int32_t led) const override final;
void setLedState(int32_t deviceId, int32_t led, bool on) override final;
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index f32472d..518aaa0 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -323,6 +323,7 @@
inline bool hasScanCode(int32_t scanCode) const {
return mEventHub->hasScanCode(mId, scanCode);
}
+ inline bool hasKeyCode(int32_t keyCode) const { return mEventHub->hasKeyCode(mId, keyCode); }
inline bool hasLed(int32_t led) const { return mEventHub->hasLed(mId, led); }
inline void setLedState(int32_t led, bool on) { return mEventHub->setLedState(mId, led, on); }
inline void getVirtualKeyDefinitions(std::vector<VirtualKeyDefinition>& outVirtualKeys) const {
diff --git a/services/inputflinger/reader/mapper/InputMapper.cpp b/services/inputflinger/reader/mapper/InputMapper.cpp
index df1acd4..b9aef54 100644
--- a/services/inputflinger/reader/mapper/InputMapper.cpp
+++ b/services/inputflinger/reader/mapper/InputMapper.cpp
@@ -84,7 +84,9 @@
return 0;
}
-void InputMapper::updateMetaState(int32_t keyCode) {}
+bool InputMapper::updateMetaState(int32_t keyCode) {
+ return false;
+}
void InputMapper::updateExternalStylusState(const StylusState& state) {}
diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h
index 15cff1c..d9adc0f 100644
--- a/services/inputflinger/reader/mapper/InputMapper.h
+++ b/services/inputflinger/reader/mapper/InputMapper.h
@@ -83,7 +83,11 @@
virtual std::optional<int32_t> getLightPlayerId(int32_t lightId) { return std::nullopt; }
virtual int32_t getMetaState();
- virtual void updateMetaState(int32_t keyCode);
+ /**
+ * Process the meta key and update the global meta state when changed.
+ * Return true if the meta key could be handled by the InputMapper.
+ */
+ virtual bool updateMetaState(int32_t keyCode);
virtual void updateExternalStylusState(const StylusState& state);
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 104d087..52af38d 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -384,8 +384,13 @@
return mMetaState;
}
-void KeyboardInputMapper::updateMetaState(int32_t keyCode) {
+bool KeyboardInputMapper::updateMetaState(int32_t keyCode) {
+ if (!android::isMetaKey(keyCode) || !getDeviceContext().hasKeyCode(keyCode)) {
+ return false;
+ }
+
updateMetaStateIfNeeded(keyCode, false);
+ return true;
}
bool KeyboardInputMapper::updateMetaStateIfNeeded(int32_t keyCode, bool down) {
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
index ca41712..fc92320 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.h
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
@@ -40,7 +40,7 @@
const int32_t* keyCodes, uint8_t* outFlags) override;
virtual int32_t getMetaState() override;
- virtual void updateMetaState(int32_t keyCode) override;
+ virtual bool updateMetaState(int32_t keyCode) override;
virtual std::optional<int32_t> getAssociatedDisplayId() override;
virtual void updateLedState(bool reset);
diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.cpp b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
index a507632..a1bd548 100644
--- a/services/inputflinger/reader/mapper/SensorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
@@ -16,8 +16,9 @@
#include <locale>
-#include "../Macros.h"
+#include <ftl/enum.h>
+#include "../Macros.h"
#include "SensorInputMapper.h"
// Log detailed debug messages about each sensor event notification to the dispatcher.
@@ -93,7 +94,7 @@
dump += StringPrintf(INDENT3 " mHasHardwareTimestamp %d\n", mHasHardwareTimestamp);
dump += INDENT3 "Sensors:\n";
for (const auto& [sensorType, sensor] : mSensors) {
- dump += StringPrintf(INDENT4 "%s\n", NamedEnum::string(sensorType).c_str());
+ dump += StringPrintf(INDENT4 "%s\n", ftl::enum_string(sensorType).c_str());
dump += StringPrintf(INDENT5 "enabled: %d\n", sensor.enabled);
dump += StringPrintf(INDENT5 "samplingPeriod: %lld\n", sensor.samplingPeriod.count());
dump += StringPrintf(INDENT5 "maxBatchReportLatency: %lld\n",
@@ -208,10 +209,10 @@
axis.max /* maxRange */, axis.scale /* resolution */,
0.0f /* power */, 0 /* minDelay */,
0 /* fifoReservedEventCount */, 0 /* fifoMaxEventCount */,
- NamedEnum::string(sensorType), 0 /* maxDelay */, 0 /* flags */,
+ ftl::enum_string(sensorType), 0 /* maxDelay */, 0 /* flags */,
getDeviceId());
- std::string prefix = "sensor." + NamedEnum::string(sensorType);
+ std::string prefix = "sensor." + ftl::enum_string(sensorType);
transform(prefix.begin(), prefix.end(), prefix.begin(), ::tolower);
int32_t reportingMode = 0;
@@ -335,7 +336,7 @@
std::chrono::microseconds maxBatchReportLatency) {
if (DEBUG_SENSOR_EVENT_DETAILS) {
ALOGD("Enable Sensor %s samplingPeriod %lld maxBatchReportLatency %lld",
- NamedEnum::string(sensorType).c_str(), samplingPeriod.count(),
+ ftl::enum_string(sensorType).c_str(), samplingPeriod.count(),
maxBatchReportLatency.count());
}
@@ -359,7 +360,7 @@
void SensorInputMapper::disableSensor(InputDeviceSensorType sensorType) {
if (DEBUG_SENSOR_EVENT_DETAILS) {
- ALOGD("Disable Sensor %s", NamedEnum::string(sensorType).c_str());
+ ALOGD("Disable Sensor %s", ftl::enum_string(sensorType).c_str());
}
if (!setSensorEnabled(sensorType, false /* enabled */)) {
@@ -393,13 +394,12 @@
nsecs_t timestamp = mHasHardwareTimestamp ? mHardwareTimestamp : when;
if (DEBUG_SENSOR_EVENT_DETAILS) {
ALOGD("Sensor %s timestamp %" PRIu64 " values [%f %f %f]",
- NamedEnum::string(sensorType).c_str(), timestamp, values[0], values[1],
- values[2]);
+ ftl::enum_string(sensorType).c_str(), timestamp, values[0], values[1], values[2]);
}
if (sensor.lastSampleTimeNs.has_value() &&
timestamp - sensor.lastSampleTimeNs.value() < sensor.samplingPeriod.count()) {
if (DEBUG_SENSOR_EVENT_DETAILS) {
- ALOGD("Sensor %s Skip a sample.", NamedEnum::string(sensorType).c_str());
+ ALOGD("Sensor %s Skip a sample.", ftl::enum_string(sensorType).c_str());
}
} else {
// Convert to Android unit
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index ac5f6b6..419b0d0 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -18,9 +18,10 @@
#include "../Macros.h"
// clang-format on
-#include <ftl/NamedEnum.h>
#include "TouchInputMapper.h"
+#include <ftl/enum.h>
+
#include "CursorButtonAccumulator.h"
#include "CursorScrollAccumulator.h"
#include "TouchButtonAccumulator.h"
@@ -259,7 +260,7 @@
void TouchInputMapper::dump(std::string& dump) {
dump += StringPrintf(INDENT2 "Touch Input Mapper (mode - %s):\n",
- NamedEnum::string(mDeviceMode).c_str());
+ ftl::enum_string(mDeviceMode).c_str());
dumpParameters(dump);
dumpVirtualKeys(dump);
dumpRawPointerAxes(dump);
@@ -515,9 +516,9 @@
void TouchInputMapper::dumpParameters(std::string& dump) {
dump += INDENT3 "Parameters:\n";
- dump += INDENT4 "GestureMode: " + NamedEnum::string(mParameters.gestureMode) + "\n";
+ dump += INDENT4 "GestureMode: " + ftl::enum_string(mParameters.gestureMode) + "\n";
- dump += INDENT4 "DeviceType: " + NamedEnum::string(mParameters.deviceType) + "\n";
+ dump += INDENT4 "DeviceType: " + ftl::enum_string(mParameters.deviceType) + "\n";
dump += StringPrintf(INDENT4 "AssociatedDisplay: hasAssociatedDisplay=%s, isExternal=%s, "
"displayId='%s'\n",
@@ -525,7 +526,7 @@
toString(mParameters.associatedDisplayIsExternal),
mParameters.uniqueDisplayId.c_str());
dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware));
- dump += INDENT4 "Orientation: " + NamedEnum::string(mParameters.orientation) + "\n";
+ dump += INDENT4 "Orientation: " + ftl::enum_string(mParameters.orientation) + "\n";
}
void TouchInputMapper::configureRawPointerAxes() {
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index e104220..a56468f 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -185,6 +185,8 @@
UNSCALED, // unscaled mapping (touchpad)
NAVIGATION, // unscaled mapping with assist gesture (touch navigation)
POINTER, // pointer mapping (pointer)
+
+ ftl_last = POINTER
};
DeviceMode mDeviceMode;
@@ -198,6 +200,8 @@
TOUCH_PAD,
TOUCH_NAVIGATION,
POINTER,
+
+ ftl_last = POINTER
};
DeviceType deviceType;
@@ -210,6 +214,8 @@
ORIENTATION_90 = DISPLAY_ORIENTATION_90,
ORIENTATION_180 = DISPLAY_ORIENTATION_180,
ORIENTATION_270 = DISPLAY_ORIENTATION_270,
+
+ ftl_last = ORIENTATION_270
};
Orientation orientation;
@@ -219,6 +225,8 @@
enum class GestureMode {
SINGLE_TOUCH,
MULTI_TOUCH,
+
+ ftl_last = MULTI_TOUCH
};
GestureMode gestureMode;
@@ -818,4 +826,4 @@
} // namespace android
-#endif // _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H
\ No newline at end of file
+#endif // _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 912e840..903f337 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -16,6 +16,7 @@
#include "../dispatcher/InputDispatcher.h"
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/thread_annotations.h>
#include <binder/Binder.h>
@@ -73,6 +74,12 @@
return event;
}
+static void assertMotionAction(int32_t expectedAction, int32_t receivedAction) {
+ ASSERT_EQ(expectedAction, receivedAction)
+ << "expected " << MotionEvent::actionToString(expectedAction) << ", got "
+ << MotionEvent::actionToString(receivedAction);
+}
+
// --- FakeInputDispatcherPolicy ---
class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface {
@@ -683,7 +690,11 @@
// --- InputDispatcherTest SetInputWindowTest ---
static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 500ms;
-static constexpr std::chrono::nanoseconds DISPATCHING_TIMEOUT = 5s;
+// Default input dispatching timeout if there is no focused application or paused window
+// from which to determine an appropriate dispatching timeout.
+static const std::chrono::duration DISPATCHING_TIMEOUT = std::chrono::milliseconds(
+ android::os::IInputConstants::UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS *
+ android::base::HwTimeoutMultiplier());
class FakeApplicationHandle : public InputApplicationHandle {
public:
@@ -796,7 +807,8 @@
}
case AINPUT_EVENT_TYPE_MOTION: {
const MotionEvent& motionEvent = static_cast<const MotionEvent&>(*event);
- EXPECT_EQ(expectedAction, motionEvent.getAction());
+ assertMotionAction(expectedAction, motionEvent.getAction());
+
if (expectedFlags.has_value()) {
EXPECT_EQ(expectedFlags.value(), motionEvent.getFlags());
}
@@ -977,6 +989,10 @@
mInfo.addTouchableRegion(frame);
}
+ void setType(WindowInfo::Type type) { mInfo.type = type; }
+
+ void setHasWallpaper(bool hasWallpaper) { mInfo.hasWallpaper = hasWallpaper; }
+
void addFlags(Flags<WindowInfo::Flag> flags) { mInfo.flags |= flags; }
void setFlags(Flags<WindowInfo::Flag> flags) { mInfo.flags = flags; }
@@ -1480,6 +1496,197 @@
windowSecond->assertNoEvents();
}
+/**
+ * Two windows: A top window, and a wallpaper behind the window.
+ * Touch goes to the top window, and then top window disappears. Ensure that wallpaper window
+ * gets ACTION_CANCEL.
+ * 1. foregroundWindow <-- has wallpaper (hasWallpaper=true)
+ * 2. wallpaperWindow <-- is wallpaper (type=InputWindowInfo::Type::WALLPAPER)
+ */
+TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCanceled) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> foregroundWindow =
+ new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
+ foregroundWindow->setHasWallpaper(true);
+ sp<FakeWindowHandle> wallpaperWindow =
+ new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
+ wallpaperWindow->setType(WindowInfo::Type::WALLPAPER);
+ constexpr int expectedWallpaperFlags =
+ AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {foregroundWindow, wallpaperWindow}}});
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {100, 200}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ // Both foreground window and its wallpaper should receive the touch down
+ foregroundWindow->consumeMotionDown();
+ wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {110, 200}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ foregroundWindow->consumeMotionMove();
+ wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
+
+ // Now the foreground window goes away, but the wallpaper stays
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wallpaperWindow}}});
+ foregroundWindow->consumeMotionCancel();
+ // Since the "parent" window of the wallpaper is gone, wallpaper should receive cancel, too.
+ wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
+}
+
+/**
+ * A single window that receives touch (on top), and a wallpaper window underneath it.
+ * The top window gets a multitouch gesture.
+ * Ensure that wallpaper gets the same gesture.
+ */
+TEST_F(InputDispatcherTest, WallpaperWindow_ReceivesMultiTouch) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
+ window->setHasWallpaper(true);
+
+ sp<FakeWindowHandle> wallpaperWindow =
+ new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
+ wallpaperWindow->setType(WindowInfo::Type::WALLPAPER);
+ constexpr int expectedWallpaperFlags =
+ AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, wallpaperWindow}}});
+
+ // Touch down on top window
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {100, 100}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ // Both top window and its wallpaper should receive the touch down
+ window->consumeMotionDown();
+ wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
+
+ // Second finger down on the top window
+ const MotionEvent secondFingerDownEvent =
+ MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
+ (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ AINPUT_SOURCE_TOUCHSCREEN)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
+ .x(100)
+ .y(100))
+ .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER)
+ .x(150)
+ .y(150))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ window->consumeMotionPointerDown(1 /* pointerIndex */);
+ wallpaperWindow->consumeMotionPointerDown(1 /* pointerIndex */, ADISPLAY_ID_DEFAULT,
+ expectedWallpaperFlags);
+ window->assertNoEvents();
+ wallpaperWindow->assertNoEvents();
+}
+
+/**
+ * Two windows: a window on the left and window on the right.
+ * A third window, wallpaper, is behind both windows, and spans both top windows.
+ * The first touch down goes to the left window. A second pointer touches down on the right window.
+ * The touch is split, so both left and right windows should receive ACTION_DOWN.
+ * The wallpaper will get the full event, so it should receive ACTION_DOWN followed by
+ * ACTION_POINTER_DOWN(1).
+ */
+TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> leftWindow =
+ new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
+ leftWindow->setFrame(Rect(0, 0, 200, 200));
+ leftWindow->setFlags(WindowInfo::Flag::SPLIT_TOUCH | WindowInfo::Flag::NOT_TOUCH_MODAL);
+ leftWindow->setHasWallpaper(true);
+
+ sp<FakeWindowHandle> rightWindow =
+ new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
+ rightWindow->setFrame(Rect(200, 0, 400, 200));
+ rightWindow->setFlags(WindowInfo::Flag::SPLIT_TOUCH | WindowInfo::Flag::NOT_TOUCH_MODAL);
+ rightWindow->setHasWallpaper(true);
+
+ sp<FakeWindowHandle> wallpaperWindow =
+ new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
+ wallpaperWindow->setFrame(Rect(0, 0, 400, 200));
+ wallpaperWindow->setType(WindowInfo::Type::WALLPAPER);
+ constexpr int expectedWallpaperFlags =
+ AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
+
+ mDispatcher->setInputWindows(
+ {{ADISPLAY_ID_DEFAULT, {leftWindow, rightWindow, wallpaperWindow}}});
+
+ // Touch down on left window
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {100, 100}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ // Both foreground window and its wallpaper should receive the touch down
+ leftWindow->consumeMotionDown();
+ wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
+
+ // Second finger down on the right window
+ const MotionEvent secondFingerDownEvent =
+ MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
+ (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ AINPUT_SOURCE_TOUCHSCREEN)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
+ .x(100)
+ .y(100))
+ .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER)
+ .x(300)
+ .y(100))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ leftWindow->consumeMotionMove();
+ // Since the touch is split, right window gets ACTION_DOWN
+ rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ wallpaperWindow->consumeMotionPointerDown(1 /* pointerIndex */, ADISPLAY_ID_DEFAULT,
+ expectedWallpaperFlags);
+
+ // Now, leftWindow, which received the first finger, disappears.
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {rightWindow, wallpaperWindow}}});
+ leftWindow->consumeMotionCancel();
+ // Since a "parent" window of the wallpaper is gone, wallpaper should receive cancel, too.
+ wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
+
+ // The pointer that's still down on the right window moves, and goes to the right window only.
+ // As far as the dispatcher's concerned though, both pointers are still present.
+ const MotionEvent secondFingerMoveEvent =
+ MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
+ .x(100)
+ .y(100))
+ .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER)
+ .x(310)
+ .y(110))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT));
+ rightWindow->consumeMotionMove();
+
+ leftWindow->assertNoEvents();
+ rightWindow->assertNoEvents();
+ wallpaperWindow->assertNoEvents();
+}
+
TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> windowLeft =
@@ -2296,11 +2503,21 @@
expectedDisplayId, expectedFlags);
}
+ void consumeMotionMove(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
+ mInputReceiver->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_MOVE,
+ expectedDisplayId, expectedFlags);
+ }
+
void consumeMotionUp(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
mInputReceiver->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_UP,
expectedDisplayId, expectedFlags);
}
+ void consumeMotionCancel(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
+ mInputReceiver->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL,
+ expectedDisplayId, expectedFlags);
+ }
+
MotionEvent* consumeMotion() {
InputEvent* event = mInputReceiver->consume();
if (!event) {
@@ -2320,6 +2537,57 @@
std::unique_ptr<FakeInputReceiver> mInputReceiver;
};
+/**
+ * Two entities that receive touch: A window, and a global monitor.
+ * The touch goes to the window, and then the window disappears.
+ * The monitor does not get cancel right away. But if more events come in, the touch gets canceled
+ * for the monitor, as well.
+ * 1. foregroundWindow
+ * 2. monitor <-- global monitor (doesn't observe z order, receives all events)
+ */
+TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_GlobalMonitorTouchIsCanceled) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
+
+ FakeMonitorReceiver monitor =
+ FakeMonitorReceiver(mDispatcher, "GlobalMonitor", ADISPLAY_ID_DEFAULT,
+ false /*isGestureMonitor*/);
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {100, 200}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ // Both the foreground window and the global monitor should receive the touch down
+ window->consumeMotionDown();
+ monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {110, 200}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ window->consumeMotionMove();
+ monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
+
+ // Now the foreground window goes away
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {}}});
+ window->consumeMotionCancel();
+ monitor.assertNoEvents(); // Global monitor does not get a cancel yet
+
+ // If more events come in, there will be no more foreground window to send them to. This will
+ // cause a cancel for the monitor, as well.
+ ASSERT_EQ(InputEventInjectionResult::FAILED,
+ injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {120, 200}))
+ << "Injection should fail because the window was removed";
+ window->assertNoEvents();
+ // Global monitor now gets the cancel
+ monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
+}
+
// Tests for gesture monitors
TEST_F(InputDispatcherTest, GestureMonitor_ReceivesMotionEvents) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
@@ -3562,7 +3830,7 @@
<< " event, got " << inputEventTypeToString(event->getType()) << " event";
const MotionEvent& motionEvent = static_cast<const MotionEvent&>(*event);
- EXPECT_EQ(expectedAction, motionEvent.getAction());
+ assertMotionAction(expectedAction, motionEvent.getAction());
for (size_t i = 0; i < points.size(); i++) {
float expectedX = points[i].x;
@@ -5466,4 +5734,134 @@
mSecondWindow->assertNoEvents();
}
+class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};
+
+TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+ window->setInputFeatures(WindowInfo::Feature::DROP_INPUT);
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+ window->setFocusable(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ setFocusedWindow(window);
+ window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);
+
+ // With the flag set, window should not get any input
+ NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyKey(&keyArgs);
+ window->assertNoEvents();
+
+ NotifyMotionArgs motionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&motionArgs);
+ window->assertNoEvents();
+
+ // With the flag cleared, the window should get input
+ window->setInputFeatures({});
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+
+ keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyKey(&keyArgs);
+ window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
+
+ motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&motionArgs);
+ window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ window->assertNoEvents();
+}
+
+TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) {
+ std::shared_ptr<FakeApplicationHandle> obscuringApplication =
+ std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> obscuringWindow =
+ new FakeWindowHandle(obscuringApplication, mDispatcher, "obscuringWindow",
+ ADISPLAY_ID_DEFAULT);
+ obscuringWindow->setFrame(Rect(0, 0, 50, 50));
+ obscuringWindow->setOwnerInfo(111, 111);
+ obscuringWindow->setFlags(WindowInfo::Flag::NOT_TOUCHABLE);
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+ window->setInputFeatures(WindowInfo::Feature::DROP_INPUT_IF_OBSCURED);
+ window->setOwnerInfo(222, 222);
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+ window->setFocusable(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}});
+ setFocusedWindow(window);
+ window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);
+
+ // With the flag set, window should not get any input
+ NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyKey(&keyArgs);
+ window->assertNoEvents();
+
+ NotifyMotionArgs motionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&motionArgs);
+ window->assertNoEvents();
+
+ // With the flag cleared, the window should get input
+ window->setInputFeatures({});
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}});
+
+ keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyKey(&keyArgs);
+ window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
+
+ motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&motionArgs);
+ window->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
+ window->assertNoEvents();
+}
+
+TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) {
+ std::shared_ptr<FakeApplicationHandle> obscuringApplication =
+ std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> obscuringWindow =
+ new FakeWindowHandle(obscuringApplication, mDispatcher, "obscuringWindow",
+ ADISPLAY_ID_DEFAULT);
+ obscuringWindow->setFrame(Rect(0, 0, 50, 50));
+ obscuringWindow->setOwnerInfo(111, 111);
+ obscuringWindow->setFlags(WindowInfo::Flag::NOT_TOUCHABLE);
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+ window->setInputFeatures(WindowInfo::Feature::DROP_INPUT_IF_OBSCURED);
+ window->setOwnerInfo(222, 222);
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+ window->setFocusable(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}});
+ setFocusedWindow(window);
+ window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);
+
+ // With the flag set, window should not get any input
+ NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyKey(&keyArgs);
+ window->assertNoEvents();
+
+ NotifyMotionArgs motionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&motionArgs);
+ window->assertNoEvents();
+
+ // When the window is no longer obscured because it went on top, it should get input
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, obscuringWindow}}});
+
+ keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyKey(&keyArgs);
+ window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
+
+ motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&motionArgs);
+ window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ window->assertNoEvents();
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index b419d9a..5c430f5 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -205,7 +205,7 @@
std::condition_variable mDevicesChangedCondition;
InputReaderConfiguration mConfig;
- std::unordered_map<int32_t, std::shared_ptr<FakePointerController>> mPointerControllers;
+ std::shared_ptr<FakePointerController> mPointerController;
std::vector<InputDeviceInfo> mInputDevices GUARDED_BY(mLock);
bool mInputDevicesChanged GUARDED_BY(mLock){false};
std::vector<DisplayViewport> mViewports;
@@ -291,8 +291,8 @@
void removeDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.erase(deviceId); }
- void setPointerController(int32_t deviceId, std::shared_ptr<FakePointerController> controller) {
- mPointerControllers.insert_or_assign(deviceId, std::move(controller));
+ void setPointerController(std::shared_ptr<FakePointerController> controller) {
+ mPointerController = std::move(controller);
}
const InputReaderConfiguration* getReaderConfiguration() const {
@@ -360,8 +360,9 @@
*outConfig = mConfig;
}
- std::shared_ptr<PointerControllerInterface> obtainPointerController(int32_t deviceId) override {
- return mPointerControllers[deviceId];
+ std::shared_ptr<PointerControllerInterface> obtainPointerController(
+ int32_t /*deviceId*/) override {
+ return mPointerController;
}
void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override {
@@ -873,6 +874,24 @@
return false;
}
+ bool hasKeyCode(int32_t deviceId, int32_t keyCode) const override {
+ Device* device = getDevice(deviceId);
+ if (!device) {
+ return false;
+ }
+ for (size_t i = 0; i < device->keysByScanCode.size(); i++) {
+ if (keyCode == device->keysByScanCode.valueAt(i).keyCode) {
+ return true;
+ }
+ }
+ for (size_t j = 0; j < device->keysByUsageCode.size(); j++) {
+ if (keyCode == device->keysByUsageCode.valueAt(j).keyCode) {
+ return true;
+ }
+ }
+ return false;
+ }
+
bool hasLed(int32_t deviceId, int32_t led) const override {
Device* device = getDevice(deviceId);
return device && device->leds.indexOfKey(led) >= 0;
@@ -2135,8 +2154,12 @@
sp<FakeInputReaderPolicy> mFakePolicy;
sp<InputReaderInterface> mReader;
+ std::shared_ptr<FakePointerController> mFakePointerController;
+
void SetUp() override {
mFakePolicy = new FakeInputReaderPolicy();
+ mFakePointerController = std::make_shared<FakePointerController>();
+ mFakePolicy->setPointerController(mFakePointerController);
mTestListener = new TestInputListener(2000ms /*eventHappenedTimeout*/,
30ms /*eventDidNotHappenTimeout*/);
@@ -3732,6 +3755,25 @@
mapper2.getMetaState());
}
+TEST_F(KeyboardInputMapperTest, Process_toggleCapsLockState) {
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_CAPSLOCK, 0, AKEYCODE_CAPS_LOCK, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_NUMLOCK, 0, AKEYCODE_NUM_LOCK, 0);
+ mFakeEventHub->addKey(EVENTHUB_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0);
+
+ // Suppose we have two mappers. (DPAD + KEYBOARD)
+ addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_DPAD,
+ AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC);
+ KeyboardInputMapper& mapper =
+ addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+ // Initialize metastate to AMETA_NUM_LOCK_ON.
+ ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper.getMetaState());
+ mapper.updateMetaState(AKEYCODE_NUM_LOCK);
+
+ mReader->toggleCapsLockState(DEVICE_ID);
+ ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper.getMetaState());
+}
+
// --- KeyboardInputMapperTest_ExternalDevice ---
class KeyboardInputMapperTest_ExternalDevice : public InputMapperTest {
@@ -3828,7 +3870,7 @@
InputMapperTest::SetUp();
mFakePointerController = std::make_shared<FakePointerController>();
- mFakePolicy->setPointerController(mDevice->getId(), mFakePointerController);
+ mFakePolicy->setPointerController(mFakePointerController);
}
void testMotionRotation(CursorInputMapper& mapper, int32_t originalX, int32_t originalY,
@@ -7793,7 +7835,7 @@
fakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
fakePointerController->setPosition(100, 200);
fakePointerController->setButtonState(0);
- mFakePolicy->setPointerController(mDevice->getId(), fakePointerController);
+ mFakePolicy->setPointerController(fakePointerController);
mFakePolicy->setDefaultPointerDisplayId(SECONDARY_DISPLAY_ID);
prepareSecondaryDisplay(ViewportType::EXTERNAL);
@@ -7946,8 +7988,7 @@
// Setup PointerController.
std::shared_ptr<FakePointerController> fakePointerController =
std::make_shared<FakePointerController>();
- mFakePolicy->setPointerController(mDevice->getId(), fakePointerController);
- mFakePolicy->setPointerController(SECOND_DEVICE_ID, fakePointerController);
+ mFakePolicy->setPointerController(fakePointerController);
// Setup policy for associated displays and show touches.
const uint8_t hdmi1 = 0;
@@ -8769,7 +8810,7 @@
mFakeEventHub->addKey(EVENTHUB_ID, BTN_LEFT, 0, AKEYCODE_UNKNOWN, 0);
mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0);
mFakePolicy->setPointerCapture(true);
- mFakePolicy->setPointerController(mDevice->getId(), fakePointerController);
+ mFakePolicy->setPointerController(fakePointerController);
MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
// captured touchpad should be a touchpad source
@@ -8919,7 +8960,7 @@
prepareAxes(POSITION | ID | SLOT);
mFakeEventHub->addKey(EVENTHUB_ID, BTN_LEFT, 0, AKEYCODE_UNKNOWN, 0);
mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0);
- mFakePolicy->setPointerController(mDevice->getId(), fakePointerController);
+ mFakePolicy->setPointerController(fakePointerController);
MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
// run uncaptured pointer tests - pushes out generic events
// FINGER 0 DOWN
@@ -8959,7 +9000,7 @@
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | ID | SLOT);
mFakeEventHub->addKey(EVENTHUB_ID, BTN_LEFT, 0, AKEYCODE_UNKNOWN, 0);
- mFakePolicy->setPointerController(mDevice->getId(), fakePointerController);
+ mFakePolicy->setPointerController(fakePointerController);
mFakePolicy->setPointerCapture(false);
MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
diff --git a/services/inputflinger/tests/LatencyTracker_test.cpp b/services/inputflinger/tests/LatencyTracker_test.cpp
index e7e1937..89c0741 100644
--- a/services/inputflinger/tests/LatencyTracker_test.cpp
+++ b/services/inputflinger/tests/LatencyTracker_test.cpp
@@ -16,6 +16,7 @@
#include "../dispatcher/LatencyTracker.h"
+#include <android-base/properties.h>
#include <binder/Binder.h>
#include <gtest/gtest.h>
#include <inttypes.h>
@@ -23,11 +24,16 @@
#define TAG "LatencyTracker_test"
+using android::base::HwTimeoutMultiplier;
using android::inputdispatcher::InputEventTimeline;
using android::inputdispatcher::LatencyTracker;
namespace android::inputdispatcher {
+const std::chrono::duration ANR_TIMEOUT = std::chrono::milliseconds(
+ android::os::IInputConstants::UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS *
+ HwTimeoutMultiplier());
+
InputEventTimeline getTestTimeline() {
InputEventTimeline t(
/*isDown*/ true,
@@ -57,6 +63,8 @@
}
void TearDown() override {}
+ void triggerEventReporting(nsecs_t lastEventTime);
+
void assertReceivedTimeline(const InputEventTimeline& timeline);
/**
* Timelines can be received in any order (order is not guaranteed). So if we are expecting more
@@ -72,8 +80,17 @@
std::deque<InputEventTimeline> mReceivedTimelines;
};
+/**
+ * Send an event that would trigger the reporting of all of the events that are at least as old as
+ * the provided 'lastEventTime'.
+ */
+void LatencyTrackerTest::triggerEventReporting(nsecs_t lastEventTime) {
+ const nsecs_t triggerEventTime =
+ lastEventTime + std::chrono::nanoseconds(ANR_TIMEOUT).count() + 1;
+ mTracker->trackListener(1 /*inputEventId*/, true /*isDown*/, triggerEventTime, 3 /*readTime*/);
+}
+
void LatencyTrackerTest::assertReceivedTimeline(const InputEventTimeline& timeline) {
- mTracker->reportNow();
ASSERT_FALSE(mReceivedTimelines.empty());
const InputEventTimeline& t = mReceivedTimelines.front();
ASSERT_EQ(timeline, t);
@@ -88,7 +105,6 @@
* equal element in B, and for every element in B there is an equal element in A.
*/
void LatencyTrackerTest::assertReceivedTimelines(const std::vector<InputEventTimeline>& timelines) {
- mTracker->reportNow();
ASSERT_EQ(timelines.size(), mReceivedTimelines.size());
for (const InputEventTimeline& expectedTimeline : timelines) {
bool found = false;
@@ -121,6 +137,7 @@
*/
TEST_F(LatencyTrackerTest, TrackListener_DoesNotTriggerReporting) {
mTracker->trackListener(1 /*inputEventId*/, false /*isDown*/, 2 /*eventTime*/, 3 /*readTime*/);
+ triggerEventReporting(2 /*eventTime*/);
assertReceivedTimeline(InputEventTimeline{false, 2, 3});
}
@@ -130,6 +147,7 @@
TEST_F(LatencyTrackerTest, TrackFinishedEvent_DoesNotTriggerReporting) {
mTracker->trackFinishedEvent(1 /*inputEventId*/, connection1, 2 /*deliveryTime*/,
3 /*consumeTime*/, 4 /*finishTime*/);
+ triggerEventReporting(4 /*eventTime*/);
assertReceivedTimelines({});
}
@@ -141,6 +159,7 @@
graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 2;
graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 3;
mTracker->trackGraphicsLatency(1 /*inputEventId*/, connection2, graphicsTimeline);
+ triggerEventReporting(3 /*eventTime*/);
assertReceivedTimelines({});
}
@@ -155,9 +174,30 @@
expectedCT.consumeTime, expectedCT.finishTime);
mTracker->trackGraphicsLatency(inputEventId, connectionToken, expectedCT.graphicsTimeline);
+ triggerEventReporting(expected.eventTime);
assertReceivedTimeline(expected);
}
+/**
+ * Send 2 events with the same inputEventId, but different eventTime's. Ensure that no crash occurs,
+ * and that the tracker drops such events completely.
+ */
+TEST_F(LatencyTrackerTest, WhenDuplicateEventsAreReported_DoesNotCrash) {
+ constexpr nsecs_t inputEventId = 1;
+ constexpr nsecs_t readTime = 3; // does not matter for this test
+ constexpr bool isDown = true; // does not matter for this test
+
+ // In the following 2 calls to trackListener, the inputEventId's are the same, but event times
+ // are different.
+ mTracker->trackListener(inputEventId, isDown, 1 /*eventTime*/, readTime);
+ mTracker->trackListener(inputEventId, isDown, 2 /*eventTime*/, readTime);
+
+ triggerEventReporting(2 /*eventTime*/);
+ // Since we sent duplicate input events, the tracker should just delete all of them, because it
+ // does not have enough information to properly track them.
+ assertReceivedTimelines({});
+}
+
TEST_F(LatencyTrackerTest, MultipleEvents_AreReportedConsistently) {
constexpr int32_t inputEventId1 = 1;
InputEventTimeline timeline1(
@@ -204,6 +244,7 @@
mTracker->trackGraphicsLatency(inputEventId2, connection2,
connectionTimeline2.graphicsTimeline);
// Now both events should be completed
+ triggerEventReporting(timeline2.eventTime);
assertReceivedTimelines({timeline1, timeline2});
}
@@ -228,6 +269,7 @@
mTracker->trackGraphicsLatency(1 /*inputEventId*/, token, expectedCT.graphicsTimeline);
expectedTimelines[0].connectionTimelines.emplace(token, std::move(expectedCT));
+ triggerEventReporting(timeline.eventTime);
assertReceivedTimelines(expectedTimelines);
}
@@ -246,6 +288,7 @@
mTracker->trackGraphicsLatency(inputEventId, connection1, expectedCT.graphicsTimeline);
mTracker->trackListener(inputEventId, expected.isDown, expected.eventTime, expected.readTime);
+ triggerEventReporting(expected.eventTime);
assertReceivedTimeline(
InputEventTimeline{expected.isDown, expected.eventTime, expected.readTime});
}
diff --git a/services/inputflinger/tests/fuzzers/Android.bp b/services/inputflinger/tests/fuzzers/Android.bp
new file mode 100644
index 0000000..df4db19
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/Android.bp
@@ -0,0 +1,45 @@
+// Copyright (C) 2021 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.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+
+cc_fuzz {
+ name: "inputflinger_latencytracker_fuzzer",
+ defaults: [
+ "inputflinger_defaults",
+ ],
+ include_dirs: [
+ "frameworks/native/services/inputflinger",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "liblog",
+ "libui",
+ "libutils",
+ "libinput",
+ "libinputflinger",
+ ],
+ srcs: [
+ "LatencyTrackerFuzzer.cpp",
+ ],
+}
diff --git a/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
new file mode 100644
index 0000000..4f066ad
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2021 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 <fuzzer/FuzzedDataProvider.h>
+#include "dispatcher/LatencyTracker.h"
+
+namespace android {
+
+namespace inputdispatcher {
+
+/**
+ * A processor of InputEventTimelines that does nothing with the provided data.
+ */
+class EmptyProcessor : public InputEventTimelineProcessor {
+public:
+ /**
+ * Just ignore the provided timeline
+ */
+ void processTimeline(const InputEventTimeline& timeline) override {
+ for (const auto& [token, connectionTimeline] : timeline.connectionTimelines) {
+ connectionTimeline.isComplete();
+ }
+ };
+};
+
+static sp<IBinder> getConnectionToken(FuzzedDataProvider& fdp,
+ std::array<sp<IBinder>, 10>& tokens) {
+ const bool useExistingToken = fdp.ConsumeBool();
+ if (useExistingToken) {
+ return tokens[fdp.ConsumeIntegralInRange<size_t>(0ul, tokens.size() - 1)];
+ }
+ return new BBinder();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+
+ EmptyProcessor emptyProcessor;
+ LatencyTracker tracker(&emptyProcessor);
+
+ // Make some pre-defined tokens to ensure that some timelines are complete.
+ std::array<sp<IBinder> /*token*/, 10> predefinedTokens;
+ for (size_t i = 0; i < predefinedTokens.size(); i++) {
+ predefinedTokens[i] = new BBinder();
+ }
+
+ // Randomly invoke LatencyTracker api's until randomness is exhausted.
+ while (fdp.remaining_bytes() > 0) {
+ fdp.PickValueInArray<std::function<void()>>({
+ [&]() -> void {
+ int32_t inputEventId = fdp.ConsumeIntegral<int32_t>();
+ int32_t isDown = fdp.ConsumeBool();
+ nsecs_t eventTime = fdp.ConsumeIntegral<nsecs_t>();
+ nsecs_t readTime = fdp.ConsumeIntegral<nsecs_t>();
+ tracker.trackListener(inputEventId, isDown, eventTime, readTime);
+ },
+ [&]() -> void {
+ int32_t inputEventId = fdp.ConsumeIntegral<int32_t>();
+ sp<IBinder> connectionToken = getConnectionToken(fdp, predefinedTokens);
+ nsecs_t deliveryTime = fdp.ConsumeIntegral<nsecs_t>();
+ nsecs_t consumeTime = fdp.ConsumeIntegral<nsecs_t>();
+ nsecs_t finishTime = fdp.ConsumeIntegral<nsecs_t>();
+ tracker.trackFinishedEvent(inputEventId, connectionToken, deliveryTime,
+ consumeTime, finishTime);
+ },
+ [&]() -> void {
+ int32_t inputEventId = fdp.ConsumeIntegral<int32_t>();
+ sp<IBinder> connectionToken = getConnectionToken(fdp, predefinedTokens);
+ std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
+ for (size_t i = 0; i < graphicsTimeline.size(); i++) {
+ graphicsTimeline[i] = fdp.ConsumeIntegral<nsecs_t>();
+ }
+ tracker.trackGraphicsLatency(inputEventId, connectionToken, graphicsTimeline);
+ },
+ })();
+ }
+
+ return 0;
+}
+
+} // namespace inputdispatcher
+
+} // namespace android
\ No newline at end of file
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index 4151b45..bba6e22 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -36,7 +36,7 @@
"-Wall",
"-Werror",
"-Wextra",
- "-fvisibility=hidden"
+ "-fvisibility=hidden",
],
header_libs: [
@@ -60,6 +60,7 @@
"libbase",
"libhidlbase",
"libfmq",
+ "packagemanager_aidl-cpp",
"android.hardware.sensors@1.0",
"android.hardware.sensors@2.0",
"android.hardware.sensors@2.1",
@@ -76,6 +77,7 @@
"libsensor",
"libsensorprivacy",
"libpermission",
+ "packagemanager_aidl-cpp",
],
}
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index c233bf0..c351676 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -168,7 +168,7 @@
}
}
- // Sanity check and clamp power if it is 0 (or close)
+ // Check and clamp power if it is 0 (or close)
constexpr float MIN_POWER_MA = 0.001; // 1 microAmp
if (sensor.power < MIN_POWER_MA) {
ALOGI("%s's reported power %f invalid, clamped to %f",
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 9ce8d9b..c58e992 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -867,7 +867,7 @@
} else if (numBytesRead == sizeof(uint32_t)) {
uint32_t numAcks = 0;
memcpy(&numAcks, buf, numBytesRead);
- // Sanity check to ensure there are no read errors in recv, numAcks is always
+ // Check to ensure there are no read errors in recv, numAcks is always
// within the range and not zero. If any of the above don't hold reset
// mWakeLockRefCount to zero.
if (numAcks > 0 && numAcks < mWakeLockRefCount) {
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 726fe8e..3081b1a 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -1197,7 +1197,7 @@
// We have a dynamic sensor.
if (!sHmacGlobalKeyIsValid) {
- // Rather than risk exposing UUIDs, we cripple dynamic sensors.
+ // Rather than risk exposing UUIDs, we slow down dynamic sensors.
ALOGW("HMAC key failure; dynamic sensor getId() will be wrong.");
return 0;
}
@@ -1223,7 +1223,7 @@
sHmacGlobalKey, sizeof(sHmacGlobalKey),
uuidAndApp, sizeof(uuidAndApp),
hash, &hashLen) == nullptr) {
- // Rather than risk exposing UUIDs, we cripple dynamic sensors.
+ // Rather than risk exposing UUIDs, we slow down dynamic sensors.
ALOGW("HMAC failure; dynamic sensor getId() will be wrong.");
return 0;
}
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index eeb3f3a..af012cd 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -66,6 +66,7 @@
"libinput",
"libutils",
"libSurfaceFlingerProp",
+ "server_configurable_flags",
],
static_libs: [
"libcompositionengine",
@@ -154,6 +155,7 @@
"DisplayRenderArea.cpp",
"Effects/Daltonizer.cpp",
"EventLog/EventLog.cpp",
+ "FlagManager.cpp",
"FpsReporter.cpp",
"FrameTracer/FrameTracer.cpp",
"FrameTracker.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 71db330..d805294 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -152,39 +152,10 @@
return result;
}
- if (CC_UNLIKELY(mBufferInfo.mBuffer == 0)) {
- // the texture has not been created yet, this Layer has
- // in fact never been drawn into. This happens frequently with
- // SurfaceView because the WindowManager can't know when the client
- // has drawn the first time.
-
- // If there is nothing under us, we paint the screen in black, otherwise
- // we just skip this update.
-
- // figure out if there is something below us
- Region under;
- bool finished = false;
- mFlinger->mDrawingState.traverseInZOrder([&](Layer* layer) {
- if (finished || layer == static_cast<BufferLayer const*>(this)) {
- finished = true;
- return;
- }
-
- under.orSelf(layer->getScreenBounds());
- });
- // if not everything below us is covered, we plug the holes!
- Region holes(targetSettings.clip.subtract(under));
- if (!holes.isEmpty()) {
- targetSettings.clearRegion.orSelf(holes);
- }
-
- if (mSidebandStream != nullptr) {
- // For surfaceview of tv sideband, there is no activeBuffer
- // in bufferqueue, we need return LayerSettings.
- return result;
- } else {
- return std::nullopt;
- }
+ if (CC_UNLIKELY(mBufferInfo.mBuffer == 0) && mSidebandStream != nullptr) {
+ // For surfaceview of tv sideband, there is no activeBuffer
+ // in bufferqueue, we need return LayerSettings.
+ return result;
}
const bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) ||
((isSecure() || isProtected()) && !targetSettings.isSecure);
@@ -316,7 +287,7 @@
// Sideband layers
auto* compositionState = editCompositionState();
- if (compositionState->sidebandStream.get()) {
+ if (compositionState->sidebandStream.get() && !compositionState->sidebandStreamHasFrame) {
compositionState->compositionType = Hwc2::IComposerClient::Composition::SIDEBAND;
return;
} else {
@@ -332,6 +303,7 @@
? 0
: mBufferInfo.mBufferSlot;
compositionState->acquireFence = mBufferInfo.mFence;
+ compositionState->sidebandStreamHasFrame = false;
}
bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 99e470d..e4f642e 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -153,11 +153,12 @@
}
bool BufferQueueLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const {
+ Mutex::Autolock lock(mQueueItemLock);
+
if (!hasFrameUpdate() || isRemovedFromCurrentState()) {
return true;
}
- Mutex::Autolock lock(mQueueItemLock);
return mQueueItems[0].item.mTimestamp <= expectedPresentTime;
}
@@ -196,11 +197,10 @@
bool BufferQueueLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
// We need to update the sideband stream if the layer has both a buffer and a sideband stream.
- const bool updateSidebandStream = hasFrameUpdate() && mSidebandStream.get();
+ editCompositionState()->sidebandStreamHasFrame = hasFrameUpdate() && mSidebandStream.get();
bool sidebandStreamChanged = true;
- if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, false) ||
- updateSidebandStream) {
+ if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, false)) {
// mSidebandStreamChanged was changed to false
mSidebandStream = mConsumer->getSidebandStream();
auto* layerCompositionState = editCompositionState();
@@ -269,13 +269,15 @@
// and return early
if (queuedBuffer) {
Mutex::Autolock lock(mQueueItemLock);
- mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage);
- mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber);
- if (mQueueItems[0].surfaceFrame) {
- addSurfaceFrameDroppedForBuffer(mQueueItems[0].surfaceFrame);
+ if (mQueuedFrames > 0) {
+ mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage);
+ mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber);
+ if (mQueueItems[0].surfaceFrame) {
+ addSurfaceFrameDroppedForBuffer(mQueueItems[0].surfaceFrame);
+ }
+ mQueueItems.erase(mQueueItems.begin());
+ mQueuedFrames--;
}
- mQueueItems.erase(mQueueItems.begin());
- mQueuedFrames--;
}
return BAD_VALUE;
} else if (updateResult != NO_ERROR || mUpdateTexImageFailed) {
@@ -305,6 +307,7 @@
return BAD_VALUE;
}
+ bool more_frames_pending = false;
if (queuedBuffer) {
// Autolock scope
auto currentFrameNumber = mConsumer->getFrameNumber();
@@ -313,7 +316,7 @@
// Remove any stale buffers that have been dropped during
// updateTexImage
- while (mQueueItems[0].item.mFrameNumber != currentFrameNumber) {
+ while (mQueuedFrames > 0 && mQueueItems[0].item.mFrameNumber != currentFrameNumber) {
mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage);
mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber);
if (mQueueItems[0].surfaceFrame) {
@@ -334,11 +337,12 @@
latchTime);
}
mQueueItems.erase(mQueueItems.begin());
+ more_frames_pending = (mQueuedFrames.fetch_sub(1) > 1);
}
// Decrement the queued-frames count. Signal another event if we
// have more frames pending.
- if ((queuedBuffer && mQueuedFrames.fetch_sub(1) > 1) || mAutoRefresh) {
+ if ((queuedBuffer && more_frames_pending) || mAutoRefresh) {
mFlinger->signalLayerUpdate();
}
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index cd531d6..7466c06 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -14,11 +14,6 @@
* limitations under the License.
*/
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-#pragma clang diagnostic ignored "-Wextra"
-
//#define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "BufferStateLayer"
@@ -596,7 +591,7 @@
return true;
}
-Rect BufferStateLayer::getBufferSize(const State& s) const {
+Rect BufferStateLayer::getBufferSize(const State& /*s*/) const {
// for buffer state layers we use the display frame size as the buffer size.
if (mBufferInfo.mBuffer == nullptr) {
@@ -618,7 +613,7 @@
}
}
- return Rect(0, 0, bufWidth, bufHeight);
+ return Rect(0, 0, static_cast<int32_t>(bufWidth), static_cast<int32_t>(bufHeight));
}
FloatRect BufferStateLayer::computeSourceBounds(const FloatRect& parentBounds) const {
@@ -702,9 +697,9 @@
bool BufferStateLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
// We need to update the sideband stream if the layer has both a buffer and a sideband stream.
- const bool updateSidebandStream = hasFrameUpdate() && mSidebandStream.get();
+ editCompositionState()->sidebandStreamHasFrame = hasFrameUpdate() && mSidebandStream.get();
- if (mSidebandStreamChanged.exchange(false) || updateSidebandStream) {
+ if (mSidebandStreamChanged.exchange(false)) {
const State& s(getDrawingState());
// mSidebandStreamChanged was true
mSidebandStream = s.sidebandStream;
@@ -817,7 +812,7 @@
eraseBufferLocked(clientCacheId);
}
-uint32_t BufferStateLayer::HwcSlotGenerator::getHwcCacheSlot(const client_cache_t& clientCacheId) {
+int BufferStateLayer::HwcSlotGenerator::getHwcCacheSlot(const client_cache_t& clientCacheId) {
std::lock_guard<std::mutex> lock(mMutex);
auto itr = mCachedBuffers.find(clientCacheId);
if (itr == mCachedBuffers.end()) {
@@ -828,7 +823,7 @@
return hwcCacheSlot;
}
-uint32_t BufferStateLayer::HwcSlotGenerator::addCachedBuffer(const client_cache_t& clientCacheId)
+int BufferStateLayer::HwcSlotGenerator::addCachedBuffer(const client_cache_t& clientCacheId)
REQUIRES(mMutex) {
if (!clientCacheId.isValid()) {
ALOGE("invalid process, returning invalid slot");
@@ -837,17 +832,17 @@
ClientCache::getInstance().registerErasedRecipient(clientCacheId, wp<ErasedRecipient>(this));
- uint32_t hwcCacheSlot = getFreeHwcCacheSlot();
+ int hwcCacheSlot = getFreeHwcCacheSlot();
mCachedBuffers[clientCacheId] = {hwcCacheSlot, mCounter++};
return hwcCacheSlot;
}
-uint32_t BufferStateLayer::HwcSlotGenerator::getFreeHwcCacheSlot() REQUIRES(mMutex) {
+int BufferStateLayer::HwcSlotGenerator::getFreeHwcCacheSlot() REQUIRES(mMutex) {
if (mFreeHwcCacheSlots.empty()) {
evictLeastRecentlyUsed();
}
- uint32_t hwcCacheSlot = mFreeHwcCacheSlots.top();
+ int hwcCacheSlot = mFreeHwcCacheSlots.top();
mFreeHwcCacheSlots.pop();
return hwcCacheSlot;
}
@@ -934,8 +929,8 @@
return false;
}
- uint32_t bufferWidth = s.buffer->getBuffer()->width;
- uint32_t bufferHeight = s.buffer->getBuffer()->height;
+ int32_t bufferWidth = s.buffer->getBuffer()->width;
+ int32_t bufferHeight = s.buffer->getBuffer()->height;
// Undo any transformations on the buffer and return the result.
if (s.bufferTransform & ui::Transform::ROT_90) {
@@ -994,6 +989,3 @@
}
} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 0a0527c..124e91a 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -178,19 +178,19 @@
class HwcSlotGenerator : public ClientCache::ErasedRecipient {
public:
HwcSlotGenerator() {
- for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
mFreeHwcCacheSlots.push(i);
}
}
void bufferErased(const client_cache_t& clientCacheId);
- uint32_t getHwcCacheSlot(const client_cache_t& clientCacheId);
+ int getHwcCacheSlot(const client_cache_t& clientCacheId);
private:
friend class SlotGenerationTest;
- uint32_t addCachedBuffer(const client_cache_t& clientCacheId) REQUIRES(mMutex);
- uint32_t getFreeHwcCacheSlot() REQUIRES(mMutex);
+ int addCachedBuffer(const client_cache_t& clientCacheId) REQUIRES(mMutex);
+ int getFreeHwcCacheSlot() REQUIRES(mMutex);
void evictLeastRecentlyUsed() REQUIRES(mMutex);
void eraseBufferLocked(const client_cache_t& clientCacheId) REQUIRES(mMutex);
@@ -202,11 +202,10 @@
std::mutex mMutex;
- std::unordered_map<client_cache_t,
- std::pair<uint32_t /*HwcCacheSlot*/, uint32_t /*counter*/>,
+ std::unordered_map<client_cache_t, std::pair<int /*HwcCacheSlot*/, uint64_t /*counter*/>,
CachedBufferHash>
mCachedBuffers GUARDED_BY(mMutex);
- std::stack<uint32_t /*HwcCacheSlot*/> mFreeHwcCacheSlots GUARDED_BY(mMutex);
+ std::stack<int /*HwcCacheSlot*/> mFreeHwcCacheSlots GUARDED_BY(mMutex);
// The cache increments this counter value when a slot is updated or used.
// Used to track the least recently-used buffer
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index aac6c91..8da2e24 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -14,10 +14,6 @@
* limitations under the License.
*/
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
#include <stdint.h>
#include <sys/types.h>
@@ -132,6 +128,3 @@
// ---------------------------------------------------------------------------
}; // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/ClientCache.cpp b/services/surfaceflinger/ClientCache.cpp
index f310738..1ef8f78 100644
--- a/services/surfaceflinger/ClientCache.cpp
+++ b/services/surfaceflinger/ClientCache.cpp
@@ -21,12 +21,12 @@
#include <cinttypes>
+#include <android-base/stringprintf.h>
+
#include "ClientCache.h"
namespace android {
-using base::StringAppendF;
-
ANDROID_SINGLETON_STATIC_INSTANCE(ClientCache);
ClientCache::ClientCache() : mDeathRecipient(new CacheDeathRecipient) {}
@@ -212,16 +212,15 @@
void ClientCache::dump(std::string& result) {
std::lock_guard lock(mMutex);
- for (auto i : mBuffers) {
- const sp<IBinder>& cacheOwner = i.second.first;
- StringAppendF(&result," Cache owner: %p\n", cacheOwner.get());
- auto &buffers = i.second.second;
- for (auto& [id, clientCacheBuffer] : buffers) {
- StringAppendF(&result, "\t ID: %d, Width/Height: %d,%d\n", (int)id,
- (int)clientCacheBuffer.buffer->getBuffer()->getWidth(),
- (int)clientCacheBuffer.buffer->getBuffer()->getHeight());
+ for (const auto& [_, cache] : mBuffers) {
+ base::StringAppendF(&result, " Cache owner: %p\n", cache.first.get());
+
+ for (const auto& [id, entry] : cache.second) {
+ const auto& buffer = entry.buffer->getBuffer();
+ base::StringAppendF(&result, "\tID: %" PRIu64 ", size: %ux%u\n", id, buffer->getWidth(),
+ buffer->getHeight());
}
}
}
-}; // namespace android
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
index 554e2f4..95d553d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
@@ -47,9 +47,6 @@
// All the layers that have queued updates.
Layers layersWithQueuedFrames;
- // If true, forces the entire display to be considered dirty and repainted
- bool repaintEverything{false};
-
// Controls how the color mode is chosen for an output
OutputColorSetting outputColorSetting{OutputColorSetting::kEnhanced};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
index 14eddb1..98c4af4 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
@@ -36,18 +36,12 @@
struct DisplayCreationArgs {
DisplayId id;
- // Unset for virtual displays
- std::optional<ui::DisplayConnectionType> connectionType;
-
// Size of the display in pixels
- ui::Size pixels = ui::Size::INVALID;
+ ui::Size pixels = ui::kInvalidSize;
// True if this display should be considered secure
bool isSecure = false;
- // Gives the initial layer stack id to be used for the display
- uint32_t layerStackId = ~0u;
-
// Optional pointer to the power advisor interface, if one is needed for
// this display.
Hwc2::PowerAdvisor* powerAdvisor = nullptr;
@@ -69,11 +63,6 @@
return *this;
}
- DisplayCreationArgsBuilder& setConnectionType(ui::DisplayConnectionType connectionType) {
- mArgs.connectionType = connectionType;
- return *this;
- }
-
DisplayCreationArgsBuilder& setPixels(ui::Size pixels) {
mArgs.pixels = pixels;
return *this;
@@ -84,11 +73,6 @@
return *this;
}
- DisplayCreationArgsBuilder& setLayerStackId(uint32_t layerStackId) {
- mArgs.layerStackId = layerStackId;
- return *this;
- }
-
DisplayCreationArgsBuilder& setPowerAdvisor(Hwc2::PowerAdvisor* powerAdvisor) {
mArgs.powerAdvisor = powerAdvisor;
return *this;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index e51019a..6d1017f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -115,10 +115,6 @@
// If set to true, the target buffer has protected content support.
const bool supportsProtectedContent;
- // Modified by each call to prepareClientComposition to indicate the
- // region of the target buffer that should be cleared.
- Region& clearRegion;
-
// Viewport of the target being rendered to. This is used to determine
// the shadow light position.
const Rect& viewport;
@@ -177,11 +173,10 @@
static inline bool operator==(const LayerFE::ClientCompositionTargetSettings& lhs,
const LayerFE::ClientCompositionTargetSettings& rhs) {
- return lhs.clip.hasSameRects(rhs.clip) &&
- lhs.needsFiltering == rhs.needsFiltering && lhs.isSecure == rhs.isSecure &&
+ return lhs.clip.hasSameRects(rhs.clip) && lhs.needsFiltering == rhs.needsFiltering &&
+ lhs.isSecure == rhs.isSecure &&
lhs.supportsProtectedContent == rhs.supportsProtectedContent &&
- lhs.clearRegion.hasSameRects(rhs.clearRegion) && lhs.viewport == rhs.viewport &&
- lhs.dataspace == rhs.dataspace &&
+ lhs.viewport == rhs.viewport && lhs.dataspace == rhs.dataspace &&
lhs.realContentIsVisible == rhs.realContentIsVisible &&
lhs.clearContent == rhs.clearContent;
}
@@ -202,8 +197,6 @@
*os << "\n .needsFiltering = " << settings.needsFiltering;
*os << "\n .isSecure = " << settings.isSecure;
*os << "\n .supportsProtectedContent = " << settings.supportsProtectedContent;
- *os << "\n .clearRegion = ";
- PrintTo(settings.clearRegion, os);
*os << "\n .viewport = ";
PrintTo(settings.viewport, os);
*os << "\n .dataspace = ";
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index a45be8a..a000661 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -22,6 +22,7 @@
#include <math/mat4.h>
#include <ui/BlurRegion.h>
#include <ui/FloatRect.h>
+#include <ui/LayerStack.h>
#include <ui/Rect.h>
#include <ui/Region.h>
#include <ui/Transform.h>
@@ -93,11 +94,9 @@
/*
* Visibility state
*/
- // the layer stack this layer belongs to
- std::optional<uint32_t> layerStackId;
- // If true, this layer should be only visible on the internal display
- bool internalOnly{false};
+ // The filter that determines which outputs include this layer
+ ui::LayerFilter outputFilter;
// If false, this layer should not be considered visible
bool isVisible{true};
@@ -167,6 +166,8 @@
// The handle to use for a sideband stream for this layer
sp<NativeHandle> sidebandStream;
+ // If true, this sideband layer has a frame update
+ bool sidebandStreamHasFrame{false};
// The color for this layer
half4 color;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 0ef0b99..a33b57d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -28,6 +28,7 @@
#include <renderengine/LayerSettings.h>
#include <ui/Fence.h>
#include <ui/GraphicTypes.h>
+#include <ui/LayerStack.h>
#include <ui/Region.h>
#include <ui/Transform.h>
#include <utils/StrongPointer.h>
@@ -180,9 +181,8 @@
// output.
virtual ui::Transform::RotationFlags getTransformHint() const = 0;
- // Sets the layer stack filtering settings for this output. See
- // belongsInOutput for full details.
- virtual void setLayerStackFilter(uint32_t layerStackId, bool isInternal) = 0;
+ // Sets the filter for this output. See Output::includesLayer.
+ virtual void setLayerFilter(ui::LayerFilter) = 0;
// Sets the output color mode
virtual void setColorProfile(const ColorProfile&) = 0;
@@ -221,20 +221,12 @@
virtual OutputCompositionState& editState() = 0;
// Gets the dirty region in layer stack space.
- // If repaintEverything is true, this will be the full display bounds.
- virtual Region getDirtyRegion(bool repaintEverything) const = 0;
+ virtual Region getDirtyRegion() const = 0;
- // Tests whether a given layerStackId belongs in this output.
- // A layer belongs to the output if its layerStackId matches the of the output layerStackId,
- // unless the layer should display on the primary output only and this is not the primary output
-
- // A layer belongs to the output if its layerStackId matches. Additionally
- // if the layer should only show in the internal (primary) display only and
- // this output allows that.
- virtual bool belongsInOutput(std::optional<uint32_t> layerStackId, bool internalOnly) const = 0;
-
- // Determines if a layer belongs to the output.
- virtual bool belongsInOutput(const sp<LayerFE>&) const = 0;
+ // Returns whether the output includes a layer, based on their respective filters.
+ // See Output::setLayerFilter.
+ virtual bool includesLayer(ui::LayerFilter) const = 0;
+ virtual bool includesLayer(const sp<LayerFE>&) const = 0;
// Returns a pointer to the output layer corresponding to the given layer on
// this output, or nullptr if the layer does not have one
@@ -294,7 +286,7 @@
virtual bool getSkipColorTransform() const = 0;
virtual FrameFences presentAndGetFrameFences() = 0;
virtual std::vector<LayerFE::LayerSettings> generateClientCompositionRequests(
- bool supportsProtectedContent, Region& clearRegion, ui::Dataspace outputDataspace) = 0;
+ bool supportsProtectedContent, ui::Dataspace outputDataspace) = 0;
virtual void appendRegionFlashRequests(
const Region& flashRegion,
std::vector<LayerFE::LayerSettings>& clientCompositionLayers) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
index 58bb41a..a63145a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
@@ -28,51 +28,36 @@
// Geometrical space to which content is projected.
// For example, this can be the layer space or the physical display space.
-struct ProjectionSpace {
+class ProjectionSpace {
+public:
ProjectionSpace() = default;
- ProjectionSpace(ui::Size size, Rect content)
- : bounds(std::move(size)), content(std::move(content)) {}
-
- // Bounds of this space. Always starts at (0,0).
- Rect bounds;
-
- // Rect onto which content is projected.
- Rect content;
-
- // The orientation of this space. This value is meaningful only in relation to the rotation
- // of another projection space and it's used to determine the rotating transformation when
- // mapping between the two.
- // As a convention when using this struct orientation = 0 for the "oriented*" projection
- // spaces. For example when the display is rotated 90 degress counterclockwise, the orientation
- // of the display space will become 90, while the orientation of the layer stack space will
- // remain the same.
- ui::Rotation orientation = ui::ROTATION_0;
+ ProjectionSpace(ui::Size size, Rect content) : mBounds(size), mContent(std::move(content)) {}
// Returns a transform which maps this.content into destination.content
// and also rotates according to this.orientation and destination.orientation
ui::Transform getTransform(const ProjectionSpace& destination) const {
- ui::Rotation rotation = destination.orientation - orientation;
+ ui::Rotation rotation = destination.getOrientation() - mOrientation;
// Compute a transformation which rotates the destination in a way it has the same
// orientation as us.
const uint32_t inverseRotationFlags = ui::Transform::toRotationFlags(-rotation);
ui::Transform inverseRotatingTransform;
- inverseRotatingTransform.set(inverseRotationFlags, destination.bounds.width(),
- destination.bounds.height());
+ inverseRotatingTransform.set(inverseRotationFlags, destination.getBounds().width,
+ destination.getBounds().height);
// The destination content rotated so it has the same orientation as us.
- Rect orientedDestContent = inverseRotatingTransform.transform(destination.content);
+ Rect orientedDestContent = inverseRotatingTransform.transform(destination.getContent());
// Compute translation from the source content to (0, 0).
- const float sourceX = content.left;
- const float sourceY = content.top;
+ const float sourceX = mContent.left;
+ const float sourceY = mContent.top;
ui::Transform sourceTranslation;
sourceTranslation.set(-sourceX, -sourceY);
// Compute scaling transform which maps source content to destination content, assuming
// they are both at (0, 0).
ui::Transform scale;
- const float scaleX = static_cast<float>(orientedDestContent.width()) / content.width();
- const float scaleY = static_cast<float>(orientedDestContent.height()) / content.height();
+ const float scaleX = static_cast<float>(orientedDestContent.width()) / mContent.width();
+ const float scaleY = static_cast<float>(orientedDestContent.height()) / mContent.height();
scale.set(scaleX, 0, 0, scaleY);
// Compute translation from (0, 0) to the orientated destination content.
@@ -83,8 +68,8 @@
// Compute rotation transform.
const uint32_t orientationFlags = ui::Transform::toRotationFlags(rotation);
- auto orientedDestWidth = destination.bounds.width();
- auto orientedDestHeight = destination.bounds.height();
+ auto orientedDestWidth = destination.getBounds().width;
+ auto orientedDestHeight = destination.getBounds().height;
if (rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270) {
std::swap(orientedDestWidth, orientedDestHeight);
}
@@ -98,9 +83,39 @@
}
bool operator==(const ProjectionSpace& other) const {
- return bounds == other.bounds && content == other.content &&
- orientation == other.orientation;
+ return mBounds == other.mBounds && mContent == other.mContent &&
+ mOrientation == other.mOrientation;
}
+
+ void setBounds(ui::Size newBounds) { mBounds = std::move(newBounds); }
+
+ void setContent(Rect newContent) { mContent = std::move(newContent); }
+
+ void setOrientation(ui::Rotation newOrientation) { mOrientation = newOrientation; }
+
+ Rect getBoundsAsRect() const { return Rect(mBounds.getWidth(), mBounds.getHeight()); }
+
+ const ui::Size& getBounds() const { return mBounds; }
+
+ const Rect& getContent() const { return mContent; }
+
+ ui::Rotation getOrientation() const { return mOrientation; }
+
+private:
+ // Bounds of this space. Always starts at (0,0).
+ ui::Size mBounds = ui::Size();
+
+ // Rect onto which content is projected.
+ Rect mContent = Rect();
+
+ // The orientation of this space. This value is meaningful only in relation to the rotation
+ // of another projection space and it's used to determine the rotating transformation when
+ // mapping between the two.
+ // As a convention when using this struct orientation = 0 for the "oriented*" projection
+ // spaces. For example when the display is rotated 90 degress counterclockwise, the orientation
+ // of the display space will become 90, while the orientation of the layer stack space will
+ // remain the same.
+ ui::Rotation mOrientation = ui::ROTATION_0;
};
} // namespace compositionengine
@@ -108,8 +123,8 @@
inline std::string to_string(const android::compositionengine::ProjectionSpace& space) {
return android::base::
StringPrintf("ProjectionSpace(bounds = %s, content = %s, orientation = %s)",
- to_string(space.bounds).c_str(), to_string(space.content).c_str(),
- toCString(space.orientation));
+ to_string(space.getBoundsAsRect()).c_str(),
+ to_string(space.getContent()).c_str(), toCString(space.getOrientation()));
}
// Defining PrintTo helps with Google Tests.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index bb540ea..b407267 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -83,9 +83,8 @@
std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(const sp<LayerFE>&) const;
private:
- bool mIsVirtual = false;
- bool mIsDisconnected = false;
DisplayId mId;
+ bool mIsDisconnected = false;
Hwc2::PowerAdvisor* mPowerAdvisor = nullptr;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
index 6b9597b..7521324 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
@@ -22,6 +22,7 @@
#include <math/mat4.h>
#include <ui/FloatRect.h>
+#include <ui/LayerStack.h>
#include <ui/Rect.h>
#include <ui/Region.h>
#include <ui/StretchEffect.h>
@@ -52,13 +53,14 @@
dumpVal(out, name, valueName, static_cast<std::underlying_type_t<EnumType>>(value));
}
-void dumpVal(std::string& out, const char* name, const FloatRect& rect);
-void dumpVal(std::string& out, const char* name, const Rect& rect);
-void dumpVal(std::string& out, const char* name, const Region& region);
-void dumpVal(std::string& out, const char* name, const ui::Transform&);
-void dumpVal(std::string& out, const char* name, const ui::Size&);
+void dumpVal(std::string& out, const char* name, ui::LayerFilter);
+void dumpVal(std::string& out, const char* name, ui::Size);
-void dumpVal(std::string& out, const char* name, const mat4& tr);
+void dumpVal(std::string& out, const char* name, const FloatRect&);
+void dumpVal(std::string& out, const char* name, const Rect&);
+void dumpVal(std::string& out, const char* name, const Region&);
+void dumpVal(std::string& out, const char* name, const ui::Transform&);
+void dumpVal(std::string& out, const char* name, const mat4&);
void dumpVal(std::string& out, const char* name, const StretchEffect&);
} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index ddcc907..6d49ce6 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -23,6 +23,7 @@
#include <compositionengine/impl/planner/Planner.h>
#include <renderengine/DisplaySettings.h>
#include <renderengine/LayerSettings.h>
+
#include <memory>
#include <utility>
#include <vector>
@@ -45,7 +46,7 @@
void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
const Rect& orientedDisplaySpaceRect) override;
void setDisplaySize(const ui::Size&) override;
- void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override;
+ void setLayerFilter(ui::LayerFilter) override;
ui::Transform::RotationFlags getTransformHint() const override;
void setColorTransform(const compositionengine::CompositionRefreshArgs&) override;
@@ -64,9 +65,10 @@
compositionengine::RenderSurface* getRenderSurface() const override;
void setRenderSurface(std::unique_ptr<compositionengine::RenderSurface>) override;
- Region getDirtyRegion(bool repaintEverything) const override;
- bool belongsInOutput(std::optional<uint32_t>, bool) const override;
- bool belongsInOutput(const sp<LayerFE>&) const override;
+ Region getDirtyRegion() const override;
+
+ bool includesLayer(ui::LayerFilter) const override;
+ bool includesLayer(const sp<LayerFE>&) const override;
compositionengine::OutputLayer* getOutputLayerForLayer(const sp<LayerFE>&) const override;
@@ -111,8 +113,7 @@
bool getSkipColorTransform() const override;
compositionengine::Output::FrameFences presentAndGetFrameFences() override;
std::vector<LayerFE::LayerSettings> generateClientCompositionRequests(
- bool supportsProtectedContent, Region& clearRegion,
- ui::Dataspace outputDataspace) override;
+ bool supportsProtectedContent, ui::Dataspace outputDataspace) override;
void appendRegionFlashRequests(const Region&, std::vector<LayerFE::LayerSettings>&) override;
void setExpensiveRenderingExpected(bool enabled) override;
void dumpBase(std::string&) const;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index f34cb94..44f754f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -32,6 +32,7 @@
#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
#include <compositionengine/ProjectionSpace.h>
+#include <ui/LayerStack.h>
#include <ui/Rect.h>
#include <ui/Region.h>
#include <ui/Transform.h>
@@ -59,11 +60,8 @@
// If true, the current frame reused the buffer from a previous client composition
bool reusedClientComposition{false};
- // If true, this output displays layers that are internal-only
- bool layerStackInternal{false};
-
- // The layer stack to display on this display
- uint32_t layerStackId{~0u};
+ // The conditions for including a layer on this output
+ ui::LayerFilter layerFilter;
// The common space for all layers in the layer stack. layerStackSpace.content is the Rect
// which gets projected on the display. The orientation of this space is always ROTATION_0.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
index a040fa9..cff6527 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
@@ -119,8 +119,8 @@
std::chrono::steady_clock::time_point now);
// A Run is a sequence of CachedSets, which is a candidate for flattening into a single
- // CachedSet. Because it is wasteful to flatten 1 CachedSet, a Run must contain more than 1
- // CachedSet
+ // CachedSet. Because it is wasteful to flatten 1 CachedSet, a run must contain more than
+ // 1 CachedSet or be used for a hole punch.
class Run {
public:
// A builder for a Run, to aid in construction
@@ -154,7 +154,13 @@
// Builds a Run instance, if a valid Run may be built.
std::optional<Run> validateAndBuild() {
- if (mLengths.size() <= 1) {
+ if (mLengths.size() == 0) {
+ return std::nullopt;
+ }
+ // Runs of length 1 which are hole punch candidates are allowed if the candidate is
+ // going to be used.
+ if (mLengths.size() == 1 &&
+ (!mHolePunchCandidate || !(mHolePunchCandidate->requiresHolePunch()))) {
return std::nullopt;
}
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 8fdf3ae..344b2f9 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -40,9 +40,12 @@
MOCK_METHOD1(setLayerCachingTexturePoolEnabled, void(bool));
MOCK_METHOD3(setProjection, void(ui::Rotation, const Rect&, const Rect&));
MOCK_METHOD1(setDisplaySize, void(const ui::Size&));
- MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool));
MOCK_CONST_METHOD0(getTransformHint, ui::Transform::RotationFlags());
+ MOCK_METHOD(void, setLayerFilter, (ui::LayerFilter));
+ MOCK_METHOD(bool, includesLayer, (ui::LayerFilter), (const));
+ MOCK_METHOD(bool, includesLayer, (const sp<compositionengine::LayerFE>&), (const));
+
MOCK_METHOD1(setColorTransform, void(const compositionengine::CompositionRefreshArgs&));
MOCK_METHOD1(setColorProfile, void(const ColorProfile&));
MOCK_METHOD2(setDisplayBrightness, void(float, float));
@@ -62,9 +65,7 @@
MOCK_CONST_METHOD0(getState, const OutputCompositionState&());
MOCK_METHOD0(editState, OutputCompositionState&());
- MOCK_CONST_METHOD1(getDirtyRegion, Region(bool));
- MOCK_CONST_METHOD2(belongsInOutput, bool(std::optional<uint32_t>, bool));
- MOCK_CONST_METHOD1(belongsInOutput, bool(const sp<compositionengine::LayerFE>&));
+ MOCK_METHOD(Region, getDirtyRegion, (), (const));
MOCK_CONST_METHOD1(getOutputLayerForLayer,
compositionengine::OutputLayer*(const sp<compositionengine::LayerFE>&));
@@ -113,8 +114,8 @@
MOCK_METHOD1(renderCachedSets, void(const CompositionRefreshArgs&));
MOCK_METHOD0(presentAndGetFrameFences, compositionengine::Output::FrameFences());
- MOCK_METHOD3(generateClientCompositionRequests,
- std::vector<LayerFE::LayerSettings>(bool, Region&, ui::Dataspace));
+ MOCK_METHOD2(generateClientCompositionRequests,
+ std::vector<LayerFE::LayerSettings>(bool, ui::Dataspace));
MOCK_METHOD2(appendRegionFlashRequests,
void(const Region&, std::vector<LayerFE::LayerSettings>&));
MOCK_METHOD1(setExpensiveRenderingExpected, void(bool));
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 2f2c686..02fa49f 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -51,12 +51,9 @@
void Display::setConfiguration(const compositionengine::DisplayCreationArgs& args) {
mId = args.id;
- mIsVirtual = !args.connectionType;
mPowerAdvisor = args.powerAdvisor;
editState().isSecure = args.isSecure;
- editState().displaySpace.bounds = Rect(args.pixels);
- setLayerStackFilter(args.layerStackId,
- args.connectionType == ui::DisplayConnectionType::Internal);
+ editState().displaySpace.setBounds(args.pixels);
setName(args.name);
}
@@ -73,7 +70,7 @@
}
bool Display::isVirtual() const {
- return mIsVirtual;
+ return VirtualDisplayId::tryCast(mId).has_value();
}
std::optional<DisplayId> Display::getDisplayId() const {
@@ -117,8 +114,8 @@
return;
}
- if (mIsVirtual) {
- ALOGW("%s: Invalid operation on virtual display", __FUNCTION__);
+ if (isVirtual()) {
+ ALOGW("%s: Invalid operation on virtual display", __func__);
return;
}
@@ -136,7 +133,7 @@
StringAppendF(&out, " Composition Display State: [\"%s\"]", getName().c_str());
out.append("\n ");
- dumpVal(out, "isVirtual", mIsVirtual);
+ dumpVal(out, "isVirtual", isVirtual());
dumpVal(out, "DisplayId", to_string(mId));
out.append("\n");
@@ -364,8 +361,7 @@
// 1) It is being handled by hardware composer, which may need this to
// keep its virtual display state machine in sync, or
// 2) There is work to be done (the dirty region isn't empty)
- if (GpuVirtualDisplayId::tryCast(mId) &&
- getDirtyRegion(refreshArgs.repaintEverything).isEmpty()) {
+ if (GpuVirtualDisplayId::tryCast(mId) && getDirtyRegion().isEmpty()) {
ALOGV("Skipping display composition");
return;
}
diff --git a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
index 5565396..01c368d 100644
--- a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
@@ -63,6 +63,18 @@
dumpVal(out, name, valueName.c_str(), value);
}
+void dumpVal(std::string& out, const char* name, ui::LayerFilter filter) {
+ out.append(name);
+ out.append("={");
+ dumpVal(out, "layerStack", filter.layerStack.id);
+ dumpVal(out, "toInternalDisplay", filter.toInternalDisplay);
+ out.push_back('}');
+}
+
+void dumpVal(std::string& out, const char* name, ui::Size size) {
+ StringAppendF(&out, "%s=[%d %d] ", name, size.width, size.height);
+}
+
void dumpVal(std::string& out, const char* name, const FloatRect& rect) {
StringAppendF(&out, "%s=[%f %f %f %f] ", name, rect.left, rect.top, rect.right, rect.bottom);
}
@@ -80,10 +92,6 @@
out.append(" ");
}
-void dumpVal(std::string& out, const char* name, const ui::Size& size) {
- StringAppendF(&out, "%s=[%d %d] ", name, size.width, size.height);
-}
-
void dumpVal(std::string& out, const char* name, const mat4& tr) {
StringAppendF(&out,
"%s=["
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 95ae5e5..eb3f3b1 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -156,38 +156,40 @@
const Rect& orientedDisplaySpaceRect) {
auto& outputState = editState();
- outputState.displaySpace.orientation = orientation;
- LOG_FATAL_IF(outputState.displaySpace.bounds == Rect::INVALID_RECT,
+ outputState.displaySpace.setOrientation(orientation);
+ LOG_FATAL_IF(outputState.displaySpace.getBoundsAsRect() == Rect::INVALID_RECT,
"The display bounds are unknown.");
// Compute orientedDisplaySpace
- ui::Size orientedSize = outputState.displaySpace.bounds.getSize();
+ ui::Size orientedSize = outputState.displaySpace.getBounds();
if (orientation == ui::ROTATION_90 || orientation == ui::ROTATION_270) {
std::swap(orientedSize.width, orientedSize.height);
}
- outputState.orientedDisplaySpace.bounds = Rect(orientedSize);
- outputState.orientedDisplaySpace.content = orientedDisplaySpaceRect;
+ outputState.orientedDisplaySpace.setBounds(orientedSize);
+ outputState.orientedDisplaySpace.setContent(orientedDisplaySpaceRect);
// Compute displaySpace.content
const uint32_t transformOrientationFlags = ui::Transform::toRotationFlags(orientation);
ui::Transform rotation;
if (transformOrientationFlags != ui::Transform::ROT_INVALID) {
- const auto displaySize = outputState.displaySpace.bounds;
+ const auto displaySize = outputState.displaySpace.getBoundsAsRect();
rotation.set(transformOrientationFlags, displaySize.width(), displaySize.height());
}
- outputState.displaySpace.content = rotation.transform(orientedDisplaySpaceRect);
+ outputState.displaySpace.setContent(rotation.transform(orientedDisplaySpaceRect));
// Compute framebufferSpace
- outputState.framebufferSpace.orientation = orientation;
- LOG_FATAL_IF(outputState.framebufferSpace.bounds == Rect::INVALID_RECT,
+ outputState.framebufferSpace.setOrientation(orientation);
+ LOG_FATAL_IF(outputState.framebufferSpace.getBoundsAsRect() == Rect::INVALID_RECT,
"The framebuffer bounds are unknown.");
- const auto scale =
- getScale(outputState.displaySpace.bounds, outputState.framebufferSpace.bounds);
- outputState.framebufferSpace.content = outputState.displaySpace.content.scale(scale.x, scale.y);
+ const auto scale = getScale(outputState.displaySpace.getBoundsAsRect(),
+ outputState.framebufferSpace.getBoundsAsRect());
+ outputState.framebufferSpace.setContent(
+ outputState.displaySpace.getContent().scale(scale.x, scale.y));
// Compute layerStackSpace
- outputState.layerStackSpace.content = layerStackSpaceRect;
- outputState.layerStackSpace.bounds = layerStackSpaceRect;
+ outputState.layerStackSpace.setContent(layerStackSpaceRect);
+ outputState.layerStackSpace.setBounds(
+ ui::Size(layerStackSpaceRect.getWidth(), layerStackSpaceRect.getHeight()));
outputState.transform = outputState.layerStackSpace.getTransform(outputState.displaySpace);
outputState.needsFiltering = outputState.transform.needsBilinearFiltering();
@@ -200,21 +202,21 @@
auto& state = editState();
// Update framebuffer space
- const Rect newBounds(size);
- state.framebufferSpace.bounds = newBounds;
+ const ui::Size newBounds(size);
+ state.framebufferSpace.setBounds(newBounds);
// Update display space
- state.displaySpace.bounds = newBounds;
+ state.displaySpace.setBounds(newBounds);
state.transform = state.layerStackSpace.getTransform(state.displaySpace);
// Update oriented display space
- const auto orientation = state.displaySpace.orientation;
+ const auto orientation = state.displaySpace.getOrientation();
ui::Size orientedSize = size;
if (orientation == ui::ROTATION_90 || orientation == ui::ROTATION_270) {
std::swap(orientedSize.width, orientedSize.height);
}
- const Rect newOrientedBounds(orientedSize);
- state.orientedDisplaySpace.bounds = newOrientedBounds;
+ const ui::Size newOrientedBounds(orientedSize);
+ state.orientedDisplaySpace.setBounds(newOrientedBounds);
if (mPlanner) {
mPlanner->setDisplaySize(size);
@@ -227,11 +229,8 @@
return static_cast<ui::Transform::RotationFlags>(getState().transform.getOrientation());
}
-void Output::setLayerStackFilter(uint32_t layerStackId, bool isInternal) {
- auto& outputState = editState();
- outputState.layerStackId = layerStackId;
- outputState.layerStackInternal = isInternal;
-
+void Output::setLayerFilter(ui::LayerFilter filter) {
+ editState().layerFilter = filter;
dirtyEntireOutput();
}
@@ -352,7 +351,7 @@
void Output::setRenderSurface(std::unique_ptr<compositionengine::RenderSurface> surface) {
mRenderSurface = std::move(surface);
const auto size = mRenderSurface->getSize();
- editState().framebufferSpace.bounds = Rect(size);
+ editState().framebufferSpace.setBounds(size);
if (mPlanner) {
mPlanner->setDisplaySize(size);
}
@@ -371,26 +370,18 @@
mRenderSurface = std::move(surface);
}
-Region Output::getDirtyRegion(bool repaintEverything) const {
+Region Output::getDirtyRegion() const {
const auto& outputState = getState();
- Region dirty(outputState.layerStackSpace.content);
- if (!repaintEverything) {
- dirty.andSelf(outputState.dirtyRegion);
- }
- return dirty;
+ return outputState.dirtyRegion.intersect(outputState.layerStackSpace.getContent());
}
-bool Output::belongsInOutput(std::optional<uint32_t> layerStackId, bool internalOnly) const {
- // The layerStackId's must match, and also the layer must not be internal
- // only when not on an internal output.
- const auto& outputState = getState();
- return layerStackId && (*layerStackId == outputState.layerStackId) &&
- (!internalOnly || outputState.layerStackInternal);
+bool Output::includesLayer(ui::LayerFilter filter) const {
+ return getState().layerFilter.includes(filter);
}
-bool Output::belongsInOutput(const sp<compositionengine::LayerFE>& layerFE) const {
+bool Output::includesLayer(const sp<LayerFE>& layerFE) const {
const auto* layerFEState = layerFE->getCompositionState();
- return layerFEState && belongsInOutput(layerFEState->layerStackId, layerFEState->internalOnly);
+ return layerFEState && includesLayer(layerFEState->outputFilter);
}
std::unique_ptr<compositionengine::OutputLayer> Output::createOutputLayer(
@@ -461,7 +452,7 @@
// Compute the resulting coverage for this output, and store it for later
const ui::Transform& tr = outputState.transform;
- Region undefinedRegion{outputState.displaySpace.bounds};
+ Region undefinedRegion{outputState.displaySpace.getBoundsAsRect()};
undefinedRegion.subtractSelf(tr.transform(coverage.aboveOpaqueLayers));
outputState.undefinedRegion = undefinedRegion;
@@ -496,8 +487,8 @@
layerFE->prepareCompositionState(compositionengine::LayerFE::StateSubset::BasicGeometry);
}
- // Only consider the layers on the given layer stack
- if (!belongsInOutput(layerFE)) {
+ // Only consider the layers on this output
+ if (!includesLayer(layerFE)) {
return;
}
@@ -658,7 +649,7 @@
// TODO(b/121291683): Why does this not use visibleRegion? (see outputSpaceVisibleRegion below)
const auto& outputState = getState();
Region drawRegion(outputState.transform.transform(visibleNonTransparentRegion));
- drawRegion.andSelf(outputState.displaySpace.bounds);
+ drawRegion.andSelf(outputState.displaySpace.getBoundsAsRect());
if (drawRegion.isEmpty()) {
return;
}
@@ -676,7 +667,7 @@
outputLayerState.visibleNonTransparentRegion = visibleNonTransparentRegion;
outputLayerState.coveredRegion = coveredRegion;
outputLayerState.outputSpaceVisibleRegion = outputState.transform.transform(
- visibleNonShadowRegion.intersect(outputState.layerStackSpace.content));
+ visibleNonShadowRegion.intersect(outputState.layerStackSpace.getContent()));
outputLayerState.shadowRegion = shadowRegion;
}
@@ -911,7 +902,7 @@
void Output::beginFrame() {
auto& outputState = editState();
- const bool dirty = !getDirtyRegion(false).isEmpty();
+ const bool dirty = !getDirtyRegion().isEmpty();
const bool empty = getOutputLayerCount() == 0;
const bool wasEmpty = !outputState.lastCompositionHadVisibleLayers;
@@ -963,14 +954,9 @@
}
if (getState().isEnabled) {
- // transform the dirty region into this screen's coordinate space
- const Region dirtyRegion = getDirtyRegion(refreshArgs.repaintEverything);
- if (!dirtyRegion.isEmpty()) {
- base::unique_fd readyFence;
- // redraw the whole screen
+ if (const auto dirtyRegion = getDirtyRegion(); !dirtyRegion.isEmpty()) {
static_cast<void>(composeSurfaces(dirtyRegion, refreshArgs));
-
- mRenderSurface->queueBuffer(std::move(readyFence));
+ mRenderSurface->queueBuffer(base::unique_fd());
}
}
@@ -1049,19 +1035,18 @@
}
}
- base::unique_fd readyFence;
if (!hasClientComposition) {
setExpensiveRenderingExpected(false);
- return readyFence;
+ return base::unique_fd();
}
ALOGV("hasClientComposition");
renderengine::DisplaySettings clientCompositionDisplay;
- clientCompositionDisplay.physicalDisplay = outputState.framebufferSpace.content;
- clientCompositionDisplay.clip = outputState.layerStackSpace.content;
+ clientCompositionDisplay.physicalDisplay = outputState.framebufferSpace.getContent();
+ clientCompositionDisplay.clip = outputState.layerStackSpace.getContent();
clientCompositionDisplay.orientation =
- ui::Transform::toRotationFlags(outputState.displaySpace.orientation);
+ ui::Transform::toRotationFlags(outputState.displaySpace.getOrientation());
clientCompositionDisplay.outputDataspace = mDisplayColorProfile->hasWideColorGamut()
? outputState.dataspace
: ui::Dataspace::UNKNOWN;
@@ -1078,13 +1063,9 @@
clientCompositionDisplay.colorTransform = outputState.colorTransformMatrix;
}
- // Note: Updated by generateClientCompositionRequests
- clientCompositionDisplay.clearRegion = Region::INVALID_REGION;
-
// Generate the client composition requests for the layers on this output.
std::vector<LayerFE::LayerSettings> clientCompositionLayers =
generateClientCompositionRequests(supportsProtectedContent,
- clientCompositionDisplay.clearRegion,
clientCompositionDisplay.outputDataspace);
appendRegionFlashRequests(debugRegion, clientCompositionLayers);
@@ -1096,7 +1077,7 @@
clientCompositionLayers)) {
outputCompositionState.reusedClientComposition = true;
setExpensiveRenderingExpected(false);
- return readyFence;
+ return base::unique_fd();
}
mClientCompositionRequestCache->add(tex->getBuffer()->getId(), clientCompositionDisplay,
clientCompositionLayers);
@@ -1129,10 +1110,12 @@
// bounds its framebuffer cache but Skia RenderEngine has no current policy. The best fix is
// probably to encapsulate the output buffer into a structure that dispatches resource cleanup
// over to RenderEngine, in which case this flag can be removed from the drawLayers interface.
- const bool useFramebufferCache = outputState.layerStackInternal;
- status_t status =
- renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, tex,
- useFramebufferCache, std::move(fd), &readyFence);
+ const bool useFramebufferCache = outputState.layerFilter.toInternalDisplay;
+ auto [status, drawFence] =
+ renderEngine
+ .drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, tex,
+ useFramebufferCache, std::move(fd))
+ .get();
if (status != NO_ERROR && mClientCompositionRequestCache) {
// If rendering was not successful, remove the request from the cache.
@@ -1140,27 +1123,25 @@
}
auto& timeStats = getCompositionEngine().getTimeStats();
- if (readyFence.get() < 0) {
+ if (drawFence.get() < 0) {
timeStats.recordRenderEngineDuration(renderEngineStart, systemTime());
} else {
timeStats.recordRenderEngineDuration(renderEngineStart,
std::make_shared<FenceTime>(
- new Fence(dup(readyFence.get()))));
+ new Fence(dup(drawFence.get()))));
}
- return readyFence;
+ return std::move(drawFence);
}
std::vector<LayerFE::LayerSettings> Output::generateClientCompositionRequests(
- bool supportsProtectedContent, Region& clearRegion, ui::Dataspace outputDataspace) {
+ bool supportsProtectedContent, ui::Dataspace outputDataspace) {
std::vector<LayerFE::LayerSettings> clientCompositionLayers;
ALOGV("Rendering client layers");
const auto& outputState = getState();
- const Region viewportRegion(outputState.layerStackSpace.content);
+ const Region viewportRegion(outputState.layerStackSpace.getContent());
bool firstLayer = true;
- // Used when a layer clears part of the buffer.
- Region stubRegion;
bool disableBlurs = false;
sp<GraphicBuffer> previousOverrideBuffer = nullptr;
@@ -1222,8 +1203,7 @@
outputState.needsFiltering,
.isSecure = outputState.isSecure,
.supportsProtectedContent = supportsProtectedContent,
- .clearRegion = clientComposition ? clearRegion : stubRegion,
- .viewport = outputState.layerStackSpace.content,
+ .viewport = outputState.layerStackSpace.getContent(),
.dataspace = outputDataspace,
.realContentIsVisible = realContentIsVisible,
.clearContent = !clientComposition,
@@ -1330,7 +1310,7 @@
void Output::dirtyEntireOutput() {
auto& outputState = editState();
- outputState.dirtyRegion.set(outputState.displaySpace.bounds);
+ outputState.dirtyRegion.set(outputState.displaySpace.getBoundsAsRect());
}
void Output::chooseCompositionStrategy() {
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index ee30ad8..acc9216 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -28,9 +28,7 @@
dumpVal(out, "usesDeviceComposition", usesDeviceComposition);
dumpVal(out, "flipClientTarget", flipClientTarget);
dumpVal(out, "reusedClientComposition", reusedClientComposition);
-
- dumpVal(out, "layerStack", layerStackId);
- dumpVal(out, "layerStackInternal", layerStackInternal);
+ dumpVal(out, "layerFilter", layerFilter);
out.append("\n ");
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 56e9d27..ecfd901 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -79,7 +79,7 @@
FloatRect activeCropFloat =
reduce(layerState.geomLayerBounds, layerState.transparentRegionHint);
- const Rect& viewport = getOutput().getState().layerStackSpace.content;
+ const Rect& viewport = getOutput().getState().layerStackSpace.getContent();
const ui::Transform& layerTransform = layerState.geomLayerTransform;
const ui::Transform& inverseLayerTransform = layerState.geomInverseLayerTransform;
// Transform to screen space.
@@ -136,7 +136,7 @@
* buffer
*/
uint32_t invTransformOrient =
- ui::Transform::toRotationFlags(outputState.displaySpace.orientation);
+ ui::Transform::toRotationFlags(outputState.displaySpace.getOrientation());
// calculate the inverse transform
if (invTransformOrient & HAL_TRANSFORM_ROT_90) {
invTransformOrient ^= HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_FLIP_H;
@@ -192,7 +192,7 @@
Rect activeCrop = layerState.geomCrop;
if (!activeCrop.isEmpty() && bufferSize.isValid()) {
activeCrop = layerTransform.transform(activeCrop);
- if (!activeCrop.intersect(outputState.layerStackSpace.content, &activeCrop)) {
+ if (!activeCrop.intersect(outputState.layerStackSpace.getContent(), &activeCrop)) {
activeCrop.clear();
}
activeCrop = inverseLayerTransform.transform(activeCrop, true);
@@ -228,7 +228,7 @@
geomLayerBounds.bottom += outset;
}
Rect frame{layerTransform.transform(reduce(geomLayerBounds, activeTransparentRegion))};
- if (!frame.intersect(outputState.layerStackSpace.content, &frame)) {
+ if (!frame.intersect(outputState.layerStackSpace.getContent(), &frame)) {
frame.clear();
}
const ui::Transform displayTransform{outputState.transform};
@@ -628,7 +628,7 @@
const auto& outputState = getOutput().getState();
Rect frame = layerFEState->cursorFrame;
- frame.intersect(outputState.layerStackSpace.content, &frame);
+ frame.intersect(outputState.layerStackSpace.getContent(), &frame);
Rect position = outputState.transform.transform(frame);
if (auto error = hwcLayer->setCursorPosition(position.left, position.top);
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index c1cd5ab..e6b716e 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -159,25 +159,23 @@
void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& texturePool,
const OutputCompositionState& outputState) {
ATRACE_CALL();
- const Rect& viewport = outputState.layerStackSpace.content;
+ const Rect& viewport = outputState.layerStackSpace.getContent();
const ui::Dataspace& outputDataspace = outputState.dataspace;
const ui::Transform::RotationFlags orientation =
- ui::Transform::toRotationFlags(outputState.framebufferSpace.orientation);
+ ui::Transform::toRotationFlags(outputState.framebufferSpace.getOrientation());
renderengine::DisplaySettings displaySettings{
- .physicalDisplay = outputState.framebufferSpace.content,
+ .physicalDisplay = outputState.framebufferSpace.getContent(),
.clip = viewport,
.outputDataspace = outputDataspace,
.orientation = orientation,
};
- Region clearRegion = Region::INVALID_REGION;
LayerFE::ClientCompositionTargetSettings targetSettings{
.clip = Region(viewport),
.needsFiltering = false,
.isSecure = outputState.isSecure,
.supportsProtectedContent = false,
- .clearRegion = clearRegion,
.viewport = viewport,
.dataspace = outputDataspace,
.realContentIsVisible = true,
@@ -274,17 +272,17 @@
bufferFence.reset(texture->getReadyFence()->dup());
}
- base::unique_fd drawFence;
- status_t result =
- renderEngine.drawLayers(displaySettings, layerSettingsPointers, texture->get(), false,
- std::move(bufferFence), &drawFence);
+ auto [status, drawFence] = renderEngine
+ .drawLayers(displaySettings, layerSettingsPointers,
+ texture->get(), false, std::move(bufferFence))
+ .get();
- if (result == NO_ERROR) {
+ if (status == NO_ERROR) {
mDrawFence = new Fence(drawFence.release());
mOutputSpace = outputState.framebufferSpace;
mTexture = texture;
mTexture->setReadyFence(mDrawFence);
- mOutputSpace.orientation = outputState.framebufferSpace.orientation;
+ mOutputSpace.setOrientation(outputState.framebufferSpace.getOrientation());
mOutputDataspace = outputDataspace;
mOrientation = orientation;
mSkipCount = 0;
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
index 936dba3..2532e3d 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
@@ -93,11 +93,7 @@
void LayerState::dump(std::string& result) const {
for (const StateInterface* field : getNonUniqueFields()) {
- if (auto viewOpt = flag_name(field->getField()); viewOpt) {
- base::StringAppendF(&result, " %16s: ", std::string(*viewOpt).c_str());
- } else {
- result.append("<UNKNOWN FIELD>:\n");
- }
+ base::StringAppendF(&result, " %16s: ", ftl::flag_string(field->getField()).c_str());
bool first = true;
for (const std::string& line : field->toStrings()) {
@@ -126,11 +122,7 @@
continue;
}
- if (auto viewOpt = flag_name(thisField->getField()); viewOpt) {
- base::StringAppendF(&result, " %16s: ", std::string(*viewOpt).c_str());
- } else {
- result.append("<UNKNOWN FIELD>:\n");
- }
+ base::StringAppendF(&result, " %16s: ", ftl::flag_string(thisField->getField()).c_str());
const auto& thisStrings = thisField->toStrings();
const auto& otherStrings = otherField->toStrings();
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index c037cc6..ed235b8 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -60,8 +60,7 @@
constexpr HalVirtualDisplayId HAL_VIRTUAL_DISPLAY_ID{456u};
constexpr GpuVirtualDisplayId GPU_VIRTUAL_DISPLAY_ID{789u};
-const ui::Size DEFAULT_RESOLUTION{1920, 1080};
-constexpr uint32_t DEFAULT_LAYER_STACK = 42;
+constexpr ui::Size DEFAULT_RESOLUTION{1920, 1080};
struct Layer {
Layer() {
@@ -161,13 +160,11 @@
EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
}
- DisplayCreationArgs getDisplayCreationArgsForPhysicalHWCDisplay() {
+ DisplayCreationArgs getDisplayCreationArgsForPhysicalDisplay() {
return DisplayCreationArgsBuilder()
.setId(DEFAULT_DISPLAY_ID)
- .setConnectionType(ui::DisplayConnectionType::Internal)
.setPixels(DEFAULT_RESOLUTION)
.setIsSecure(true)
- .setLayerStackId(DEFAULT_LAYER_STACK)
.setPowerAdvisor(&mPowerAdvisor)
.build();
}
@@ -177,7 +174,6 @@
.setId(GPU_VIRTUAL_DISPLAY_ID)
.setPixels(DEFAULT_RESOLUTION)
.setIsSecure(false)
- .setLayerStackId(DEFAULT_LAYER_STACK)
.setPowerAdvisor(&mPowerAdvisor)
.build();
}
@@ -193,14 +189,13 @@
using Display = DisplayTestCommon::PartialMockDisplay;
std::shared_ptr<Display> mDisplay =
createPartialMockDisplay<Display>(mCompositionEngine,
- getDisplayCreationArgsForPhysicalHWCDisplay());
+ getDisplayCreationArgsForPhysicalDisplay());
};
struct FullDisplayImplTestCommon : public DisplayTestCommon {
using Display = DisplayTestCommon::FullImplDisplay;
std::shared_ptr<Display> mDisplay =
- createDisplay<Display>(mCompositionEngine,
- getDisplayCreationArgsForPhysicalHWCDisplay());
+ createDisplay<Display>(mCompositionEngine, getDisplayCreationArgsForPhysicalDisplay());
};
struct DisplayWithLayersTestCommon : public FullDisplayImplTestCommon {
@@ -218,8 +213,7 @@
LayerNoHWC2Layer mLayer3;
StrictMock<HWC2::mock::Layer> hwc2LayerUnknown;
std::shared_ptr<Display> mDisplay =
- createDisplay<Display>(mCompositionEngine,
- getDisplayCreationArgsForPhysicalHWCDisplay());
+ createDisplay<Display>(mCompositionEngine, getDisplayCreationArgsForPhysicalDisplay());
};
/*
@@ -232,7 +226,7 @@
TEST_F(DisplayCreationTest, createPhysicalInternalDisplay) {
auto display =
- impl::createDisplay(mCompositionEngine, getDisplayCreationArgsForPhysicalHWCDisplay());
+ impl::createDisplay(mCompositionEngine, getDisplayCreationArgsForPhysicalDisplay());
EXPECT_TRUE(display->isSecure());
EXPECT_FALSE(display->isVirtual());
EXPECT_EQ(DEFAULT_DISPLAY_ID, display->getId());
@@ -252,13 +246,11 @@
using DisplaySetConfigurationTest = PartialMockDisplayTestCommon;
-TEST_F(DisplaySetConfigurationTest, configuresInternalSecurePhysicalDisplay) {
+TEST_F(DisplaySetConfigurationTest, configuresPhysicalDisplay) {
mDisplay->setConfiguration(DisplayCreationArgsBuilder()
.setId(DEFAULT_DISPLAY_ID)
- .setConnectionType(ui::DisplayConnectionType::Internal)
.setPixels(DEFAULT_RESOLUTION)
.setIsSecure(true)
- .setLayerStackId(DEFAULT_LAYER_STACK)
.setPowerAdvisor(&mPowerAdvisor)
.setName(getDisplayNameFromCurrentTest())
.build());
@@ -266,28 +258,11 @@
EXPECT_EQ(DEFAULT_DISPLAY_ID, mDisplay->getId());
EXPECT_TRUE(mDisplay->isSecure());
EXPECT_FALSE(mDisplay->isVirtual());
- EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId);
- EXPECT_TRUE(mDisplay->getState().layerStackInternal);
EXPECT_FALSE(mDisplay->isValid());
-}
-TEST_F(DisplaySetConfigurationTest, configuresExternalInsecurePhysicalDisplay) {
- mDisplay->setConfiguration(DisplayCreationArgsBuilder()
- .setId(DEFAULT_DISPLAY_ID)
- .setConnectionType(ui::DisplayConnectionType::External)
- .setPixels(DEFAULT_RESOLUTION)
- .setIsSecure(false)
- .setLayerStackId(DEFAULT_LAYER_STACK)
- .setPowerAdvisor(&mPowerAdvisor)
- .setName(getDisplayNameFromCurrentTest())
- .build());
-
- EXPECT_EQ(DEFAULT_DISPLAY_ID, mDisplay->getId());
- EXPECT_FALSE(mDisplay->isSecure());
- EXPECT_FALSE(mDisplay->isVirtual());
- EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId);
- EXPECT_FALSE(mDisplay->getState().layerStackInternal);
- EXPECT_FALSE(mDisplay->isValid());
+ const auto& filter = mDisplay->getState().layerFilter;
+ EXPECT_EQ(ui::INVALID_LAYER_STACK, filter.layerStack);
+ EXPECT_FALSE(filter.toInternalDisplay);
}
TEST_F(DisplaySetConfigurationTest, configuresHalVirtualDisplay) {
@@ -295,7 +270,6 @@
.setId(HAL_VIRTUAL_DISPLAY_ID)
.setPixels(DEFAULT_RESOLUTION)
.setIsSecure(false)
- .setLayerStackId(DEFAULT_LAYER_STACK)
.setPowerAdvisor(&mPowerAdvisor)
.setName(getDisplayNameFromCurrentTest())
.build());
@@ -303,9 +277,11 @@
EXPECT_EQ(HAL_VIRTUAL_DISPLAY_ID, mDisplay->getId());
EXPECT_FALSE(mDisplay->isSecure());
EXPECT_TRUE(mDisplay->isVirtual());
- EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId);
- EXPECT_FALSE(mDisplay->getState().layerStackInternal);
EXPECT_FALSE(mDisplay->isValid());
+
+ const auto& filter = mDisplay->getState().layerFilter;
+ EXPECT_EQ(ui::INVALID_LAYER_STACK, filter.layerStack);
+ EXPECT_FALSE(filter.toInternalDisplay);
}
TEST_F(DisplaySetConfigurationTest, configuresGpuVirtualDisplay) {
@@ -313,7 +289,6 @@
.setId(GPU_VIRTUAL_DISPLAY_ID)
.setPixels(DEFAULT_RESOLUTION)
.setIsSecure(false)
- .setLayerStackId(DEFAULT_LAYER_STACK)
.setPowerAdvisor(&mPowerAdvisor)
.setName(getDisplayNameFromCurrentTest())
.build());
@@ -321,9 +296,11 @@
EXPECT_EQ(GPU_VIRTUAL_DISPLAY_ID, mDisplay->getId());
EXPECT_FALSE(mDisplay->isSecure());
EXPECT_TRUE(mDisplay->isVirtual());
- EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId);
- EXPECT_FALSE(mDisplay->getState().layerStackInternal);
EXPECT_FALSE(mDisplay->isValid());
+
+ const auto& filter = mDisplay->getState().layerFilter;
+ EXPECT_EQ(ui::INVALID_LAYER_STACK, filter.layerStack);
+ EXPECT_FALSE(filter.toInternalDisplay);
}
/*
@@ -899,13 +876,10 @@
mDisplay->editState().isEnabled = true;
mDisplay->editState().usesClientComposition = false;
- mDisplay->editState().layerStackSpace.content = Rect(0, 0, 1, 1);
+ mDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1));
mDisplay->editState().dirtyRegion = Region::INVALID_REGION;
- CompositionRefreshArgs refreshArgs;
- refreshArgs.repaintEverything = false;
-
- mDisplay->finishFrame(refreshArgs);
+ mDisplay->finishFrame({});
}
TEST_F(DisplayFinishFrameTest, skipsCompositionIfNotDirty) {
@@ -920,13 +894,10 @@
gpuDisplay->editState().isEnabled = true;
gpuDisplay->editState().usesClientComposition = false;
- gpuDisplay->editState().layerStackSpace.content = Rect(0, 0, 1, 1);
+ gpuDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1));
gpuDisplay->editState().dirtyRegion = Region::INVALID_REGION;
- CompositionRefreshArgs refreshArgs;
- refreshArgs.repaintEverything = false;
-
- gpuDisplay->finishFrame(refreshArgs);
+ gpuDisplay->finishFrame({});
}
TEST_F(DisplayFinishFrameTest, performsCompositionIfDirty) {
@@ -941,34 +912,9 @@
gpuDisplay->editState().isEnabled = true;
gpuDisplay->editState().usesClientComposition = false;
- gpuDisplay->editState().layerStackSpace.content = Rect(0, 0, 1, 1);
+ gpuDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1));
gpuDisplay->editState().dirtyRegion = Region(Rect(0, 0, 1, 1));
-
- CompositionRefreshArgs refreshArgs;
- refreshArgs.repaintEverything = false;
-
- gpuDisplay->finishFrame(refreshArgs);
-}
-
-TEST_F(DisplayFinishFrameTest, performsCompositionIfRepaintEverything) {
- auto args = getDisplayCreationArgsForGpuVirtualDisplay();
- std::shared_ptr<impl::Display> gpuDisplay = impl::createDisplay(mCompositionEngine, args);
-
- mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
- gpuDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
-
- // We expect a single call to queueBuffer when composition is not skipped.
- EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(1);
-
- gpuDisplay->editState().isEnabled = true;
- gpuDisplay->editState().usesClientComposition = false;
- gpuDisplay->editState().layerStackSpace.content = Rect(0, 0, 1, 1);
- gpuDisplay->editState().dirtyRegion = Region::INVALID_REGION;
-
- CompositionRefreshArgs refreshArgs;
- refreshArgs.repaintEverything = true;
-
- gpuDisplay->finishFrame(refreshArgs);
+ gpuDisplay->finishFrame({});
}
/*
@@ -998,10 +944,8 @@
Display>(mCompositionEngine,
DisplayCreationArgsBuilder()
.setId(DEFAULT_DISPLAY_ID)
- .setConnectionType(ui::DisplayConnectionType::Internal)
.setPixels(DEFAULT_RESOLUTION)
.setIsSecure(true)
- .setLayerStackId(DEFAULT_LAYER_STACK)
.setPowerAdvisor(&mPowerAdvisor)
.build());
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index ada5adf..224dad1 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -49,6 +49,7 @@
MOCK_CONST_METHOD0(getMaxVirtualDisplayDimension, size_t());
MOCK_METHOD3(allocateVirtualDisplay, bool(HalVirtualDisplayId, ui::Size, ui::PixelFormat*));
MOCK_METHOD2(allocatePhysicalDisplay, void(hal::HWDisplayId, PhysicalDisplayId));
+
MOCK_METHOD1(createLayer, std::shared_ptr<HWC2::Layer>(HalDisplayId));
MOCK_METHOD5(getDeviceCompositionChanges,
status_t(HalDisplayId, bool, std::chrono::steady_clock::time_point,
@@ -110,11 +111,15 @@
MOCK_CONST_METHOD1(dump, void(std::string&));
MOCK_CONST_METHOD0(getComposer, android::Hwc2::Composer*());
- MOCK_CONST_METHOD1(getHwcDisplayId, std::optional<hal::HWDisplayId>(int32_t));
- MOCK_CONST_METHOD0(getInternalHwcDisplayId, std::optional<hal::HWDisplayId>());
- MOCK_CONST_METHOD0(getExternalHwcDisplayId, std::optional<hal::HWDisplayId>());
- MOCK_CONST_METHOD1(toPhysicalDisplayId, std::optional<PhysicalDisplayId>(hal::HWDisplayId));
- MOCK_CONST_METHOD1(fromPhysicalDisplayId, std::optional<hal::HWDisplayId>(PhysicalDisplayId));
+
+ MOCK_METHOD(hal::HWDisplayId, getPrimaryHwcDisplayId, (), (const, override));
+ MOCK_METHOD(PhysicalDisplayId, getPrimaryDisplayId, (), (const, override));
+ MOCK_METHOD(bool, isHeadless, (), (const, override));
+
+ MOCK_METHOD(std::optional<PhysicalDisplayId>, toPhysicalDisplayId, (hal::HWDisplayId),
+ (const, override));
+ MOCK_METHOD(std::optional<hal::HWDisplayId>, fromPhysicalDisplayId, (PhysicalDisplayId),
+ (const, override));
};
} // namespace mock
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index c8c6012..53b71b7 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -158,7 +158,7 @@
mLayerFEState.geomBufferSize = Rect{0, 0, 1920, 1080};
mLayerFEState.geomBufferTransform = TR_IDENT;
- mOutputState.layerStackSpace.content = Rect{0, 0, 1920, 1080};
+ mOutputState.layerStackSpace.setContent(Rect{0, 0, 1920, 1080});
}
FloatRect calculateOutputSourceCrop() {
@@ -229,7 +229,7 @@
mLayerFEState.geomBufferUsesDisplayInverseTransform = entry.bufferInvDisplay;
mLayerFEState.geomBufferTransform = entry.buffer;
- mOutputState.displaySpace.orientation = toRotation(entry.display);
+ mOutputState.displaySpace.setOrientation(toRotation(entry.display));
EXPECT_THAT(calculateOutputSourceCrop(), entry.expected) << "entry " << i;
}
@@ -243,7 +243,7 @@
}
TEST_F(OutputLayerSourceCropTest, viewportAffectsCrop) {
- mOutputState.layerStackSpace.content = Rect{0, 0, 960, 540};
+ mOutputState.layerStackSpace.setContent(Rect{0, 0, 960, 540});
const FloatRect expected{0.f, 0.f, 960.f, 540.f};
EXPECT_THAT(calculateOutputSourceCrop(), expected);
@@ -265,7 +265,7 @@
mLayerFEState.geomCrop = Rect{0, 0, 1920, 1080};
mLayerFEState.geomLayerBounds = FloatRect{0.f, 0.f, 1920.f, 1080.f};
- mOutputState.layerStackSpace.content = Rect{0, 0, 1920, 1080};
+ mOutputState.layerStackSpace.setContent(Rect{0, 0, 1920, 1080});
mOutputState.transform = ui::Transform{TR_IDENT};
}
@@ -313,7 +313,7 @@
}
TEST_F(OutputLayerDisplayFrameTest, viewportAffectsFrame) {
- mOutputState.layerStackSpace.content = Rect{0, 0, 960, 540};
+ mOutputState.layerStackSpace.setContent(Rect{0, 0, 960, 540});
const Rect expected{0, 0, 960, 540};
EXPECT_THAT(calculateOutputDisplayFrame(), expected);
}
@@ -399,7 +399,7 @@
mLayerFEState.geomLayerTransform.set(entry.layer, 1920, 1080);
mLayerFEState.geomBufferTransform = entry.buffer;
- mOutputState.displaySpace.orientation = toRotation(entry.display);
+ mOutputState.displaySpace.setOrientation(toRotation(entry.display));
mOutputState.transform = ui::Transform{entry.display};
const auto actual = mOutputLayer.calculateOutputRelativeBufferTransform(entry.display);
@@ -511,7 +511,7 @@
mLayerFEState.geomLayerTransform.set(entry.layer, 1920, 1080);
mLayerFEState.geomBufferTransform = entry.buffer;
- mOutputState.displaySpace.orientation = toRotation(entry.display);
+ mOutputState.displaySpace.setOrientation(toRotation(entry.display));
mOutputState.transform = ui::Transform{entry.display};
const auto actual = mOutputLayer.calculateOutputRelativeBufferTransform(entry.internal);
@@ -942,7 +942,7 @@
// This test simulates a scenario where displayInstallOrientation is set to
// ROT_90. This only has an effect on the transform; orientation stays 0 (see
// DisplayDevice::setProjection).
- mOutputState.displaySpace.orientation = ui::ROTATION_0;
+ mOutputState.displaySpace.setOrientation(ui::ROTATION_0);
mOutputState.transform = ui::Transform{TR_ROT_90};
// Buffers are pre-rotated based on the transform hint (ROT_90); their
// geomBufferTransform is set to the inverse transform.
@@ -1237,7 +1237,7 @@
mLayerFEState.cursorFrame = kDefaultCursorFrame;
- mOutputState.layerStackSpace.content = kDefaultDisplayViewport;
+ mOutputState.layerStackSpace.setContent(kDefaultDisplayViewport);
mOutputState.transform = ui::Transform{kDefaultTransform};
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 09f5a5e..bec7479 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -35,6 +35,7 @@
#include "CallOrderStateMachineHelper.h"
#include "MockHWC2.h"
#include "RegionMatcher.h"
+#include "TestUtils.h"
#include "renderengine/ExternalTexture.h"
namespace android::compositionengine {
@@ -142,7 +143,8 @@
std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
mOutput->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
- mOutput->editState().displaySpace.bounds = kDefaultDisplaySize;
+ mOutput->editState().displaySpace.setBounds(
+ ui::Size(kDefaultDisplaySize.getWidth(), kDefaultDisplaySize.getHeight()));
EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
}
@@ -288,8 +290,10 @@
TEST_F(OutputTest, setProjectionWorks) {
const Rect displayRect{0, 0, 1000, 2000};
- mOutput->editState().displaySpace.bounds = displayRect;
- mOutput->editState().framebufferSpace.bounds = displayRect;
+ mOutput->editState().displaySpace.setBounds(
+ ui::Size(displayRect.getWidth(), displayRect.getHeight()));
+ mOutput->editState().framebufferSpace.setBounds(
+ ui::Size(displayRect.getWidth(), displayRect.getHeight()));
const ui::Rotation orientation = ui::ROTATION_90;
const Rect frame{50, 60, 100, 100};
@@ -297,28 +301,29 @@
mOutput->setProjection(orientation, viewport, frame);
- EXPECT_EQ(orientation, mOutput->getState().displaySpace.orientation);
- EXPECT_EQ(frame, mOutput->getState().orientedDisplaySpace.content);
- EXPECT_EQ(viewport, mOutput->getState().layerStackSpace.content);
+ EXPECT_EQ(orientation, mOutput->getState().displaySpace.getOrientation());
+ EXPECT_EQ(frame, mOutput->getState().orientedDisplaySpace.getContent());
+ EXPECT_EQ(viewport, mOutput->getState().layerStackSpace.getContent());
const auto state = mOutput->getState();
- EXPECT_EQ(ui::ROTATION_0, state.layerStackSpace.orientation);
- EXPECT_EQ(viewport, state.layerStackSpace.content);
- EXPECT_EQ(viewport, state.layerStackSpace.bounds);
+ EXPECT_EQ(ui::ROTATION_0, state.layerStackSpace.getOrientation());
+ EXPECT_EQ(viewport, state.layerStackSpace.getContent());
+ EXPECT_EQ(Rect(0, 0, 20, 20), state.layerStackSpace.getBoundsAsRect());
- EXPECT_EQ(ui::ROTATION_0, state.orientedDisplaySpace.orientation);
- EXPECT_EQ(frame, state.orientedDisplaySpace.content);
- EXPECT_EQ(Rect(0, 0, 2000, 1000), state.orientedDisplaySpace.bounds);
+ EXPECT_EQ(ui::ROTATION_0, state.orientedDisplaySpace.getOrientation());
+ EXPECT_EQ(frame, state.orientedDisplaySpace.getContent());
+ EXPECT_EQ(Rect(0, 0, 2000, 1000), state.orientedDisplaySpace.getBoundsAsRect());
- EXPECT_EQ(displayRect, state.displaySpace.bounds);
- EXPECT_EQ(Rect(900, 50, 940, 100), state.displaySpace.content);
- EXPECT_EQ(orientation, state.displaySpace.orientation);
+ EXPECT_EQ(displayRect, state.displaySpace.getBoundsAsRect());
+ EXPECT_EQ(Rect(900, 50, 940, 100), state.displaySpace.getContent());
+ EXPECT_EQ(orientation, state.displaySpace.getOrientation());
- EXPECT_EQ(displayRect, state.framebufferSpace.bounds);
- EXPECT_EQ(Rect(900, 50, 940, 100), state.framebufferSpace.content);
- EXPECT_EQ(orientation, state.framebufferSpace.orientation);
+ EXPECT_EQ(displayRect, state.framebufferSpace.getBoundsAsRect());
+ EXPECT_EQ(Rect(900, 50, 940, 100), state.framebufferSpace.getContent());
+ EXPECT_EQ(orientation, state.framebufferSpace.getOrientation());
- EXPECT_EQ(state.displaySpace.content, state.transform.transform(state.layerStackSpace.content));
+ EXPECT_EQ(state.displaySpace.getContent(),
+ state.transform.transform(state.layerStackSpace.getContent()));
EXPECT_EQ(ui::Transform::ROT_90, mOutput->getTransformHint());
}
@@ -326,8 +331,10 @@
TEST_F(OutputTest, setProjectionWithSmallFramebufferWorks) {
const Rect displayRect{0, 0, 1000, 2000};
const Rect framebufferRect{0, 0, 500, 1000};
- mOutput->editState().displaySpace.bounds = displayRect;
- mOutput->editState().framebufferSpace.bounds = framebufferRect;
+ mOutput->editState().displaySpace.setBounds(
+ ui::Size(displayRect.getWidth(), displayRect.getHeight()));
+ mOutput->editState().framebufferSpace.setBounds(
+ ui::Size(framebufferRect.getWidth(), framebufferRect.getHeight()));
const ui::Rotation orientation = ui::ROTATION_90;
const Rect frame{50, 60, 100, 100};
@@ -335,28 +342,29 @@
mOutput->setProjection(orientation, viewport, frame);
- EXPECT_EQ(orientation, mOutput->getState().displaySpace.orientation);
- EXPECT_EQ(frame, mOutput->getState().orientedDisplaySpace.content);
- EXPECT_EQ(viewport, mOutput->getState().layerStackSpace.content);
+ EXPECT_EQ(orientation, mOutput->getState().displaySpace.getOrientation());
+ EXPECT_EQ(frame, mOutput->getState().orientedDisplaySpace.getContent());
+ EXPECT_EQ(viewport, mOutput->getState().layerStackSpace.getContent());
const auto state = mOutput->getState();
- EXPECT_EQ(ui::ROTATION_0, state.layerStackSpace.orientation);
- EXPECT_EQ(viewport, state.layerStackSpace.content);
- EXPECT_EQ(viewport, state.layerStackSpace.bounds);
+ EXPECT_EQ(ui::ROTATION_0, state.layerStackSpace.getOrientation());
+ EXPECT_EQ(viewport, state.layerStackSpace.getContent());
+ EXPECT_EQ(Rect(0, 0, 20, 20), state.layerStackSpace.getBoundsAsRect());
- EXPECT_EQ(ui::ROTATION_0, state.orientedDisplaySpace.orientation);
- EXPECT_EQ(frame, state.orientedDisplaySpace.content);
- EXPECT_EQ(Rect(0, 0, 2000, 1000), state.orientedDisplaySpace.bounds);
+ EXPECT_EQ(ui::ROTATION_0, state.orientedDisplaySpace.getOrientation());
+ EXPECT_EQ(frame, state.orientedDisplaySpace.getContent());
+ EXPECT_EQ(Rect(0, 0, 2000, 1000), state.orientedDisplaySpace.getBoundsAsRect());
- EXPECT_EQ(displayRect, state.displaySpace.bounds);
- EXPECT_EQ(Rect(900, 50, 940, 100), state.displaySpace.content);
- EXPECT_EQ(orientation, state.displaySpace.orientation);
+ EXPECT_EQ(displayRect, state.displaySpace.getBoundsAsRect());
+ EXPECT_EQ(Rect(900, 50, 940, 100), state.displaySpace.getContent());
+ EXPECT_EQ(orientation, state.displaySpace.getOrientation());
- EXPECT_EQ(framebufferRect, state.framebufferSpace.bounds);
- EXPECT_EQ(Rect(450, 25, 470, 50), state.framebufferSpace.content);
- EXPECT_EQ(orientation, state.framebufferSpace.orientation);
+ EXPECT_EQ(framebufferRect, state.framebufferSpace.getBoundsAsRect());
+ EXPECT_EQ(Rect(450, 25, 470, 50), state.framebufferSpace.getContent());
+ EXPECT_EQ(orientation, state.framebufferSpace.getOrientation());
- EXPECT_EQ(state.displaySpace.content, state.transform.transform(state.layerStackSpace.content));
+ EXPECT_EQ(state.displaySpace.getContent(),
+ state.transform.transform(state.layerStackSpace.getContent()));
}
/*
@@ -364,16 +372,16 @@
*/
TEST_F(OutputTest, setDisplaySpaceSizeUpdatesOutputStateAndDirtiesEntireOutput) {
- mOutput->editState().layerStackSpace.content = Rect(0, 0, 2000, 1000);
- mOutput->editState().layerStackSpace.bounds = Rect(0, 0, 2000, 1000);
- mOutput->editState().orientedDisplaySpace.content = Rect(0, 0, 1800, 900);
- mOutput->editState().orientedDisplaySpace.bounds = Rect(0, 0, 2000, 1000);
- mOutput->editState().framebufferSpace.content = Rect(0, 0, 900, 1800);
- mOutput->editState().framebufferSpace.bounds = Rect(0, 0, 1000, 2000);
- mOutput->editState().framebufferSpace.orientation = ui::ROTATION_90;
- mOutput->editState().displaySpace.content = Rect(0, 0, 900, 1800);
- mOutput->editState().displaySpace.bounds = Rect(0, 0, 1000, 2000);
- mOutput->editState().displaySpace.orientation = ui::ROTATION_90;
+ mOutput->editState().layerStackSpace.setContent(Rect(0, 0, 2000, 1000));
+ mOutput->editState().layerStackSpace.setBounds(ui::Size(2000, 1000));
+ mOutput->editState().orientedDisplaySpace.setContent(Rect(0, 0, 1800, 900));
+ mOutput->editState().orientedDisplaySpace.setBounds(ui::Size(2000, 1000));
+ mOutput->editState().framebufferSpace.setContent(Rect(0, 0, 900, 1800));
+ mOutput->editState().framebufferSpace.setBounds(ui::Size(1000, 2000));
+ mOutput->editState().framebufferSpace.setOrientation(ui::ROTATION_90);
+ mOutput->editState().displaySpace.setContent(Rect(0, 0, 900, 1800));
+ mOutput->editState().displaySpace.setBounds(ui::Size(1000, 2000));
+ mOutput->editState().displaySpace.setOrientation(ui::ROTATION_90);
const ui::Size newDisplaySize{500, 1000};
@@ -384,36 +392,38 @@
const auto state = mOutput->getState();
const Rect displayRect(newDisplaySize);
- EXPECT_EQ(ui::ROTATION_0, state.layerStackSpace.orientation);
- EXPECT_EQ(Rect(0, 0, 2000, 1000), state.layerStackSpace.content);
- EXPECT_EQ(Rect(0, 0, 2000, 1000), state.layerStackSpace.bounds);
+ EXPECT_EQ(ui::ROTATION_0, state.layerStackSpace.getOrientation());
+ EXPECT_EQ(Rect(0, 0, 2000, 1000), state.layerStackSpace.getContent());
+ EXPECT_EQ(Rect(0, 0, 2000, 1000), state.layerStackSpace.getBoundsAsRect());
- EXPECT_EQ(ui::ROTATION_0, state.orientedDisplaySpace.orientation);
- EXPECT_EQ(Rect(0, 0, 1000, 500), state.orientedDisplaySpace.bounds);
+ EXPECT_EQ(ui::ROTATION_0, state.orientedDisplaySpace.getOrientation());
+ EXPECT_EQ(Rect(0, 0, 1000, 500), state.orientedDisplaySpace.getBoundsAsRect());
- EXPECT_EQ(displayRect, state.displaySpace.bounds);
- EXPECT_EQ(ui::ROTATION_90, state.displaySpace.orientation);
+ EXPECT_EQ(displayRect, state.displaySpace.getBoundsAsRect());
+ EXPECT_EQ(ui::ROTATION_90, state.displaySpace.getOrientation());
- EXPECT_EQ(displayRect, state.framebufferSpace.bounds);
- EXPECT_EQ(ui::ROTATION_90, state.framebufferSpace.orientation);
+ EXPECT_EQ(displayRect, state.framebufferSpace.getBoundsAsRect());
+ EXPECT_EQ(ui::ROTATION_90, state.framebufferSpace.getOrientation());
- EXPECT_EQ(state.displaySpace.content, state.transform.transform(state.layerStackSpace.content));
+ EXPECT_EQ(state.displaySpace.getContent(),
+ state.transform.transform(state.layerStackSpace.getContent()));
EXPECT_THAT(state.dirtyRegion, RegionEq(Region(displayRect)));
}
/*
- * Output::setLayerStackFilter()
+ * Output::setLayerFilter()
*/
-TEST_F(OutputTest, setLayerStackFilterSetsFilterAndDirtiesEntireOutput) {
- const uint32_t layerStack = 123u;
- mOutput->setLayerStackFilter(layerStack, true);
+TEST_F(OutputTest, setLayerFilterSetsFilterAndDirtiesEntireOutput) {
+ constexpr ui::LayerFilter kFilter{ui::LayerStack{123u}, true};
+ mOutput->setLayerFilter(kFilter);
- EXPECT_TRUE(mOutput->getState().layerStackInternal);
- EXPECT_EQ(layerStack, mOutput->getState().layerStackId);
+ const auto& state = mOutput->getState();
+ EXPECT_EQ(kFilter.layerStack, state.layerFilter.layerStack);
+ EXPECT_TRUE(state.layerFilter.toInternalDisplay);
- EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
+ EXPECT_THAT(state.dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
}
/*
@@ -560,133 +570,107 @@
mOutput->setRenderSurface(std::unique_ptr<RenderSurface>(renderSurface));
- EXPECT_EQ(Rect(newDisplaySize), mOutput->getState().framebufferSpace.bounds);
+ EXPECT_EQ(Rect(newDisplaySize), mOutput->getState().framebufferSpace.getBoundsAsRect());
}
/*
* Output::getDirtyRegion()
*/
-TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingTrue) {
+TEST_F(OutputTest, getDirtyRegion) {
const Rect viewport{100, 200};
- mOutput->editState().layerStackSpace.content = viewport;
+ mOutput->editState().layerStackSpace.setContent(viewport);
mOutput->editState().dirtyRegion.set(50, 300);
- {
- Region result = mOutput->getDirtyRegion(true);
-
- EXPECT_THAT(result, RegionEq(Region(viewport)));
- }
-}
-
-TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingFalse) {
- const Rect viewport{100, 200};
- mOutput->editState().layerStackSpace.content = viewport;
- mOutput->editState().dirtyRegion.set(50, 300);
-
- {
- Region result = mOutput->getDirtyRegion(false);
-
- // The dirtyRegion should be clipped to the display bounds.
- EXPECT_THAT(result, RegionEq(Region(Rect(50, 200))));
- }
+ // The dirty region should be clipped to the display bounds.
+ EXPECT_THAT(mOutput->getDirtyRegion(), RegionEq(Region(Rect(50, 200))));
}
/*
- * Output::belongsInOutput()
+ * Output::includesLayer()
*/
-TEST_F(OutputTest, belongsInOutputFiltersAsExpected) {
- const uint32_t layerStack1 = 123u;
- const uint32_t layerStack2 = 456u;
+TEST_F(OutputTest, layerFiltering) {
+ const ui::LayerStack layerStack1{123u};
+ const ui::LayerStack layerStack2{456u};
- // If the output accepts layerStack1 and internal-only layers....
- mOutput->setLayerStackFilter(layerStack1, true);
+ // If the output is associated to layerStack1 and to an internal display...
+ mOutput->setLayerFilter({layerStack1, true});
- // A layer with no layerStack does not belong to it, internal-only or not.
- EXPECT_FALSE(mOutput->belongsInOutput(std::nullopt, false));
- EXPECT_FALSE(mOutput->belongsInOutput(std::nullopt, true));
+ // It excludes layers with no layer stack, internal-only or not.
+ EXPECT_FALSE(mOutput->includesLayer({ui::INVALID_LAYER_STACK, false}));
+ EXPECT_FALSE(mOutput->includesLayer({ui::INVALID_LAYER_STACK, true}));
- // Any layer with layerStack1 belongs to it, internal-only or not.
- EXPECT_TRUE(mOutput->belongsInOutput(layerStack1, false));
- EXPECT_TRUE(mOutput->belongsInOutput(layerStack1, true));
- EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, true));
- EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, false));
+ // It includes layers on layerStack1, internal-only or not.
+ EXPECT_TRUE(mOutput->includesLayer({layerStack1, false}));
+ EXPECT_TRUE(mOutput->includesLayer({layerStack1, true}));
+ EXPECT_FALSE(mOutput->includesLayer({layerStack2, true}));
+ EXPECT_FALSE(mOutput->includesLayer({layerStack2, false}));
- // If the output accepts layerStack21 but not internal-only layers...
- mOutput->setLayerStackFilter(layerStack1, false);
+ // If the output is associated to layerStack1 but not to an internal display...
+ mOutput->setLayerFilter({layerStack1, false});
- // Only non-internal layers with layerStack1 belong to it.
- EXPECT_TRUE(mOutput->belongsInOutput(layerStack1, false));
- EXPECT_FALSE(mOutput->belongsInOutput(layerStack1, true));
- EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, true));
- EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, false));
+ // It includes layers on layerStack1, unless they are internal-only.
+ EXPECT_TRUE(mOutput->includesLayer({layerStack1, false}));
+ EXPECT_FALSE(mOutput->includesLayer({layerStack1, true}));
+ EXPECT_FALSE(mOutput->includesLayer({layerStack2, true}));
+ EXPECT_FALSE(mOutput->includesLayer({layerStack2, false}));
}
-TEST_F(OutputTest, belongsInOutputHandlesLayerWithNoCompositionState) {
+TEST_F(OutputTest, layerFilteringWithoutCompositionState) {
NonInjectedLayer layer;
sp<LayerFE> layerFE(layer.layerFE);
- // If the layer has no composition state, it does not belong to any output.
+ // Layers without composition state are excluded.
EXPECT_CALL(*layer.layerFE, getCompositionState).WillOnce(Return(nullptr));
- EXPECT_FALSE(mOutput->belongsInOutput(layerFE));
+ EXPECT_FALSE(mOutput->includesLayer(layerFE));
}
-TEST_F(OutputTest, belongsInOutputFiltersLayersAsExpected) {
+TEST_F(OutputTest, layerFilteringWithCompositionState) {
NonInjectedLayer layer;
sp<LayerFE> layerFE(layer.layerFE);
- const uint32_t layerStack1 = 123u;
- const uint32_t layerStack2 = 456u;
+ const ui::LayerStack layerStack1{123u};
+ const ui::LayerStack layerStack2{456u};
- // If the output accepts layerStack1 and internal-only layers....
- mOutput->setLayerStackFilter(layerStack1, true);
+ // If the output is associated to layerStack1 and to an internal display...
+ mOutput->setLayerFilter({layerStack1, true});
- // A layer with no layerStack does not belong to it, internal-only or not.
- layer.layerFEState.layerStackId = std::nullopt;
- layer.layerFEState.internalOnly = false;
- EXPECT_FALSE(mOutput->belongsInOutput(layerFE));
+ // It excludes layers with no layer stack, internal-only or not.
+ layer.layerFEState.outputFilter = {ui::INVALID_LAYER_STACK, false};
+ EXPECT_FALSE(mOutput->includesLayer(layerFE));
- layer.layerFEState.layerStackId = std::nullopt;
- layer.layerFEState.internalOnly = true;
- EXPECT_FALSE(mOutput->belongsInOutput(layerFE));
+ layer.layerFEState.outputFilter = {ui::INVALID_LAYER_STACK, true};
+ EXPECT_FALSE(mOutput->includesLayer(layerFE));
- // Any layer with layerStack1 belongs to it, internal-only or not.
- layer.layerFEState.layerStackId = layerStack1;
- layer.layerFEState.internalOnly = false;
- EXPECT_TRUE(mOutput->belongsInOutput(layerFE));
+ // It includes layers on layerStack1, internal-only or not.
+ layer.layerFEState.outputFilter = {layerStack1, false};
+ EXPECT_TRUE(mOutput->includesLayer(layerFE));
- layer.layerFEState.layerStackId = layerStack1;
- layer.layerFEState.internalOnly = true;
- EXPECT_TRUE(mOutput->belongsInOutput(layerFE));
+ layer.layerFEState.outputFilter = {layerStack1, true};
+ EXPECT_TRUE(mOutput->includesLayer(layerFE));
- layer.layerFEState.layerStackId = layerStack2;
- layer.layerFEState.internalOnly = true;
- EXPECT_FALSE(mOutput->belongsInOutput(layerFE));
+ layer.layerFEState.outputFilter = {layerStack2, true};
+ EXPECT_FALSE(mOutput->includesLayer(layerFE));
- layer.layerFEState.layerStackId = layerStack2;
- layer.layerFEState.internalOnly = false;
- EXPECT_FALSE(mOutput->belongsInOutput(layerFE));
+ layer.layerFEState.outputFilter = {layerStack2, false};
+ EXPECT_FALSE(mOutput->includesLayer(layerFE));
- // If the output accepts layerStack1 but not internal-only layers...
- mOutput->setLayerStackFilter(layerStack1, false);
+ // If the output is associated to layerStack1 but not to an internal display...
+ mOutput->setLayerFilter({layerStack1, false});
- // Only non-internal layers with layerStack1 belong to it.
- layer.layerFEState.layerStackId = layerStack1;
- layer.layerFEState.internalOnly = false;
- EXPECT_TRUE(mOutput->belongsInOutput(layerFE));
+ // It includes layers on layerStack1, unless they are internal-only.
+ layer.layerFEState.outputFilter = {layerStack1, false};
+ EXPECT_TRUE(mOutput->includesLayer(layerFE));
- layer.layerFEState.layerStackId = layerStack1;
- layer.layerFEState.internalOnly = true;
- EXPECT_FALSE(mOutput->belongsInOutput(layerFE));
+ layer.layerFEState.outputFilter = {layerStack1, true};
+ EXPECT_FALSE(mOutput->includesLayer(layerFE));
- layer.layerFEState.layerStackId = layerStack2;
- layer.layerFEState.internalOnly = true;
- EXPECT_FALSE(mOutput->belongsInOutput(layerFE));
+ layer.layerFEState.outputFilter = {layerStack2, true};
+ EXPECT_FALSE(mOutput->includesLayer(layerFE));
- layer.layerFEState.layerStackId = layerStack2;
- layer.layerFEState.internalOnly = false;
- EXPECT_FALSE(mOutput->belongsInOutput(layerFE));
+ layer.layerFEState.outputFilter = {layerStack2, false};
+ EXPECT_FALSE(mOutput->includesLayer(layerFE));
}
/*
@@ -1079,7 +1063,8 @@
OutputRebuildLayerStacksTest() {
mOutput.mState.isEnabled = true;
mOutput.mState.transform = kIdentityTransform;
- mOutput.mState.displaySpace.bounds = kOutputBounds;
+ mOutput.mState.displaySpace.setBounds(
+ ui::Size(kOutputBounds.getWidth(), kOutputBounds.getHeight()));
mRefreshArgs.updatingOutputGeometryThisFrame = true;
@@ -1268,21 +1253,22 @@
struct OutputPartialMock : public OutputPartialMockBase {
// Sets up the helper functions called by the function under test to use
// mock implementations.
- MOCK_CONST_METHOD1(belongsInOutput, bool(const sp<compositionengine::LayerFE>&));
+ MOCK_METHOD(bool, includesLayer, (const sp<compositionengine::LayerFE>&),
+ (const, override));
MOCK_CONST_METHOD1(getOutputLayerOrderedByZByIndex, OutputLayer*(size_t));
MOCK_METHOD2(ensureOutputLayer,
compositionengine::OutputLayer*(std::optional<size_t>, const sp<LayerFE>&));
};
OutputEnsureOutputLayerIfVisibleTest() {
- EXPECT_CALL(mOutput, belongsInOutput(sp<LayerFE>(mLayer.layerFE)))
+ EXPECT_CALL(mOutput, includesLayer(sp<LayerFE>(mLayer.layerFE)))
.WillRepeatedly(Return(true));
EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1u));
EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(0u))
.WillRepeatedly(Return(&mLayer.outputLayer));
- mOutput.mState.displaySpace.bounds = Rect(0, 0, 200, 300);
- mOutput.mState.layerStackSpace.content = Rect(0, 0, 200, 300);
+ mOutput.mState.displaySpace.setBounds(ui::Size(200, 300));
+ mOutput.mState.layerStackSpace.setContent(Rect(0, 0, 200, 300));
mOutput.mState.transform = ui::Transform(TR_IDENT, 200, 300);
mLayer.layerFEState.isVisible = true;
@@ -1326,8 +1312,8 @@
const Region OutputEnsureOutputLayerIfVisibleTest::kFullBounds90Rotation =
Region(Rect(0, 0, 200, 100));
-TEST_F(OutputEnsureOutputLayerIfVisibleTest, performsGeomLatchBeforeCheckingIfLayerBelongs) {
- EXPECT_CALL(mOutput, belongsInOutput(sp<LayerFE>(mLayer.layerFE))).WillOnce(Return(false));
+TEST_F(OutputEnsureOutputLayerIfVisibleTest, performsGeomLatchBeforeCheckingIfLayerIncluded) {
+ EXPECT_CALL(mOutput, includesLayer(sp<LayerFE>(mLayer.layerFE))).WillOnce(Return(false));
EXPECT_CALL(*mLayer.layerFE,
prepareCompositionState(compositionengine::LayerFE::StateSubset::BasicGeometry));
@@ -1337,8 +1323,8 @@
}
TEST_F(OutputEnsureOutputLayerIfVisibleTest,
- skipsLatchIfAlreadyLatchedBeforeCheckingIfLayerBelongs) {
- EXPECT_CALL(mOutput, belongsInOutput(sp<LayerFE>(mLayer.layerFE))).WillOnce(Return(false));
+ skipsLatchIfAlreadyLatchedBeforeCheckingIfLayerIncluded) {
+ EXPECT_CALL(mOutput, includesLayer(sp<LayerFE>(mLayer.layerFE))).WillOnce(Return(false));
ensureOutputLayerIfVisible();
}
@@ -1362,7 +1348,7 @@
}
TEST_F(OutputEnsureOutputLayerIfVisibleTest, takesNotSoEarlyOutifDrawRegionEmpty) {
- mOutput.mState.displaySpace.bounds = Rect(0, 0, 0, 0);
+ mOutput.mState.displaySpace.setBounds(ui::Size(0, 0));
ensureOutputLayerIfVisible();
}
@@ -1559,7 +1545,7 @@
mLayer.layerFEState.contentDirty = true;
mLayer.layerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
- mOutput.mState.layerStackSpace.content = Rect(0, 0, 300, 200);
+ mOutput.mState.layerStackSpace.setContent(Rect(0, 0, 300, 200));
mOutput.mState.transform = ui::Transform(TR_ROT_90, 200, 300);
EXPECT_CALL(mOutput, getOutputLayerCount()).WillOnce(Return(0u));
@@ -1585,7 +1571,7 @@
mLayer.layerFEState.contentDirty = true;
mLayer.layerFEState.geomLayerTransform = ui::Transform(TR_IDENT, 100, 200);
- mOutput.mState.layerStackSpace.content = Rect(0, 0, 300, 200);
+ mOutput.mState.layerStackSpace.setContent(Rect(0, 0, 300, 200));
mOutput.mState.transform = ui::Transform(TR_ROT_90, 200, 300);
EXPECT_CALL(mOutput, ensureOutputLayer(Eq(0u), Eq(mLayer.layerFE)))
@@ -2530,7 +2516,7 @@
struct OutputPartialMock : public OutputPartialMockBase {
// Sets up the helper functions called by the function under test to use
// mock implementations.
- MOCK_CONST_METHOD1(getDirtyRegion, Region(bool));
+ MOCK_METHOD(Region, getDirtyRegion, (), (const));
};
OutputBeginFrameTest() {
@@ -2542,8 +2528,7 @@
struct IfGetDirtyRegionExpectationState
: public CallOrderStateMachineHelper<TestType, IfGetDirtyRegionExpectationState> {
[[nodiscard]] auto ifGetDirtyRegionReturns(Region dirtyRegion) {
- EXPECT_CALL(getInstance()->mOutput, getDirtyRegion(false))
- .WillOnce(Return(dirtyRegion));
+ EXPECT_CALL(getInstance()->mOutput, getDirtyRegion()).WillOnce(Return(dirtyRegion));
return nextState<AndIfGetOutputLayerCountExpectationState>();
}
};
@@ -2683,7 +2668,7 @@
struct OutputPartialMock : public OutputPartialMockBase {
// Sets up the helper functions called by the function under test to use
// mock implementations.
- MOCK_CONST_METHOD1(getDirtyRegion, Region(bool));
+ MOCK_METHOD(Region, getDirtyRegion, (), (const));
MOCK_METHOD2(composeSurfaces,
std::optional<base::unique_fd>(
const Region&, const compositionengine::CompositionRefreshArgs&));
@@ -2711,7 +2696,6 @@
TEST_F(OutputDevOptRepaintFlashTest, doesNothingIfFlashDelayNotSet) {
mRefreshArgs.devOptFlashDirtyRegionsDelay = {};
- mRefreshArgs.repaintEverything = true;
mOutput.mState.isEnabled = true;
mOutput.devOptRepaintFlash(mRefreshArgs);
@@ -2719,7 +2703,6 @@
TEST_F(OutputDevOptRepaintFlashTest, postsAndPreparesANewFrameIfNotEnabled) {
mRefreshArgs.devOptFlashDirtyRegionsDelay = std::chrono::microseconds(1);
- mRefreshArgs.repaintEverything = true;
mOutput.mState.isEnabled = false;
InSequence seq;
@@ -2729,13 +2712,12 @@
mOutput.devOptRepaintFlash(mRefreshArgs);
}
-TEST_F(OutputDevOptRepaintFlashTest, postsAndPreparesANewFrameIfNotDirty) {
+TEST_F(OutputDevOptRepaintFlashTest, postsAndPreparesANewFrameIfEnabled) {
mRefreshArgs.devOptFlashDirtyRegionsDelay = std::chrono::microseconds(1);
- mRefreshArgs.repaintEverything = true;
mOutput.mState.isEnabled = true;
InSequence seq;
- EXPECT_CALL(mOutput, getDirtyRegion(true)).WillOnce(Return(kEmptyRegion));
+ EXPECT_CALL(mOutput, getDirtyRegion()).WillOnce(Return(kEmptyRegion));
EXPECT_CALL(mOutput, postFramebuffer());
EXPECT_CALL(mOutput, prepareFrame());
@@ -2744,11 +2726,10 @@
TEST_F(OutputDevOptRepaintFlashTest, alsoComposesSurfacesAndQueuesABufferIfDirty) {
mRefreshArgs.devOptFlashDirtyRegionsDelay = std::chrono::microseconds(1);
- mRefreshArgs.repaintEverything = false;
mOutput.mState.isEnabled = true;
InSequence seq;
- EXPECT_CALL(mOutput, getDirtyRegion(false)).WillOnce(Return(kNotEmptyRegion));
+ EXPECT_CALL(mOutput, getDirtyRegion()).WillOnce(Return(kNotEmptyRegion));
EXPECT_CALL(mOutput, composeSurfaces(RegionEq(kNotEmptyRegion), Ref(mRefreshArgs)));
EXPECT_CALL(*mRenderSurface, queueBuffer(_));
EXPECT_CALL(mOutput, postFramebuffer());
@@ -2992,8 +2973,8 @@
// Sets up the helper functions called by the function under test to use
// mock implementations.
MOCK_CONST_METHOD0(getSkipColorTransform, bool());
- MOCK_METHOD3(generateClientCompositionRequests,
- std::vector<LayerFE::LayerSettings>(bool, Region&, ui::Dataspace));
+ MOCK_METHOD2(generateClientCompositionRequests,
+ std::vector<LayerFE::LayerSettings>(bool, ui::Dataspace));
MOCK_METHOD2(appendRegionFlashRequests,
void(const Region&, std::vector<LayerFE::LayerSettings>&));
MOCK_METHOD1(setExpensiveRenderingExpected, void(bool));
@@ -3005,11 +2986,11 @@
mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
mOutput.cacheClientCompositionRequests(MAX_CLIENT_COMPOSITION_CACHE_SIZE);
- mOutput.mState.orientedDisplaySpace.content = kDefaultOutputFrame;
- mOutput.mState.layerStackSpace.content = kDefaultOutputViewport;
- mOutput.mState.framebufferSpace.content = kDefaultOutputDestinationClip;
- mOutput.mState.displaySpace.content = kDefaultOutputDestinationClip;
- mOutput.mState.displaySpace.orientation = kDefaultOutputOrientation;
+ mOutput.mState.orientedDisplaySpace.setContent(kDefaultOutputFrame);
+ mOutput.mState.layerStackSpace.setContent(kDefaultOutputViewport);
+ mOutput.mState.framebufferSpace.setContent(kDefaultOutputDestinationClip);
+ mOutput.mState.displaySpace.setContent(kDefaultOutputDestinationClip);
+ mOutput.mState.displaySpace.setOrientation(kDefaultOutputOrientation);
mOutput.mState.transform = ui::Transform{kDefaultOutputOrientationFlags};
mOutput.mState.dataspace = kDefaultOutputDataspace;
mOutput.mState.colorTransformMatrix = kDefaultColorTransformMat;
@@ -3142,15 +3123,20 @@
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
- EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
+ EXPECT_CALL(mOutput, generateClientCompositionRequests(_, kDefaultOutputDataspace))
.WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
.WillRepeatedly(Return());
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, IsEmpty(), _, false, _, _))
- .WillRepeatedly(Return(NO_ERROR));
-
+ EXPECT_CALL(mRenderEngine, drawLayers(_, IsEmpty(), _, false, _))
+ .WillRepeatedly([&](const renderengine::DisplaySettings&,
+ const std::vector<const renderengine::LayerSettings*>&,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&)
+ -> std::future<renderengine::RenderEngineResult> {
+ return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
+ });
verify().execute().expectAFenceWasReturned();
}
@@ -3165,7 +3151,7 @@
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
- EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
+ EXPECT_CALL(mOutput, generateClientCompositionRequests(_, kDefaultOutputDataspace))
.WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
.WillRepeatedly(
@@ -3175,8 +3161,14 @@
}));
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _, _))
- .WillRepeatedly(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
+ .WillRepeatedly([&](const renderengine::DisplaySettings&,
+ const std::vector<const renderengine::LayerSettings*>&,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&)
+ -> std::future<renderengine::RenderEngineResult> {
+ return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
+ });
verify().execute().expectAFenceWasReturned();
}
@@ -3188,14 +3180,13 @@
r1.geometry.boundaries = FloatRect{1, 2, 3, 4};
r2.geometry.boundaries = FloatRect{5, 6, 7, 8};
- const constexpr uint32_t kInternalLayerStack = 1234;
- mOutput.setLayerStackFilter(kInternalLayerStack, true);
+ mOutput.setLayerFilter({ui::LayerStack{1234u}, true});
EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
- EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
+ EXPECT_CALL(mOutput, generateClientCompositionRequests(_, kDefaultOutputDataspace))
.WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
.WillRepeatedly(
@@ -3205,8 +3196,14 @@
}));
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _, _))
- .WillRepeatedly(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _))
+ .WillRepeatedly([&](const renderengine::DisplaySettings&,
+ const std::vector<const renderengine::LayerSettings*>&,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&)
+ -> std::future<renderengine::RenderEngineResult> {
+ return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
+ });
verify().execute().expectAFenceWasReturned();
}
@@ -3223,15 +3220,18 @@
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
- EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
+ EXPECT_CALL(mOutput, generateClientCompositionRequests(_, kDefaultOutputDataspace))
.WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
.WillRepeatedly(Return());
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _, _))
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
.Times(2)
- .WillOnce(Return(NO_ERROR));
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
verify().execute().expectAFenceWasReturned();
EXPECT_FALSE(mOutput.mState.reusedClientComposition);
@@ -3252,14 +3252,15 @@
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
- EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
+ EXPECT_CALL(mOutput, generateClientCompositionRequests(_, kDefaultOutputDataspace))
.WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
.WillRepeatedly(Return());
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _, _))
- .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false));
verify().execute().expectAFenceWasReturned();
@@ -3281,7 +3282,7 @@
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
- EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
+ EXPECT_CALL(mOutput, generateClientCompositionRequests(_, kDefaultOutputDataspace))
.WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
.WillRepeatedly(Return());
@@ -3293,8 +3294,14 @@
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_))
.WillOnce(Return(mOutputBuffer))
.WillOnce(Return(otherOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _, _))
- .WillRepeatedly(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
+ .WillRepeatedly([&](const renderengine::DisplaySettings&,
+ const std::vector<const renderengine::LayerSettings*>&,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&)
+ -> std::future<renderengine::RenderEngineResult> {
+ return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
+ });
verify().execute().expectAFenceWasReturned();
EXPECT_FALSE(mOutput.mState.reusedClientComposition);
@@ -3316,17 +3323,19 @@
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
- EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
+ EXPECT_CALL(mOutput, generateClientCompositionRequests(_, kDefaultOutputDataspace))
.WillOnce(Return(std::vector<LayerFE::LayerSettings>{r1, r2}))
.WillOnce(Return(std::vector<LayerFE::LayerSettings>{r1, r3}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
.WillRepeatedly(Return());
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _, _))
- .WillOnce(Return(NO_ERROR));
- EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r3)), _, false, _, _))
- .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r3)), _, false, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
verify().execute().expectAFenceWasReturned();
EXPECT_FALSE(mOutput.mState.reusedClientComposition);
@@ -3339,7 +3348,7 @@
OutputComposeSurfacesTest_UsesExpectedDisplaySettings() {
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
- EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
+ EXPECT_CALL(mOutput, generateClientCompositionRequests(_, kDefaultOutputDataspace))
.WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
.WillRepeatedly(Return());
@@ -3375,8 +3384,9 @@
struct ExpectDisplaySettingsState
: public CallOrderStateMachineHelper<TestType, ExpectDisplaySettingsState> {
auto thenExpectDisplaySettingsUsed(renderengine::DisplaySettings settings) {
- EXPECT_CALL(getInstance()->mRenderEngine, drawLayers(settings, _, _, false, _, _))
- .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(getInstance()->mRenderEngine, drawLayers(settings, _, _, false, _))
+ .WillOnce(Return(ByMove(futureOf<renderengine::RenderEngineResult>(
+ {NO_ERROR, base::unique_fd()}))));
return nextState<ExecuteState>();
}
};
@@ -3391,7 +3401,7 @@
.andIfSkipColorTransform(false)
.thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
- Region::INVALID_REGION, kDefaultOutputOrientationFlags})
+ kDefaultOutputOrientationFlags})
.execute()
.expectAFenceWasReturned();
}
@@ -3402,7 +3412,7 @@
.andIfSkipColorTransform(false)
.thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
- Region::INVALID_REGION, kDefaultOutputOrientationFlags})
+ kDefaultOutputOrientationFlags})
.execute()
.expectAFenceWasReturned();
}
@@ -3413,7 +3423,7 @@
.andIfSkipColorTransform(false)
.thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
kDefaultMaxLuminance, kDefaultOutputDataspace,
- kDefaultColorTransformMat, Region::INVALID_REGION,
+ kDefaultColorTransformMat,
kDefaultOutputOrientationFlags})
.execute()
.expectAFenceWasReturned();
@@ -3425,7 +3435,7 @@
.andIfSkipColorTransform(false)
.thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
kDefaultMaxLuminance, kDefaultOutputDataspace,
- kDefaultColorTransformMat, Region::INVALID_REGION,
+ kDefaultColorTransformMat,
kDefaultOutputOrientationFlags})
.execute()
.expectAFenceWasReturned();
@@ -3438,7 +3448,7 @@
.andIfSkipColorTransform(true)
.thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
- Region::INVALID_REGION, kDefaultOutputOrientationFlags})
+ kDefaultOutputOrientationFlags})
.execute()
.expectAFenceWasReturned();
}
@@ -3469,13 +3479,20 @@
EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
- EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, _))
+ EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _))
.WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
.WillRepeatedly(Return());
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _, _))
- .WillRepeatedly(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _))
+ .WillRepeatedly(
+ [&](const renderengine::DisplaySettings&,
+ const std::vector<const renderengine::LayerSettings*>&,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+ return futureOf<renderengine::RenderEngineResult>(
+ {NO_ERROR, base::unique_fd()});
+ });
}
Layer mLayer1;
@@ -3527,7 +3544,9 @@
EXPECT_CALL(*mRenderSurface, setProtected(true));
// Must happen after setting the protected content state.
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
}
@@ -3590,14 +3609,16 @@
TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering, IfExepensiveOutputDataspaceIsUsed) {
mOutput.mState.dataspace = kExpensiveOutputDataspace;
- EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kExpensiveOutputDataspace))
+ EXPECT_CALL(mOutput, generateClientCompositionRequests(_, kExpensiveOutputDataspace))
.WillOnce(Return(std::vector<LayerFE::LayerSettings>{}));
// For this test, we also check the call order of key functions.
InSequence seq;
EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true));
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
}
@@ -3613,9 +3634,11 @@
EXPECT_CALL(mLayer.outputLayer,
writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0,
/*zIsOverridden*/ false, /*isPeekingThrough*/ false));
- EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
+ EXPECT_CALL(mOutput, generateClientCompositionRequests(_, kDefaultOutputDataspace))
.WillOnce(Return(std::vector<LayerFE::LayerSettings>{}));
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _))
+ .WillOnce(Return(ByMove(futureOf<renderengine::RenderEngineResult>(
+ {NO_ERROR, base::unique_fd()}))));
EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1u));
EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(0u))
.WillRepeatedly(Return(&mLayer.outputLayer));
@@ -3653,10 +3676,9 @@
struct OutputPartialMock : public OutputPartialMockBase {
// compositionengine::Output overrides
std::vector<LayerFE::LayerSettings> generateClientCompositionRequests(
- bool supportsProtectedContent, Region& clearRegion,
- ui::Dataspace dataspace) override {
+ bool supportsProtectedContent, ui::Dataspace dataspace) override {
return impl::Output::generateClientCompositionRequests(supportsProtectedContent,
- clearRegion, dataspace);
+ dataspace);
}
};
@@ -3691,12 +3713,12 @@
struct GenerateClientCompositionRequestsTest_ThreeLayers
: public GenerateClientCompositionRequestsTest {
GenerateClientCompositionRequestsTest_ThreeLayers() {
- mOutput.mState.orientedDisplaySpace.content = kDisplayFrame;
- mOutput.mState.layerStackSpace.content = kDisplayViewport;
- mOutput.mState.displaySpace.content = kDisplayDestinationClip;
+ mOutput.mState.orientedDisplaySpace.setContent(kDisplayFrame);
+ mOutput.mState.layerStackSpace.setContent(kDisplayViewport);
+ mOutput.mState.displaySpace.setContent(kDisplayDestinationClip);
mOutput.mState.transform =
ui::Transform{ui::Transform::toRotationFlags(kDisplayOrientation)};
- mOutput.mState.displaySpace.orientation = kDisplayOrientation;
+ mOutput.mState.displaySpace.setOrientation(kDisplayOrientation);
mOutput.mState.needsFiltering = false;
mOutput.mState.isSecure = false;
@@ -3740,11 +3762,9 @@
EXPECT_CALL(mLayers[1].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
EXPECT_CALL(mLayers[2].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
- Region accumClearRegion(Rect(10, 11, 12, 13));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
- accumClearRegion, kDisplayDataspace);
+ kDisplayDataspace);
EXPECT_EQ(0u, requests.size());
- EXPECT_THAT(accumClearRegion, RegionEq(Region(Rect(10, 11, 12, 13))));
}
TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, requiresVisibleRegionAfterViewportClip) {
@@ -3752,11 +3772,9 @@
mLayers[1].mOutputLayerState.visibleRegion = Region(Rect(4000, 0, 4010, 10));
mLayers[2].mOutputLayerState.visibleRegion = Region(Rect(-10, -10, 0, 0));
- Region accumClearRegion(Rect(10, 11, 12, 13));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
- accumClearRegion, kDisplayDataspace);
+ kDisplayDataspace);
EXPECT_EQ(0u, requests.size());
- EXPECT_THAT(accumClearRegion, RegionEq(Region(Rect(10, 11, 12, 13))));
}
TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, gathersClientCompositionRequests) {
@@ -3771,16 +3789,13 @@
.WillOnce(Return(std::vector<LayerFE::LayerSettings>(
{mShadowSettings, mLayers[2].mLayerSettings})));
- Region accumClearRegion(Rect(10, 11, 12, 13));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
- accumClearRegion, kDisplayDataspace);
+ kDisplayDataspace);
ASSERT_EQ(3u, requests.size());
EXPECT_EQ(mLayers[1].mLayerSettings, requests[0]);
EXPECT_EQ(mShadowSettings, requests[1]);
EXPECT_EQ(mLayers[2].mLayerSettings, requests[2]);
- EXPECT_THAT(accumClearRegion, RegionEq(Region(Rect(10, 11, 12, 13))));
-
// Check that a timestamp was set for the layers that generated requests
EXPECT_TRUE(0 == mLayers[0].mOutputLayerState.clientCompositionTimestamp);
EXPECT_TRUE(0 != mLayers[1].mOutputLayerState.clientCompositionTimestamp);
@@ -3811,16 +3826,13 @@
.WillOnce(Return(std::vector<LayerFE::LayerSettings>(
{mShadowSettings, mLayers[2].mLayerSettings})));
- Region accumClearRegion(Rect(10, 11, 12, 13));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
- accumClearRegion, kDisplayDataspace);
+ kDisplayDataspace);
ASSERT_EQ(3u, requests.size());
EXPECT_EQ(mLayers[1].mLayerSettings, requests[0]);
EXPECT_EQ(mShadowSettings, requests[1]);
EXPECT_EQ(mLayers[2].mLayerSettings, requests[2]);
- EXPECT_THAT(accumClearRegion, RegionEq(Region(Rect(10, 11, 12, 13))));
-
// Check that a timestamp was set for the layers that generated requests
EXPECT_TRUE(0 == mLayers[0].mOutputLayerState.clientCompositionTimestamp);
EXPECT_TRUE(0 != mLayers[1].mOutputLayerState.clientCompositionTimestamp);
@@ -3844,13 +3856,10 @@
EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientCompositionList(_))
.WillOnce(Return(std::vector<LayerFE::LayerSettings>({mLayers[2].mLayerSettings})));
- Region accumClearRegion(Rect(10, 11, 12, 13));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
- accumClearRegion, kDisplayDataspace);
+ kDisplayDataspace);
ASSERT_EQ(1u, requests.size());
EXPECT_EQ(mLayers[2].mLayerSettings, requests[0]);
-
- EXPECT_THAT(accumClearRegion, RegionEq(Region(Rect(10, 11, 12, 13))));
}
TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers,
@@ -3870,13 +3879,10 @@
EXPECT_CALL(*mLayers[2].mLayerFE, prepareClientCompositionList(_))
.WillOnce(Return(std::vector<LayerFE::LayerSettings>({mLayers[2].mLayerSettings})));
- Region accumClearRegion(Rect(10, 11, 12, 13));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
- accumClearRegion, kDisplayDataspace);
+ kDisplayDataspace);
ASSERT_EQ(1u, requests.size());
EXPECT_EQ(mLayers[2].mLayerSettings, requests[0]);
-
- EXPECT_THAT(accumClearRegion, RegionEq(Region(Rect(10, 11, 12, 13))));
}
TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, clearsHWCLayersIfOpaqueAndNotFirst) {
@@ -3897,15 +3903,12 @@
mLayers[0].mLayerFEState.isOpaque = true;
mLayers[1].mLayerFEState.isOpaque = true;
mLayers[2].mLayerFEState.isOpaque = true;
- Region accumClearRegion(Rect(10, 11, 12, 13));
- Region stubRegion;
compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
Region(kDisplayFrame),
false, /* needs filtering */
false, /* secure */
false, /* supports protected content */
- stubRegion, /* clear region */
kDisplayViewport,
kDisplayDataspace,
false /* realContentIsVisible */,
@@ -3917,7 +3920,6 @@
false, /* needs filtering */
false, /* secure */
false, /* supports protected content */
- accumClearRegion,
kDisplayViewport,
kDisplayDataspace,
true /* realContentIsVisible */,
@@ -3937,15 +3939,13 @@
.WillOnce(Return(std::vector<LayerFE::LayerSettings>({mLayers[2].mLayerSettings})));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
- accumClearRegion, kDisplayDataspace);
+ kDisplayDataspace);
ASSERT_EQ(2u, requests.size());
// The second layer is expected to be rendered as alpha=0 black with no blending
EXPECT_EQ(mBlackoutSettings, requests[0]);
EXPECT_EQ(mLayers[2].mLayerSettings, requests[1]);
-
- EXPECT_THAT(accumClearRegion, RegionEq(Region(Rect(10, 11, 12, 13))));
}
TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers,
@@ -3954,14 +3954,11 @@
mLayers[1].mOutputLayerState.visibleRegion = Region(Rect(-10, -10, 30, 30));
mLayers[2].mOutputLayerState.visibleRegion = Region(Rect(-10, 0, 40, 4000));
- Region accumClearRegion(Rect(10, 11, 12, 13));
-
compositionengine::LayerFE::ClientCompositionTargetSettings layer0TargetSettings{
Region(Rect(10, 10, 20, 20)),
false, /* needs filtering */
false, /* secure */
false, /* supports protected content */
- accumClearRegion,
kDisplayViewport,
kDisplayDataspace,
true /* realContentIsVisible */,
@@ -3973,7 +3970,6 @@
false, /* needs filtering */
false, /* secure */
false, /* supports protected content */
- accumClearRegion,
kDisplayViewport,
kDisplayDataspace,
true /* realContentIsVisible */,
@@ -3985,7 +3981,6 @@
false, /* needs filtering */
false, /* secure */
false, /* supports protected content */
- accumClearRegion,
kDisplayViewport,
kDisplayDataspace,
true /* realContentIsVisible */,
@@ -4002,7 +3997,7 @@
static_cast<void>(
mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
- accumClearRegion, kDisplayDataspace));
+ kDisplayDataspace));
}
TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers,
@@ -4010,14 +4005,11 @@
mOutput.mState.needsFiltering = false;
EXPECT_CALL(mLayers[0].mOutputLayer, needsFiltering()).WillRepeatedly(Return(true));
- Region accumClearRegion(Rect(10, 11, 12, 13));
-
compositionengine::LayerFE::ClientCompositionTargetSettings layer0TargetSettings{
Region(kDisplayFrame),
true, /* needs filtering */
false, /* secure */
false, /* supports protected content */
- accumClearRegion,
kDisplayViewport,
kDisplayDataspace,
true /* realContentIsVisible */,
@@ -4029,7 +4021,6 @@
false, /* needs filtering */
false, /* secure */
false, /* supports protected content */
- accumClearRegion,
kDisplayViewport,
kDisplayDataspace,
true /* realContentIsVisible */,
@@ -4041,7 +4032,6 @@
false, /* needs filtering */
false, /* secure */
false, /* supports protected content */
- accumClearRegion,
kDisplayViewport,
kDisplayDataspace,
true /* realContentIsVisible */,
@@ -4058,7 +4048,7 @@
static_cast<void>(
mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
- accumClearRegion, kDisplayDataspace));
+ kDisplayDataspace));
}
TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers,
@@ -4066,14 +4056,11 @@
mOutput.mState.needsFiltering = true;
EXPECT_CALL(mLayers[0].mOutputLayer, needsFiltering()).WillRepeatedly(Return(true));
- Region accumClearRegion(Rect(10, 11, 12, 13));
-
compositionengine::LayerFE::ClientCompositionTargetSettings layer0TargetSettings{
Region(kDisplayFrame),
true, /* needs filtering */
false, /* secure */
false, /* supports protected content */
- accumClearRegion,
kDisplayViewport,
kDisplayDataspace,
true /* realContentIsVisible */,
@@ -4086,7 +4073,6 @@
true, /* needs filtering */
false, /* secure */
false, /* supports protected content */
- accumClearRegion,
kDisplayViewport,
kDisplayDataspace,
true /* realContentIsVisible */,
@@ -4098,7 +4084,6 @@
true, /* needs filtering */
false, /* secure */
false, /* supports protected content */
- accumClearRegion,
kDisplayViewport,
kDisplayDataspace,
true /* realContentIsVisible */,
@@ -4115,21 +4100,18 @@
static_cast<void>(
mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
- accumClearRegion, kDisplayDataspace));
+ kDisplayDataspace));
}
TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers,
wholeOutputSecurityUsedToGenerateRequests) {
mOutput.mState.isSecure = true;
- Region accumClearRegion(Rect(10, 11, 12, 13));
-
compositionengine::LayerFE::ClientCompositionTargetSettings layer0TargetSettings{
Region(kDisplayFrame),
false, /* needs filtering */
true, /* secure */
false, /* supports protected content */
- accumClearRegion,
kDisplayViewport,
kDisplayDataspace,
true /* realContentIsVisible */,
@@ -4141,7 +4123,6 @@
false, /* needs filtering */
true, /* secure */
false, /* supports protected content */
- accumClearRegion,
kDisplayViewport,
kDisplayDataspace,
true /* realContentIsVisible */,
@@ -4153,7 +4134,6 @@
false, /* needs filtering */
true, /* secure */
false, /* supports protected content */
- accumClearRegion,
kDisplayViewport,
kDisplayDataspace,
true /* realContentIsVisible */,
@@ -4170,19 +4150,17 @@
static_cast<void>(
mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
- accumClearRegion, kDisplayDataspace));
+ kDisplayDataspace));
}
TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers,
protectedContentSupportUsedToGenerateRequests) {
- Region accumClearRegion(Rect(10, 11, 12, 13));
compositionengine::LayerFE::ClientCompositionTargetSettings layer0TargetSettings{
Region(kDisplayFrame),
false, /* needs filtering */
false, /* secure */
true, /* supports protected content */
- accumClearRegion,
kDisplayViewport,
kDisplayDataspace,
true /* realContentIsVisible */,
@@ -4194,7 +4172,6 @@
false, /* needs filtering */
false, /* secure */
true, /* supports protected content */
- accumClearRegion,
kDisplayViewport,
kDisplayDataspace,
true /* realContentIsVisible */,
@@ -4206,7 +4183,6 @@
false, /* needs filtering */
false, /* secure */
true, /* supports protected content */
- accumClearRegion,
kDisplayViewport,
kDisplayDataspace,
true /* realContentIsVisible */,
@@ -4222,7 +4198,6 @@
.WillOnce(Return(std::vector<LayerFE::LayerSettings>()));
static_cast<void>(mOutput.generateClientCompositionRequests(true /* supportsProtectedContent */,
- accumClearRegion,
kDisplayDataspace));
}
@@ -4343,11 +4318,11 @@
const ui::Rotation kPortraitOrientation = ui::ROTATION_90;
constexpr ui::Dataspace kOutputDataspace = ui::Dataspace::DISPLAY_P3;
- mOutput.mState.orientedDisplaySpace.content = kPortraitFrame;
- mOutput.mState.layerStackSpace.content = kPortraitViewport;
- mOutput.mState.displaySpace.content = kPortraitDestinationClip;
+ mOutput.mState.orientedDisplaySpace.setContent(kPortraitFrame);
+ mOutput.mState.layerStackSpace.setContent(kPortraitViewport);
+ mOutput.mState.displaySpace.setContent(kPortraitDestinationClip);
mOutput.mState.transform = ui::Transform{ui::Transform::toRotationFlags(kPortraitOrientation)};
- mOutput.mState.displaySpace.orientation = kPortraitOrientation;
+ mOutput.mState.displaySpace.setOrientation(kPortraitOrientation);
mOutput.mState.needsFiltering = false;
mOutput.mState.isSecure = true;
@@ -4370,14 +4345,11 @@
EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(1u))
.WillRepeatedly(Return(&rightLayer.mOutputLayer));
- Region accumClearRegion(Rect(10, 11, 12, 13));
-
compositionengine::LayerFE::ClientCompositionTargetSettings leftLayerSettings{
Region(Rect(0, 0, 1000, 1000)),
false, /* needs filtering */
true, /* secure */
true, /* supports protected content */
- accumClearRegion,
kPortraitViewport,
kOutputDataspace,
true /* realContentIsVisible */,
@@ -4395,7 +4367,6 @@
false, /* needs filtering */
true, /* secure */
true, /* supports protected content */
- accumClearRegion,
kPortraitViewport,
kOutputDataspace,
true /* realContentIsVisible */,
@@ -4409,8 +4380,8 @@
.WillOnce(Return(std::vector<LayerFE::LayerSettings>({rightLayer.mLayerSettings})));
constexpr bool supportsProtectedContent = true;
- auto requests = mOutput.generateClientCompositionRequests(supportsProtectedContent,
- accumClearRegion, kOutputDataspace);
+ auto requests =
+ mOutput.generateClientCompositionRequests(supportsProtectedContent, kOutputDataspace);
ASSERT_EQ(2u, requests.size());
EXPECT_EQ(leftLayer.mLayerSettings, requests[0]);
EXPECT_EQ(rightLayer.mLayerSettings, requests[1]);
@@ -4423,13 +4394,11 @@
const Region kShadowRegion = Region(kContentWithShadow).subtract(kContent);
const Region kPartialShadowRegion = Region(kContentWithShadow).subtract(Rect(40, 40, 60, 80));
- Region accumClearRegion(Rect(10, 11, 12, 13));
compositionengine::LayerFE::ClientCompositionTargetSettings layer2Settings{
Region(Rect(60, 40, 70, 80)).merge(Rect(40, 80, 70, 90)), /* visible region */
false, /* needs filtering */
false, /* secure */
false, /* supports protected content */
- accumClearRegion,
kDisplayViewport,
kDisplayDataspace,
false /* realContentIsVisible */,
@@ -4449,7 +4418,7 @@
.WillOnce(Return(std::vector<LayerFE::LayerSettings>({mShadowSettings})));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
- accumClearRegion, kDisplayDataspace);
+ kDisplayDataspace);
ASSERT_EQ(1u, requests.size());
EXPECT_EQ(mShadowSettings, requests[0]);
@@ -4469,13 +4438,11 @@
mLayers[2].mOutputLayerState.visibleRegion = kPartialContentWithPartialShadowRegion;
mLayers[2].mOutputLayerState.shadowRegion = kShadowRegion;
- Region accumClearRegion(Rect(10, 11, 12, 13));
compositionengine::LayerFE::ClientCompositionTargetSettings layer2Settings{
Region(Rect(50, 40, 70, 80)).merge(Rect(40, 80, 70, 90)), /* visible region */
false, /* needs filtering */
false, /* secure */
false, /* supports protected content */
- accumClearRegion,
kDisplayViewport,
kDisplayDataspace,
true /* realContentIsVisible */,
@@ -4490,7 +4457,7 @@
{mShadowSettings, mLayers[2].mLayerSettings})));
auto requests = mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */,
- accumClearRegion, kDisplayDataspace);
+ kDisplayDataspace);
ASSERT_EQ(2u, requests.size());
EXPECT_EQ(mShadowSettings, requests[0]);
diff --git a/services/surfaceflinger/CompositionEngine/tests/ProjectionSpaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/ProjectionSpaceTest.cpp
index 704f5a8..19b3928 100644
--- a/services/surfaceflinger/CompositionEngine/tests/ProjectionSpaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/ProjectionSpaceTest.cpp
@@ -53,40 +53,40 @@
TEST(ProjectionSpaceTest, getTransformToSelfIsIdentity) {
ProjectionSpace space;
- space.content = Rect(100, 200);
- space.bounds = Rect(100, 200);
+ space.setContent(Rect(100, 200));
+ space.setBounds(ui::Size(100, 200));
const ui::Transform identity;
for (int rotation = 0; rotation <= 3; rotation++) {
- space.orientation = ui::Rotation(rotation);
+ space.setOrientation(ui::Rotation(rotation));
EXPECT_EQ(space.getTransform(space), identity);
}
}
TEST(ProjectionSpaceTest, getTransformWhenTranslationIsNeeded) {
ProjectionSpace source;
- source.content = Rect(10, 10, 20, 20);
- source.bounds = Rect(100, 200);
+ source.setContent(Rect(10, 10, 20, 20));
+ source.setBounds(ui::Size(100, 200));
ProjectionSpace dest;
- dest.content = Rect(10, 20, 30, 20);
- dest.bounds = source.bounds;
+ dest.setContent(Rect(10, 20, 30, 20));
+ dest.setBounds(source.getBounds());
const auto transform = source.getTransform(dest);
- EXPECT_EQ(transform.transform(source.content), dest.content);
+ EXPECT_EQ(transform.transform(source.getContent()), dest.getContent());
}
TEST(ProjectionSpaceTest, getTransformWhenScaleIsNeeded) {
ProjectionSpace source;
- source.content = Rect(0, 0, 20, 20);
- source.bounds = Rect(100, 200);
+ source.setContent(Rect(0, 0, 20, 20));
+ source.setBounds(ui::Size(100, 200));
ProjectionSpace dest;
- dest.content = Rect(0, 0, 40, 30);
- dest.bounds = source.bounds;
+ dest.setContent(Rect(0, 0, 40, 30));
+ dest.setBounds(source.getBounds());
const auto transform = source.getTransform(dest);
- EXPECT_EQ(transform.transform(source.content), dest.content);
+ EXPECT_EQ(transform.transform(source.getContent()), dest.getContent());
}
TEST(ProjectionSpaceTest, getSideStripTest) {
@@ -99,7 +99,7 @@
void testTransform(const ProjectionSpace& source, const ProjectionSpace& dest) {
const auto transform = source.getTransform(dest);
- EXPECT_EQ(transform.transform(source.content), dest.content)
+ EXPECT_EQ(transform.transform(source.getContent()), dest.getContent())
<< "Source content doesn't map to dest content when projecting " << to_string(source)
<< " onto " << to_string(dest);
@@ -113,8 +113,8 @@
// | | | *
// +-----+ +-------*
// source(ROTATION_0) dest (ROTATION_90)
- const auto sourceStrip = getSideStrip(source.content, source.orientation);
- const auto destStrip = getSideStrip(dest.content, dest.orientation);
+ const auto sourceStrip = getSideStrip(source.getContent(), source.getOrientation());
+ const auto destStrip = getSideStrip(dest.getContent(), dest.getOrientation());
ASSERT_NE(sourceStrip, Rect::INVALID_RECT);
ASSERT_NE(destStrip, Rect::INVALID_RECT);
const auto mappedStrip = transform.transform(sourceStrip);
@@ -126,16 +126,16 @@
TEST(ProjectionSpaceTest, getTransformWithOrienations) {
ProjectionSpace source;
- source.bounds = Rect(12, 13, 678, 789);
- source.content = Rect(40, 50, 234, 343);
+ source.setBounds(ui::Size(666, 776));
+ source.setContent(Rect(40, 50, 234, 343));
ProjectionSpace dest;
- dest.bounds = Rect(17, 18, 879, 564);
- dest.content = Rect(43, 52, 432, 213);
+ dest.setBounds(ui::Size(862, 546));
+ dest.setContent(Rect(43, 52, 432, 213));
for (int sourceRot = 0; sourceRot <= 3; sourceRot++) {
- source.orientation = ui::Rotation(sourceRot);
+ source.setOrientation(ui::Rotation(sourceRot));
for (int destRot = 0; destRot <= 3; destRot++) {
- dest.orientation = ui::Rotation(destRot);
+ dest.setOrientation(ui::Rotation(destRot));
testTransform(source, dest);
}
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index 5090bb2..431cc93 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -35,7 +35,7 @@
constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1920;
constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1080;
-constexpr DisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId(123u);
+constexpr DisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(123u);
const std::string DEFAULT_DISPLAY_NAME = "Mock Display";
using testing::_;
diff --git a/services/surfaceflinger/CompositionEngine/tests/TestUtils.h b/services/surfaceflinger/CompositionEngine/tests/TestUtils.h
new file mode 100644
index 0000000..c80fde6
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/TestUtils.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <future>
+
+namespace android::compositionengine {
+namespace {
+
+template <class T>
+std::future<T> futureOf(T obj) {
+ std::promise<T> resultPromise;
+ std::future<T> resultFuture = resultPromise.get_future();
+ resultPromise.set_value(std::move(obj));
+ return resultFuture;
+}
+} // namespace
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index ec81322..ecb05f8 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -27,6 +27,8 @@
#include <utils/Errors.h>
#include <memory>
+#include "tests/TestUtils.h"
+
namespace android::compositionengine {
using namespace std::chrono_literals;
@@ -121,7 +123,7 @@
// set up minimium params needed for rendering
mOutputState.dataspace = ui::Dataspace::SRGB;
mOutputState.framebufferSpace = ProjectionSpace(ui::Size(10, 20), Rect(10, 5));
- mOutputState.framebufferSpace.orientation = ui::ROTATION_90;
+ mOutputState.framebufferSpace.setOrientation(ui::ROTATION_90);
mOutputState.layerStackSpace = ProjectionSpace(ui::Size(20, 10), Rect(5, 10));
}
}
@@ -342,19 +344,19 @@
clientCompList2.push_back({});
clientCompList2[0].alpha = 0.75f;
- const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings,
- const std::vector<const renderengine::LayerSettings*>& layers,
- const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd&&, base::unique_fd*) -> size_t {
- EXPECT_EQ(mOutputState.framebufferSpace.content, displaySettings.physicalDisplay);
- EXPECT_EQ(mOutputState.layerStackSpace.content, displaySettings.clip);
- EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.orientation),
+ const auto drawLayers =
+ [&](const renderengine::DisplaySettings& displaySettings,
+ const std::vector<const renderengine::LayerSettings*>& layers,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+ EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay);
+ EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip);
+ EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()),
displaySettings.orientation);
EXPECT_EQ(0.5f, layers[0]->alpha);
EXPECT_EQ(0.75f, layers[1]->alpha);
EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace);
-
- return NO_ERROR;
+ return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
};
EXPECT_CALL(*layerFE1,
@@ -363,7 +365,7 @@
EXPECT_CALL(*layerFE2,
prepareClientCompositionList(ClientCompositionTargetSettingsSecureEq(false)))
.WillOnce(Return(clientCompList2));
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
mOutputState.isSecure = false;
cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
expectReadyBuffer(cachedSet);
@@ -394,19 +396,20 @@
clientCompList2.push_back({});
clientCompList2[0].alpha = 0.75f;
- const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings,
- const std::vector<const renderengine::LayerSettings*>& layers,
- const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd&&, base::unique_fd*) -> size_t {
- EXPECT_EQ(mOutputState.framebufferSpace.content, displaySettings.physicalDisplay);
- EXPECT_EQ(mOutputState.layerStackSpace.content, displaySettings.clip);
- EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.orientation),
+ const auto drawLayers =
+ [&](const renderengine::DisplaySettings& displaySettings,
+ const std::vector<const renderengine::LayerSettings*>& layers,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+ EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay);
+ EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip);
+ EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()),
displaySettings.orientation);
EXPECT_EQ(0.5f, layers[0]->alpha);
EXPECT_EQ(0.75f, layers[1]->alpha);
EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace);
- return NO_ERROR;
+ return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
};
EXPECT_CALL(*layerFE1,
@@ -415,7 +418,7 @@
EXPECT_CALL(*layerFE2,
prepareClientCompositionList(ClientCompositionTargetSettingsSecureEq(true)))
.WillOnce(Return(clientCompList2));
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
mOutputState.isSecure = true;
cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
expectReadyBuffer(cachedSet);
@@ -448,24 +451,25 @@
mOutputState.framebufferSpace = ProjectionSpace(ui::Size(10, 20), Rect(2, 3, 10, 5));
- const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings,
- const std::vector<const renderengine::LayerSettings*>& layers,
- const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd&&, base::unique_fd*) -> size_t {
- EXPECT_EQ(mOutputState.framebufferSpace.content, displaySettings.physicalDisplay);
- EXPECT_EQ(mOutputState.layerStackSpace.content, displaySettings.clip);
- EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.orientation),
+ const auto drawLayers =
+ [&](const renderengine::DisplaySettings& displaySettings,
+ const std::vector<const renderengine::LayerSettings*>& layers,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
+ EXPECT_EQ(mOutputState.framebufferSpace.getContent(), displaySettings.physicalDisplay);
+ EXPECT_EQ(mOutputState.layerStackSpace.getContent(), displaySettings.clip);
+ EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.getOrientation()),
displaySettings.orientation);
EXPECT_EQ(0.5f, layers[0]->alpha);
EXPECT_EQ(0.75f, layers[1]->alpha);
EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace);
- return NO_ERROR;
+ return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
};
EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1));
EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2));
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
expectReadyBuffer(cachedSet);
@@ -650,10 +654,11 @@
EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2));
EXPECT_CALL(*layerFE3, prepareClientCompositionList(_)).WillOnce(Return(clientCompList3));
- const auto drawLayers = [&](const renderengine::DisplaySettings&,
- const std::vector<const renderengine::LayerSettings*>& layers,
- const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd&&, base::unique_fd*) -> size_t {
+ const auto drawLayers =
+ [&](const renderengine::DisplaySettings&,
+ const std::vector<const renderengine::LayerSettings*>& layers,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
// If the highlight layer is enabled, it will increase the size by 1.
// We're interested in the third layer either way.
EXPECT_GE(layers.size(), 4u);
@@ -673,10 +678,10 @@
EXPECT_EQ(1.0f, holePunchBackgroundSettings->alpha);
}
- return NO_ERROR;
+ return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
};
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
}
@@ -710,10 +715,11 @@
EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2));
EXPECT_CALL(*layerFE3, prepareClientCompositionList(_)).WillOnce(Return(clientCompList3));
- const auto drawLayers = [&](const renderengine::DisplaySettings&,
- const std::vector<const renderengine::LayerSettings*>& layers,
- const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd&&, base::unique_fd*) -> size_t {
+ const auto drawLayers =
+ [&](const renderengine::DisplaySettings&,
+ const std::vector<const renderengine::LayerSettings*>& layers,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
// If the highlight layer is enabled, it will increase the size by 1.
// We're interested in the third layer either way.
EXPECT_GE(layers.size(), 4u);
@@ -734,10 +740,10 @@
EXPECT_EQ(1.0f, holePunchBackgroundSettings->alpha);
}
- return NO_ERROR;
+ return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
};
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
}
@@ -859,10 +865,11 @@
BackgroundBlurOnly)))
.WillOnce(Return(clientCompList3));
- const auto drawLayers = [&](const renderengine::DisplaySettings&,
- const std::vector<const renderengine::LayerSettings*>& layers,
- const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd&&, base::unique_fd*) -> int32_t {
+ const auto drawLayers =
+ [&](const renderengine::DisplaySettings&,
+ const std::vector<const renderengine::LayerSettings*>& layers,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
// If the highlight layer is enabled, it will increase the size by 1.
// We're interested in the third layer either way.
EXPECT_GE(layers.size(), 3u);
@@ -871,10 +878,10 @@
EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), blurSettings->source.solidColor);
EXPECT_EQ(0.0f, blurSettings->alpha);
- return NO_ERROR;
+ return futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()});
};
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).WillOnce(Invoke(drawLayers));
cachedSet.render(mRenderEngine, mTexturePool, mOutputState);
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index a28fb2c..9b0a75f 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -26,6 +26,8 @@
#include <renderengine/mock/RenderEngine.h>
#include <chrono>
+#include "tests/TestUtils.h"
+
namespace android::compositionengine {
using namespace std::chrono_literals;
using impl::planner::CachedSet;
@@ -141,7 +143,7 @@
// set up minimium params needed for rendering
mOutputState.dataspace = ui::Dataspace::SRGB;
mOutputState.framebufferSpace = ProjectionSpace(ui::Size(10, 20), Rect(10, 5));
- mOutputState.framebufferSpace.orientation = ui::ROTATION_90;
+ mOutputState.framebufferSpace.setOrientation(ui::ROTATION_90);
}
}
@@ -167,7 +169,9 @@
void FlattenerTest::expectAllLayersFlattened(const std::vector<const LayerState*>& layers) {
// layers would be flattened but the buffer would not be overridden
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
@@ -401,7 +405,9 @@
// caleed for Layer2 and Layer3
layerState1->resetFramesSinceBufferUpdate();
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
@@ -423,7 +429,9 @@
layerState1->incrementFramesSinceBufferUpdate();
mTime += 200ms;
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
@@ -474,7 +482,9 @@
// called for Layer1 and Layer2
layerState3->resetFramesSinceBufferUpdate();
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
@@ -487,11 +497,13 @@
EXPECT_EQ(nullptr, overrideBuffer5);
// Layers 1 and 2 will be flattened a new drawFrame would be called for Layer4 and Layer5
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mOutputState.framebufferSpace.orientation = ui::ROTATION_90;
+ mOutputState.framebufferSpace.setOrientation(ui::ROTATION_90);
mFlattener->renderCachedSets(mOutputState, std::nullopt);
EXPECT_NE(nullptr, overrideBuffer1);
@@ -504,7 +516,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mOutputState.framebufferSpace.orientation = ui::ROTATION_180;
+ mOutputState.framebufferSpace.setOrientation(ui::ROTATION_180);
mFlattener->renderCachedSets(mOutputState, std::nullopt);
EXPECT_NE(nullptr, overrideBuffer1);
@@ -515,8 +527,9 @@
layerState3->incrementFramesSinceBufferUpdate();
mTime += 200ms;
-
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
@@ -531,7 +544,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mOutputState.framebufferSpace.orientation = ui::ROTATION_270;
+ mOutputState.framebufferSpace.setOrientation(ui::ROTATION_270);
mFlattener->renderCachedSets(mOutputState, std::nullopt);
EXPECT_NE(nullptr, overrideBuffer1);
@@ -570,7 +583,9 @@
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
// This will render a CachedSet.
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
mFlattener->renderCachedSets(mOutputState, std::nullopt);
// We've rendered a CachedSet, but we haven't merged it in.
@@ -580,7 +595,7 @@
// This time we merge the CachedSet in, so we have a new hash, and we should
// only have two sets.
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).Times(0);
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
@@ -632,7 +647,9 @@
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
// This will render a CachedSet.
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
mFlattener->renderCachedSets(mOutputState, std::nullopt);
// We've rendered a CachedSet, but we haven't merged it in.
@@ -642,7 +659,7 @@
// This time we merge the CachedSet in, so we have a new hash, and we should
// only have two sets.
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).Times(0);
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
@@ -660,6 +677,75 @@
EXPECT_EQ(peekThroughLayer1, peekThroughLayer2);
}
+// A test that verifies the hole puch optimization can be done on a single layer.
+TEST_F(FlattenerTest, flattenLayers_holePunchSingleLayer) {
+ mTestLayers[0]->outputLayerCompositionState.displayFrame = Rect(0, 0, 5, 5);
+
+ // An opaque static background
+ auto& layerState0 = mTestLayers[0]->layerState;
+ const auto& overrideBuffer0 = layerState0->getOutputLayer()->getState().overrideInfo.buffer;
+
+ // a rounded updating layer
+ auto& layerState1 = mTestLayers[1]->layerState;
+ const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer;
+
+ EXPECT_CALL(*mTestLayers[1]->layerFE, hasRoundedCorners()).WillRepeatedly(Return(true));
+
+ std::vector<LayerFE::LayerSettings> clientCompositionList = {
+ LayerFE::LayerSettings{},
+ };
+ clientCompositionList[0].source.buffer.buffer = std::make_shared<
+ renderengine::ExternalTexture>(mTestLayers[1]->layerFECompositionState.buffer,
+ mRenderEngine,
+ renderengine::ExternalTexture::Usage::READABLE);
+ EXPECT_CALL(*mTestLayers[1]->layerFE, prepareClientCompositionList(_))
+ .WillOnce(Return(clientCompositionList));
+
+ const std::vector<const LayerState*> layers = {
+ layerState0.get(),
+ layerState1.get(),
+ };
+
+ initializeFlattener(layers);
+
+ // layer 1 satisfies every condition in CachedSet::requiresHolePunch()
+ mTime += 200ms;
+ layerState1->resetFramesSinceBufferUpdate(); // it is updating
+
+ initializeOverrideBuffer(layers);
+ // Expect no cache invalidation the first time (there's no cache yet)
+ EXPECT_EQ(getNonBufferHash(layers),
+ mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
+
+ // This will render a CachedSet of layer 0. Though it is just one layer, it satisfies the
+ // exception that there would be a hole punch above it.
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
+ mFlattener->renderCachedSets(mOutputState, std::nullopt);
+
+ // We've rendered a CachedSet, but we haven't merged it in.
+ EXPECT_EQ(nullptr, overrideBuffer0);
+
+ // This time we merge the CachedSet in and we should still have only two sets.
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
+ initializeOverrideBuffer(layers);
+ EXPECT_EQ(getNonBufferHash(layers),
+ mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
+ mFlattener->renderCachedSets(mOutputState, std::nullopt);
+
+ EXPECT_NE(nullptr, overrideBuffer0); // got overridden
+ EXPECT_EQ(nullptr, overrideBuffer1); // did not
+
+ // expect 0's peek though layer to be 1's output layer
+ const auto* peekThroughLayer0 =
+ layerState0->getOutputLayer()->getState().overrideInfo.peekThroughLayer;
+ const auto* peekThroughLayer1 =
+ layerState1->getOutputLayer()->getState().overrideInfo.peekThroughLayer;
+ EXPECT_EQ(&mTestLayers[1]->outputLayer, peekThroughLayer0);
+ EXPECT_EQ(nullptr, peekThroughLayer1);
+}
+
TEST_F(FlattenerTest, flattenLayers_flattensBlurBehindRunIfFirstRun) {
auto& layerState1 = mTestLayers[0]->layerState;
@@ -685,7 +771,9 @@
layerState3->resetFramesSinceBufferUpdate();
// layers would be flattened but the buffer would not be overridden
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
@@ -729,7 +817,9 @@
layerState1->resetFramesSinceBufferUpdate();
// layers would be flattened but the buffer would not be overridden
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillRepeatedly(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillRepeatedly(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
@@ -781,7 +871,9 @@
layerState1->resetFramesSinceBufferUpdate();
// layers would be flattened but the buffer would not be overridden
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
@@ -828,7 +920,9 @@
layerStateWithBlurBehind->resetFramesSinceBufferUpdate();
// layers would be flattened but the buffer would not be overridden
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
@@ -869,7 +963,9 @@
// Mark the layers inactive
mTime += 200ms;
// layers would be flattened but the buffer would not be overridden
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
@@ -881,7 +977,7 @@
// Simulate attempting to render prior to merging the new cached set with the layer stack.
// Here we should not try to re-render.
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).Times(0);
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
mFlattener->renderCachedSets(mOutputState, std::nullopt);
// We provide the override buffer now that it's rendered
@@ -928,13 +1024,15 @@
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
for (size_t i = 0; i < kMaxDeferRenderAttempts; i++) {
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).Times(0);
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
mFlattener->renderCachedSets(mOutputState,
std::chrono::steady_clock::now() -
(kCachedSetRenderDuration + 10ms));
}
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
mFlattener->renderCachedSets(mOutputState,
std::chrono::steady_clock::now() -
(kCachedSetRenderDuration + 10ms));
@@ -968,7 +1066,9 @@
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
// This will render a CachedSet.
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
mFlattener->renderCachedSets(mOutputState, std::nullopt);
// We've rendered a CachedSet, but we haven't merged it in.
@@ -978,7 +1078,7 @@
// This time we merge the CachedSet in, so we have a new hash, and we should
// only have two sets.
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).Times(0);
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
@@ -1017,7 +1117,9 @@
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
// This will render a CachedSet.
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
mFlattener->renderCachedSets(mOutputState, std::nullopt);
// We've rendered a CachedSet, but we haven't merged it in.
@@ -1027,7 +1129,7 @@
// This time we merge the CachedSet in, so we have a new hash, and we should
// only have two sets.
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).Times(0);
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
@@ -1066,7 +1168,9 @@
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
// This will render a CachedSet.
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(
+ futureOf<renderengine::RenderEngineResult>({NO_ERROR, base::unique_fd()}))));
mFlattener->renderCachedSets(mOutputState, std::nullopt);
// We've rendered a CachedSet, but we haven't merged it in.
@@ -1076,7 +1180,7 @@
// This time we merge the CachedSet in, so we have a new hash, and we should
// only have two sets.
- EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).Times(0);
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 4445eea..3397118 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -116,11 +116,11 @@
}
int DisplayDevice::getWidth() const {
- return mCompositionDisplay->getState().displaySpace.bounds.getWidth();
+ return mCompositionDisplay->getState().displaySpace.getBounds().width;
}
int DisplayDevice::getHeight() const {
- return mCompositionDisplay->getState().displaySpace.bounds.getHeight();
+ return mCompositionDisplay->getState().displaySpace.getBounds().height;
}
void DisplayDevice::setDisplayName(const std::string& displayName) {
@@ -139,6 +139,34 @@
return mCompositionDisplay->getRenderSurface()->getPageFlipCount();
}
+std::pair<gui::DisplayInfo, ui::Transform> DisplayDevice::getInputInfo() const {
+ gui::DisplayInfo info;
+ info.displayId = getLayerStack().id;
+
+ // The physical orientation is set when the orientation of the display panel is
+ // different than the default orientation of the device. Other services like
+ // InputFlinger do not know about this, so we do not need to expose the physical
+ // orientation of the panel outside of SurfaceFlinger.
+ const ui::Rotation inversePhysicalOrientation = ui::ROTATION_0 - mPhysicalOrientation;
+ auto width = getWidth();
+ auto height = getHeight();
+ if (inversePhysicalOrientation == ui::ROTATION_90 ||
+ inversePhysicalOrientation == ui::ROTATION_270) {
+ std::swap(width, height);
+ }
+ const ui::Transform undoPhysicalOrientation(ui::Transform::toRotationFlags(
+ inversePhysicalOrientation),
+ width, height);
+ const auto& displayTransform = undoPhysicalOrientation * getTransform();
+ // Send the inverse display transform to input so it can convert display coordinates to
+ // logical display.
+ info.transform = displayTransform.inverse();
+
+ info.logicalWidth = getLayerStackSpaceRect().width();
+ info.logicalHeight = getLayerStackSpaceRect().height();
+ return {info, displayTransform};
+}
+
// ----------------------------------------------------------------------------
void DisplayDevice::setPowerMode(hal::PowerMode mode) {
mPowerMode = mode;
@@ -232,7 +260,7 @@
}
void DisplayDevice::setLayerStack(ui::LayerStack stack) {
- mCompositionDisplay->setLayerStackFilter(stack, isInternal());
+ mCompositionDisplay->setLayerFilter({stack, isInternal()});
if (mRefreshRateOverlay) {
mRefreshRateOverlay->setLayerStack(stack);
}
@@ -262,13 +290,15 @@
if (!orientedDisplaySpaceRect.isValid()) {
// The destination frame can be invalid if it has never been set,
// in that case we assume the whole display size.
- orientedDisplaySpaceRect = getCompositionDisplay()->getState().displaySpace.bounds;
+ orientedDisplaySpaceRect =
+ getCompositionDisplay()->getState().displaySpace.getBoundsAsRect();
}
if (layerStackSpaceRect.isEmpty()) {
// The layerStackSpaceRect can be invalid if it has never been set, in that case
// we assume the whole framebuffer size.
- layerStackSpaceRect = getCompositionDisplay()->getState().framebufferSpace.bounds;
+ layerStackSpaceRect =
+ getCompositionDisplay()->getState().framebufferSpace.getBoundsAsRect();
if (orientation == ui::ROTATION_90 || orientation == ui::ROTATION_270) {
std::swap(layerStackSpaceRect.right, layerStackSpaceRect.bottom);
}
@@ -336,8 +366,8 @@
return mCompositionDisplay->isSecure();
}
-const Rect& DisplayDevice::getBounds() const {
- return mCompositionDisplay->getState().displaySpace.bounds;
+const Rect DisplayDevice::getBounds() const {
+ return mCompositionDisplay->getState().displaySpace.getBoundsAsRect();
}
const Region& DisplayDevice::getUndefinedRegion() const {
@@ -349,7 +379,7 @@
}
ui::LayerStack DisplayDevice::getLayerStack() const {
- return mCompositionDisplay->getState().layerStackId;
+ return mCompositionDisplay->getState().layerFilter.layerStack;
}
ui::Transform::RotationFlags DisplayDevice::getTransformHint() const {
@@ -361,11 +391,11 @@
}
const Rect& DisplayDevice::getLayerStackSpaceRect() const {
- return mCompositionDisplay->getState().layerStackSpace.content;
+ return mCompositionDisplay->getState().layerStackSpace.getContent();
}
const Rect& DisplayDevice::getOrientedDisplaySpaceRect() const {
- return mCompositionDisplay->getState().orientedDisplaySpace.content;
+ return mCompositionDisplay->getState().orientedDisplaySpace.getContent();
}
bool DisplayDevice::hasWideColorGamut() const {
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 4d435c7..4a731bd 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -86,9 +86,7 @@
bool isVirtual() const { return !mConnectionType; }
bool isPrimary() const { return mIsPrimary; }
- bool isInternal() const {
- return !isVirtual() && mConnectionType == ui::DisplayConnectionType::Internal;
- }
+ bool isInternal() const { return mConnectionType == ui::DisplayConnectionType::Internal; }
// isSecure indicates whether this display can be trusted to display
// secure surfaces.
@@ -158,8 +156,8 @@
// Return true if intent is supported by the display.
bool hasRenderIntent(ui::RenderIntent intent) const;
- const Rect& getBounds() const;
- const Rect& bounds() const { return getBounds(); }
+ const Rect getBounds() const;
+ const Rect bounds() const { return getBounds(); }
void setDisplayName(const std::string& displayName);
const std::string& getDisplayName() const { return mDisplayName; }
@@ -169,6 +167,10 @@
return mDeviceProductInfo;
}
+ // Get the DisplayInfo that will be sent to InputFlinger, and the display transform that should
+ // be applied to all the input windows on the display.
+ std::pair<gui::DisplayInfo, ui::Transform> getInputInfo() const;
+
/* ------------------------------------------------------------------------
* Display power mode management.
*/
@@ -273,7 +275,7 @@
std::atomic<nsecs_t> mLastHwVsync = 0;
- // TODO(b/74619554): Remove special cases for primary display.
+ // TODO(b/182939859): Remove special cases for primary display.
const bool mIsPrimary;
uint32_t mFlags = 0;
@@ -311,7 +313,7 @@
int32_t sequenceId = sNextSequenceId++;
std::optional<Physical> physical;
sp<IGraphicBufferProducer> surface;
- ui::LayerStack layerStack = ui::NO_LAYER_STACK;
+ ui::LayerStack layerStack;
uint32_t flags = 0;
Rect layerStackSpaceRect;
Rect orientedDisplaySpaceRect;
@@ -354,16 +356,4 @@
DisplayModeId activeModeId;
};
-// Predicates for display lookup.
-
-struct WithLayerStack {
- explicit WithLayerStack(ui::LayerStack layerStack) : layerStack(layerStack) {}
-
- bool operator()(const DisplayDevice& display) const {
- return display.getLayerStack() == layerStack;
- }
-
- ui::LayerStack layerStack;
-};
-
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index a790b4c..256bca9 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -212,8 +212,6 @@
RETURN_IF_INVALID_DISPLAY(*displayId, false);
auto& displayData = mDisplayData[*displayId];
- LOG_FATAL_IF(displayData.isVirtual, "%s: Invalid operation on virtual display with ID %s",
- __FUNCTION__, to_string(*displayId).c_str());
{
// There have been reports of HWCs that signal several vsync events
@@ -271,7 +269,6 @@
display->setConnected(true);
auto& displayData = mDisplayData[displayId];
displayData.hwcDisplay = std::move(display);
- displayData.isVirtual = true;
return true;
}
@@ -279,10 +276,8 @@
PhysicalDisplayId displayId) {
mPhysicalDisplayIdMap[hwcDisplayId] = displayId;
- if (!mInternalHwcDisplayId) {
- mInternalHwcDisplayId = hwcDisplayId;
- } else if (mInternalHwcDisplayId != hwcDisplayId && !mExternalHwcDisplayId) {
- mExternalHwcDisplayId = hwcDisplayId;
+ if (!mPrimaryHwcDisplayId) {
+ mPrimaryHwcDisplayId = hwcDisplayId;
}
auto& displayData = mDisplayData[displayId];
@@ -372,7 +367,7 @@
ui::DisplayConnectionType type;
const auto error = hwcDisplay->getConnectionType(&type);
- const auto FALLBACK_TYPE = hwcDisplay->getId() == mInternalHwcDisplayId
+ const auto FALLBACK_TYPE = hwcDisplay->getId() == mPrimaryHwcDisplayId
? ui::DisplayConnectionType::Internal
: ui::DisplayConnectionType::External;
@@ -428,9 +423,6 @@
RETURN_IF_INVALID_DISPLAY(displayId);
auto& displayData = mDisplayData[displayId];
- LOG_FATAL_IF(displayData.isVirtual, "%s: Invalid operation on virtual display with ID %s",
- __FUNCTION__, to_string(displayId).c_str());
-
// NOTE: we use our own internal lock here because we have to call
// into the HWC with the lock held, and we want to make sure
// that even if HWC blocks (which it shouldn't), it won't
@@ -597,14 +589,11 @@
status_t HWComposer::setPowerMode(PhysicalDisplayId displayId, hal::PowerMode mode) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
- const auto& displayData = mDisplayData[displayId];
- LOG_FATAL_IF(displayData.isVirtual, "%s: Invalid operation on virtual display with ID %s",
- __FUNCTION__, to_string(displayId).c_str());
-
if (mode == hal::PowerMode::OFF) {
setVsyncEnabled(displayId, hal::Vsync::DISABLE);
}
+ const auto& displayData = mDisplayData[displayId];
auto& hwcDisplay = displayData.hwcDisplay;
switch (mode) {
case hal::PowerMode::OFF:
@@ -678,12 +667,6 @@
auto& displayData = mDisplayData[displayId];
const auto hwcDisplayId = displayData.hwcDisplay->getId();
- // TODO(b/74619554): Select internal/external display from remaining displays.
- if (hwcDisplayId == mInternalHwcDisplayId) {
- mInternalHwcDisplayId.reset();
- } else if (hwcDisplayId == mExternalHwcDisplayId) {
- mExternalHwcDisplayId.reset();
- }
mPhysicalDisplayIdMap.erase(hwcDisplayId);
mDisplayData.erase(displayId);
}
@@ -693,9 +676,6 @@
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
const auto& displayData = mDisplayData[displayId];
- LOG_FATAL_IF(!displayData.isVirtual, "%s: Invalid operation on physical display with ID %s",
- __FUNCTION__, to_string(displayId).c_str());
-
auto error = displayData.hwcDisplay->setOutputBuffer(buffer, acquireFence);
RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
return NO_ERROR;
@@ -853,8 +833,7 @@
std::optional<hal::HWDisplayId> HWComposer::fromPhysicalDisplayId(
PhysicalDisplayId displayId) const {
- if (const auto it = mDisplayData.find(displayId);
- it != mDisplayData.end() && !it->second.isVirtual) {
+ if (const auto it = mDisplayData.find(displayId); it != mDisplayData.end()) {
return it->second.hwcDisplay->getId();
}
return {};
@@ -868,7 +847,8 @@
return true;
}
- if (!mHasMultiDisplaySupport && mInternalHwcDisplayId && mExternalHwcDisplayId) {
+ // Legacy mode only supports IDs LEGACY_DISPLAY_TYPE_PRIMARY and LEGACY_DISPLAY_TYPE_EXTERNAL.
+ if (!mHasMultiDisplaySupport && mPhysicalDisplayIdMap.size() == 2) {
ALOGE("Ignoring connection of tertiary display %" PRIu64, hwcDisplayId);
return true;
}
@@ -909,7 +889,7 @@
}
info = [this, hwcDisplayId, &port, &data, hasDisplayIdentificationData] {
- const bool isPrimary = !mInternalHwcDisplayId;
+ const bool isPrimary = !mPrimaryHwcDisplayId;
if (mHasMultiDisplaySupport) {
if (const auto info = parseDisplayIdentificationData(port, data)) {
return *info;
@@ -922,8 +902,8 @@
}
return DisplayIdentificationInfo{.id = PhysicalDisplayId::fromPort(port),
- .name = isPrimary ? "Internal display"
- : "External display",
+ .name = isPrimary ? "Primary display"
+ : "Secondary display",
.deviceProductInfo = std::nullopt};
}();
}
@@ -936,9 +916,12 @@
std::optional<DisplayIdentificationInfo> HWComposer::onHotplugDisconnect(
hal::HWDisplayId hwcDisplayId) {
+ LOG_ALWAYS_FATAL_IF(hwcDisplayId == mPrimaryHwcDisplayId,
+ "Primary display cannot be disconnected.");
+
const auto displayId = toPhysicalDisplayId(hwcDisplayId);
if (!displayId) {
- ALOGE("Ignoring disconnection of invalid HWC display %" PRIu64, hwcDisplayId);
+ LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Invalid HWC display");
return {};
}
@@ -947,7 +930,7 @@
if (isConnected(*displayId)) {
mDisplayData[*displayId].hwcDisplay->setConnected(false);
} else {
- ALOGW("Attempted to disconnect unknown display %" PRIu64, hwcDisplayId);
+ LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Already disconnected");
}
// The cleanup of Disconnect is handled through HWComposer::disconnectDisplay
// via SurfaceFlinger's onHotplugReceived callback handling
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 49f96d9..0a090da 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_SF_HWCOMPOSER_H
-#define ANDROID_SF_HWCOMPOSER_H
+#pragma once
#include <cstdint>
#include <future>
@@ -228,14 +227,18 @@
virtual const std::unordered_map<std::string, bool>& getSupportedLayerGenericMetadata()
const = 0;
- // for debugging ----------------------------------------------------------
virtual void dump(std::string& out) const = 0;
virtual Hwc2::Composer* getComposer() const = 0;
- // TODO(b/74619554): Remove special cases for internal/external display.
- virtual std::optional<hal::HWDisplayId> getInternalHwcDisplayId() const = 0;
- virtual std::optional<hal::HWDisplayId> getExternalHwcDisplayId() const = 0;
+ // Returns the first display connected at boot. It cannot be disconnected, which implies an
+ // internal connection type. Its connection via HWComposer::onHotplug, which in practice is
+ // immediately after HWComposer construction, must occur before any call to this function.
+ //
+ // TODO(b/182939859): Remove special cases for primary display.
+ virtual hal::HWDisplayId getPrimaryHwcDisplayId() const = 0;
+ virtual PhysicalDisplayId getPrimaryDisplayId() const = 0;
+ virtual bool isHeadless() const = 0;
virtual std::optional<PhysicalDisplayId> toPhysicalDisplayId(hal::HWDisplayId) const = 0;
virtual std::optional<hal::HWDisplayId> fromPhysicalDisplayId(PhysicalDisplayId) const = 0;
@@ -366,14 +369,19 @@
Hwc2::Composer* getComposer() const override { return mComposer.get(); }
- // TODO(b/74619554): Remove special cases for internal/external display.
- std::optional<hal::HWDisplayId> getInternalHwcDisplayId() const override {
- return mInternalHwcDisplayId;
+ hal::HWDisplayId getPrimaryHwcDisplayId() const override {
+ LOG_ALWAYS_FATAL_IF(!mPrimaryHwcDisplayId, "Missing HWC primary display");
+ return *mPrimaryHwcDisplayId;
}
- std::optional<hal::HWDisplayId> getExternalHwcDisplayId() const override {
- return mExternalHwcDisplayId;
+
+ PhysicalDisplayId getPrimaryDisplayId() const override {
+ const auto id = toPhysicalDisplayId(getPrimaryHwcDisplayId());
+ LOG_ALWAYS_FATAL_IF(!id, "Missing primary display");
+ return *id;
}
+ virtual bool isHeadless() const override { return !mPrimaryHwcDisplayId; }
+
std::optional<PhysicalDisplayId> toPhysicalDisplayId(hal::HWDisplayId) const override;
std::optional<hal::HWDisplayId> fromPhysicalDisplayId(PhysicalDisplayId) const override;
@@ -382,12 +390,9 @@
friend TestableSurfaceFlinger;
struct DisplayData {
- bool isVirtual = false;
std::unique_ptr<HWC2::Display> hwcDisplay;
sp<Fence> lastPresentFence = Fence::NO_FENCE; // signals when the last set op retires
std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
- buffer_handle_t outbufHandle = nullptr;
- sp<Fence> outbufAcquireFence = Fence::NO_FENCE;
bool validateWasSkipped;
hal::Error presentError;
@@ -418,8 +423,7 @@
bool mRegisteredCallback = false;
std::unordered_map<hal::HWDisplayId, PhysicalDisplayId> mPhysicalDisplayIdMap;
- std::optional<hal::HWDisplayId> mInternalHwcDisplayId;
- std::optional<hal::HWDisplayId> mExternalHwcDisplayId;
+ std::optional<hal::HWDisplayId> mPrimaryHwcDisplayId;
bool mHasMultiDisplaySupport = false;
const size_t mMaxVirtualDisplayDimension;
@@ -428,5 +432,3 @@
} // namespace impl
} // namespace android
-
-#endif // ANDROID_SF_HWCOMPOSER_H
diff --git a/services/surfaceflinger/FlagManager.cpp b/services/surfaceflinger/FlagManager.cpp
new file mode 100644
index 0000000..f0c5b58
--- /dev/null
+++ b/services/surfaceflinger/FlagManager.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2021 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 "FlagManager.h"
+
+#include <SurfaceFlingerProperties.sysprop.h>
+#include <android-base/parsebool.h>
+#include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
+#include <log/log.h>
+#include <server_configurable_flags/get_flags.h>
+#include <cinttypes>
+
+namespace android {
+static constexpr const char* kExperimentNamespace = "surface_flinger_native_boot";
+static constexpr const int64_t kDemoFlag = -1;
+
+FlagManager::~FlagManager() = default;
+
+void FlagManager::dump(std::string& result) const {
+ base::StringAppendF(&result, "FlagManager values: \n");
+ base::StringAppendF(&result, "demo_flag: %" PRId64 "\n", demo_flag());
+}
+
+namespace {
+template <typename T>
+std::optional<T> doParse(const char* str);
+
+template <>
+[[maybe_unused]] std::optional<int32_t> doParse(const char* str) {
+ int32_t ret;
+ return base::ParseInt(str, &ret) ? std::make_optional(ret) : std::nullopt;
+}
+
+template <>
+[[maybe_unused]] std::optional<int64_t> doParse(const char* str) {
+ int64_t ret;
+ return base::ParseInt(str, &ret) ? std::make_optional(ret) : std::nullopt;
+}
+
+template <>
+[[maybe_unused]] std::optional<bool> doParse(const char* str) {
+ base::ParseBoolResult parseResult = base::ParseBool(str);
+ switch (parseResult) {
+ case base::ParseBoolResult::kTrue:
+ return std::make_optional(true);
+ case base::ParseBoolResult::kFalse:
+ return std::make_optional(false);
+ case base::ParseBoolResult::kError:
+ return std::nullopt;
+ }
+}
+} // namespace
+
+std::string FlagManager::getServerConfigurableFlag(const std::string& experimentFlagName) const {
+ return server_configurable_flags::GetServerConfigurableFlag(kExperimentNamespace,
+ experimentFlagName, "");
+}
+
+template int32_t FlagManager::getValue<int32_t>(const std::string&, std::optional<int32_t>,
+ int32_t) const;
+template int64_t FlagManager::getValue<int64_t>(const std::string&, std::optional<int64_t>,
+ int64_t) const;
+template bool FlagManager::getValue<bool>(const std::string&, std::optional<bool>, bool) const;
+template <typename T>
+T FlagManager::getValue(const std::string& experimentFlagName, std::optional<T> systemPropertyOpt,
+ T defaultValue) const {
+ // System property takes precedence over the experiment config server value.
+ if (systemPropertyOpt.has_value()) {
+ return *systemPropertyOpt;
+ }
+ std::string str = getServerConfigurableFlag(experimentFlagName);
+ return str.empty() ? defaultValue : doParse<T>(str.c_str()).value_or(defaultValue);
+}
+
+int64_t FlagManager::demo_flag() const {
+ std::optional<int64_t> sysPropVal = std::nullopt;
+ return getValue("DemoFeature__demo_flag", sysPropVal, kDemoFlag);
+}
+} // namespace android
diff --git a/services/surfaceflinger/FlagManager.h b/services/surfaceflinger/FlagManager.h
new file mode 100644
index 0000000..65e30a4
--- /dev/null
+++ b/services/surfaceflinger/FlagManager.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <optional>
+#include <string>
+
+namespace android {
+// Manages flags for SurfaceFlinger, including default values, system properties, and Mendel
+// experiment configuration values.
+class FlagManager {
+public:
+ FlagManager() = default;
+ virtual ~FlagManager();
+ void dump(std::string& result) const;
+
+ int64_t demo_flag() const;
+
+private:
+ friend class FlagManagerTest;
+
+ // Wrapper for mocking in test.
+ virtual std::string getServerConfigurableFlag(const std::string& experimentFlagName) const;
+
+ template <typename T>
+ T getValue(const std::string& experimentFlagName, std::optional<T> systemPropertyOpt,
+ T defaultValue) const;
+};
+} // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 638bb9b..ef6f115 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -107,7 +107,7 @@
mDrawingState.requestedCrop = mDrawingState.crop;
mDrawingState.z = 0;
mDrawingState.color.a = 1.0f;
- mDrawingState.layerStack = 0;
+ mDrawingState.layerStack = ui::DEFAULT_LAYER_STACK;
mDrawingState.sequence = 0;
mDrawingState.requested_legacy = mDrawingState.active_legacy;
mDrawingState.width = UINT32_MAX;
@@ -392,7 +392,6 @@
void Layer::prepareBasicGeometryCompositionState() {
const auto& drawingState{getDrawingState()};
- const uint32_t layerStack = getLayerStack();
const auto alpha = static_cast<float>(getAlpha());
const bool opaque = isOpaque(drawingState);
const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f;
@@ -404,9 +403,7 @@
}
auto* compositionState = editCompositionState();
- compositionState->layerStackId =
- (layerStack != ~0u) ? std::make_optional(layerStack) : std::nullopt;
- compositionState->internalOnly = getPrimaryDisplayOnly();
+ compositionState->outputFilter = getOutputFilter();
compositionState->isVisible = isVisible();
compositionState->isOpaque = opaque && !usesRoundedCorners && alpha == 1.f;
compositionState->shadowRadius = mEffectiveShadowRadius;
@@ -729,14 +726,14 @@
mDrawingState.bufferlessSurfaceFramesTX.clear();
}
-uint32_t Layer::getTransactionFlags(uint32_t flags) {
- auto ret = mTransactionFlags & flags;
- mTransactionFlags &= ~flags;
- return ret;
+uint32_t Layer::clearTransactionFlags(uint32_t mask) {
+ const auto flags = mTransactionFlags & mask;
+ mTransactionFlags &= ~mask;
+ return flags;
}
-uint32_t Layer::setTransactionFlags(uint32_t flags) {
- return mTransactionFlags |= flags;
+void Layer::setTransactionFlags(uint32_t mask) {
+ mTransactionFlags |= mask;
}
bool Layer::setPosition(float x, float y) {
@@ -1006,7 +1003,7 @@
return true;
}
-bool Layer::setLayerStack(uint32_t layerStack) {
+bool Layer::setLayerStack(ui::LayerStack layerStack) {
if (mDrawingState.layerStack == layerStack) return false;
mDrawingState.sequence++;
mDrawingState.layerStack = layerStack;
@@ -1053,12 +1050,11 @@
return priority == PRIORITY_FOCUSED_WITH_MODE || priority == PRIORITY_FOCUSED_WITHOUT_MODE;
};
-uint32_t Layer::getLayerStack() const {
- auto p = mDrawingParent.promote();
- if (p == nullptr) {
- return getDrawingState().layerStack;
+ui::LayerStack Layer::getLayerStack() const {
+ if (const auto parent = mDrawingParent.promote()) {
+ return parent->getLayerStack();
}
- return p->getLayerStack();
+ return getDrawingState().layerStack;
}
bool Layer::setShadowRadius(float shadowRadius) {
@@ -1372,7 +1368,7 @@
info.mVisibleRegion = getVisibleRegion(display);
info.mSurfaceDamageRegion = surfaceDamageRegion;
- info.mLayerStack = getLayerStack();
+ info.mLayerStack = getLayerStack().id;
info.mX = ds.transform.tx();
info.mY = ds.transform.ty();
info.mZ = ds.z;
@@ -2089,7 +2085,7 @@
LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy,
[&]() { return layerInfo->mutable_transparent_region(); });
- layerInfo->set_layer_stack(getLayerStack());
+ layerInfo->set_layer_stack(getLayerStack().id);
layerInfo->set_z(state.z);
LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(),
@@ -2136,7 +2132,7 @@
if (traceFlags & SurfaceTracing::TRACE_INPUT) {
WindowInfo info;
if (useDrawing) {
- info = fillInputInfo({nullptr});
+ info = fillInputInfo(ui::Transform());
} else {
info = state.inputInfo;
}
@@ -2165,7 +2161,7 @@
return getCroppedBufferSize(getDrawingState());
}
-void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& toNonRotatedDisplay) {
+void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& displayTransform) {
// Transform layer size to screen space and inset it by surface insets.
// If this is a portal window, set the touchableRegion to the layerBounds.
Rect layerBounds = info.portalToDisplayId == ADISPLAY_ID_NONE
@@ -2185,13 +2181,13 @@
return;
}
- ui::Transform layerToDisplay = getInputTransform();
+ const ui::Transform layerTransform = getInputTransform();
// Transform that takes window coordinates to non-rotated display coordinates
- ui::Transform t = toNonRotatedDisplay * layerToDisplay;
+ ui::Transform t = displayTransform * layerTransform;
int32_t xSurfaceInset = info.surfaceInset;
int32_t ySurfaceInset = info.surfaceInset;
- // Bring screenBounds into non-rotated space
- Rect screenBounds = toNonRotatedDisplay.transform(Rect{mScreenBounds});
+ // Bring screenBounds into non-unrotated space
+ Rect screenBounds = displayTransform.transform(Rect{mScreenBounds});
const float xScale = t.getScaleX();
const float yScale = t.getScaleY();
@@ -2270,47 +2266,21 @@
}
}
-WindowInfo Layer::fillInputInfo(const sp<DisplayDevice>& display) {
+WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform) {
if (!hasInputInfo()) {
mDrawingState.inputInfo.name = getName();
mDrawingState.inputInfo.ownerUid = mOwnerUid;
mDrawingState.inputInfo.ownerPid = mOwnerPid;
mDrawingState.inputInfo.inputFeatures = WindowInfo::Feature::NO_INPUT_CHANNEL;
mDrawingState.inputInfo.flags = WindowInfo::Flag::NOT_TOUCH_MODAL;
- mDrawingState.inputInfo.displayId = getLayerStack();
+ mDrawingState.inputInfo.displayId = getLayerStack().id;
}
WindowInfo info = mDrawingState.inputInfo;
info.id = sequence;
- info.displayId = getLayerStack();
+ info.displayId = getLayerStack().id;
- // Transform that goes from "logical(rotated)" display to the non-rotated display.
- ui::Transform toNonRotatedDisplay;
- if (display) {
- // The physical orientation is set when the orientation of the display panel is different
- // than the default orientation of the device. We do not need to expose the physical
- // orientation of the panel outside of SurfaceFlinger.
- const ui::Rotation inversePhysicalOrientation =
- ui::ROTATION_0 - display->getPhysicalOrientation();
- auto width = display->getWidth();
- auto height = display->getHeight();
- if (inversePhysicalOrientation == ui::ROTATION_90 ||
- inversePhysicalOrientation == ui::ROTATION_270) {
- std::swap(width, height);
- }
- const auto rotationFlags = ui::Transform::toRotationFlags(inversePhysicalOrientation);
- const ui::Transform undoPhysicalOrientation(rotationFlags, width, height);
- toNonRotatedDisplay = undoPhysicalOrientation * display->getTransform();
-
- // Send the inverse of the display orientation so that input can transform points back to
- // the rotated display space.
- const ui::Rotation inverseOrientation = ui::ROTATION_0 - display->getOrientation();
- info.displayOrientation = ui::Transform::toRotationFlags(inverseOrientation);
-
- info.displayWidth = width;
- info.displayHeight = height;
- }
- fillInputFrameInfo(info, toNonRotatedDisplay);
+ fillInputFrameInfo(info, displayTransform);
// For compatibility reasons we let layers which can receive input
// receive input before they have actually submitted a buffer. Because
@@ -2326,15 +2296,11 @@
auto cropLayer = mDrawingState.touchableRegionCrop.promote();
if (info.replaceTouchableRegionWithCrop) {
- if (cropLayer == nullptr) {
- info.touchableRegion = Region(toNonRotatedDisplay.transform(Rect{mScreenBounds}));
- } else {
- info.touchableRegion =
- Region(toNonRotatedDisplay.transform(Rect{cropLayer->mScreenBounds}));
- }
+ const Rect bounds(cropLayer ? cropLayer->mScreenBounds : mScreenBounds);
+ info.touchableRegion = Region(displayTransform.transform(bounds));
} else if (cropLayer != nullptr) {
info.touchableRegion = info.touchableRegion.intersect(
- toNonRotatedDisplay.transform(Rect{cropLayer->mScreenBounds}));
+ displayTransform.transform(Rect{cropLayer->mScreenBounds}));
}
// Inherit the trusted state from the parent hierarchy, but don't clobber the trusted state
@@ -2345,9 +2311,8 @@
// If the layer is a clone, we need to crop the input region to cloned root to prevent
// touches from going outside the cloned area.
if (isClone()) {
- sp<Layer> clonedRoot = getClonedRoot();
- if (clonedRoot != nullptr) {
- Rect rect = toNonRotatedDisplay.transform(Rect{clonedRoot->mScreenBounds});
+ if (const sp<Layer> clonedRoot = getClonedRoot()) {
+ const Rect rect = displayTransform.transform(Rect{clonedRoot->mScreenBounds});
info.touchableRegion = info.touchableRegion.intersect(rect);
}
}
@@ -2543,14 +2508,14 @@
}
}
-bool Layer::getPrimaryDisplayOnly() const {
+bool Layer::isInternalDisplayOverlay() const {
const State& s(mDrawingState);
if (s.flags & layer_state_t::eLayerSkipScreenshot) {
return true;
}
sp<Layer> parent = mDrawingParent.promote();
- return parent == nullptr ? false : parent->getPrimaryDisplayOnly();
+ return parent && parent->isInternalDisplayOverlay();
}
void Layer::setClonedChild(const sp<Layer>& clonedChild) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 470103c..3c3c7d0 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -151,12 +151,7 @@
Geometry requested_legacy;
int32_t z;
- // The identifier of the layer stack this layer belongs to. A layer can
- // only be associated to a single layer stack. A layer stack is a
- // z-ordered group of layers which can be associated to one or more
- // displays. Using the same layer stack on different displays is a way
- // to achieve mirroring.
- uint32_t layerStack;
+ ui::LayerStack layerStack;
uint32_t flags;
uint8_t reserved[2];
@@ -405,8 +400,8 @@
virtual bool setTransparentRegionHint(const Region& transparent);
virtual bool setTrustedOverlay(bool);
virtual bool setFlags(uint32_t flags, uint32_t mask);
- virtual bool setLayerStack(uint32_t layerStack);
- virtual uint32_t getLayerStack() const;
+ virtual bool setLayerStack(ui::LayerStack);
+ virtual ui::LayerStack getLayerStack() const;
virtual bool setMetadata(const LayerMetadata& data);
virtual void setChildrenDrawingParent(const sp<Layer>&);
virtual bool reparent(const sp<IBinder>& newParentHandle);
@@ -645,13 +640,12 @@
bool isLegacyDataSpace() const;
uint32_t getTransactionFlags() const { return mTransactionFlags; }
- uint32_t getTransactionFlags(uint32_t flags);
- uint32_t setTransactionFlags(uint32_t flags);
- // Deprecated, please use compositionengine::Output::belongsInOutput()
- // instead.
- // TODO(lpique): Move the remaining callers (screencap) to the new function.
- bool belongsToDisplay(uint32_t layerStack) const { return getLayerStack() == layerStack; }
+ // Sets the masked bits.
+ void setTransactionFlags(uint32_t mask);
+
+ // Clears and returns the masked bits.
+ uint32_t clearTransactionFlags(uint32_t mask);
FloatRect getBounds(const Region& activeTransparentRegion) const;
FloatRect getBounds() const;
@@ -684,6 +678,14 @@
*/
bool isHiddenByPolicy() const;
+ // True if the layer should be skipped in screenshots, screen recordings,
+ // and mirroring to external or virtual displays.
+ bool isInternalDisplayOverlay() const;
+
+ ui::LayerFilter getOutputFilter() const {
+ return {getLayerStack(), isInternalDisplayOverlay()};
+ }
+
bool isRemovedFromCurrentState() const;
LayerProto* writeToProto(LayersProto& layersProto, uint32_t traceFlags, const DisplayDevice*);
@@ -700,8 +702,6 @@
gui::WindowInfo::Type getWindowType() const { return mWindowType; }
- bool getPrimaryDisplayOnly() const;
-
void updateMirrorInfo();
/*
@@ -851,7 +851,8 @@
bool getPremultipledAlpha() const;
void setInputInfo(const gui::WindowInfo& info);
- gui::WindowInfo fillInputInfo(const sp<DisplayDevice>& display);
+ gui::WindowInfo fillInputInfo(const ui::Transform& displayTransform);
+
/**
* Returns whether this layer has an explicitly set input-info.
*/
@@ -1072,8 +1073,8 @@
// hasInputInfo() or no-op if no such parent is found.
void fillTouchOcclusionMode(gui::WindowInfo& info);
- // Fills in the frame and transform info for the gui::WindowInfo
- void fillInputFrameInfo(gui::WindowInfo& info, const ui::Transform& toNonRotatedDisplay);
+ // Fills in the frame and transform info for the gui::WindowInfo.
+ void fillInputFrameInfo(gui::WindowInfo&, const ui::Transform& displayTransform);
// Cached properties computed from drawing state
// Effective transform taking into account parent transforms and any parent scaling, which is
diff --git a/services/surfaceflinger/LayerVector.cpp b/services/surfaceflinger/LayerVector.cpp
index aee820a..f52e60d 100644
--- a/services/surfaceflinger/LayerVector.cpp
+++ b/services/surfaceflinger/LayerVector.cpp
@@ -45,8 +45,8 @@
const auto& lState = l->getDrawingState();
const auto& rState = r->getDrawingState();
- uint32_t ls = lState.layerStack;
- uint32_t rs = rState.layerStack;
+ const auto ls = lState.layerStack;
+ const auto rs = rState.layerStack;
if (ls != rs)
return (ls > rs) ? 1 : -1;
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index bc32a1d..0789e8d 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -25,6 +25,10 @@
#include "Client.h"
#include "Layer.h"
+#include <SkBlendMode.h>
+#include <SkPaint.h>
+#include <SkRect.h>
+#include <SkSurface.h>
#include <gui/IProducerListener.h>
#undef LOG_TAG
@@ -32,85 +36,64 @@
namespace android {
-void RefreshRateOverlay::SevenSegmentDrawer::drawRect(const Rect& r, const half4& color,
- const sp<GraphicBuffer>& buffer,
- uint8_t* pixels) {
- for (int32_t j = r.top; j < r.bottom; j++) {
- if (j >= buffer->getHeight()) {
- break;
- }
-
- for (int32_t i = r.left; i < r.right; i++) {
- if (i >= buffer->getWidth()) {
- break;
- }
-
- uint8_t* iter = pixels + 4 * (i + (buffer->getStride() * j));
- iter[0] = uint8_t(color.r * 255);
- iter[1] = uint8_t(color.g * 255);
- iter[2] = uint8_t(color.b * 255);
- iter[3] = uint8_t(color.a * 255);
- }
- }
-}
-
-void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left,
- const half4& color,
- const sp<GraphicBuffer>& buffer,
- uint8_t* pixels) {
- const Rect rect = [&]() {
+void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left, SkColor& color,
+ SkCanvas& canvas) {
+ const SkRect rect = [&]() {
switch (segment) {
case Segment::Upper:
- return Rect(left, 0, left + DIGIT_WIDTH, DIGIT_SPACE);
+ return SkRect::MakeLTRB(left, 0, left + DIGIT_WIDTH, DIGIT_SPACE);
case Segment::UpperLeft:
- return Rect(left, 0, left + DIGIT_SPACE, DIGIT_HEIGHT / 2);
+ return SkRect::MakeLTRB(left, 0, left + DIGIT_SPACE, DIGIT_HEIGHT / 2);
case Segment::UpperRight:
- return Rect(left + DIGIT_WIDTH - DIGIT_SPACE, 0, left + DIGIT_WIDTH,
- DIGIT_HEIGHT / 2);
+ return SkRect::MakeLTRB(left + DIGIT_WIDTH - DIGIT_SPACE, 0, left + DIGIT_WIDTH,
+ DIGIT_HEIGHT / 2);
case Segment::Middle:
- return Rect(left, DIGIT_HEIGHT / 2 - DIGIT_SPACE / 2, left + DIGIT_WIDTH,
- DIGIT_HEIGHT / 2 + DIGIT_SPACE / 2);
+ return SkRect::MakeLTRB(left, DIGIT_HEIGHT / 2 - DIGIT_SPACE / 2,
+ left + DIGIT_WIDTH, DIGIT_HEIGHT / 2 + DIGIT_SPACE / 2);
case Segment::LowerLeft:
- return Rect(left, DIGIT_HEIGHT / 2, left + DIGIT_SPACE, DIGIT_HEIGHT);
+ return SkRect::MakeLTRB(left, DIGIT_HEIGHT / 2, left + DIGIT_SPACE, DIGIT_HEIGHT);
case Segment::LowerRight:
- return Rect(left + DIGIT_WIDTH - DIGIT_SPACE, DIGIT_HEIGHT / 2, left + DIGIT_WIDTH,
- DIGIT_HEIGHT);
- case Segment::Buttom:
- return Rect(left, DIGIT_HEIGHT - DIGIT_SPACE, left + DIGIT_WIDTH, DIGIT_HEIGHT);
+ return SkRect::MakeLTRB(left + DIGIT_WIDTH - DIGIT_SPACE, DIGIT_HEIGHT / 2,
+ left + DIGIT_WIDTH, DIGIT_HEIGHT);
+ case Segment::Bottom:
+ return SkRect::MakeLTRB(left, DIGIT_HEIGHT - DIGIT_SPACE, left + DIGIT_WIDTH,
+ DIGIT_HEIGHT);
}
}();
- drawRect(rect, color, buffer, pixels);
+ SkPaint paint;
+ paint.setColor(color);
+ paint.setBlendMode(SkBlendMode::kSrc);
+ canvas.drawRect(rect, paint);
}
-void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, const half4& color,
- const sp<GraphicBuffer>& buffer,
- uint8_t* pixels) {
+void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, SkColor& color,
+ SkCanvas& canvas) {
if (digit < 0 || digit > 9) return;
if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 7 ||
digit == 8 || digit == 9)
- drawSegment(Segment::Upper, left, color, buffer, pixels);
+ drawSegment(Segment::Upper, left, color, canvas);
if (digit == 0 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || digit == 9)
- drawSegment(Segment::UpperLeft, left, color, buffer, pixels);
+ drawSegment(Segment::UpperLeft, left, color, canvas);
if (digit == 0 || digit == 1 || digit == 2 || digit == 3 || digit == 4 || digit == 7 ||
digit == 8 || digit == 9)
- drawSegment(Segment::UpperRight, left, color, buffer, pixels);
+ drawSegment(Segment::UpperRight, left, color, canvas);
if (digit == 2 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || digit == 8 ||
digit == 9)
- drawSegment(Segment::Middle, left, color, buffer, pixels);
+ drawSegment(Segment::Middle, left, color, canvas);
if (digit == 0 || digit == 2 || digit == 6 || digit == 8)
- drawSegment(Segment::LowerLeft, left, color, buffer, pixels);
+ drawSegment(Segment::LowerLeft, left, color, canvas);
if (digit == 0 || digit == 1 || digit == 3 || digit == 4 || digit == 5 || digit == 6 ||
digit == 7 || digit == 8 || digit == 9)
- drawSegment(Segment::LowerRight, left, color, buffer, pixels);
+ drawSegment(Segment::LowerRight, left, color, canvas);
if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 8 ||
digit == 9)
- drawSegment(Segment::Buttom, left, color, buffer, pixels);
+ drawSegment(Segment::Bottom, left, color, canvas);
}
-std::vector<sp<GraphicBuffer>> RefreshRateOverlay::SevenSegmentDrawer::drawNumber(
- int number, const half4& color, bool showSpinner) {
+std::vector<sp<GraphicBuffer>> RefreshRateOverlay::SevenSegmentDrawer::draw(
+ int number, SkColor& color, ui::Transform::RotationFlags rotation, bool showSpinner) {
if (number < 0 || number > 1000) return {};
const auto hundreds = number / 100;
@@ -120,55 +103,76 @@
std::vector<sp<GraphicBuffer>> buffers;
const auto loopCount = showSpinner ? 6 : 1;
for (int i = 0; i < loopCount; i++) {
+ // Pre-rotate the buffer before it reaches SurfaceFlinger.
+ SkMatrix canvasTransform = SkMatrix();
+ auto [bufferWidth, bufferHeight] = [&] {
+ switch (rotation) {
+ case ui::Transform::ROT_90:
+ canvasTransform.setTranslate(BUFFER_HEIGHT, 0);
+ canvasTransform.preRotate(90);
+ return std::make_tuple(BUFFER_HEIGHT, BUFFER_WIDTH);
+ case ui::Transform::ROT_270:
+ canvasTransform.setRotate(270, BUFFER_WIDTH / 2.0, BUFFER_WIDTH / 2.0);
+ return std::make_tuple(BUFFER_HEIGHT, BUFFER_WIDTH);
+ default:
+ return std::make_tuple(BUFFER_WIDTH, BUFFER_HEIGHT);
+ }
+ }();
sp<GraphicBuffer> buffer =
- new GraphicBuffer(BUFFER_WIDTH, BUFFER_HEIGHT, HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ new GraphicBuffer(bufferWidth, bufferHeight, HAL_PIXEL_FORMAT_RGBA_8888, 1,
GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER |
GRALLOC_USAGE_HW_TEXTURE,
"RefreshRateOverlayBuffer");
const status_t bufferStatus = buffer->initCheck();
LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "RefreshRateOverlay: Buffer failed to allocate: %d",
bufferStatus);
- uint8_t* pixels;
- buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));
- // Clear buffer content
- drawRect(Rect(BUFFER_WIDTH, BUFFER_HEIGHT), half4(0), buffer, pixels);
+
+ sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(bufferWidth, bufferHeight);
+ SkCanvas* canvas = surface->getCanvas();
+ canvas->setMatrix(canvasTransform);
+
int left = 0;
if (hundreds != 0) {
- drawDigit(hundreds, left, color, buffer, pixels);
+ drawDigit(hundreds, left, color, *canvas);
}
left += DIGIT_WIDTH + DIGIT_SPACE;
if (tens != 0) {
- drawDigit(tens, left, color, buffer, pixels);
+ drawDigit(tens, left, color, *canvas);
}
left += DIGIT_WIDTH + DIGIT_SPACE;
- drawDigit(ones, left, color, buffer, pixels);
+ drawDigit(ones, left, color, *canvas);
left += DIGIT_WIDTH + DIGIT_SPACE;
if (showSpinner) {
switch (i) {
case 0:
- drawSegment(Segment::Upper, left, color, buffer, pixels);
+ drawSegment(Segment::Upper, left, color, *canvas);
break;
case 1:
- drawSegment(Segment::UpperRight, left, color, buffer, pixels);
+ drawSegment(Segment::UpperRight, left, color, *canvas);
break;
case 2:
- drawSegment(Segment::LowerRight, left, color, buffer, pixels);
+ drawSegment(Segment::LowerRight, left, color, *canvas);
break;
case 3:
- drawSegment(Segment::Buttom, left, color, buffer, pixels);
+ drawSegment(Segment::Bottom, left, color, *canvas);
break;
case 4:
- drawSegment(Segment::LowerLeft, left, color, buffer, pixels);
+ drawSegment(Segment::LowerLeft, left, color, *canvas);
break;
case 5:
- drawSegment(Segment::UpperLeft, left, color, buffer, pixels);
+ drawSegment(Segment::UpperLeft, left, color, *canvas);
break;
}
}
+ void* pixels = nullptr;
+ buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&pixels));
+ const SkImageInfo& imageInfo = surface->imageInfo();
+ size_t dstRowBytes = buffer->getStride() * imageInfo.bytesPerPixel();
+ canvas->readPixels(imageInfo, pixels, dstRowBytes, 0, 0);
buffer->unlock();
buffers.emplace_back(buffer);
}
@@ -214,7 +218,22 @@
const std::vector<std::shared_ptr<renderengine::ExternalTexture>>&
RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) {
- if (mBufferCache.find(fps) == mBufferCache.end()) {
+ ui::Transform::RotationFlags transformHint = mLayer->getTransformHint();
+ // Tell SurfaceFlinger about the pre-rotation on the buffer.
+ const auto transform = [&] {
+ switch (transformHint) {
+ case ui::Transform::ROT_90:
+ return ui::Transform::ROT_270;
+ case ui::Transform::ROT_270:
+ return ui::Transform::ROT_90;
+ default:
+ return ui::Transform::ROT_0;
+ }
+ }();
+ mLayer->setTransform(transform);
+
+ if (mBufferCache.find(transformHint) == mBufferCache.end() ||
+ mBufferCache.at(transformHint).find(fps) == mBufferCache.at(transformHint).end()) {
// Ensure the range is > 0, so we don't divide by 0.
const auto rangeLength = std::max(1u, mHighFps - mLowFps);
// Clip values outside the range [mLowFps, mHighFps]. The current fps may be outside
@@ -222,12 +241,14 @@
fps = std::max(fps, mLowFps);
fps = std::min(fps, mHighFps);
const auto fpsScale = static_cast<float>(fps - mLowFps) / rangeLength;
- half4 color;
- color.r = HIGH_FPS_COLOR.r * fpsScale + LOW_FPS_COLOR.r * (1 - fpsScale);
- color.g = HIGH_FPS_COLOR.g * fpsScale + LOW_FPS_COLOR.g * (1 - fpsScale);
- color.b = HIGH_FPS_COLOR.b * fpsScale + LOW_FPS_COLOR.b * (1 - fpsScale);
- color.a = ALPHA;
- auto buffers = SevenSegmentDrawer::drawNumber(fps, color, mShowSpinner);
+ SkColor4f colorBase = SkColor4f::FromColor(HIGH_FPS_COLOR) * fpsScale;
+ SkColor4f lowFpsColor = SkColor4f::FromColor(LOW_FPS_COLOR) * (1 - fpsScale);
+ colorBase.fR = colorBase.fR + lowFpsColor.fR;
+ colorBase.fG = colorBase.fG + lowFpsColor.fG;
+ colorBase.fB = colorBase.fB + lowFpsColor.fB;
+ colorBase.fA = ALPHA;
+ SkColor color = colorBase.toSkColor();
+ auto buffers = SevenSegmentDrawer::draw(fps, color, transformHint, mShowSpinner);
std::vector<std::shared_ptr<renderengine::ExternalTexture>> textures;
std::transform(buffers.begin(), buffers.end(), std::back_inserter(textures),
[&](const auto& buffer) -> std::shared_ptr<renderengine::ExternalTexture> {
@@ -237,10 +258,10 @@
renderengine::ExternalTexture::
Usage::READABLE);
});
- mBufferCache.emplace(fps, textures);
+ mBufferCache[transformHint].emplace(fps, textures);
}
- return mBufferCache[fps];
+ return mBufferCache[transformHint][fps];
}
void RefreshRateOverlay::setViewport(ui::Size viewport) {
@@ -260,7 +281,7 @@
mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
}
-void RefreshRateOverlay::setLayerStack(uint32_t stack) {
+void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) {
mLayer->setLayerStack(stack);
mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
}
diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h
index f9baa89..63ae383 100644
--- a/services/surfaceflinger/RefreshRateOverlay.h
+++ b/services/surfaceflinger/RefreshRateOverlay.h
@@ -18,10 +18,13 @@
#include <math/vec4.h>
#include <renderengine/RenderEngine.h>
+#include <ui/LayerStack.h>
#include <ui/Rect.h>
#include <ui/Size.h>
#include <utils/StrongPointer.h>
+#include <SkCanvas.h>
+#include <SkColor.h>
#include <unordered_map>
#include "Fps.h"
@@ -39,7 +42,7 @@
public:
RefreshRateOverlay(SurfaceFlinger&, uint32_t lowFps, uint32_t highFps, bool showSpinner);
- void setLayerStack(uint32_t stack);
+ void setLayerStack(ui::LayerStack);
void setViewport(ui::Size);
void changeRefreshRate(const Fps&);
void onInvalidate();
@@ -47,20 +50,16 @@
private:
class SevenSegmentDrawer {
public:
- static std::vector<sp<GraphicBuffer>> drawNumber(int number, const half4& color,
- bool showSpinner);
+ static std::vector<sp<GraphicBuffer>> draw(int number, SkColor& color,
+ ui::Transform::RotationFlags, bool showSpinner);
static uint32_t getHeight() { return BUFFER_HEIGHT; }
static uint32_t getWidth() { return BUFFER_WIDTH; }
private:
- enum class Segment { Upper, UpperLeft, UpperRight, Middle, LowerLeft, LowerRight, Buttom };
+ enum class Segment { Upper, UpperLeft, UpperRight, Middle, LowerLeft, LowerRight, Bottom };
- static void drawRect(const Rect& r, const half4& color, const sp<GraphicBuffer>& buffer,
- uint8_t* pixels);
- static void drawSegment(Segment segment, int left, const half4& color,
- const sp<GraphicBuffer>& buffer, uint8_t* pixels);
- static void drawDigit(int digit, int left, const half4& color,
- const sp<GraphicBuffer>& buffer, uint8_t* pixels);
+ static void drawSegment(Segment segment, int left, SkColor& color, SkCanvas& canvas);
+ static void drawDigit(int digit, int left, SkColor& color, SkCanvas& canvas);
static constexpr uint32_t DIGIT_HEIGHT = 100;
static constexpr uint32_t DIGIT_WIDTH = 64;
@@ -80,13 +79,15 @@
sp<IBinder> mIBinder;
sp<IGraphicBufferProducer> mGbp;
- std::unordered_map<int, std::vector<std::shared_ptr<renderengine::ExternalTexture>>>
+ std::unordered_map<
+ ui::Transform::RotationFlags,
+ std::unordered_map<int, std::vector<std::shared_ptr<renderengine::ExternalTexture>>>>
mBufferCache;
std::optional<int> mCurrentFps;
int mFrame = 0;
static constexpr float ALPHA = 0.8f;
- const half3 LOW_FPS_COLOR = half3(1.0f, 0.0f, 0.0f);
- const half3 HIGH_FPS_COLOR = half3(0.0f, 1.0f, 0.0f);
+ const SkColor LOW_FPS_COLOR = SK_ColorRED;
+ const SkColor HIGH_FPS_COLOR = SK_ColorGREEN;
const bool mShowSpinner;
diff --git a/services/surfaceflinger/RenderArea.cpp b/services/surfaceflinger/RenderArea.cpp
index 9a6c853..5fea521 100644
--- a/services/surfaceflinger/RenderArea.cpp
+++ b/services/surfaceflinger/RenderArea.cpp
@@ -14,10 +14,6 @@
* limitations under the License.
*/
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
#include "RenderArea.h"
namespace android {
@@ -33,6 +29,3 @@
}
} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 81a669a..b00423e 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -140,6 +140,8 @@
return 0;
}
+ constexpr float kScoreForFractionalPairs = .8f;
+
// Slightly prefer seamless switches.
constexpr float kSeamedSwitchPenalty = 0.95f;
const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty;
@@ -156,19 +158,29 @@
const auto layerPeriod = layer.desiredRefreshRate.getPeriodNsecs();
if (layer.vote == LayerVoteType::ExplicitDefault) {
// Find the actual rate the layer will render, assuming
- // that layerPeriod is the minimal time to render a frame
+ // that layerPeriod is the minimal period to render a frame.
+ // For example if layerPeriod is 20ms and displayPeriod is 16ms,
+ // then the actualLayerPeriod will be 32ms, because it is the
+ // smallest multiple of the display period which is >= layerPeriod.
auto actualLayerPeriod = displayPeriod;
int multiplier = 1;
while (layerPeriod > actualLayerPeriod + MARGIN_FOR_PERIOD_CALCULATION) {
multiplier++;
actualLayerPeriod = displayPeriod * multiplier;
}
+
+ // Because of the threshold we used above it's possible that score is slightly
+ // above 1.
return std::min(1.0f,
static_cast<float>(layerPeriod) / static_cast<float>(actualLayerPeriod));
}
if (layer.vote == LayerVoteType::ExplicitExactOrMultiple ||
layer.vote == LayerVoteType::Heuristic) {
+ if (isFractionalPairOrMultiple(refreshRate.getFps(), layer.desiredRefreshRate)) {
+ return kScoreForFractionalPairs * seamlessness;
+ }
+
// Calculate how many display vsyncs we need to present a single frame for this
// layer
const auto [displayFramesQuotient, displayFramesRemainder] =
@@ -318,18 +330,28 @@
const bool hasExplicitVoteLayers = explicitDefaultVoteLayers > 0 ||
explicitExactOrMultipleVoteLayers > 0 || explicitExact > 0;
+ const Policy* policy = getCurrentPolicyLocked();
+ const auto& defaultMode = mRefreshRates.at(policy->defaultMode);
+ // If the default mode group is different from the group of current mode,
+ // this means a layer requesting a seamed mode switch just disappeared and
+ // we should switch back to the default group.
+ // However if a seamed layer is still present we anchor around the group
+ // of the current mode, in order to prevent unnecessary seamed mode switches
+ // (e.g. when pausing a video playback).
+ const auto anchorGroup = seamedFocusedLayers > 0 ? mCurrentRefreshRate->getModeGroup()
+ : defaultMode->getModeGroup();
+
// Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've
// selected a refresh rate to see if we should apply touch boost.
if (globalSignals.touch && !hasExplicitVoteLayers) {
ALOGV("TouchBoost - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str());
setTouchConsidered();
- return getMaxRefreshRateByPolicyLocked();
+ return getMaxRefreshRateByPolicyLocked(anchorGroup);
}
// If the primary range consists of a single refresh rate then we can only
// move out the of range if layers explicitly request a different refresh
// rate.
- const Policy* policy = getCurrentPolicyLocked();
const bool primaryRangeIsSingleRate =
policy->primaryRange.min.equalsWithMargin(policy->primaryRange.max);
@@ -341,7 +363,9 @@
}
if (layers.empty() || noVoteLayers == layers.size()) {
- return getMaxRefreshRateByPolicyLocked();
+ const auto& refreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup);
+ ALOGV("no layers with votes - choose %s", refreshRate.getName().c_str());
+ return refreshRate;
}
// Only if all layers want Min we should return Min
@@ -358,8 +382,6 @@
scores.emplace_back(RefreshRateScore{refreshRate, 0.0f});
}
- const auto& defaultMode = mRefreshRates.at(policy->defaultMode);
-
for (const auto& layer : layers) {
ALOGV("Calculating score for %s (%s, weight %.2f, desired %.2f) ", layer.name.c_str(),
layerVoteTypeString(layer.vote).c_str(), layer.weight,
@@ -397,10 +419,7 @@
// mode group otherwise. In second case, if the current mode group is different
// from the default, this means a layer with seamlessness=SeamedAndSeamless has just
// disappeared.
- const bool isInPolicyForDefault = seamedFocusedLayers > 0
- ? scores[i].refreshRate->getModeGroup() == mCurrentRefreshRate->getModeGroup()
- : scores[i].refreshRate->getModeGroup() == defaultMode->getModeGroup();
-
+ const bool isInPolicyForDefault = scores[i].refreshRate->getModeGroup() == anchorGroup;
if (layer.seamlessness == Seamlessness::Default && !isInPolicyForDefault) {
ALOGV("%s ignores %s. Current mode = %s", formatLayerInfo(layer, weight).c_str(),
scores[i].refreshRate->toString().c_str(),
@@ -421,7 +440,7 @@
const auto layerScore =
calculateLayerScoreLocked(layer, *scores[i].refreshRate, isSeamlessSwitch);
- ALOGV("%s gives %s score of %.2f", formatLayerInfo(layer, weight).c_str(),
+ ALOGV("%s gives %s score of %.4f", formatLayerInfo(layer, weight).c_str(),
scores[i].refreshRate->getName().c_str(), layerScore);
scores[i].score += weight * layerScore;
}
@@ -439,9 +458,9 @@
// range instead of picking a random score from the app range.
if (std::all_of(scores.begin(), scores.end(),
[](RefreshRateScore score) { return score.score == 0; })) {
- ALOGV("layers not scored - choose %s",
- getMaxRefreshRateByPolicyLocked().getName().c_str());
- return getMaxRefreshRateByPolicyLocked();
+ const auto& refreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup);
+ ALOGV("layers not scored - choose %s", refreshRate.getName().c_str());
+ return refreshRate;
} else {
return *bestRefreshRate;
}
@@ -451,7 +470,7 @@
// interactive (as opposed to ExplicitExactOrMultiple) and therefore if those posted an explicit
// vote we should not change it if we get a touch event. Only apply touch boost if it will
// actually increase the refresh rate over the normal selection.
- const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked();
+ const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup);
const bool touchBoostForExplicitExact = [&] {
if (mSupportsFrameRateOverride) {
@@ -582,7 +601,7 @@
template <typename Iter>
const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) const {
- constexpr auto EPSILON = 0.001f;
+ constexpr auto kEpsilon = 0.0001f;
const RefreshRate* bestRefreshRate = begin->refreshRate;
float max = begin->score;
for (auto i = begin; i != end; ++i) {
@@ -591,7 +610,7 @@
ATRACE_INT(refreshRate->getName().c_str(), round<int>(score * 100));
- if (score > max * (1 + EPSILON)) {
+ if (score > max * (1 + kEpsilon)) {
max = score;
bestRefreshRate = refreshRate;
}
@@ -634,10 +653,10 @@
return getMaxRefreshRateByPolicyLocked();
}
-const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked() const {
+const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked(int anchorGroup) const {
for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); it++) {
const auto& refreshRate = (**it);
- if (mCurrentRefreshRate->getModeGroup() == refreshRate.getModeGroup()) {
+ if (anchorGroup == refreshRate.getModeGroup()) {
return refreshRate;
}
}
@@ -923,6 +942,17 @@
return static_cast<int>(numPeriodsRounded);
}
+bool RefreshRateConfigs::isFractionalPairOrMultiple(Fps smaller, Fps bigger) {
+ if (smaller.getValue() > bigger.getValue()) {
+ return isFractionalPairOrMultiple(bigger, smaller);
+ }
+
+ const auto multiplier = std::round(bigger.getValue() / smaller.getValue());
+ constexpr float kCoef = 1000.f / 1001.f;
+ return bigger.equalsWithMargin(Fps(smaller.getValue() * multiplier / kCoef)) ||
+ bigger.equalsWithMargin(Fps(smaller.getValue() * multiplier * kCoef));
+}
+
void RefreshRateConfigs::dump(std::string& result) const {
std::lock_guard lock(mLock);
base::StringAppendF(&result, "DesiredDisplayModeSpecs (DisplayManager): %s\n\n",
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 4a9a1fd..3713587 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -335,6 +335,10 @@
// layer refresh rate.
static int getFrameRateDivider(Fps displayFrameRate, Fps layerFrameRate);
+ // Returns if the provided frame rates have a ratio t*1000/1001 or t*1001/1000
+ // for an integer t.
+ static bool isFractionalPairOrMultiple(Fps, Fps);
+
using UidToFrameRateOverride = std::map<uid_t, Fps>;
// Returns the frame rate override for each uid.
//
@@ -384,7 +388,11 @@
// Returns the highest refresh rate according to the current policy. May change at runtime. Only
// uses the primary range, not the app request range.
- const RefreshRate& getMaxRefreshRateByPolicyLocked() const REQUIRES(mLock);
+ const RefreshRate& getMaxRefreshRateByPolicyLocked() const REQUIRES(mLock) {
+ return getMaxRefreshRateByPolicyLocked(mCurrentRefreshRate->getModeGroup());
+ }
+
+ const RefreshRate& getMaxRefreshRateByPolicyLocked(int anchorGroup) const REQUIRES(mLock);
// Returns the current refresh rate, if allowed. Otherwise the default that is allowed by
// the policy.
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 80b2504..c64ccd1 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -677,7 +677,7 @@
}
}
-void Scheduler::notifyTouchEvent() {
+void Scheduler::onTouchHint() {
if (mTouchTimer) {
mTouchTimer->reset();
@@ -886,7 +886,7 @@
void Scheduler::onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline) {
if (timeline.refreshRequired) {
- mSchedulerCallback.repaintEverythingForHWC();
+ mSchedulerCallback.scheduleRefresh(FrameHint::kNone);
}
std::lock_guard<std::mutex> lock(mVsyncTimelineLock);
@@ -899,21 +899,21 @@
}
void Scheduler::onDisplayRefreshed(nsecs_t timestamp) {
- bool callRepaint = false;
- {
+ const bool refresh = [=] {
std::lock_guard<std::mutex> lock(mVsyncTimelineLock);
if (mLastVsyncPeriodChangeTimeline && mLastVsyncPeriodChangeTimeline->refreshRequired) {
- if (mLastVsyncPeriodChangeTimeline->refreshTimeNanos < timestamp) {
- mLastVsyncPeriodChangeTimeline->refreshRequired = false;
- } else {
- // We need to send another refresh as refreshTimeNanos is still in the future
- callRepaint = true;
+ if (timestamp < mLastVsyncPeriodChangeTimeline->refreshTimeNanos) {
+ // We need to schedule another refresh as refreshTimeNanos is still in the future.
+ return true;
}
- }
- }
- if (callRepaint) {
- mSchedulerCallback.repaintEverythingForHWC();
+ mLastVsyncPeriodChangeTimeline->refreshRequired = false;
+ }
+ return false;
+ }();
+
+ if (refresh) {
+ mSchedulerCallback.scheduleRefresh(FrameHint::kNone);
}
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 4b6905b..420ba61 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -56,10 +56,13 @@
} // namespace frametimeline
struct ISchedulerCallback {
+ // Indicates frame activity, i.e. whether commit and/or composite is taking place.
+ enum class FrameHint { kNone, kActive };
+
+ virtual void scheduleRefresh(FrameHint) = 0;
virtual void setVsyncEnabled(bool) = 0;
virtual void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&,
scheduler::RefreshRateConfigEvent) = 0;
- virtual void repaintEverythingForHWC() = 0;
virtual void kernelTimerChanged(bool expired) = 0;
virtual void triggerOnFrameRateOverridesChanged() = 0;
@@ -136,8 +139,8 @@
bool isIdleTimerEnabled() const { return mIdleTimer.has_value(); }
void resetIdleTimer();
- // Function that resets the touch timer.
- void notifyTouchEvent();
+ // Indicates that touch interaction is taking place.
+ void onTouchHint();
void setDisplayPowerState(bool normal);
@@ -194,6 +197,8 @@
private:
friend class TestableScheduler;
+ using FrameHint = ISchedulerCallback::FrameHint;
+
// In order to make sure that the features don't override themselves, we need a state machine
// to keep track which feature requested the config change.
enum class ContentDetectionState { Off, On };
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index bfe619c..5a881a3 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -109,6 +109,7 @@
#include "DisplayRenderArea.h"
#include "EffectLayer.h"
#include "Effects/Daltonizer.h"
+#include "FlagManager.h"
#include "FpsReporter.h"
#include "FrameTimeline/FrameTimeline.h"
#include "FrameTracer/FrameTracer.h"
@@ -168,6 +169,7 @@
using android::hardware::power::Boost;
using base::StringAppendF;
+using gui::DisplayInfo;
using gui::IWindowInfosListener;
using gui::WindowInfo;
using ui::ColorMode;
@@ -416,10 +418,7 @@
property_get("ro.build.type", value, "user");
mIsUserBuild = strcmp(value, "user") == 0;
- property_get("debug.sf.showupdates", value, "0");
- mDebugRegion = atoi(value);
-
- ALOGI_IF(mDebugRegion, "showupdates enabled");
+ mDebugFlashDelay = base::GetUintProperty("debug.sf.showupdates"s, 0u);
// DDMS debugging deprecated (b/120782499)
property_get("debug.sf.ddms", value, "0");
@@ -619,17 +618,20 @@
}
std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIdsLocked() const {
- const auto display = getDefaultDisplayDeviceLocked();
- if (!display) {
- return {};
- }
-
std::vector<PhysicalDisplayId> displayIds;
displayIds.reserve(mPhysicalDisplayTokens.size());
- displayIds.push_back(display->getPhysicalId());
+ const auto defaultDisplayId = [this]() REQUIRES(mStateLock) {
+ if (const auto display = getDefaultDisplayDeviceLocked()) {
+ return display->getPhysicalId();
+ }
+
+ // fallback to the internal display id if the active display is unknown
+ return getInternalDisplayIdLocked();
+ }();
+ displayIds.push_back(defaultDisplayId);
for (const auto& [id, token] : mPhysicalDisplayTokens) {
- if (id != display->getPhysicalId()) {
+ if (id != defaultDisplayId) {
displayIds.push_back(id);
}
}
@@ -679,6 +681,7 @@
const nsecs_t duration = now - mBootTime;
ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
+ mFlagManager = std::make_unique<android::FlagManager>();
mFrameTracer->initialize();
mFrameTimeline->onBootFinished();
@@ -796,10 +799,10 @@
// Process any initial hotplug and resulting display changes.
processDisplayHotplugEventsLocked();
const auto display = getDefaultDisplayDeviceLocked();
- LOG_ALWAYS_FATAL_IF(!display, "Missing internal display after registering composer callback.");
+ LOG_ALWAYS_FATAL_IF(!display, "Missing primary display after registering composer callback.");
const auto displayId = display->getPhysicalId();
LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(displayId),
- "Internal display is disconnected.");
+ "Primary display is disconnected.");
// initialize our drawing state
mDrawingState = mCurrentState;
@@ -968,6 +971,11 @@
return NAME_NOT_FOUND;
}
+ const auto displayId = PhysicalDisplayId::tryCast(display->getId());
+ if (!displayId) {
+ return INVALID_OPERATION;
+ }
+
info->activeDisplayModeId = static_cast<int32_t>(display->getActiveMode()->getId().value());
const auto& supportedModes = display->getSupportedModes();
@@ -1027,18 +1035,18 @@
}
info->activeColorMode = display->getCompositionDisplay()->getState().colorMode;
- const auto displayId = display->getPhysicalId();
- info->supportedColorModes = getDisplayColorModes(displayId);
-
+ info->supportedColorModes = getDisplayColorModes(*display);
info->hdrCapabilities = display->getHdrCapabilities();
+
info->autoLowLatencyModeSupported =
- getHwComposer().hasDisplayCapability(displayId,
+ getHwComposer().hasDisplayCapability(*displayId,
hal::DisplayCapability::AUTO_LOW_LATENCY_MODE);
std::vector<hal::ContentType> types;
- getHwComposer().getSupportedContentTypes(displayId, &types);
+ getHwComposer().getSupportedContentTypes(*displayId, &types);
info->gameContentTypeSupported = std::any_of(types.begin(), types.end(), [](auto type) {
return type == hal::ContentType::GAME;
});
+
return NO_ERROR;
}
@@ -1065,8 +1073,8 @@
}
if (display->setDesiredActiveMode(info)) {
- // This will trigger HWC refresh without resetting the idle timer.
- repaintEverythingForHWC();
+ scheduleRefresh(FrameHint::kNone);
+
// Start receiving vsync samples now, so that we can detect a period
// switch.
mScheduler->resyncToHardwareVsync(true, info.mode->getVsyncPeriod());
@@ -1262,15 +1270,15 @@
}).wait();
}
-std::vector<ColorMode> SurfaceFlinger::getDisplayColorModes(PhysicalDisplayId displayId) {
- auto modes = getHwComposer().getColorModes(displayId);
- bool isInternalDisplay = displayId == getInternalDisplayIdLocked();
+std::vector<ColorMode> SurfaceFlinger::getDisplayColorModes(const DisplayDevice& display) {
+ auto modes = getHwComposer().getColorModes(display.getPhysicalId());
- // If it's built-in display and the configuration claims it's not wide color capable,
+ // If the display is internal and the configuration claims it's not wide color capable,
// filter out all wide color modes. The typical reason why this happens is that the
// hardware is not good enough to support GPU composition of wide color, and thus the
// OEMs choose to disable this capability.
- if (isInternalDisplay && !hasWideColorDisplay) {
+ if (display.getConnectionType() == ui::DisplayConnectionType::Internal &&
+ !hasWideColorDisplay) {
const auto newEnd = std::remove_if(modes.begin(), modes.end(), isWideColorMode);
modes.erase(newEnd, modes.end());
}
@@ -1294,34 +1302,41 @@
}
status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ColorMode mode) {
- schedule([=]() MAIN_THREAD {
- const auto displayId = getPhysicalDisplayIdLocked(displayToken);
- if (!displayId) {
- ALOGE("Invalid display token %p", displayToken.get());
- return;
- }
- const auto modes = getDisplayColorModes(*displayId);
- bool exists = std::find(std::begin(modes), std::end(modes), mode) != std::end(modes);
- if (mode < ColorMode::NATIVE || !exists) {
- ALOGE("Attempt to set invalid active color mode %s (%d) for display token %p",
- decodeColorMode(mode).c_str(), mode, displayToken.get());
- return;
- }
+ if (!displayToken) {
+ return BAD_VALUE;
+ }
+
+ auto future = schedule([=]() MAIN_THREAD -> status_t {
const auto display = getDisplayDeviceLocked(displayToken);
if (!display) {
ALOGE("Attempt to set active color mode %s (%d) for invalid display token %p",
decodeColorMode(mode).c_str(), mode, displayToken.get());
- } else if (display->isVirtual()) {
+ return NAME_NOT_FOUND;
+ }
+
+ if (display->isVirtual()) {
ALOGW("Attempt to set active color mode %s (%d) for virtual display",
decodeColorMode(mode).c_str(), mode);
- } else {
- display->getCompositionDisplay()->setColorProfile(
- compositionengine::Output::ColorProfile{mode, Dataspace::UNKNOWN,
- RenderIntent::COLORIMETRIC,
- Dataspace::UNKNOWN});
+ return INVALID_OPERATION;
}
- }).wait();
+ const auto modes = getDisplayColorModes(*display);
+ const bool exists = std::find(modes.begin(), modes.end(), mode) != modes.end();
+
+ if (mode < ColorMode::NATIVE || !exists) {
+ ALOGE("Attempt to set invalid active color mode %s (%d) for display token %p",
+ decodeColorMode(mode).c_str(), mode, displayToken.get());
+ return BAD_VALUE;
+ }
+
+ display->getCompositionDisplay()->setColorProfile(
+ {mode, Dataspace::UNKNOWN, RenderIntent::COLORIMETRIC, Dataspace::UNKNOWN});
+
+ return NO_ERROR;
+ });
+
+ // TODO(b/195698395): Propagate error.
+ future.wait();
return NO_ERROR;
}
@@ -1641,7 +1656,7 @@
Boost powerBoost = static_cast<Boost>(boostId);
if (powerBoost == Boost::INTERACTION) {
- mScheduler->notifyTouchEvent();
+ mScheduler->onTouchHint();
}
return NO_ERROR;
@@ -1658,16 +1673,26 @@
return mScheduler->createDisplayEventConnection(handle, eventRegistration);
}
-void SurfaceFlinger::signalTransaction() {
- mScheduler->resetIdleTimer();
+void SurfaceFlinger::scheduleInvalidate(FrameHint hint) {
+ if (hint == FrameHint::kActive) {
+ mScheduler->resetIdleTimer();
+ }
mPowerAdvisor.notifyDisplayUpdateImminent();
mEventQueue->invalidate();
}
+void SurfaceFlinger::scheduleRefresh(FrameHint hint) {
+ mForceRefresh = true;
+ scheduleInvalidate(hint);
+}
+
+void SurfaceFlinger::scheduleRepaint() {
+ mGeometryDirty = true;
+ scheduleRefresh(FrameHint::kActive);
+}
+
void SurfaceFlinger::signalLayerUpdate() {
- mScheduler->resetIdleTimer();
- mPowerAdvisor.notifyDisplayUpdateImminent();
- mEventQueue->invalidate();
+ scheduleInvalidate(FrameHint::kActive);
}
void SurfaceFlinger::signalRefresh() {
@@ -1738,8 +1763,8 @@
void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId,
hal::Connection connection) {
- ALOGI("%s(%" PRIu64 ", %s)", __func__, hwcDisplayId,
- connection == hal::Connection::CONNECTED ? "connected" : "disconnected");
+ const bool connected = connection == hal::Connection::CONNECTED;
+ ALOGI("%s HAL display %" PRIu64, connected ? "Connecting" : "Disconnecting", hwcDisplayId);
// Only lock if we're not on the main thread. This function is normally
// called on a hwbinder thread, but for the primary display it's called on
@@ -1770,7 +1795,7 @@
void SurfaceFlinger::onComposerHalRefresh(hal::HWDisplayId) {
Mutex::Autolock lock(mStateLock);
- repaintEverythingForHWC();
+ scheduleRefresh(FrameHint::kNone);
}
void SurfaceFlinger::setVsyncEnabled(bool enabled) {
@@ -1931,17 +1956,13 @@
}
if (mRefreshRateOverlaySpinner) {
- if (Mutex::Autolock lock(mStateLock);
- const auto display = getDefaultDisplayDeviceLocked()) {
- if (display) {
- display->onInvalidate();
- } else {
- ALOGW("%s: default display is null", __func__);
- }
+ Mutex::Autolock lock(mStateLock);
+ if (const auto display = getDefaultDisplayDeviceLocked()) {
+ display->onInvalidate();
}
}
- bool refreshNeeded;
+ bool refreshNeeded = mForceRefresh.exchange(false);
{
mTracePostComposition = mTracing.flagIsSet(SurfaceTracing::TRACE_COMPOSITION) ||
mTracing.flagIsSet(SurfaceTracing::TRACE_SYNC) ||
@@ -1951,8 +1972,9 @@
mFrameTimeline->setSfWakeUp(vsyncId, frameStart, Fps::fromPeriodNsecs(stats.vsyncPeriod));
- refreshNeeded = handleMessageTransaction();
+ refreshNeeded |= flushAndCommitTransactions();
refreshNeeded |= handleMessageInvalidate();
+
if (tracePreComposition) {
if (mVisibleRegionsDirty) {
mTracing.notifyLocked("visibleRegionsDirty");
@@ -1974,7 +1996,6 @@
updateCursorAsync();
updateInputFlinger();
- refreshNeeded |= mRepaintEverything;
if (refreshNeeded && CC_LIKELY(mBootStage != BootStage::BOOTLOADER)) {
// Signal a refresh if a transaction modified the window state,
// a new buffer was latched, or if HWC has requested a full
@@ -1996,25 +2017,23 @@
notifyRegionSamplingThread();
}
-bool SurfaceFlinger::handleMessageTransaction() {
+bool SurfaceFlinger::flushAndCommitTransactions() {
ATRACE_CALL();
- if (getTransactionFlags(eTransactionFlushNeeded)) {
+ if (clearTransactionFlags(eTransactionFlushNeeded)) {
flushTransactionQueues();
}
- uint32_t transactionFlags = peekTransactionFlags();
- bool runHandleTransaction =
- ((transactionFlags & (~eTransactionFlushNeeded)) != 0) || mForceTraversal;
- if (runHandleTransaction) {
- handleTransaction(eTransactionMask);
+ const bool shouldCommit = (getTransactionFlags() & ~eTransactionFlushNeeded) || mForceTraversal;
+ if (shouldCommit) {
+ commitTransactions();
}
if (transactionFlushNeeded()) {
setTransactionFlags(eTransactionFlushNeeded);
}
- return runHandleTransaction;
+ return shouldCommit;
}
void SurfaceFlinger::onMessageRefresh() {
@@ -2038,7 +2057,6 @@
refreshArgs.layersWithQueuedFrames.push_back(layerFE);
}
- refreshArgs.repaintEverything = mRepaintEverything.exchange(false);
refreshArgs.outputColorSetting = useColorManagement
? mDisplayColorSetting
: compositionengine::OutputColorSetting::kUnmanaged;
@@ -2046,7 +2064,7 @@
refreshArgs.forceOutputColorMode = mForceColorMode;
refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty;
- refreshArgs.updatingGeometryThisFrame = mGeometryInvalid || mVisibleRegionsDirty;
+ refreshArgs.updatingGeometryThisFrame = mGeometryDirty.exchange(false) || mVisibleRegionsDirty;
refreshArgs.blursAreExpensive = mBlursAreExpensive;
refreshArgs.internalDisplayRotationFlags = DisplayDevice::getPrimaryDisplayRotationFlags();
@@ -2055,11 +2073,11 @@
mDrawingState.colorMatrixChanged = false;
}
- refreshArgs.devOptForceClientComposition = mDebugDisableHWC || mDebugRegion;
+ refreshArgs.devOptForceClientComposition = mDebugDisableHWC;
- if (mDebugRegion != 0) {
- refreshArgs.devOptFlashDirtyRegionsDelay =
- std::chrono::milliseconds(mDebugRegion > 1 ? mDebugRegion : 0);
+ if (mDebugFlashDelay != 0) {
+ refreshArgs.devOptForceClientComposition = true;
+ refreshArgs.devOptFlashDirtyRegionsDelay = std::chrono::milliseconds(mDebugFlashDelay);
}
const auto prevVsyncTime = mScheduler->getPreviousVsyncFrom(mExpectedPresentTime);
@@ -2068,8 +2086,6 @@
refreshArgs.previousPresentFence = mPreviousPresentFences[0].fenceTime;
refreshArgs.nextInvalidateTime = mEventQueue->nextExpectedInvalidate();
- mGeometryInvalid = false;
-
// Store the present time just before calling to the composition engine so we could notify
// the scheduler.
const auto presentTime = systemTime();
@@ -2291,7 +2307,7 @@
int32_t maxArea = 0;
mDrawingState.traverse([&, compositionDisplay = compositionDisplay](Layer* layer) {
const auto layerFe = layer->getCompositionEngineLayerFE();
- if (layer->isVisible() && compositionDisplay->belongsInOutput(layerFe)) {
+ if (layer->isVisible() && compositionDisplay->includesLayer(layerFe)) {
const Dataspace transfer =
static_cast<Dataspace>(layer->getDataSpace() & Dataspace::TRANSFER_MASK);
const bool isHdr = (transfer == Dataspace::TRANSFER_ST2084 ||
@@ -2448,29 +2464,26 @@
}
}
-void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) {
+void SurfaceFlinger::commitTransactions() {
ATRACE_CALL();
- // here we keep a copy of the drawing state (that is the state that's
- // going to be overwritten by handleTransactionLocked()) outside of
- // mStateLock so that the side-effects of the State assignment
- // don't happen with mStateLock held (which can cause deadlocks).
+ // Keep a copy of the drawing state (that is going to be overwritten
+ // by commitTransactionsLocked) outside of mStateLock so that the side
+ // effects of the State assignment don't happen with mStateLock held,
+ // which can cause deadlocks.
State drawingState(mDrawingState);
- Mutex::Autolock _l(mStateLock);
+ Mutex::Autolock lock(mStateLock);
mDebugInTransaction = systemTime();
// Here we're guaranteed that some transaction flags are set
- // so we can call handleTransactionLocked() unconditionally.
- // We call getTransactionFlags(), which will also clear the flags,
- // with mStateLock held to guarantee that mCurrentState won't change
- // until the transaction is committed.
+ // so we can call commitTransactionsLocked unconditionally.
+ // We clear the flags with mStateLock held to guarantee that
+ // mCurrentState won't change until the transaction is committed.
modulateVsync(&VsyncModulator::onTransactionCommit);
- transactionFlags = getTransactionFlags(eTransactionMask);
- handleTransactionLocked(transactionFlags);
+ commitTransactionsLocked(clearTransactionFlags(eTransactionMask));
mDebugInTransaction = 0;
- // here the transaction has been committed
}
void SurfaceFlinger::loadDisplayModes(PhysicalDisplayId displayId, DisplayModes& outModes,
@@ -2733,14 +2746,12 @@
compositionengine::DisplayCreationArgsBuilder builder;
if (const auto& physical = state.physical) {
builder.setId(physical->id);
- builder.setConnectionType(physical->type);
} else {
builder.setId(acquireVirtualDisplay(resolution, pixelFormat));
}
builder.setPixels(resolution);
builder.setIsSecure(state.isSecure);
- builder.setLayerStackId(state.layerStack);
builder.setPowerAdvisor(&mPowerAdvisor);
builder.setName(state.displayName);
auto compositionDisplay = getCompositionEngine().createDisplay(builder.build());
@@ -2846,7 +2857,7 @@
setPowerModeInternal(display, hal::PowerMode::ON);
// TODO(b/175678251) Call a listener instead.
- if (currentState.physical->hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) {
+ if (currentState.physical->hwcDisplayId == getHwComposer().getPrimaryHwcDisplayId()) {
updateInternalDisplayVsyncLocked(display);
}
}
@@ -2926,8 +2937,8 @@
mDrawingState.displays = mCurrentState.displays;
}
-void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) {
- // Commit display transactions
+void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) {
+ // Commit display transactions.
const bool displayTransactionNeeded = transactionFlags & eDisplayTransactionNeeded;
if (displayTransactionNeeded) {
processDisplayChangesLocked();
@@ -2941,18 +2952,9 @@
mSomeChildrenChanged = false;
}
- // Update transform hint
+ // Update transform hint.
if (transactionFlags & (eTransformHintUpdateNeeded | eDisplayTransactionNeeded)) {
- // The transform hint might have changed for some layers
- // (either because a display has changed, or because a layer
- // as changed).
- //
- // Walk through all the layers in currentLayers,
- // and update their transform hint.
- //
- // If a layer is visible only on a single display, then that
- // display is used to calculate the hint, otherwise we use the
- // default display.
+ // Layers and/or displays have changed, so update the transform hint for each layer.
//
// NOTE: we do this here, rather than when presenting the display so that
// the hint is set before we acquire a buffer from the surface texture.
@@ -2963,30 +2965,29 @@
// (soon to become the drawing state list).
//
sp<const DisplayDevice> hintDisplay;
- uint32_t currentlayerStack = 0;
- bool first = true;
+ ui::LayerStack layerStack;
+
mCurrentState.traverse([&](Layer* layer) REQUIRES(mStateLock) {
// NOTE: we rely on the fact that layers are sorted by
// layerStack first (so we don't have to traverse the list
// of displays for every layer).
- uint32_t layerStack = layer->getLayerStack();
- if (first || currentlayerStack != layerStack) {
- currentlayerStack = layerStack;
- // figure out if this layerstack is mirrored
- // (more than one display) if so, pick the default display,
- // if not, pick the only display it's on.
+ if (const auto filter = layer->getOutputFilter(); layerStack != filter.layerStack) {
+ layerStack = filter.layerStack;
hintDisplay = nullptr;
+
+ // Find the display that includes the layer.
for (const auto& [token, display] : mDisplays) {
- if (display->getCompositionDisplay()
- ->belongsInOutput(layer->getLayerStack(),
- layer->getPrimaryDisplayOnly())) {
- if (hintDisplay) {
- hintDisplay = nullptr;
- break;
- } else {
- hintDisplay = display;
- }
+ if (!display->getCompositionDisplay()->includesLayer(filter)) {
+ continue;
}
+
+ // Pick the primary display if another display mirrors the layer.
+ if (hintDisplay) {
+ hintDisplay = nullptr;
+ break;
+ }
+
+ hintDisplay = display;
}
}
@@ -3000,20 +3001,10 @@
hintDisplay = getDefaultDisplayDeviceLocked();
}
- // could be null if there is no display available at all to get
- // the transform hint from.
- if (hintDisplay) {
- layer->updateTransformHint(hintDisplay->getTransformHint());
- }
-
- first = false;
+ layer->updateTransformHint(hintDisplay->getTransformHint());
});
}
- /*
- * Perform our own transaction if needed
- */
-
if (mLayersAdded) {
mLayersAdded = false;
// Layers have been added.
@@ -3035,7 +3026,9 @@
});
}
- commitTransaction();
+ doCommitTransactions();
+ signalSynchronousTransactions(CountDownLatch::eSyncTransaction);
+ mAnimTransactionPending = false;
}
void SurfaceFlinger::updateInputFlinger() {
@@ -3067,17 +3060,32 @@
void SurfaceFlinger::notifyWindowInfos() {
std::vector<WindowInfo> windowInfos;
+ std::vector<DisplayInfo> displayInfos;
+ std::unordered_map<const DisplayDevice*, const ui::Transform> displayTransforms;
+
+ if (enablePerWindowInputRotation()) {
+ for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
+ const auto& [info, transform] = display->getInputInfo();
+ displayInfos.emplace_back(info);
+ displayTransforms.emplace(display.get(), transform);
+ }
+ }
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
if (!layer->needsInputInfo()) return;
- sp<DisplayDevice> display = enablePerWindowInputRotation()
- ? ON_MAIN_THREAD(getDisplayWithInputByLayer(layer))
- : nullptr;
+
+ const DisplayDevice* display = nullptr;
+ if (enablePerWindowInputRotation()) {
+ display = ON_MAIN_THREAD(getDisplayWithInputByLayer(layer)).get();
+ }
+
// When calculating the screen bounds we ignore the transparent region since it may
// result in an unwanted offset.
- windowInfos.push_back(layer->fillInputInfo(display));
+ const auto it = displayTransforms.find(display);
+ windowInfos.push_back(
+ layer->fillInputInfo(it != displayTransforms.end() ? it->second : ui::Transform()));
});
- mWindowInfosListenerInvoker->windowInfosChanged(windowInfos,
+ mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos,
mInputWindowCommands.syncInputWindows);
}
@@ -3181,14 +3189,9 @@
mEventQueue->setDuration(config.sfWorkDuration);
}
-void SurfaceFlinger::commitTransaction() {
+void SurfaceFlinger::doCommitTransactions() {
ATRACE_CALL();
- commitTransactionLocked();
- signalSynchronousTransactions(CountDownLatch::eSyncTransaction);
- mAnimTransactionPending = false;
-}
-void SurfaceFlinger::commitTransactionLocked() {
if (!mLayersPendingRemoval.isEmpty()) {
// Notify removed layers now that they can't be drawn from
for (const auto& l : mLayersPendingRemoval) {
@@ -3232,11 +3235,10 @@
void SurfaceFlinger::commitOffscreenLayers() {
for (Layer* offscreenLayer : mOffscreenLayers) {
offscreenLayer->traverse(LayerVector::StateSet::Drawing, [](Layer* layer) {
- uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
- if (!trFlags) return;
-
- layer->doTransaction(0);
- layer->commitChildList();
+ if (layer->clearTransactionFlags(eTransactionNeeded)) {
+ layer->doTransaction(0);
+ layer->commitChildList();
+ }
});
}
}
@@ -3244,7 +3246,7 @@
void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) {
for (const auto& [token, displayDevice] : ON_MAIN_THREAD(mDisplays)) {
auto display = displayDevice->getCompositionDisplay();
- if (display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) {
+ if (display->includesLayer(layer->getOutputFilter())) {
display->editState().dirtyRegion.orSelf(dirty);
}
}
@@ -3272,14 +3274,14 @@
// Display is now waiting on Layer 1's frame, which is behind layer 0's
// second frame. But layer 0's second frame could be waiting on display.
mDrawingState.traverse([&](Layer* layer) {
- uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
- if (trFlags || mForceTransactionDisplayChange) {
- const uint32_t flags = layer->doTransaction(0);
- if (flags & Layer::eVisibleRegion)
- mVisibleRegionsDirty = true;
- }
+ if (layer->clearTransactionFlags(eTransactionNeeded) || mForceTransactionDisplayChange) {
+ const uint32_t flags = layer->doTransaction(0);
+ if (flags & Layer::eVisibleRegion) {
+ mVisibleRegionsDirty = true;
+ }
+ }
- if (layer->hasReadyFrame()) {
+ if (layer->hasReadyFrame()) {
frameQueued = true;
if (layer->shouldPresentNow(expectedPresentTime)) {
mLayersWithQueuedFrames.emplace(layer);
@@ -3287,7 +3289,7 @@
ATRACE_NAME("!layer->shouldPresentNow()");
layer->useEmptyDamage();
}
- } else {
+ } else {
layer->useEmptyDamage();
}
});
@@ -3340,10 +3342,6 @@
return !mLayersWithQueuedFrames.empty() && newDataLatched;
}
-void SurfaceFlinger::invalidateHwcGeometry() {
- mGeometryInvalid = true;
-}
-
status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc,
const sp<IBinder>& parentHandle,
@@ -3390,23 +3388,23 @@
}));
}
-uint32_t SurfaceFlinger::peekTransactionFlags() {
+uint32_t SurfaceFlinger::getTransactionFlags() const {
return mTransactionFlags;
}
-uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) {
- return mTransactionFlags.fetch_and(~flags) & flags;
+uint32_t SurfaceFlinger::clearTransactionFlags(uint32_t mask) {
+ return mTransactionFlags.fetch_and(~mask) & mask;
}
-uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) {
- return setTransactionFlags(flags, TransactionSchedule::Late);
+uint32_t SurfaceFlinger::setTransactionFlags(uint32_t mask) {
+ return setTransactionFlags(mask, TransactionSchedule::Late);
}
-uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, TransactionSchedule schedule,
- const sp<IBinder>& token) {
- uint32_t old = mTransactionFlags.fetch_or(flags);
- modulateVsync(&VsyncModulator::setTransactionSchedule, schedule, token);
- if ((old & flags) == 0) signalTransaction();
+uint32_t SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule schedule,
+ const sp<IBinder>& applyToken) {
+ const uint32_t old = mTransactionFlags.fetch_or(mask);
+ modulateVsync(&VsyncModulator::setTransactionSchedule, schedule, applyToken);
+ if ((old & mask) == 0) scheduleInvalidate(FrameHint::kActive);
return old;
}
@@ -4465,7 +4463,7 @@
d.what = DisplayState::eDisplayProjectionChanged |
DisplayState::eLayerStackChanged;
d.token = token;
- d.layerStack = 0;
+ d.layerStack = ui::DEFAULT_LAYER_STACK;
d.orientation = ui::ROTATION_0;
d.orientedDisplaySpaceRect.makeInvalid();
d.layerStackSpaceRect.makeInvalid();
@@ -4496,23 +4494,22 @@
}
sp<DisplayDevice> SurfaceFlinger::getDisplayWithInputByLayer(Layer* layer) const {
- sp<DisplayDevice> display;
- for (const auto& pair : mDisplays) {
- const auto& displayDevice = pair.second;
- if (!displayDevice->receivesInput() ||
- !displayDevice->getCompositionDisplay()
- ->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) {
+ const auto filter = layer->getOutputFilter();
+ sp<DisplayDevice> inputDisplay;
+
+ for (const auto& [_, display] : mDisplays) {
+ if (!display->receivesInput() || !display->getCompositionDisplay()->includesLayer(filter)) {
continue;
}
// Don't return immediately so that we can log duplicates.
- if (display) {
- ALOGE("Multiple display devices claim to accept input for the same layerstack: %d",
- layer->getLayerStack());
+ if (inputDisplay) {
+ ALOGE("Multiple displays claim to accept input for the same layer stack: %u",
+ filter.layerStack.id);
continue;
}
- display = displayDevice;
+ inputDisplay = display;
}
- return display;
+ return inputDisplay;
}
void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) {
@@ -4557,7 +4554,7 @@
mVisibleRegionsDirty = true;
mHasPoweredOff = true;
- repaintEverything();
+ scheduleRefresh(FrameHint::kActive);
} else if (mode == hal::PowerMode::OFF) {
// Turn off the display
if (SurfaceFlinger::setSchedFifo(false) != NO_ERROR) {
@@ -4950,7 +4947,7 @@
DisplayProto* displayProto = layersTraceProto.add_displays();
displayProto->set_id(display->getId().value);
displayProto->set_name(display->getDisplayName());
- displayProto->set_layer_stack(display->getLayerStack());
+ displayProto->set_layer_stack(display->getLayerStack().id);
LayerProtoHelper::writeSizeToProto(display->getWidth(), display->getHeight(),
[&]() { return displayProto->mutable_size(); });
LayerProtoHelper::writeToProto(display->getLayerStackSpaceRect(), [&]() {
@@ -5170,7 +5167,7 @@
colorizer.bold(result);
result.append("h/w composer state:\n");
colorizer.reset(result);
- bool hwcDisabled = mDebugDisableHWC || mDebugRegion;
+ const bool hwcDisabled = mDebugDisableHWC || mDebugFlashDelay;
StringAppendF(&result, " h/w composer %s\n", hwcDisabled ? "disabled" : "enabled");
getHwComposer().dump(result);
@@ -5180,6 +5177,11 @@
const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
alloc.dump(result);
+ /*
+ * Dump flag/property manager state
+ */
+ mFlagManager->dump(result);
+
result.append(mTimeStats->miniDump());
result.append("\n");
}
@@ -5379,9 +5381,8 @@
status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
uint32_t flags) {
- status_t credentialCheck = CheckTransactCodeCredentials(code);
- if (credentialCheck != OK) {
- return credentialCheck;
+ if (const status_t error = CheckTransactCodeCredentials(code); error != OK) {
+ return error;
}
status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
@@ -5398,47 +5399,43 @@
}
int n;
switch (code) {
- case 1000: // SHOW_CPU, NOT SUPPORTED ANYMORE
- case 1001: // SHOW_FPS, NOT SUPPORTED ANYMORE
+ case 1000: // Unused.
+ case 1001:
+ return NAME_NOT_FOUND;
+ case 1002: // Toggle flashing on surface damage.
+ if (const int delay = data.readInt32(); delay > 0) {
+ mDebugFlashDelay = delay;
+ } else {
+ mDebugFlashDelay = mDebugFlashDelay ? 0 : 1;
+ }
+ scheduleRepaint();
return NO_ERROR;
- case 1002: // SHOW_UPDATES
- n = data.readInt32();
- mDebugRegion = n ? n : (mDebugRegion ? 0 : 1);
- invalidateHwcGeometry();
- repaintEverything();
+ case 1004: // Force refresh ahead of next VSYNC.
+ scheduleRefresh(FrameHint::kActive);
return NO_ERROR;
- case 1004:{ // repaint everything
- repaintEverything();
+ case 1005: { // Force commit ahead of next VSYNC.
+ Mutex::Autolock lock(mStateLock);
+ setTransactionFlags(eTransactionNeeded | eDisplayTransactionNeeded |
+ eTraversalNeeded);
return NO_ERROR;
}
- case 1005:{ // force transaction
- Mutex::Autolock _l(mStateLock);
- setTransactionFlags(
- eTransactionNeeded|
- eDisplayTransactionNeeded|
- eTraversalNeeded);
- return NO_ERROR;
- }
- case 1006:{ // send empty update
+ case 1006: // Force refresh immediately.
signalRefresh();
return NO_ERROR;
- }
- case 1008: // toggle use of hw composer
- n = data.readInt32();
- mDebugDisableHWC = n != 0;
- invalidateHwcGeometry();
- repaintEverything();
+ case 1007: // Unused.
+ return NAME_NOT_FOUND;
+ case 1008: // Toggle forced GPU composition.
+ mDebugDisableHWC = data.readInt32() != 0;
+ scheduleRepaint();
return NO_ERROR;
- case 1009: // toggle use of transform hint
- n = data.readInt32();
- mDebugDisableTransformHint = n != 0;
- invalidateHwcGeometry();
- repaintEverything();
+ case 1009: // Toggle use of transform hint.
+ mDebugDisableTransformHint = data.readInt32() != 0;
+ scheduleRepaint();
return NO_ERROR;
- case 1010: // interrogate.
+ case 1010: // Interrogate.
reply->writeInt32(0);
reply->writeInt32(0);
- reply->writeInt32(mDebugRegion);
+ reply->writeInt32(mDebugFlashDelay);
reply->writeInt32(0);
reply->writeInt32(mDebugDisableHWC);
return NO_ERROR;
@@ -5493,12 +5490,15 @@
mClientColorMatrix = mat4();
}
+ // TODO(b/193487656): Restore once HWASan bug is fixed.
+#if 0
// Check that supplied matrix's last row is {0,0,0,1} so we can avoid
// the division by w in the fragment shader
float4 lastRow(transpose(mClientColorMatrix)[3]);
if (any(greaterThan(abs(lastRow - float4{0, 0, 0, 1}), float4{1e-4f}))) {
ALOGE("The color transform's last row must be (0, 0, 0, 1)");
}
+#endif
updateColorMatrixLocked();
return NO_ERROR;
@@ -5552,8 +5552,7 @@
if (data.readInt32(&colorMode) == NO_ERROR) {
mForceColorMode = static_cast<ColorMode>(colorMode);
}
- invalidateHwcGeometry();
- repaintEverything();
+ scheduleRepaint();
return NO_ERROR;
}
// Deprecate, use 1030 to check whether the device is color managed.
@@ -5684,37 +5683,25 @@
}
case 1035: {
const int modeId = data.readInt32();
- mDebugDisplayModeSetByBackdoor = false;
- const auto displayId = [&]() -> std::optional<PhysicalDisplayId> {
- uint64_t inputDisplayId = 0;
- if (data.readUint64(&inputDisplayId) == NO_ERROR) {
- const auto token = getPhysicalDisplayToken(
- static_cast<PhysicalDisplayId>(inputDisplayId));
- if (!token) {
- ALOGE("No display with id: %" PRIu64, inputDisplayId);
- return std::nullopt;
- }
-
- return std::make_optional<PhysicalDisplayId>(inputDisplayId);
+ const auto display = [&]() -> sp<IBinder> {
+ uint64_t value;
+ if (data.readUint64(&value) != NO_ERROR) {
+ return getDefaultDisplayDevice()->getDisplayToken().promote();
}
- return getDefaultDisplayDevice()->getPhysicalId();
+ if (const auto id = DisplayId::fromValue<PhysicalDisplayId>(value)) {
+ return getPhysicalDisplayToken(*id);
+ }
+
+ ALOGE("Invalid physical display ID");
+ return nullptr;
}();
- if (!displayId) {
- ALOGE("No display found");
- return NO_ERROR;
- }
-
- status_t result = setActiveMode(getPhysicalDisplayToken(*displayId), modeId);
- if (result != NO_ERROR) {
- return result;
- }
-
- mDebugDisplayModeSetByBackdoor = true;
-
- return NO_ERROR;
+ mDebugDisplayModeSetByBackdoor = false;
+ const status_t result = setActiveMode(display, modeId);
+ mDebugDisplayModeSetByBackdoor = result == NO_ERROR;
+ return result;
}
case 1036: {
if (data.readInt32() > 0) {
@@ -5731,12 +5718,10 @@
// Inject a hotplug connected event for the primary display. This will deallocate and
// reallocate the display state including framebuffers.
case 1037: {
- std::optional<hal::HWDisplayId> hwcId;
- {
- Mutex::Autolock lock(mStateLock);
- hwcId = getHwComposer().getInternalHwcDisplayId();
- }
- onComposerHalHotplug(*hwcId, hal::Connection::CONNECTED);
+ const hal::HWDisplayId hwcId =
+ (Mutex::Autolock(mStateLock), getHwComposer().getPrimaryHwcDisplayId());
+
+ onComposerHalHotplug(hwcId, hal::Connection::CONNECTED);
return NO_ERROR;
}
// Modify the max number of display frames stored within FrameTimeline
@@ -5777,14 +5762,11 @@
std::optional<PhysicalDisplayId> inputId = std::nullopt;
if (uint64_t inputDisplayId;
data.readUint64(&inputDisplayId) == NO_ERROR) {
- const auto token = getPhysicalDisplayToken(
- static_cast<PhysicalDisplayId>(inputDisplayId));
- if (!token) {
+ inputId = DisplayId::fromValue<PhysicalDisplayId>(inputDisplayId);
+ if (!inputId || getPhysicalDisplayToken(*inputId)) {
ALOGE("No display with id: %" PRIu64, inputDisplayId);
return NAME_NOT_FOUND;
}
-
- inputId = std::make_optional<PhysicalDisplayId>(inputDisplayId);
}
{
Mutex::Autolock lock(mStateLock);
@@ -5801,8 +5783,7 @@
if (error != OK) {
return error;
}
- invalidateHwcGeometry();
- repaintEverything();
+ scheduleRepaint();
return NO_ERROR;
}
}
@@ -5810,17 +5791,6 @@
return err;
}
-void SurfaceFlinger::repaintEverything() {
- mRepaintEverything = true;
- signalTransaction();
-}
-
-void SurfaceFlinger::repaintEverythingForHWC() {
- mRepaintEverything = true;
- mPowerAdvisor.notifyDisplayUpdateImminent();
- mEventQueue->invalidate();
-}
-
void SurfaceFlinger::kernelTimerChanged(bool expired) {
static bool updateOverlay =
property_get_bool("debug.sf.kernel_idle_timer_update_overlay", true);
@@ -6042,7 +6012,7 @@
captureListener);
}
-status_t SurfaceFlinger::captureDisplay(uint64_t displayIdOrLayerStack,
+status_t SurfaceFlinger::captureDisplay(DisplayId displayId,
const sp<IScreenCaptureListener>& captureListener) {
ui::LayerStack layerStack;
wp<const DisplayDevice> displayWeak;
@@ -6050,21 +6020,14 @@
ui::Dataspace dataspace;
{
Mutex::Autolock lock(mStateLock);
- auto display = getDisplayDeviceLocked(PhysicalDisplayId{displayIdOrLayerStack});
- // Fall back to first display whose layer stack matches.
- if (!display) {
- const auto layerStack = static_cast<ui::LayerStack>(displayIdOrLayerStack);
- display = findDisplay(WithLayerStack(layerStack));
- }
-
+ const auto display = getDisplayDeviceLocked(displayId);
if (!display) {
return NAME_NOT_FOUND;
}
- layerStack = display->getLayerStack();
displayWeak = display;
-
+ layerStack = display->getLayerStack();
size = display->getLayerStackSpaceRect().getSize();
dataspace =
@@ -6149,7 +6112,11 @@
}
}
- const auto display = findDisplay(WithLayerStack(parent->getLayerStack()));
+ const auto display =
+ findDisplay([layerStack = parent->getLayerStack()](const auto& display) {
+ return display.getLayerStack() == layerStack;
+ });
+
if (!display) {
return NAME_NOT_FOUND;
}
@@ -6364,7 +6331,6 @@
const auto display = renderArea.getDisplayDevice();
std::vector<Layer*> renderedLayers;
- Region clearRegion = Region::INVALID_REGION;
bool disableBlurs = false;
traverseLayers([&](Layer* layer) {
disableBlurs |= layer->getDrawingState().sidebandStream != nullptr;
@@ -6376,7 +6342,6 @@
renderArea.needsFiltering(),
renderArea.isSecure(),
useProtected,
- clearRegion,
layerStackSpaceRect,
clientCompositionDisplay.outputDataspace,
true, /* realContentIsVisible */
@@ -6414,16 +6379,17 @@
clientCompositionLayerPointers.begin(),
std::pointer_traits<renderengine::LayerSettings*>::pointer_to);
- clientCompositionDisplay.clearRegion = clearRegion;
// Use an empty fence for the buffer fence, since we just created the buffer so
// there is no need for synchronization with the GPU.
base::unique_fd bufferFence;
- base::unique_fd drawFence;
getRenderEngine().useProtectedContext(useProtected);
const constexpr bool kUseFramebufferCache = false;
- getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer,
- kUseFramebufferCache, std::move(bufferFence), &drawFence);
+ auto [status, drawFence] =
+ getRenderEngine()
+ .drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer,
+ kUseFramebufferCache, std::move(bufferFence))
+ .get();
if (drawFence >= 0) {
sp<Fence> releaseFence = new Fence(dup(drawFence));
@@ -6436,7 +6402,7 @@
// Always switch back to unprotected context.
getRenderEngine().useProtectedContext(false);
- return NO_ERROR;
+ return status;
}
void SurfaceFlinger::windowInfosReported() {
@@ -6463,12 +6429,12 @@
// We loop through the first level of layers without traversing,
// as we need to determine which layers belong to the requested display.
for (const auto& layer : mDrawingState.layersSortedByZ) {
- if (!layer->belongsToDisplay(layerStack)) {
+ if (layer->getLayerStack() != layerStack) {
continue;
}
// relative layers are traversed in Layer::traverseInZOrder
layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
- if (layer->getPrimaryDisplayOnly()) {
+ if (layer->isInternalDisplayOverlay()) {
return;
}
if (!layer->isVisible()) {
@@ -6827,33 +6793,29 @@
}
status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const {
- const auto maxSupportedRefreshRate = [&] {
- const auto display = getDefaultDisplayDevice();
- if (display) {
- return display->refreshRateConfigs().getSupportedRefreshRateRange().max;
+ Fps maxRefreshRate(60.f);
+
+ if (!getHwComposer().isHeadless()) {
+ if (const auto display = getDefaultDisplayDevice()) {
+ maxRefreshRate = display->refreshRateConfigs().getSupportedRefreshRateRange().max;
}
- ALOGW("%s: default display is null", __func__);
- return Fps(60);
- }();
- *buffers = getMaxAcquiredBufferCountForRefreshRate(maxSupportedRefreshRate);
+ }
+
+ *buffers = getMaxAcquiredBufferCountForRefreshRate(maxRefreshRate);
return NO_ERROR;
}
-int SurfaceFlinger::getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const {
- const auto refreshRate = [&] {
- const auto frameRateOverride = mScheduler->getFrameRateOverride(uid);
- if (frameRateOverride.has_value()) {
- return frameRateOverride.value();
- }
+uint32_t SurfaceFlinger::getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const {
+ Fps refreshRate(60.f);
- const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
- if (display) {
- return display->refreshRateConfigs().getCurrentRefreshRate().getFps();
+ if (const auto frameRateOverride = mScheduler->getFrameRateOverride(uid)) {
+ refreshRate = *frameRateOverride;
+ } else if (!getHwComposer().isHeadless()) {
+ if (const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked())) {
+ refreshRate = display->refreshRateConfigs().getCurrentRefreshRate().getFps();
}
+ }
- ALOGW("%s: default display is null", __func__);
- return Fps(60);
- }();
return getMaxAcquiredBufferCountForRefreshRate(refreshRate);
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index bcfe626..9dedfa7 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -89,6 +89,7 @@
class Client;
class EventThread;
+class FlagManager;
class FpsReporter;
class TunnelModeEnabledReporter;
class HdrLayerInfoReporter;
@@ -285,8 +286,12 @@
template <typename F, typename T = std::invoke_result_t<F>>
[[nodiscard]] std::future<T> schedule(F&&);
- // force full composition on all displays
- void repaintEverything();
+ // Schedule commit of transactions on the main thread ahead of the next VSYNC.
+ void scheduleInvalidate(FrameHint);
+ // As above, but also force refresh regardless if transactions were committed.
+ void scheduleRefresh(FrameHint) override;
+ // As above, but also force dirty geometry to repaint.
+ void scheduleRepaint();
surfaceflinger::Factory& getFactory() { return mFactory; }
@@ -348,7 +353,6 @@
uint32_t permissions,
std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks)
REQUIRES(mStateLock);
- virtual void commitTransactionLocked();
virtual void processDisplayAdded(const wp<IBinder>& displayToken, const DisplayDeviceState&)
REQUIRES(mStateLock);
@@ -628,12 +632,10 @@
sp<IDisplayEventConnection> createDisplayEventConnection(
ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp,
ISurfaceComposer::EventRegistrationFlags eventRegistration = {}) override;
- status_t captureDisplay(const DisplayCaptureArgs& args,
- const sp<IScreenCaptureListener>& captureListener) override;
- status_t captureDisplay(uint64_t displayOrLayerStack,
- const sp<IScreenCaptureListener>& captureListener) override;
- status_t captureLayers(const LayerCaptureArgs& args,
- const sp<IScreenCaptureListener>& captureListener) override;
+
+ status_t captureDisplay(const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&) override;
+ status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&) override;
+ status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&) override;
status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats) override;
status_t getDisplayState(const sp<IBinder>& displayToken, ui::DisplayState*)
@@ -746,8 +748,6 @@
void setVsyncEnabled(bool) override;
// Initiates a refresh rate change to be applied on invalidate.
void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ModeEvent) override;
- // Forces full composition on all displays without resetting the scheduler idle timer.
- void repaintEverythingForHWC() override;
// Called when kernel idle timer has expired. Used to update the refresh rate overlay.
void kernelTimerChanged(bool expired) override;
// Called when the frame rate override list changed to trigger an event.
@@ -766,8 +766,6 @@
* Message handling
*/
// Can only be called from the main thread or with mStateLock held
- void signalTransaction();
- // Can only be called from the main thread or with mStateLock held
void signalLayerUpdate();
void signalRefresh();
@@ -799,8 +797,12 @@
// incoming transactions
void onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTime);
- // Returns whether the transaction actually modified any state
- bool handleMessageTransaction();
+ // Returns whether transactions were committed.
+ bool flushAndCommitTransactions() EXCLUDES(mStateLock);
+
+ void commitTransactions() EXCLUDES(mStateLock);
+ void commitTransactionsLocked(uint32_t transactionFlags) REQUIRES(mStateLock);
+ void doCommitTransactions() REQUIRES(mStateLock);
// Handle the REFRESH message queue event, sending the current frame down to RenderEngine and
// the Composer HAL for presentation
@@ -809,9 +811,6 @@
// Returns whether a new buffer has been latched (see handlePageFlip())
bool handleMessageInvalidate();
- void handleTransaction(uint32_t transactionFlags);
- void handleTransactionLocked(uint32_t transactionFlags) REQUIRES(mStateLock);
-
void updateInputFlinger();
void notifyWindowInfos();
void commitInputWindowCommands() REQUIRES(mStateLock);
@@ -843,18 +842,23 @@
void flushTransactionQueues();
// Returns true if there is at least one transaction that needs to be flushed
bool transactionFlushNeeded();
- uint32_t getTransactionFlags(uint32_t flags);
- uint32_t peekTransactionFlags();
- // Can only be called from the main thread or with mStateLock held
- uint32_t setTransactionFlags(uint32_t flags);
+
+ uint32_t getTransactionFlags() const;
+
+ // Sets the masked bits, and returns the old flags.
+ uint32_t setTransactionFlags(uint32_t mask);
+
+ // Clears and returns the masked bits.
+ uint32_t clearTransactionFlags(uint32_t mask);
+
// Indicate SF should call doTraversal on layers, but don't trigger a wakeup! We use this cases
// where there are still pending transactions but we know they won't be ready until a frame
// arrives from a different layer. So we need to ensure we performTransaction from invalidate
// but there is no need to try and wake up immediately to do it. Rather we rely on
// onFrameAvailable or another layer update to wake us up.
void setTraversalNeeded();
- uint32_t setTransactionFlags(uint32_t flags, TransactionSchedule, const sp<IBinder>& = {});
- void commitTransaction() REQUIRES(mStateLock);
+ uint32_t setTransactionFlags(uint32_t mask, TransactionSchedule,
+ const sp<IBinder>& applyToken = {});
void commitOffscreenLayers();
bool transactionIsReadyToBeApplied(
const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime,
@@ -937,7 +941,7 @@
return width > mMaxRenderTargetSize || height > mMaxRenderTargetSize;
}
- int getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const;
+ uint32_t getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const;
/*
* Display and layer stack management
@@ -1028,8 +1032,6 @@
/*
* Compositing
*/
- void invalidateHwcGeometry();
-
void postComposition();
void getCompositorTiming(CompositorTiming* compositorTiming);
void updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
@@ -1113,15 +1115,19 @@
return {};
}
- // TODO(b/74619554): Remove special cases for primary display.
+ // TODO(b/182939859): SF conflates the primary (a.k.a. default) display with the first display
+ // connected at boot, which is typically internal. (Theoretically, it must be internal because
+ // SF does not support disconnecting it, though in practice HWC may circumvent this limitation.)
+ //
+ // SF inherits getInternalDisplayToken and getInternalDisplayId from ISurfaceComposer, so these
+ // locked counterparts are named consistently. Once SF supports headless mode and can designate
+ // any display as primary, the "internal" misnomer will be phased out.
sp<IBinder> getInternalDisplayTokenLocked() const REQUIRES(mStateLock) {
- const auto displayId = getInternalDisplayIdLocked();
- return displayId ? getPhysicalDisplayTokenLocked(*displayId) : nullptr;
+ return getPhysicalDisplayTokenLocked(getInternalDisplayIdLocked());
}
- std::optional<PhysicalDisplayId> getInternalDisplayIdLocked() const REQUIRES(mStateLock) {
- const auto hwcDisplayId = getHwComposer().getInternalHwcDisplayId();
- return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
+ PhysicalDisplayId getInternalDisplayIdLocked() const REQUIRES(mStateLock) {
+ return getHwComposer().getPrimaryDisplayId();
}
// Toggles use of HAL/GPU virtual displays.
@@ -1202,8 +1208,7 @@
/*
* Misc
*/
- std::vector<ui::ColorMode> getDisplayColorModes(PhysicalDisplayId displayId)
- REQUIRES(mStateLock);
+ std::vector<ui::ColorMode> getDisplayColorModes(const DisplayDevice&) REQUIRES(mStateLock);
static int calculateMaxAcquiredBufferCount(Fps refreshRate,
std::chrono::nanoseconds presentLatency);
@@ -1245,7 +1250,8 @@
bool mLayersRemoved = false;
bool mLayersAdded = false;
- std::atomic<bool> mRepaintEverything = false;
+ std::atomic_bool mForceRefresh = false;
+ std::atomic_bool mGeometryDirty = false;
// constant members (no synchronization needed for access)
const nsecs_t mBootTime = systemTime();
@@ -1272,7 +1278,6 @@
bool mSomeDataspaceChanged = false;
bool mForceTransactionDisplayChange = false;
- bool mGeometryInvalid = false;
bool mAnimCompositionPending = false;
// Tracks layers that have pending frames which are candidates for being
@@ -1307,13 +1312,13 @@
std::optional<DisplayIdGenerator<HalVirtualDisplayId>> hal;
} mVirtualDisplayIdGenerators;
- // don't use a lock for these, we don't care
- int mDebugRegion = 0;
- bool mDebugDisableHWC = false;
- bool mDebugDisableTransformHint = false;
+ std::atomic_uint mDebugFlashDelay = 0;
+ std::atomic_bool mDebugDisableHWC = false;
+ std::atomic_bool mDebugDisableTransformHint = false;
+ std::atomic<nsecs_t> mDebugInTransaction = 0;
+ std::atomic_bool mForceFullDamage = false;
+
bool mLayerCachingEnabled = false;
- volatile nsecs_t mDebugInTransaction = 0;
- bool mForceFullDamage = false;
bool mPropagateBackpressureClientComposition = false;
sp<SurfaceInterceptor> mInterceptor;
@@ -1510,6 +1515,8 @@
wp<IBinder> mActiveDisplayToken GUARDED_BY(mStateLock);
const sp<WindowInfosListenerInvoker> mWindowInfosListenerInvoker;
+
+ std::unique_ptr<FlagManager> mFlagManager;
};
} // namespace android
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 9be3abe..0782fef 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -323,11 +323,10 @@
}
void SurfaceInterceptor::addLayerStackLocked(Transaction* transaction, int32_t layerId,
- uint32_t layerStack)
-{
+ ui::LayerStack layerStack) {
SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
LayerStackChange* layerStackChange(change->mutable_layer_stack());
- layerStackChange->set_layer_stack(layerStack);
+ layerStackChange->set_layer_stack(layerStack.id);
}
void SurfaceInterceptor::addCropLocked(Transaction* transaction, int32_t layerId,
@@ -568,12 +567,11 @@
}
}
-void SurfaceInterceptor::addDisplayLayerStackLocked(Transaction* transaction,
- int32_t sequenceId, uint32_t layerStack)
-{
+void SurfaceInterceptor::addDisplayLayerStackLocked(Transaction* transaction, int32_t sequenceId,
+ ui::LayerStack layerStack) {
DisplayChange* dispChange(createDisplayChangeLocked(transaction, sequenceId));
LayerStackChange* layerStackChange(dispChange->mutable_layer_stack());
- layerStackChange->set_layer_stack(layerStack);
+ layerStackChange->set_layer_stack(layerStack.id);
}
void SurfaceInterceptor::addDisplayFlagsLocked(Transaction* transaction, int32_t sequenceId,
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index 7b331b9..970c3e5 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -160,7 +160,7 @@
void addTransparentRegionLocked(Transaction* transaction, int32_t layerId,
const Region& transRegion);
void addFlagsLocked(Transaction* transaction, int32_t layerId, uint8_t flags, uint8_t mask);
- void addLayerStackLocked(Transaction* transaction, int32_t layerId, uint32_t layerStack);
+ void addLayerStackLocked(Transaction* transaction, int32_t layerId, ui::LayerStack);
void addCropLocked(Transaction* transaction, int32_t layerId, const Rect& rect);
void addCornerRadiusLocked(Transaction* transaction, int32_t layerId, float cornerRadius);
void addBackgroundBlurRadiusLocked(Transaction* transaction, int32_t layerId,
@@ -183,8 +183,7 @@
DisplayChange* createDisplayChangeLocked(Transaction* transaction, int32_t sequenceId);
void addDisplaySurfaceLocked(Transaction* transaction, int32_t sequenceId,
const sp<const IGraphicBufferProducer>& surface);
- void addDisplayLayerStackLocked(Transaction* transaction, int32_t sequenceId,
- uint32_t layerStack);
+ void addDisplayLayerStackLocked(Transaction* transaction, int32_t sequenceId, ui::LayerStack);
void addDisplayFlagsLocked(Transaction* transaction, int32_t sequenceId, uint32_t flags);
void addDisplaySizeLocked(Transaction* transaction, int32_t sequenceId, uint32_t w,
uint32_t h);
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
index dc2aa58..b93d127 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
@@ -21,6 +21,7 @@
namespace android {
+using gui::DisplayInfo;
using gui::IWindowInfosListener;
using gui::WindowInfo;
@@ -67,6 +68,7 @@
}
void WindowInfosListenerInvoker::windowInfosChanged(const std::vector<WindowInfo>& windowInfos,
+ const std::vector<DisplayInfo>& displayInfos,
bool shouldSync) {
std::unordered_set<sp<IWindowInfosListener>, ISurfaceComposer::SpHash<IWindowInfosListener>>
windowInfosListeners;
@@ -81,7 +83,7 @@
mCallbacksPending = windowInfosListeners.size();
for (const auto& listener : windowInfosListeners) {
- listener->onWindowInfosChanged(windowInfos,
+ listener->onWindowInfosChanged(windowInfos, displayInfos,
shouldSync ? mWindowInfosReportedListener : nullptr);
}
}
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h
index 5e5796f..ecd797a 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.h
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.h
@@ -33,7 +33,8 @@
void addWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener);
void removeWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener);
- void windowInfosChanged(const std::vector<gui::WindowInfo>& windowInfos, bool shouldSync);
+ void windowInfosChanged(const std::vector<gui::WindowInfo>&,
+ const std::vector<gui::DisplayInfo>&, bool shouldSync);
protected:
void binderDied(const wp<IBinder>& who) override;
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index fa3f0e7..d33bc10 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -93,7 +93,7 @@
ASSERT_TRUE(mBGSurfaceControl->isValid());
Transaction t;
- t.setDisplayLayerStack(mDisplay, 0);
+ t.setDisplayLayerStack(mDisplay, ui::DEFAULT_LAYER_STACK);
ASSERT_EQ(NO_ERROR,
t.setLayer(mBGSurfaceControl, INT_MAX - 3).show(mBGSurfaceControl).apply());
}
diff --git a/services/surfaceflinger/tests/EffectLayer_test.cpp b/services/surfaceflinger/tests/EffectLayer_test.cpp
index 93656f3..9fa0452 100644
--- a/services/surfaceflinger/tests/EffectLayer_test.cpp
+++ b/services/surfaceflinger/tests/EffectLayer_test.cpp
@@ -33,7 +33,7 @@
mParentLayer = createColorLayer("Parent layer", Color::RED);
asTransaction([&](Transaction& t) {
- t.setDisplayLayerStack(display, 0);
+ t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
t.setLayer(mParentLayer, INT32_MAX - 2).show(mParentLayer);
t.setFlags(mParentLayer, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
});
diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp
index 9fa3d4c..8d7e175 100644
--- a/services/surfaceflinger/tests/IPC_test.cpp
+++ b/services/surfaceflinger/tests/IPC_test.cpp
@@ -159,7 +159,7 @@
{0, 0, static_cast<int32_t>(width),
static_cast<int32_t>(height)},
Color::RED);
- transaction->setLayerStack(mSurfaceControl, 0)
+ transaction->setLayerStack(mSurfaceControl, ui::DEFAULT_LAYER_STACK)
.setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max())
.setBuffer(mSurfaceControl, gb)
.setAcquireFence(mSurfaceControl, fence)
@@ -232,7 +232,7 @@
mDisplayHeight = mode.resolution.getHeight();
Transaction setupTransaction;
- setupTransaction.setDisplayLayerStack(mPrimaryDisplay, 0);
+ setupTransaction.setDisplayLayerStack(mPrimaryDisplay, ui::DEFAULT_LAYER_STACK);
setupTransaction.apply();
}
@@ -310,7 +310,7 @@
Color::RED);
Transaction transaction;
- transaction.setLayerStack(sc, 0)
+ transaction.setLayerStack(sc, ui::DEFAULT_LAYER_STACK)
.setLayer(sc, std::numeric_limits<int32_t>::max() - 1)
.setBuffer(sc, gb)
.setAcquireFence(sc, fence)
diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h
index 0bc8fe7..6bd7920 100644
--- a/services/surfaceflinger/tests/LayerTransactionTest.h
+++ b/services/surfaceflinger/tests/LayerTransactionTest.h
@@ -266,7 +266,7 @@
sp<IBinder> mDisplay;
uint32_t mDisplayWidth;
uint32_t mDisplayHeight;
- uint32_t mDisplayLayerStack;
+ ui::LayerStack mDisplayLayerStack = ui::DEFAULT_LAYER_STACK;
Rect mDisplayRect = Rect::INVALID_RECT;
// leave room for ~256 layers
@@ -294,8 +294,6 @@
// vsyncs.
mBufferPostDelay = static_cast<int32_t>(1e6 / mode.refreshRate) * 3;
- mDisplayLayerStack = 0;
-
mBlackBgSurface =
createSurface(mClient, "BaseSurface", 0 /* buffer width */, 0 /* buffer height */,
PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect);
diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
index 43d957c..4076253 100644
--- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
@@ -643,7 +643,8 @@
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
- Transaction().setLayerStack(layer, mDisplayLayerStack + 1).apply();
+ const auto layerStack = ui::LayerStack::fromValue(mDisplayLayerStack.id + 1);
+ Transaction().setLayerStack(layer, layerStack).apply();
{
SCOPED_TRACE("non-existing layer stack");
getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp
index ee4d367..e1a7ecc 100644
--- a/services/surfaceflinger/tests/LayerUpdate_test.cpp
+++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp
@@ -63,7 +63,7 @@
TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
asTransaction([&](Transaction& t) {
- t.setDisplayLayerStack(display, 0);
+ t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
t.setLayer(mBGSurfaceControl, INT32_MAX - 2).show(mBGSurfaceControl);
diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp
index d027865..3ec6da9 100644
--- a/services/surfaceflinger/tests/MirrorLayer_test.cpp
+++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp
@@ -36,7 +36,7 @@
mParentLayer = createColorLayer("Parent layer", Color::RED);
mChildLayer = createColorLayer("Child layer", Color::GREEN, mParentLayer.get());
asTransaction([&](Transaction& t) {
- t.setDisplayLayerStack(display, 0);
+ t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
t.setLayer(mParentLayer, INT32_MAX - 2).show(mParentLayer);
t.setCrop(mChildLayer, Rect(0, 0, 400, 400)).show(mChildLayer);
t.setPosition(mChildLayer, 50, 50);
diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
index 08de01c..1ed6c65 100644
--- a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
+++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
@@ -52,7 +52,7 @@
mColorLayer = 0;
}
- void createDisplay(const ui::Size& layerStackSize, uint32_t layerStack) {
+ void createDisplay(const ui::Size& layerStackSize, ui::LayerStack layerStack) {
mVirtualDisplay =
SurfaceComposerClient::createDisplay(String8("VirtualDisplay"), false /*secure*/);
asTransaction([&](Transaction& t) {
@@ -63,7 +63,7 @@
});
}
- void createColorLayer(uint32_t layerStack) {
+ void createColorLayer(ui::LayerStack layerStack) {
mColorLayer =
createSurface(mClient, "ColorLayer", 0 /* buffer width */, 0 /* buffer height */,
PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect);
@@ -90,8 +90,9 @@
};
TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInVirtualDisplay) {
- createDisplay(mMainDisplayState.layerStackSpaceRect, 1 /* layerStack */);
- createColorLayer(1 /* layerStack */);
+ constexpr ui::LayerStack kLayerStack{1u};
+ createDisplay(mMainDisplayState.layerStackSpaceRect, kLayerStack);
+ createColorLayer(kLayerStack);
asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
@@ -113,8 +114,8 @@
// Assumption here is that the new mirrored display has the same layer stack rect as the
// primary display that it is mirroring.
- createDisplay(mMainDisplayState.layerStackSpaceRect, 0 /* layerStack */);
- createColorLayer(0 /* layerStack */);
+ createDisplay(mMainDisplayState.layerStackSpaceRect, ui::DEFAULT_LAYER_STACK);
+ createColorLayer(ui::DEFAULT_LAYER_STACK);
asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
diff --git a/services/surfaceflinger/tests/RelativeZ_test.cpp b/services/surfaceflinger/tests/RelativeZ_test.cpp
index fde6e6e..50a4092 100644
--- a/services/surfaceflinger/tests/RelativeZ_test.cpp
+++ b/services/surfaceflinger/tests/RelativeZ_test.cpp
@@ -43,7 +43,7 @@
mForegroundLayer = createColorLayer("Foreground layer", Color::GREEN);
asTransaction([&](Transaction& t) {
- t.setDisplayLayerStack(display, 0);
+ t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
t.setLayer(mBackgroundLayer, INT32_MAX - 2).show(mBackgroundLayer);
t.setLayer(mForegroundLayer, INT32_MAX - 1).show(mForegroundLayer);
});
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index ab2064e..95301b3 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -53,7 +53,7 @@
TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
asTransaction([&](Transaction& t) {
- t.setDisplayLayerStack(display, 0);
+ t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
t.setLayer(mBGSurfaceControl, INT32_MAX - 2).show(mBGSurfaceControl);
@@ -563,7 +563,7 @@
Transaction()
.show(redLayer)
.show(secureLayer)
- .setLayerStack(redLayer, 0)
+ .setLayerStack(redLayer, ui::DEFAULT_LAYER_STACK)
.setLayer(redLayer, INT32_MAX)
.apply();
@@ -655,7 +655,7 @@
Transaction()
.show(layer)
.hide(mFGSurfaceControl)
- .setLayerStack(layer, 0)
+ .setLayerStack(layer, ui::DEFAULT_LAYER_STACK)
.setLayer(layer, INT32_MAX)
.setColor(layer, {layerColor.r / 255, layerColor.g / 255, layerColor.b / 255})
.setCrop(layer, bounds)
@@ -702,7 +702,7 @@
.show(layer)
.show(childLayer)
.hide(mFGSurfaceControl)
- .setLayerStack(layer, 0)
+ .setLayerStack(layer, ui::DEFAULT_LAYER_STACK)
.setLayer(layer, INT32_MAX)
.setColor(layer, {layerColor.r / 255, layerColor.g / 255, layerColor.b / 255})
.setColor(childLayer, {childColor.r / 255, childColor.g / 255, childColor.b / 255})
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index a424059..ee16f40 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -283,7 +283,7 @@
ASSERT_TRUE(mFGSurfaceControl->isValid());
Transaction t;
- t.setDisplayLayerStack(display, 0);
+ t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
ASSERT_EQ(NO_ERROR,
t.setLayer(mBGSurfaceControl, INT_MAX - 3)
.show(mBGSurfaceControl)
@@ -380,7 +380,7 @@
}
void SurfaceInterceptorTest::layerStackUpdate(Transaction& t) {
- t.setLayerStack(mBGSurfaceControl, STACK_UPDATE);
+ t.setLayerStack(mBGSurfaceControl, ui::LayerStack::fromValue(STACK_UPDATE));
}
void SurfaceInterceptorTest::hiddenFlagUpdate(Transaction& t) {
diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h
index 89f6086..60cffb1 100644
--- a/services/surfaceflinger/tests/TransactionTestHarnesses.h
+++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h
@@ -65,7 +65,7 @@
SurfaceComposerClient::Transaction t;
t.setDisplaySurface(vDisplay, producer);
- t.setDisplayLayerStack(vDisplay, 0);
+ t.setDisplayLayerStack(vDisplay, ui::DEFAULT_LAYER_STACK);
t.setDisplayProjection(vDisplay, displayState.orientation,
Rect(displayState.layerStackSpaceRect), Rect(resolution));
t.apply();
diff --git a/services/surfaceflinger/tests/WindowInfosListener_test.cpp b/services/surfaceflinger/tests/WindowInfosListener_test.cpp
index 89228d5..0069111 100644
--- a/services/surfaceflinger/tests/WindowInfosListener_test.cpp
+++ b/services/surfaceflinger/tests/WindowInfosListener_test.cpp
@@ -22,6 +22,7 @@
namespace android {
using Transaction = SurfaceComposerClient::Transaction;
+using gui::DisplayInfo;
using gui::WindowInfo;
class WindowInfosListenerTest : public ::testing::Test {
@@ -40,7 +41,8 @@
struct SyncWindowInfosListener : public gui::WindowInfosListener {
public:
- void onWindowInfosChanged(const std::vector<WindowInfo>& windowInfos) override {
+ void onWindowInfosChanged(const std::vector<WindowInfo>& windowInfos,
+ const std::vector<DisplayInfo>&) override {
windowInfosPromise.set_value(windowInfos);
}
@@ -84,7 +86,7 @@
ISurfaceComposerClient::eFXSurfaceBufferState);
Transaction()
- .setLayerStack(surfaceControl, 0)
+ .setLayerStack(surfaceControl, ui::DEFAULT_LAYER_STACK)
.show(surfaceControl)
.setLayer(surfaceControl, INT32_MAX - 1)
.setInputWindowInfo(surfaceControl, windowInfo)
@@ -112,7 +114,7 @@
ISurfaceComposerClient::eFXSurfaceBufferState);
Transaction()
- .setLayerStack(surfaceControl, 0)
+ .setLayerStack(surfaceControl, ui::DEFAULT_LAYER_STACK)
.show(surfaceControl)
.setLayer(surfaceControl, INT32_MAX - 1)
.setInputWindowInfo(surfaceControl, windowInfo)
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 162711d..b3b4ec1 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -279,7 +279,7 @@
}
bool waitForHotplugEvent(Display displayId, bool connected) {
- return waitForHotplugEvent(PhysicalDisplayId(displayId), connected);
+ return waitForHotplugEvent(physicalIdFromHwcDisplayId(displayId), connected);
}
bool waitForHotplugEvent(PhysicalDisplayId displayId, bool connected) {
@@ -305,7 +305,7 @@
}
bool waitForModeChangedEvent(Display display, int32_t modeId) {
- PhysicalDisplayId displayId(display);
+ PhysicalDisplayId displayId = physicalIdFromHwcDisplayId(display);
int waitCount = 20;
while (waitCount--) {
while (!mReceivedDisplayEvents.empty()) {
@@ -363,7 +363,7 @@
{
TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, 0);
+ ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
}
@@ -426,7 +426,7 @@
{
TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, 0);
+ ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
}
@@ -479,7 +479,7 @@
{
TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, 0);
+ ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
}
@@ -534,7 +534,7 @@
{
TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, 0);
+ ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
}
@@ -586,7 +586,7 @@
{
TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, 0);
+ ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
}
@@ -651,7 +651,7 @@
{
TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, 0);
+ ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
}
@@ -703,7 +703,7 @@
{
TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, 0);
+ ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
}
@@ -750,7 +750,7 @@
{
TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, 0);
+ ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
}
@@ -797,7 +797,7 @@
{
TransactionScope ts(*mFakeComposerClient);
- ts.setDisplayLayerStack(display, 0);
+ ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
}
@@ -1195,7 +1195,7 @@
fillSurfaceRGBA8(mFGSurfaceControl, RED);
Transaction t;
- t.setDisplayLayerStack(display, 0);
+ t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK);
t.setLayer(mBGSurfaceControl, INT32_MAX - 2);
t.show(mBGSurfaceControl);
@@ -1342,7 +1342,7 @@
ALOGD("TransactionTest::SetLayerStack");
{
TransactionScope ts(*sFakeComposer);
- ts.setLayerStack(mFGSurfaceControl, 1);
+ ts.setLayerStack(mFGSurfaceControl, ui::LayerStack{1});
}
// Foreground layer should have disappeared.
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 9e704c3..078b0d4 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -23,7 +23,10 @@
cc_test {
name: "libsurfaceflinger_unittest",
- defaults: ["surfaceflinger_defaults"],
+ defaults: [
+ "skia_renderengine_deps",
+ "surfaceflinger_defaults",
+ ],
test_suites: ["device-tests"],
sanitize: {
// Using the address sanitizer not only helps uncover issues in the code
@@ -54,6 +57,7 @@
"DisplayDevice_InitiateModeChange.cpp",
"DisplayDevice_SetProjectionTest.cpp",
"EventThreadTest.cpp",
+ "FlagManagerTest.cpp",
"FpsReporterTest.cpp",
"FpsTest.cpp",
"FramebufferSurfaceTest.cpp",
@@ -67,10 +71,10 @@
"MessageQueueTest.cpp",
"SurfaceFlinger_CreateDisplayTest.cpp",
"SurfaceFlinger_DestroyDisplayTest.cpp",
+ "SurfaceFlinger_DisplayTransactionCommitTest.cpp",
"SurfaceFlinger_GetDisplayNativePrimariesTest.cpp",
- "SurfaceFlinger_HandleTransactionLockedTest.cpp",
- "SurfaceFlinger_NotifyPowerBoostTest.cpp",
"SurfaceFlinger_HotplugTest.cpp",
+ "SurfaceFlinger_NotifyPowerBoostTest.cpp",
"SurfaceFlinger_OnInitializeDisplaysTest.cpp",
"SurfaceFlinger_SetDisplayStateTest.cpp",
"SurfaceFlinger_SetPowerModeInternalTest.cpp",
@@ -161,6 +165,7 @@
"libsync",
"libui",
"libutils",
+ "server_configurable_flags",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
diff --git a/services/surfaceflinger/tests/unittests/CachingTest.cpp b/services/surfaceflinger/tests/unittests/CachingTest.cpp
index 6a7ec9b..6f85498 100644
--- a/services/surfaceflinger/tests/unittests/CachingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CachingTest.cpp
@@ -14,11 +14,6 @@
* limitations under the License.
*/
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-#pragma clang diagnostic ignored "-Wextra"
-
#undef LOG_TAG
#define LOG_TAG "CachingTest"
@@ -42,7 +37,7 @@
sp<IBinder> binder = new BBinder();
// test getting invalid client_cache_id
client_cache_t id;
- uint32_t slot = mHwcSlotGenerator->getHwcCacheSlot(id);
+ int slot = mHwcSlotGenerator->getHwcCacheSlot(id);
EXPECT_EQ(BufferQueue::INVALID_BUFFER_SLOT, slot);
}
@@ -51,7 +46,7 @@
client_cache_t id;
id.token = binder;
id.id = 0;
- uint32_t slot = mHwcSlotGenerator->getHwcCacheSlot(id);
+ int slot = mHwcSlotGenerator->getHwcCacheSlot(id);
EXPECT_EQ(BufferQueue::NUM_BUFFER_SLOTS - 1, slot);
client_cache_t idB;
@@ -72,31 +67,28 @@
std::vector<client_cache_t> ids;
uint32_t cacheId = 0;
// fill up cache
- for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
client_cache_t id;
id.token = binder;
id.id = cacheId;
ids.push_back(id);
- uint32_t slot = mHwcSlotGenerator->getHwcCacheSlot(id);
+ int slot = mHwcSlotGenerator->getHwcCacheSlot(id);
EXPECT_EQ(BufferQueue::NUM_BUFFER_SLOTS - (i + 1), slot);
cacheId++;
}
- for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
- uint32_t slot = mHwcSlotGenerator->getHwcCacheSlot(ids[i]);
+ for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ int slot = mHwcSlotGenerator->getHwcCacheSlot(ids[static_cast<uint32_t>(i)]);
EXPECT_EQ(BufferQueue::NUM_BUFFER_SLOTS - (i + 1), slot);
}
- for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
client_cache_t id;
id.token = binder;
id.id = cacheId;
- uint32_t slot = mHwcSlotGenerator->getHwcCacheSlot(id);
+ int slot = mHwcSlotGenerator->getHwcCacheSlot(id);
EXPECT_EQ(BufferQueue::NUM_BUFFER_SLOTS - (i + 1), slot);
cacheId++;
}
}
} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 52a36a2..5135ff9 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -77,12 +77,12 @@
constexpr hal::HWLayerId HWC_LAYER = 5000;
constexpr Transform DEFAULT_TRANSFORM = static_cast<Transform>(0);
-constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID(42);
+constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u);
constexpr int DEFAULT_DISPLAY_WIDTH = 1920;
constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
constexpr int DEFAULT_TEXTURE_ID = 6000;
-constexpr int DEFAULT_LAYER_STACK = 7000;
+constexpr ui::LayerStack LAYER_STACK{7000u};
constexpr int DEFAULT_DISPLAY_MAX_LUMINANCE = 500;
@@ -157,7 +157,7 @@
// pain)
// mFlinger.mutableVisibleRegionsDirty() = true;
- mFlinger.mutableGeometryInvalid() = true;
+ mFlinger.mutableGeometryDirty() = true;
}
template <typename Case>
@@ -255,6 +255,14 @@
LayerCase::cleanup(this);
}
+template <class T>
+std::future<T> futureOf(T obj) {
+ std::promise<T> resultPromise;
+ std::future<T> resultFuture = resultPromise.get_future();
+ resultPromise.set_value(std::move(obj));
+ return resultFuture;
+}
+
/* ------------------------------------------------------------------------
* Variants for each display configuration which can be tested
*/
@@ -287,10 +295,8 @@
auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
.setId(DEFAULT_DISPLAY_ID)
- .setConnectionType(ui::DisplayConnectionType::Internal)
.setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
.setIsSecure(Derived::IS_SECURE)
- .setLayerStackId(DEFAULT_LAYER_STACK)
.setPowerAdvisor(&test->mPowerAdvisor)
.setName(std::string("Injected display for ") +
test_info->test_case_name() + "." + test_info->name())
@@ -309,7 +315,7 @@
.setPowerMode(Derived::INIT_POWER_MODE)
.inject();
Mock::VerifyAndClear(test->mNativeWindow);
- test->mDisplay->setLayerStack(DEFAULT_LAYER_STACK);
+ test->mDisplay->setLayerStack(LAYER_STACK);
}
template <typename Case>
@@ -339,16 +345,18 @@
template <typename Case>
static void setupCommonScreensCaptureCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
- .WillRepeatedly([](const renderengine::DisplaySettings& displaySettings,
- const std::vector<const renderengine::LayerSettings*>&,
- const std::shared_ptr<renderengine::ExternalTexture>&,
- const bool, base::unique_fd&&, base::unique_fd*) -> status_t {
+ .WillRepeatedly([&](const renderengine::DisplaySettings& displaySettings,
+ const std::vector<const renderengine::LayerSettings*>&,
+ const std::shared_ptr<renderengine::ExternalTexture>&,
+ const bool, base::unique_fd &&)
+ -> std::future<renderengine::RenderEngineResult> {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.clip);
- return NO_ERROR;
+ return futureOf<renderengine::RenderEngineResult>(
+ {NO_ERROR, base::unique_fd()});
});
}
@@ -388,17 +396,19 @@
.WillOnce(DoAll(SetArgPointee<0>(test->mNativeWindowBuffer), SetArgPointee<1>(-1),
Return(0)));
EXPECT_CALL(*test->mRenderEngine, drawLayers)
- .WillRepeatedly([](const renderengine::DisplaySettings& displaySettings,
- const std::vector<const renderengine::LayerSettings*>&,
- const std::shared_ptr<renderengine::ExternalTexture>&,
- const bool, base::unique_fd&&, base::unique_fd*) -> status_t {
+ .WillRepeatedly([&](const renderengine::DisplaySettings& displaySettings,
+ const std::vector<const renderengine::LayerSettings*>&,
+ const std::shared_ptr<renderengine::ExternalTexture>&,
+ const bool, base::unique_fd &&)
+ -> std::future<renderengine::RenderEngineResult> {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.clip);
EXPECT_EQ(ui::Dataspace::UNKNOWN, displaySettings.outputDataspace);
- return NO_ERROR;
+ return futureOf<renderengine::RenderEngineResult>(
+ {NO_ERROR, base::unique_fd()});
});
}
@@ -622,10 +632,10 @@
static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
- .WillOnce([](const renderengine::DisplaySettings& displaySettings,
- const std::vector<const renderengine::LayerSettings*>& layerSettings,
- const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd&&, base::unique_fd*) -> status_t {
+ .WillOnce([&](const renderengine::DisplaySettings& displaySettings,
+ const std::vector<const renderengine::LayerSettings*>& layerSettings,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -633,11 +643,14 @@
displaySettings.clip);
// screen capture adds an additional color layer as an alpha
// prefill, so gtet the back layer.
+ std::future<renderengine::RenderEngineResult> resultFuture =
+ futureOf<renderengine::RenderEngineResult>(
+ {NO_ERROR, base::unique_fd()});
if (layerSettings.empty()) {
ADD_FAILURE() << "layerSettings was not expected to be empty in "
"setupREBufferCompositionCommonCallExpectations "
"verification lambda";
- return NO_ERROR;
+ return resultFuture;
}
const renderengine::LayerSettings* layer = layerSettings.back();
EXPECT_THAT(layer->source.buffer.buffer, Not(IsNull()));
@@ -649,7 +662,7 @@
EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
EXPECT_EQ(LayerProperties::COLOR[3], layer->alpha);
- return NO_ERROR;
+ return resultFuture;
});
}
@@ -671,10 +684,10 @@
static void setupREColorCompositionCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
- .WillOnce([](const renderengine::DisplaySettings& displaySettings,
- const std::vector<const renderengine::LayerSettings*>& layerSettings,
- const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd&&, base::unique_fd*) -> status_t {
+ .WillOnce([&](const renderengine::DisplaySettings& displaySettings,
+ const std::vector<const renderengine::LayerSettings*>& layerSettings,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -682,11 +695,14 @@
displaySettings.clip);
// screen capture adds an additional color layer as an alpha
// prefill, so get the back layer.
+ std::future<renderengine::RenderEngineResult> resultFuture =
+ futureOf<renderengine::RenderEngineResult>(
+ {NO_ERROR, base::unique_fd()});
if (layerSettings.empty()) {
ADD_FAILURE()
<< "layerSettings was not expected to be empty in "
"setupREColorCompositionCallExpectations verification lambda";
- return NO_ERROR;
+ return resultFuture;
}
const renderengine::LayerSettings* layer = layerSettings.back();
EXPECT_THAT(layer->source.buffer.buffer, IsNull());
@@ -696,7 +712,7 @@
EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
EXPECT_EQ(LayerProperties::COLOR[3], layer->alpha);
- return NO_ERROR;
+ return resultFuture;
});
}
@@ -748,10 +764,10 @@
static void setupInsecureREBufferCompositionCommonCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
- .WillOnce([](const renderengine::DisplaySettings& displaySettings,
- const std::vector<const renderengine::LayerSettings*>& layerSettings,
- const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
- base::unique_fd&&, base::unique_fd*) -> status_t {
+ .WillOnce([&](const renderengine::DisplaySettings& displaySettings,
+ const std::vector<const renderengine::LayerSettings*>& layerSettings,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd &&) -> std::future<renderengine::RenderEngineResult> {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -759,11 +775,14 @@
displaySettings.clip);
// screen capture adds an additional color layer as an alpha
// prefill, so get the back layer.
+ std::future<renderengine::RenderEngineResult> resultFuture =
+ futureOf<renderengine::RenderEngineResult>(
+ {NO_ERROR, base::unique_fd()});
if (layerSettings.empty()) {
ADD_FAILURE() << "layerSettings was not expected to be empty in "
"setupInsecureREBufferCompositionCommonCallExpectations "
"verification lambda";
- return NO_ERROR;
+ return resultFuture;
}
const renderengine::LayerSettings* layer = layerSettings.back();
EXPECT_THAT(layer->source.buffer.buffer, IsNull());
@@ -771,7 +790,7 @@
EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
EXPECT_EQ(1.0f, layer->alpha);
- return NO_ERROR;
+ return resultFuture;
});
}
@@ -834,7 +853,7 @@
template <typename L>
static void initLayerDrawingStateAndComputeBounds(CompositionTest* test, sp<L> layer) {
auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer);
- layerDrawingState.layerStack = DEFAULT_LAYER_STACK;
+ layerDrawingState.layerStack = LAYER_STACK;
layerDrawingState.width = 100;
layerDrawingState.height = 100;
layerDrawingState.color = half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_SetProjectionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_SetProjectionTest.cpp
index 9fe30f8..3d24ecb 100644
--- a/services/surfaceflinger/tests/unittests/DisplayDevice_SetProjectionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayDevice_SetProjectionTest.cpp
@@ -84,10 +84,10 @@
EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_0, mHardwareDisplaySize.width,
mHardwareDisplaySize.height),
compositionState.transform);
- EXPECT_EQ(ui::ROTATION_0, compositionState.displaySpace.orientation);
- EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
- EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.orientedDisplaySpace.content);
- EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.layerStackSpace.content);
+ EXPECT_EQ(ui::ROTATION_0, compositionState.displaySpace.getOrientation());
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.getContent());
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.orientedDisplaySpace.getContent());
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.layerStackSpace.getContent());
EXPECT_EQ(false, compositionState.needsFiltering);
}
@@ -96,13 +96,14 @@
EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_90, mHardwareDisplaySize.width,
mHardwareDisplaySize.height),
compositionState.transform);
- EXPECT_EQ(ui::ROTATION_90, compositionState.displaySpace.orientation);
- EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
+ EXPECT_EQ(ui::ROTATION_90, compositionState.displaySpace.getOrientation());
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.getContent());
// For 90, the orientedDisplaySpaceRect and layerStackSpaceRect have the hardware display
// size width and height swapped
EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)),
- compositionState.orientedDisplaySpace.content);
- EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)), compositionState.layerStackSpace.content);
+ compositionState.orientedDisplaySpace.getContent());
+ EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)),
+ compositionState.layerStackSpace.getContent());
EXPECT_EQ(false, compositionState.needsFiltering);
}
@@ -111,9 +112,9 @@
EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_180, mHardwareDisplaySize.width,
mHardwareDisplaySize.height),
compositionState.transform);
- EXPECT_EQ(ui::ROTATION_180, compositionState.displaySpace.orientation);
- EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.orientedDisplaySpace.content);
- EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.layerStackSpace.content);
+ EXPECT_EQ(ui::ROTATION_180, compositionState.displaySpace.getOrientation());
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.orientedDisplaySpace.getContent());
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.layerStackSpace.getContent());
EXPECT_EQ(false, compositionState.needsFiltering);
}
@@ -122,13 +123,14 @@
EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_270, mHardwareDisplaySize.width,
mHardwareDisplaySize.height),
compositionState.transform);
- EXPECT_EQ(ui::ROTATION_270, compositionState.displaySpace.orientation);
- EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
+ EXPECT_EQ(ui::ROTATION_270, compositionState.displaySpace.getOrientation());
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.getContent());
// For 270, the orientedDisplaySpaceRect and layerStackSpaceRect have the hardware display
// size width and height swapped
EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)),
- compositionState.orientedDisplaySpace.content);
- EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)), compositionState.layerStackSpace.content);
+ compositionState.orientedDisplaySpace.getContent());
+ EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)),
+ compositionState.layerStackSpace.getContent());
EXPECT_EQ(false, compositionState.needsFiltering);
}
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index cc24323..5a21e7b 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -122,7 +122,7 @@
sp<DisplayDevice> DisplayTransactionTest::injectDefaultInternalDisplay(
std::function<void(FakeDisplayDeviceInjector&)> injectExtra) {
- constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID(777);
+ constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(255u);
constexpr int DEFAULT_DISPLAY_WIDTH = 1080;
constexpr int DEFAULT_DISPLAY_HEIGHT = 1920;
constexpr HWDisplayId DEFAULT_DISPLAY_HWC_DISPLAY_ID = 0;
@@ -139,20 +139,18 @@
EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64));
EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(AnyNumber());
- constexpr auto kConnectionType = ui::DisplayConnectionType::Internal;
- constexpr bool kIsPrimary = true;
-
auto compositionDisplay =
compositionengine::impl::createDisplay(mFlinger.getCompositionEngine(),
compositionengine::DisplayCreationArgsBuilder()
.setId(DEFAULT_DISPLAY_ID)
- .setConnectionType(kConnectionType)
.setPixels({DEFAULT_DISPLAY_WIDTH,
DEFAULT_DISPLAY_HEIGHT})
.setPowerAdvisor(&mPowerAdvisor)
.build());
- auto injector = FakeDisplayDeviceInjector(mFlinger, compositionDisplay, kConnectionType,
+ constexpr bool kIsPrimary = true;
+ auto injector = FakeDisplayDeviceInjector(mFlinger, compositionDisplay,
+ ui::DisplayConnectionType::Internal,
DEFAULT_DISPLAY_HWC_DISPLAY_ID, kIsPrimary);
injector.setNativeWindow(mNativeWindow);
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index de058a4..0f1cc67 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -267,11 +267,6 @@
.setPixels({WIDTH, HEIGHT})
.setPowerAdvisor(&test->mPowerAdvisor);
- const auto connectionType = CONNECTION_TYPE::value;
- if (connectionType) {
- ceDisplayArgs.setConnectionType(*connectionType);
- }
-
auto compositionDisplay =
compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
ceDisplayArgs.build());
@@ -279,7 +274,7 @@
auto injector =
TestableSurfaceFlinger::FakeDisplayDeviceInjector(test->mFlinger,
compositionDisplay,
- connectionType,
+ CONNECTION_TYPE::value,
HWC_DISPLAY_ID_OPT::value,
static_cast<bool>(PRIMARY));
@@ -388,7 +383,6 @@
auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
.setId(DisplayVariant::DISPLAY_ID::get())
- .setConnectionType(PhysicalDisplay::CONNECTION_TYPE)
.setPixels({DisplayVariant::WIDTH, DisplayVariant::HEIGHT})
.setIsSecure(static_cast<bool>(DisplayVariant::SECURE))
.setPowerAdvisor(&test->mPowerAdvisor)
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 4ff7592..28d0222 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -41,10 +41,13 @@
namespace {
-constexpr PhysicalDisplayId INTERNAL_DISPLAY_ID(111);
-constexpr PhysicalDisplayId EXTERNAL_DISPLAY_ID(222);
-constexpr PhysicalDisplayId DISPLAY_ID_64BIT(0xabcd12349876fedcULL);
+constexpr PhysicalDisplayId INTERNAL_DISPLAY_ID = PhysicalDisplayId::fromPort(111u);
+constexpr PhysicalDisplayId EXTERNAL_DISPLAY_ID = PhysicalDisplayId::fromPort(222u);
+constexpr PhysicalDisplayId DISPLAY_ID_64BIT =
+ PhysicalDisplayId::fromEdid(0xffu, 0xffffu, 0xffff'ffffu);
+
constexpr std::chrono::duration VSYNC_PERIOD(16ms);
+
class MockVSyncSource : public VSyncSource {
public:
const char* getName() const override { return "test"; }
diff --git a/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp b/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp
new file mode 100644
index 0000000..0905cd1
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2021 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 <cstdint>
+#undef LOG_TAG
+#define LOG_TAG "FlagManagerTest"
+
+#include "FlagManager.h"
+
+#include <android-base/properties.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <server_configurable_flags/get_flags.h>
+#include <optional>
+
+namespace android {
+
+using testing::Return;
+
+class MockFlagManager : public FlagManager {
+public:
+ MockFlagManager() = default;
+ ~MockFlagManager() = default;
+
+ MOCK_METHOD(std::string, getServerConfigurableFlag, (const std::string& experimentFlagName),
+ (const, override));
+};
+
+class FlagManagerTest : public testing::Test {
+public:
+ FlagManagerTest();
+ ~FlagManagerTest() override;
+ std::unique_ptr<MockFlagManager> mFlagManager;
+
+ template <typename T>
+ T getValue(const std::string& experimentFlagName, std::optional<T> systemPropertyOpt,
+ T defaultValue);
+};
+
+FlagManagerTest::FlagManagerTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+ mFlagManager = std::make_unique<MockFlagManager>();
+}
+
+FlagManagerTest::~FlagManagerTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+template <typename T>
+T FlagManagerTest::getValue(const std::string& experimentFlagName,
+ std::optional<T> systemPropertyOpt, T defaultValue) {
+ return mFlagManager->getValue(experimentFlagName, systemPropertyOpt, defaultValue);
+}
+
+namespace {
+TEST_F(FlagManagerTest, getValue_bool_default) {
+ EXPECT_CALL(*mFlagManager, getServerConfigurableFlag).Times(1).WillOnce(Return(""));
+ const bool defaultValue = false;
+ std::optional<bool> systemPropertyValue = std::nullopt;
+ const bool result = FlagManagerTest::getValue("test_flag", systemPropertyValue, defaultValue);
+ ASSERT_EQ(result, defaultValue);
+}
+
+TEST_F(FlagManagerTest, getValue_bool_sysprop) {
+ const bool defaultValue = false;
+ std::optional<bool> systemPropertyValue = std::make_optional(true);
+ const bool result = FlagManagerTest::getValue("test_flag", systemPropertyValue, defaultValue);
+ ASSERT_EQ(result, true);
+}
+
+TEST_F(FlagManagerTest, getValue_bool_experiment) {
+ EXPECT_CALL(*mFlagManager, getServerConfigurableFlag).Times(1).WillOnce(Return("1"));
+ const bool defaultValue = false;
+ std::optional<bool> systemPropertyValue = std::nullopt;
+ const bool result = FlagManagerTest::getValue("test_flag", systemPropertyValue, defaultValue);
+ ASSERT_EQ(result, true);
+}
+
+TEST_F(FlagManagerTest, getValue_int32_default) {
+ EXPECT_CALL(*mFlagManager, getServerConfigurableFlag).Times(1).WillOnce(Return(""));
+ int32_t defaultValue = 30;
+ std::optional<int32_t> systemPropertyValue = std::nullopt;
+ int32_t result = FlagManagerTest::getValue("test_flag", systemPropertyValue, defaultValue);
+ ASSERT_EQ(result, defaultValue);
+}
+
+TEST_F(FlagManagerTest, getValue_int32_sysprop) {
+ int32_t defaultValue = 30;
+ std::optional<int32_t> systemPropertyValue = std::make_optional(10);
+ int32_t result = FlagManagerTest::getValue("test_flag", systemPropertyValue, defaultValue);
+ ASSERT_EQ(result, 10);
+}
+
+TEST_F(FlagManagerTest, getValue_int32_experiment) {
+ EXPECT_CALL(*mFlagManager, getServerConfigurableFlag).Times(1).WillOnce(Return("50"));
+ std::int32_t defaultValue = 30;
+ std::optional<std::int32_t> systemPropertyValue = std::nullopt;
+ std::int32_t result = FlagManagerTest::getValue("test_flag", systemPropertyValue, defaultValue);
+ ASSERT_EQ(result, 50);
+}
+
+TEST_F(FlagManagerTest, getValue_int64_default) {
+ EXPECT_CALL(*mFlagManager, getServerConfigurableFlag).Times(1).WillOnce(Return(""));
+ int64_t defaultValue = 30;
+ std::optional<int64_t> systemPropertyValue = std::nullopt;
+ int64_t result = getValue("flag_name", systemPropertyValue, defaultValue);
+ ASSERT_EQ(result, defaultValue);
+}
+
+TEST_F(FlagManagerTest, getValue_int64_sysprop) {
+ int64_t defaultValue = 30;
+ std::optional<int64_t> systemPropertyValue = std::make_optional(10);
+ int64_t result = getValue("flag_name", systemPropertyValue, defaultValue);
+ ASSERT_EQ(result, 10);
+}
+
+TEST_F(FlagManagerTest, getValue_int64_experiment) {
+ EXPECT_CALL(*mFlagManager, getServerConfigurableFlag).Times(1).WillOnce(Return("50"));
+ int64_t defaultValue = 30;
+ std::optional<int64_t> systemPropertyValue = std::nullopt;
+ int64_t result = getValue("flag_name", systemPropertyValue, defaultValue);
+ ASSERT_EQ(result, 50);
+}
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index 02ec7fc..bb21ad6 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -118,13 +118,15 @@
std::shared_ptr<RefreshRateConfigs> mConfigs = std::make_shared<
RefreshRateConfigs>(DisplayModes{DisplayMode::Builder(0)
.setId(DisplayModeId(0))
- .setPhysicalDisplayId(PhysicalDisplayId(0))
+ .setPhysicalDisplayId(
+ PhysicalDisplayId::fromPort(0))
.setVsyncPeriod(int32_t(LO_FPS_PERIOD))
.setGroup(0)
.build(),
DisplayMode::Builder(1)
.setId(DisplayModeId(1))
- .setPhysicalDisplayId(PhysicalDisplayId(0))
+ .setPhysicalDisplayId(
+ PhysicalDisplayId::fromPort(0))
.setVsyncPeriod(int32_t(HI_FPS_PERIOD))
.setGroup(0)
.build()},
diff --git a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
index 6916764..597e5e7 100644
--- a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
@@ -72,7 +72,8 @@
mIdleTimer->stop();
}
-TEST_F(OneShotTimerTest, resetTest) {
+// TODO(b/186417847) This test is flaky. Reenable once fixed.
+TEST_F(OneShotTimerTest, DISABLED_resetTest) {
fake::FakeClock* clock = new fake::FakeClock();
mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
mResetTimerCallback.getInvocable(),
@@ -94,7 +95,8 @@
EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
}
-TEST_F(OneShotTimerTest, resetBackToBackTest) {
+// TODO(b/186417847) This test is flaky. Reenable once fixed.
+TEST_F(OneShotTimerTest, DISABLED_resetBackToBackTest) {
fake::FakeClock* clock = new fake::FakeClock();
mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
mResetTimerCallback.getInvocable(),
@@ -144,7 +146,8 @@
EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
}
-TEST_F(OneShotTimerTest, idleTimerIdlesTest) {
+// TODO(b/186417847) This test is flaky. Reenable once fixed.
+TEST_F(OneShotTimerTest, DISABLED_idleTimerIdlesTest) {
fake::FakeClock* clock = new fake::FakeClock();
mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
mResetTimerCallback.getInvocable(),
@@ -169,7 +172,8 @@
EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
}
-TEST_F(OneShotTimerTest, timeoutCallbackExecutionTest) {
+// TODO(b/186417847) This test is flaky. Reenable once fixed.
+TEST_F(OneShotTimerTest, DISABLED_timeoutCallbackExecutionTest) {
fake::FakeClock* clock = new fake::FakeClock();
mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
mResetTimerCallback.getInvocable(),
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index c1dba2b..618c10d 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -98,9 +98,15 @@
static inline const DisplayModeId HWC_CONFIG_ID_30 = DisplayModeId(4);
static inline const DisplayModeId HWC_CONFIG_ID_25 = DisplayModeId(5);
static inline const DisplayModeId HWC_CONFIG_ID_50 = DisplayModeId(6);
+ static inline const DisplayModeId HWC_CONFIG_ID_24 = DisplayModeId(7);
+ static inline const DisplayModeId HWC_CONFIG_ID_24_FRAC = DisplayModeId(8);
+ static inline const DisplayModeId HWC_CONFIG_ID_30_FRAC = DisplayModeId(9);
+ static inline const DisplayModeId HWC_CONFIG_ID_60_FRAC = DisplayModeId(10);
// Test configs
DisplayModePtr mConfig60 = createDisplayMode(HWC_CONFIG_ID_60, 0, Fps(60.0f).getPeriodNsecs());
+ DisplayModePtr mConfig60Frac =
+ createDisplayMode(HWC_CONFIG_ID_60_FRAC, 0, Fps(59.94f).getPeriodNsecs());
DisplayModePtr mConfig90 = createDisplayMode(HWC_CONFIG_ID_90, 0, Fps(90.0f).getPeriodNsecs());
DisplayModePtr mConfig90DifferentGroup =
createDisplayMode(HWC_CONFIG_ID_90, 1, Fps(90.0f).getPeriodNsecs());
@@ -116,9 +122,15 @@
DisplayModePtr mConfig30 = createDisplayMode(HWC_CONFIG_ID_30, 0, Fps(30.0f).getPeriodNsecs());
DisplayModePtr mConfig30DifferentGroup =
createDisplayMode(HWC_CONFIG_ID_30, 1, Fps(30.0f).getPeriodNsecs());
+ DisplayModePtr mConfig30Frac =
+ createDisplayMode(HWC_CONFIG_ID_30_FRAC, 0, Fps(29.97f).getPeriodNsecs());
+ DisplayModePtr mConfig25 = createDisplayMode(HWC_CONFIG_ID_25, 0, Fps(25.0f).getPeriodNsecs());
DisplayModePtr mConfig25DifferentGroup =
createDisplayMode(HWC_CONFIG_ID_25, 1, Fps(25.0f).getPeriodNsecs());
DisplayModePtr mConfig50 = createDisplayMode(HWC_CONFIG_ID_50, 0, Fps(50.0f).getPeriodNsecs());
+ DisplayModePtr mConfig24 = createDisplayMode(HWC_CONFIG_ID_24, 0, Fps(24.0f).getPeriodNsecs());
+ DisplayModePtr mConfig24Frac =
+ createDisplayMode(HWC_CONFIG_ID_24_FRAC, 0, Fps(23.976f).getPeriodNsecs());
// Test device configurations
// The positions of the configs in the arrays below MUST match their IDs. For example,
@@ -145,6 +157,11 @@
mConfig50};
DisplayModes m60_120Device = {mConfig60, mConfig120};
+ // This is a typical TV configuration.
+ DisplayModes m24_25_30_50_60WithFracDevice = {mConfig24, mConfig24Frac, mConfig25,
+ mConfig30, mConfig30Frac, mConfig50,
+ mConfig60, mConfig60Frac};
+
// Expected RefreshRate objects
RefreshRate mExpected60Config = {mConfig60, RefreshRate::ConstructorTag(0)};
RefreshRate mExpectedAlmost60Config = {createDisplayMode(HWC_CONFIG_ID_60, 0, 16666665),
@@ -181,7 +198,7 @@
int64_t vsyncPeriod, ui::Size resolution) {
return DisplayMode::Builder(hal::HWConfigId(modeId.value()))
.setId(modeId)
- .setPhysicalDisplayId(PhysicalDisplayId(0))
+ .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
.setVsyncPeriod(int32_t(vsyncPeriod))
.setGroup(group)
.setHeight(resolution.height)
@@ -332,10 +349,19 @@
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}),
- 0);
+ ASSERT_EQ(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}),
+ NO_ERROR);
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ // We select max even when this will cause a non-seamless switch.
+ refreshRateConfigs = std::make_unique<RefreshRateConfigs>(m60_90DeviceWithDifferentGroups,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+ ASSERT_EQ(refreshRateConfigs->setDisplayManagerPolicy(
+ {HWC_CONFIG_ID_90, /*allowGroupSwitching*/ true, {Fps(0), Fps(90)}}),
+ NO_ERROR);
+ EXPECT_EQ(mExpected90DifferentGroupConfig,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
}
TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_90) {
@@ -1230,7 +1256,109 @@
const auto& refreshRate =
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
EXPECT_TRUE(refreshRate.getFps().equalsWithMargin(Fps(test.second)))
- << "Expecting " << test.first << "fps => " << test.second << "Hz";
+ << "Expecting " << test.first << "fps => " << test.second << "Hz"
+ << " but it was " << refreshRate.getFps();
+ }
+}
+
+TEST_F(RefreshRateConfigsTest,
+ getBestRefreshRate_ExplicitExactOrMultiple_WithFractionalRefreshRates) {
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ // Test that 23.976 will choose 24 if 23.976 is not supported
+ {
+ android::DisplayModes modes = {mConfig24, mConfig25, mConfig30,
+ mConfig30Frac, mConfig60, mConfig60Frac};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ lr.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr.desiredRefreshRate = Fps(23.976f);
+ lr.name = "ExplicitExactOrMultiple 23.976 fps";
+ EXPECT_EQ(HWC_CONFIG_ID_24,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+ .getModeId());
+ }
+
+ // Test that 24 will choose 23.976 if 24 is not supported
+ {
+ android::DisplayModes modes = {mConfig24Frac, mConfig25, mConfig30,
+ mConfig30Frac, mConfig60, mConfig60Frac};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ lr.desiredRefreshRate = Fps(24.f);
+ lr.name = "ExplicitExactOrMultiple 24 fps";
+ EXPECT_EQ(HWC_CONFIG_ID_24_FRAC,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+ .getModeId());
+ }
+
+ // Test that 29.97 will prefer 59.94 over 60 and 30
+ {
+ android::DisplayModes modes = {mConfig24, mConfig24Frac, mConfig25,
+ mConfig30, mConfig60, mConfig60Frac};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ lr.desiredRefreshRate = Fps(29.97f);
+ lr.name = "ExplicitExactOrMultiple 29.97f fps";
+ EXPECT_EQ(HWC_CONFIG_ID_60_FRAC,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+ .getModeId());
+ }
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExact_WithFractionalRefreshRates) {
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ // Test that voting for supported refresh rate will select this refresh rate
+ {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m24_25_30_50_60WithFracDevice,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ for (auto desiredRefreshRate : {23.976f, 24.f, 25.f, 29.97f, 30.f, 50.f, 59.94f, 60.f}) {
+ lr.vote = LayerVoteType::ExplicitExact;
+ lr.desiredRefreshRate = Fps(desiredRefreshRate);
+ std::stringstream ss;
+ ss << "ExplicitExact " << desiredRefreshRate << " fps";
+ lr.name = ss.str();
+
+ auto selecteRefreshRate =
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
+
+ EXPECT_TRUE(selecteRefreshRate.getFps().equalsWithMargin(lr.desiredRefreshRate))
+ << "Expecting " << lr.desiredRefreshRate << " but it was "
+ << selecteRefreshRate.getFps();
+ }
+ }
+
+ // Test that 23.976 will choose 24 if 23.976 is not supported
+ {
+ android::DisplayModes modes = {mConfig24, mConfig25, mConfig30,
+ mConfig30Frac, mConfig60, mConfig60Frac};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ lr.vote = LayerVoteType::ExplicitExact;
+ lr.desiredRefreshRate = Fps(23.976f);
+ lr.name = "ExplicitExact 23.976 fps";
+ EXPECT_EQ(HWC_CONFIG_ID_24,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+ .getModeId());
+ }
+
+ // Test that 24 will choose 23.976 if 24 is not supported
+ {
+ android::DisplayModes modes = {mConfig24Frac, mConfig25, mConfig30,
+ mConfig30Frac, mConfig60, mConfig60Frac};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60);
+ lr.desiredRefreshRate = Fps(24.f);
+ lr.name = "ExplicitExact 24 fps";
+ EXPECT_EQ(HWC_CONFIG_ID_24_FRAC,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+ .getModeId());
}
}
@@ -2028,6 +2156,29 @@
refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
}
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_FractionalRefreshRates_ExactAndDefault) {
+ RefreshRateConfigs::Config config = {.enableFrameRateOverride = true};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m24_25_30_50_60WithFracDevice,
+ /*currentConfigId=*/HWC_CONFIG_ID_60, config);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 0.5f},
+ LayerRequirement{.weight = 0.5f}};
+ auto& explicitDefaultLayer = layers[0];
+ auto& explicitExactOrMultipleLayer = layers[1];
+
+ explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple;
+ explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple";
+ explicitExactOrMultipleLayer.desiredRefreshRate = Fps(60);
+
+ explicitDefaultLayer.vote = LayerVoteType::ExplicitDefault;
+ explicitDefaultLayer.name = "ExplicitDefault";
+ explicitDefaultLayer.desiredRefreshRate = Fps(59.94f);
+
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
TEST_F(RefreshRateConfigsTest, testComparisonOperator) {
EXPECT_TRUE(mExpected60Config < mExpected90Config);
EXPECT_FALSE(mExpected60Config < mExpected60Config);
@@ -2123,6 +2274,33 @@
EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(Fps(60.f), Fps(59.94f)));
}
+TEST_F(RefreshRateConfigsTest, isFractionalPairOrMultiple) {
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(23.976f), Fps(24.f)));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(24.f), Fps(23.976f)));
+
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(29.97f), Fps(30.f)));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(30.f), Fps(29.97f)));
+
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(59.94f), Fps(60.f)));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(60.f), Fps(59.94f)));
+
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(29.97f), Fps(60.f)));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(60.f), Fps(29.97f)));
+
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(59.94f), Fps(30.f)));
+ EXPECT_TRUE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(30.f), Fps(59.94f)));
+
+ const std::vector<float> refreshRates = {23.976f, 24.f, 25.f, 29.97f, 30.f, 50.f, 59.94f, 60.f};
+ for (auto refreshRate : refreshRates) {
+ EXPECT_FALSE(
+ RefreshRateConfigs::isFractionalPairOrMultiple(Fps(refreshRate), Fps(refreshRate)));
+ }
+
+ EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(24.f), Fps(25.f)));
+ EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(23.978f), Fps(25.f)));
+ EXPECT_FALSE(RefreshRateConfigs::isFractionalPairOrMultiple(Fps(29.97f), Fps(59.94f)));
+}
+
TEST_F(RefreshRateConfigsTest, getFrameRateOverrides_noLayers) {
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device, /*currentConfigId=*/
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index 12b155b..0a8759d 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -81,7 +81,7 @@
int64_t vsyncPeriod) {
return DisplayMode::Builder(static_cast<hal::HWConfigId>(modeId.value()))
.setId(modeId)
- .setPhysicalDisplayId(PhysicalDisplayId(0))
+ .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
.setVsyncPeriod(static_cast<int32_t>(vsyncPeriod))
.setGroup(group)
.build();
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 5713c2f..e2b3993 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -34,7 +34,7 @@
namespace android {
namespace {
-constexpr PhysicalDisplayId PHYSICAL_DISPLAY_ID(999);
+constexpr PhysicalDisplayId PHYSICAL_DISPLAY_ID = PhysicalDisplayId::fromPort(255u);
class SchedulerTest : public testing::Test {
protected:
@@ -53,13 +53,13 @@
const DisplayModePtr mode60 = DisplayMode::Builder(0)
.setId(DisplayModeId(0))
- .setPhysicalDisplayId(PhysicalDisplayId(0))
+ .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
.setVsyncPeriod(Fps(60.f).getPeriodNsecs())
.setGroup(0)
.build();
const DisplayModePtr mode120 = DisplayMode::Builder(1)
.setId(DisplayModeId(1))
- .setPhysicalDisplayId(PhysicalDisplayId(0))
+ .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
.setVsyncPeriod(Fps(120.f).getPeriodNsecs())
.setGroup(0)
.build();
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
similarity index 74%
rename from services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
rename to services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
index b713334..6959ee3 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
@@ -22,8 +22,7 @@
namespace android {
namespace {
-class HandleTransactionLockedTest : public DisplayTransactionTest {
-public:
+struct DisplayTransactionCommitTest : DisplayTransactionTest {
template <typename Case>
void setupCommonPreconditions();
@@ -55,7 +54,7 @@
};
template <typename Case>
-void HandleTransactionLockedTest::setupCommonPreconditions() {
+void DisplayTransactionCommitTest::setupCommonPreconditions() {
// Wide color displays support is configured appropriately
Case::WideColorSupport::injectConfigChange(this);
@@ -68,7 +67,7 @@
}
template <typename Case, bool connected>
-void HandleTransactionLockedTest::expectHotplugReceived(mock::EventThread* eventThread) {
+void DisplayTransactionCommitTest::expectHotplugReceived(mock::EventThread* eventThread) {
const auto convert = [](auto physicalDisplayId) {
return std::make_optional(DisplayId{physicalDisplayId});
};
@@ -79,7 +78,7 @@
}
template <typename Case>
-void HandleTransactionLockedTest::setupCommonCallExpectationsForConnectProcessing() {
+void DisplayTransactionCommitTest::setupCommonCallExpectationsForConnectProcessing() {
Case::Display::setupHwcHotplugCallExpectations(this);
Case::Display::setupFramebufferConsumerBufferQueueCallExpectations(this);
@@ -97,7 +96,7 @@
}
template <typename Case>
-void HandleTransactionLockedTest::setupCommonCallExpectationsForDisconnectProcessing() {
+void DisplayTransactionCommitTest::setupCommonCallExpectationsForDisconnectProcessing() {
EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
expectHotplugReceived<Case, false>(mEventThread);
@@ -105,7 +104,7 @@
}
template <typename Case>
-void HandleTransactionLockedTest::verifyDisplayIsConnected(const sp<IBinder>& displayToken) {
+void DisplayTransactionCommitTest::verifyDisplayIsConnected(const sp<IBinder>& displayToken) {
// The display device should have been set up in the list of displays.
ASSERT_TRUE(hasDisplayDevice(displayToken));
const auto& device = getDisplayDevice(displayToken);
@@ -137,7 +136,7 @@
}
template <typename Case>
-void HandleTransactionLockedTest::verifyPhysicalDisplayIsConnected() {
+void DisplayTransactionCommitTest::verifyPhysicalDisplayIsConnected() {
// HWComposer should have an entry for the display
EXPECT_TRUE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
@@ -150,14 +149,14 @@
verifyDisplayIsConnected<Case>(displayToken);
}
-void HandleTransactionLockedTest::verifyDisplayIsNotConnected(const sp<IBinder>& displayToken) {
+void DisplayTransactionCommitTest::verifyDisplayIsNotConnected(const sp<IBinder>& displayToken) {
EXPECT_FALSE(hasDisplayDevice(displayToken));
EXPECT_FALSE(hasCurrentDisplayState(displayToken));
EXPECT_FALSE(hasDrawingDisplayState(displayToken));
}
template <typename Case>
-void HandleTransactionLockedTest::processesHotplugConnectCommon() {
+void DisplayTransactionCommitTest::processesHotplugConnectCommon() {
// --------------------------------------------------------------------
// Preconditions
@@ -174,7 +173,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
@@ -191,7 +190,7 @@
}
template <typename Case>
-void HandleTransactionLockedTest::ignoresHotplugConnectCommon() {
+void DisplayTransactionCommitTest::ignoresHotplugConnectCommon() {
// --------------------------------------------------------------------
// Preconditions
@@ -203,7 +202,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
@@ -213,7 +212,7 @@
}
template <typename Case>
-void HandleTransactionLockedTest::processesHotplugDisconnectCommon() {
+void DisplayTransactionCommitTest::processesHotplugDisconnectCommon() {
// --------------------------------------------------------------------
// Preconditions
@@ -238,7 +237,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
@@ -255,18 +254,18 @@
verifyDisplayIsNotConnected(existing.token());
}
-TEST_F(HandleTransactionLockedTest, processesHotplugConnectPrimaryDisplay) {
+TEST_F(DisplayTransactionCommitTest, processesHotplugConnectPrimaryDisplay) {
processesHotplugConnectCommon<SimplePrimaryDisplayCase>();
}
-TEST_F(HandleTransactionLockedTest, processesHotplugConnectExternalDisplay) {
+TEST_F(DisplayTransactionCommitTest, processesHotplugConnectExternalDisplay) {
// Inject a primary display.
PrimaryDisplayVariant::injectHwcDisplay(this);
processesHotplugConnectCommon<SimpleExternalDisplayCase>();
}
-TEST_F(HandleTransactionLockedTest, ignoresHotplugConnectIfPrimaryAndExternalAlreadyConnected) {
+TEST_F(DisplayTransactionCommitTest, ignoresHotplugConnectIfPrimaryAndExternalAlreadyConnected) {
// Inject both a primary and external display.
PrimaryDisplayVariant::injectHwcDisplay(this);
ExternalDisplayVariant::injectHwcDisplay(this);
@@ -281,108 +280,119 @@
ignoresHotplugConnectCommon<SimpleTertiaryDisplayCase>();
}
-TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectPrimaryDisplay) {
- processesHotplugDisconnectCommon<SimplePrimaryDisplayCase>();
+TEST_F(DisplayTransactionCommitTest, processesHotplugDisconnectPrimaryDisplay) {
+ EXPECT_EXIT(processesHotplugDisconnectCommon<SimplePrimaryDisplayCase>(),
+ testing::KilledBySignal(SIGABRT), "Primary display cannot be disconnected.");
}
-TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectExternalDisplay) {
+TEST_F(DisplayTransactionCommitTest, processesHotplugDisconnectExternalDisplay) {
processesHotplugDisconnectCommon<SimpleExternalDisplayCase>();
}
-TEST_F(HandleTransactionLockedTest, processesHotplugConnectThenDisconnectPrimary) {
- using Case = SimplePrimaryDisplayCase;
+TEST_F(DisplayTransactionCommitTest, processesHotplugConnectThenDisconnectPrimary) {
+ EXPECT_EXIT(
+ [this] {
+ using Case = SimplePrimaryDisplayCase;
- // --------------------------------------------------------------------
- // Preconditions
+ // --------------------------------------------------------------------
+ // Preconditions
- setupCommonPreconditions<Case>();
+ setupCommonPreconditions<Case>();
- // A hotplug connect event is enqueued for a display
- Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
- // A hotplug disconnect event is also enqueued for the same display
- Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
+ // A hotplug connect event is enqueued for a display
+ Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
+ // A hotplug disconnect event is also enqueued for the same display
+ Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
- // --------------------------------------------------------------------
- // Call Expectations
+ // --------------------------------------------------------------------
+ // Call Expectations
- setupCommonCallExpectationsForConnectProcessing<Case>();
- setupCommonCallExpectationsForDisconnectProcessing<Case>();
+ setupCommonCallExpectationsForConnectProcessing<Case>();
+ setupCommonCallExpectationsForDisconnectProcessing<Case>();
- EXPECT_CALL(*mComposer,
- setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
- .WillOnce(Return(Error::NONE));
- EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mComposer,
+ setVsyncEnabled(Case::Display::HWC_DISPLAY_ID,
+ IComposerClient::Vsync::DISABLE))
+ .WillOnce(Return(Error::NONE));
+ EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
- // --------------------------------------------------------------------
- // Invocation
+ // --------------------------------------------------------------------
+ // Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
- // --------------------------------------------------------------------
- // Postconditions
+ // --------------------------------------------------------------------
+ // Postconditions
- // HWComposer should not have an entry for the display
- EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+ // HWComposer should not have an entry for the display
+ EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
- // SF should not have a display token.
- const auto displayId = Case::Display::DISPLAY_ID::get();
- ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
- ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 0);
+ // SF should not have a display token.
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
+ ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 0);
+ }(),
+ testing::KilledBySignal(SIGABRT), "Primary display cannot be disconnected.");
}
-TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectThenConnectPrimary) {
- using Case = SimplePrimaryDisplayCase;
+TEST_F(DisplayTransactionCommitTest, processesHotplugDisconnectThenConnectPrimary) {
+ EXPECT_EXIT(
+ [this] {
+ using Case = SimplePrimaryDisplayCase;
- // --------------------------------------------------------------------
- // Preconditions
+ // --------------------------------------------------------------------
+ // Preconditions
- setupCommonPreconditions<Case>();
+ setupCommonPreconditions<Case>();
- // The display is already completely set up.
- Case::Display::injectHwcDisplay(this);
- auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
- existing.inject();
+ // The display is already completely set up.
+ Case::Display::injectHwcDisplay(this);
+ auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
+ existing.inject();
- // A hotplug disconnect event is enqueued for a display
- Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
- // A hotplug connect event is also enqueued for the same display
- Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
+ // A hotplug disconnect event is enqueued for a display
+ Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
+ // A hotplug connect event is also enqueued for the same display
+ Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
- // --------------------------------------------------------------------
- // Call Expectations
+ // --------------------------------------------------------------------
+ // Call Expectations
- setupCommonCallExpectationsForConnectProcessing<Case>();
- setupCommonCallExpectationsForDisconnectProcessing<Case>();
+ setupCommonCallExpectationsForConnectProcessing<Case>();
+ setupCommonCallExpectationsForDisconnectProcessing<Case>();
- // --------------------------------------------------------------------
- // Invocation
+ // --------------------------------------------------------------------
+ // Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
- // --------------------------------------------------------------------
- // Postconditions
+ // --------------------------------------------------------------------
+ // Postconditions
- // The existing token should have been removed
- verifyDisplayIsNotConnected(existing.token());
- const auto displayId = Case::Display::DISPLAY_ID::get();
- ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
- ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 1);
- EXPECT_NE(existing.token(), mFlinger.mutablePhysicalDisplayTokens()[displayId]);
+ // The existing token should have been removed
+ verifyDisplayIsNotConnected(existing.token());
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
+ ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 1);
+ EXPECT_NE(existing.token(), mFlinger.mutablePhysicalDisplayTokens()[displayId]);
- // A new display should be connected in its place
+ // A new display should be connected in its place
- verifyPhysicalDisplayIsConnected<Case>();
+ verifyPhysicalDisplayIsConnected<Case>();
- // --------------------------------------------------------------------
- // Cleanup conditions
+ // --------------------------------------------------------------------
+ // Cleanup conditions
- EXPECT_CALL(*mComposer,
- setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
- .WillOnce(Return(Error::NONE));
- EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mComposer,
+ setVsyncEnabled(Case::Display::HWC_DISPLAY_ID,
+ IComposerClient::Vsync::DISABLE))
+ .WillOnce(Return(Error::NONE));
+ EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
+ }(),
+ testing::KilledBySignal(SIGABRT), "Primary display cannot be disconnected.");
}
-TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAdded) {
+TEST_F(DisplayTransactionCommitTest, processesVirtualDisplayAdded) {
using Case = HwcVirtualDisplayCase;
// --------------------------------------------------------------------
@@ -433,7 +443,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
@@ -453,7 +463,7 @@
mFlinger.mutableDrawingState().displays.removeItem(displayToken);
}
-TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAddedWithNoSurface) {
+TEST_F(DisplayTransactionCommitTest, processesVirtualDisplayAddedWithNoSurface) {
using Case = HwcVirtualDisplayCase;
// --------------------------------------------------------------------
@@ -479,7 +489,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
@@ -493,7 +503,7 @@
EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), draw.isVirtual());
}
-TEST_F(HandleTransactionLockedTest, processesVirtualDisplayRemoval) {
+TEST_F(DisplayTransactionCommitTest, processesVirtualDisplayRemoval) {
using Case = HwcVirtualDisplayCase;
// --------------------------------------------------------------------
@@ -511,7 +521,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
@@ -520,11 +530,11 @@
verifyDisplayIsNotConnected(existing.token());
}
-TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackChanges) {
+TEST_F(DisplayTransactionCommitTest, processesDisplayLayerStackChanges) {
using Case = NonHwcVirtualDisplayCase;
- constexpr uint32_t oldLayerStack = 0u;
- constexpr uint32_t newLayerStack = 123u;
+ constexpr ui::LayerStack oldLayerStack = ui::DEFAULT_LAYER_STACK;
+ constexpr ui::LayerStack newLayerStack{123u};
// --------------------------------------------------------------------
// Preconditions
@@ -540,7 +550,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
@@ -548,7 +558,7 @@
EXPECT_EQ(newLayerStack, display.mutableDisplayDevice()->getLayerStack());
}
-TEST_F(HandleTransactionLockedTest, processesDisplayTransformChanges) {
+TEST_F(DisplayTransactionCommitTest, processesDisplayTransformChanges) {
using Case = NonHwcVirtualDisplayCase;
constexpr ui::Rotation oldTransform = ui::ROTATION_0;
@@ -568,7 +578,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
@@ -576,7 +586,7 @@
EXPECT_EQ(newTransform, display.mutableDisplayDevice()->getOrientation());
}
-TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackRectChanges) {
+TEST_F(DisplayTransactionCommitTest, processesDisplayLayerStackRectChanges) {
using Case = NonHwcVirtualDisplayCase;
const Rect oldLayerStackRect(0, 0, 0, 0);
@@ -596,7 +606,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
@@ -604,7 +614,7 @@
EXPECT_EQ(newLayerStackRect, display.mutableDisplayDevice()->getLayerStackSpaceRect());
}
-TEST_F(HandleTransactionLockedTest, processesDisplayRectChanges) {
+TEST_F(DisplayTransactionCommitTest, processesDisplayRectChanges) {
using Case = NonHwcVirtualDisplayCase;
const Rect oldDisplayRect(0, 0);
@@ -624,7 +634,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
// --------------------------------------------------------------------
// Postconditions
@@ -632,7 +642,7 @@
EXPECT_EQ(newDisplayRect, display.mutableDisplayDevice()->getOrientedDisplaySpaceRect());
}
-TEST_F(HandleTransactionLockedTest, processesDisplayWidthChanges) {
+TEST_F(DisplayTransactionCommitTest, processesDisplayWidthChanges) {
using Case = NonHwcVirtualDisplayCase;
constexpr int oldWidth = 0;
@@ -674,10 +684,10 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
}
-TEST_F(HandleTransactionLockedTest, processesDisplayHeightChanges) {
+TEST_F(DisplayTransactionCommitTest, processesDisplayHeightChanges) {
using Case = NonHwcVirtualDisplayCase;
constexpr int oldWidth = 0;
@@ -719,10 +729,10 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
}
-TEST_F(HandleTransactionLockedTest, processesDisplaySizeDisplayRectAndLayerStackRectChanges) {
+TEST_F(DisplayTransactionCommitTest, processesDisplaySizeDisplayRectAndLayerStackRectChanges) {
using Case = NonHwcVirtualDisplayCase;
constexpr uint32_t kOldWidth = 567;
@@ -769,7 +779,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
EXPECT_EQ(display.mutableDisplayDevice()->getBounds(), kNewSize);
EXPECT_EQ(display.mutableDisplayDevice()->getWidth(), kNewWidth);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
index ef8b149..bafa910 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
@@ -63,15 +63,11 @@
// The primary display should have a current state
ASSERT_TRUE(hasCurrentDisplayState(primaryDisplay.token()));
const auto& primaryDisplayState = getCurrentDisplayState(primaryDisplay.token());
- // The layer stack state should be set to zero
- EXPECT_EQ(0u, primaryDisplayState.layerStack);
- // The orientation state should be set to zero
+
+ // The primary display state should be reset
+ EXPECT_EQ(ui::DEFAULT_LAYER_STACK, primaryDisplayState.layerStack);
EXPECT_EQ(ui::ROTATION_0, primaryDisplayState.orientation);
-
- // The orientedDisplaySpaceRect state should be set to INVALID
EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.orientedDisplaySpaceRect);
-
- // The layerStackSpaceRect state should be set to INVALID
EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.layerStackSpaceRect);
// The width and height should both be zero
@@ -99,4 +95,4 @@
}
} // namespace
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp
index fc40818..7d9e22b 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp
@@ -25,6 +25,8 @@
namespace android {
namespace {
+constexpr ui::LayerStack LAYER_STACK{456u};
+
class SetDisplayStateLockedTest : public DisplayTransactionTest {};
TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingWithUnknownDisplay) {
@@ -38,7 +40,7 @@
DisplayState state;
state.what = DisplayState::eLayerStackChanged;
state.token = displayToken;
- state.layerStack = 456;
+ state.layerStack = LAYER_STACK;
// --------------------------------------------------------------------
// Invocation
@@ -167,13 +169,13 @@
display.inject();
// The display has a layer stack set
- display.mutableCurrentDisplayState().layerStack = 456u;
+ display.mutableCurrentDisplayState().layerStack = LAYER_STACK;
// The incoming request sets the same layer stack
DisplayState state;
state.what = DisplayState::eLayerStackChanged;
state.token = display.token();
- state.layerStack = 456u;
+ state.layerStack = LAYER_STACK;
// --------------------------------------------------------------------
// Invocation
@@ -187,7 +189,7 @@
EXPECT_EQ(0u, flags);
// The current display state is unchanged
- EXPECT_EQ(456u, display.getCurrentDisplayState().layerStack);
+ EXPECT_EQ(LAYER_STACK, display.getCurrentDisplayState().layerStack);
}
TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfLayerStackChanged) {
@@ -201,13 +203,13 @@
display.inject();
// The display has a layer stack set
- display.mutableCurrentDisplayState().layerStack = 654u;
+ display.mutableCurrentDisplayState().layerStack = ui::LayerStack{LAYER_STACK.id + 1};
// The incoming request sets a different layer stack
DisplayState state;
state.what = DisplayState::eLayerStackChanged;
state.token = display.token();
- state.layerStack = 456u;
+ state.layerStack = LAYER_STACK;
// --------------------------------------------------------------------
// Invocation
@@ -221,7 +223,7 @@
EXPECT_EQ(eDisplayTransactionNeeded, flags);
// The desired display state has been set to the new value.
- EXPECT_EQ(456u, display.getCurrentDisplayState().layerStack);
+ EXPECT_EQ(LAYER_STACK, display.getCurrentDisplayState().layerStack);
}
TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingIfFlagsNotChanged) {
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
index e32c4bf..7ead0af 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
@@ -292,7 +292,9 @@
}
TEST_F(SetupNewDisplayDeviceInternalTest, createSimpleExternalDisplay) {
- setupNewDisplayDeviceInternalTest<SimpleExternalDisplayCase>();
+ // External displays must be secondary, as the primary display cannot be disconnected.
+ EXPECT_EXIT(setupNewDisplayDeviceInternalTest<SimpleExternalDisplayCase>(),
+ testing::KilledBySignal(SIGABRT), "Missing primary display");
}
TEST_F(SetupNewDisplayDeviceInternalTest, createNonHwcVirtualDisplay) {
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 40c881e..d8352ed 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -209,7 +209,7 @@
ISchedulerCallback* callback = nullptr, bool hasMultipleModes = false) {
DisplayModes modes{DisplayMode::Builder(0)
.setId(DisplayModeId(0))
- .setPhysicalDisplayId(PhysicalDisplayId(0))
+ .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
.setVsyncPeriod(16'666'667)
.setGroup(0)
.build()};
@@ -217,7 +217,7 @@
if (hasMultipleModes) {
modes.emplace_back(DisplayMode::Builder(1)
.setId(DisplayModeId(1))
- .setPhysicalDisplayId(PhysicalDisplayId(0))
+ .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
.setVsyncPeriod(11'111'111)
.setGroup(0)
.build());
@@ -316,9 +316,9 @@
dispSurface, producer);
}
- auto handleTransactionLocked(uint32_t transactionFlags) {
- Mutex::Autolock _l(mFlinger->mStateLock);
- return mFlinger->handleTransactionLocked(transactionFlags);
+ auto commitTransactionsLocked(uint32_t transactionFlags) {
+ Mutex::Autolock lock(mFlinger->mStateLock);
+ return mFlinger->commitTransactionsLocked(transactionFlags);
}
void onComposerHalHotplug(hal::HWDisplayId hwcDisplayId, hal::Connection connection) {
@@ -326,7 +326,7 @@
}
auto setDisplayStateLocked(const DisplayState& s) {
- Mutex::Autolock _l(mFlinger->mStateLock);
+ Mutex::Autolock lock(mFlinger->mStateLock);
return mFlinger->setDisplayStateLocked(s);
}
@@ -426,7 +426,7 @@
auto& mutableDisplays() { return mFlinger->mDisplays; }
auto& mutableDrawingState() { return mFlinger->mDrawingState; }
auto& mutableEventQueue() { return mFlinger->mEventQueue; }
- auto& mutableGeometryInvalid() { return mFlinger->mGeometryInvalid; }
+ auto& mutableGeometryDirty() { return mFlinger->mGeometryDirty; }
auto& mutableInterceptor() { return mFlinger->mInterceptor; }
auto& mutableMainThreadId() { return mFlinger->mMainThreadId; }
auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; }
@@ -439,8 +439,7 @@
auto& mutableHwcDisplayData() { return getHwComposer().mDisplayData; }
auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; }
- auto& mutableInternalHwcDisplayId() { return getHwComposer().mInternalHwcDisplayId; }
- auto& mutableExternalHwcDisplayId() { return getHwComposer().mExternalHwcDisplayId; }
+ auto& mutablePrimaryHwcDisplayId() { return getHwComposer().mPrimaryHwcDisplayId; }
auto& mutableUseFrameRateApi() { return mFlinger->useFrameRateApi; }
auto fromHandle(const sp<IBinder>& handle) {
@@ -600,13 +599,12 @@
LOG_ALWAYS_FATAL_IF(!physicalId);
flinger->mutableHwcPhysicalDisplayIdMap().emplace(mHwcDisplayId, *physicalId);
if (mIsPrimary) {
- flinger->mutableInternalHwcDisplayId() = mHwcDisplayId;
+ flinger->mutablePrimaryHwcDisplayId() = mHwcDisplayId;
} else {
- // If there is an external HWC display there should always be an internal ID
+ // If there is an external HWC display, there should always be a primary ID
// as well. Set it to some arbitrary value.
- auto& internalId = flinger->mutableInternalHwcDisplayId();
- if (!internalId) internalId = mHwcDisplayId - 1;
- flinger->mutableExternalHwcDisplayId() = mHwcDisplayId;
+ auto& primaryId = flinger->mutablePrimaryHwcDisplayId();
+ if (!primaryId) primaryId = mHwcDisplayId - 1;
}
}
}
@@ -645,7 +643,7 @@
DisplayModePtr activeMode =
DisplayMode::Builder(FakeHwcDisplayInjector::DEFAULT_ACTIVE_CONFIG)
.setId(mActiveModeId)
- .setPhysicalDisplayId(PhysicalDisplayId(0))
+ .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
.setWidth(FakeHwcDisplayInjector::DEFAULT_WIDTH)
.setHeight(FakeHwcDisplayInjector::DEFAULT_HEIGHT)
.setVsyncPeriod(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)
@@ -764,9 +762,9 @@
};
private:
+ void scheduleRefresh(FrameHint) override {}
void setVsyncEnabled(bool) override {}
void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ModeEvent) override {}
- void repaintEverythingForHWC() override {}
void kernelTimerChanged(bool) override {}
void triggerOnFrameRateOverridesChanged() {}
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp
index 7de1872..20d41e6 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp
@@ -18,6 +18,7 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#undef LOG_TAG
#define LOG_TAG "MockComposer"
#include "mock/DisplayHardware/MockComposer.h"
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
index ab19886..291559f 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h
@@ -23,20 +23,20 @@
namespace android::mock {
struct SchedulerCallback final : ISchedulerCallback {
+ MOCK_METHOD(void, scheduleRefresh, (FrameHint), (override));
MOCK_METHOD1(setVsyncEnabled, void(bool));
MOCK_METHOD2(changeRefreshRate,
void(const scheduler::RefreshRateConfigs::RefreshRate&,
scheduler::RefreshRateConfigEvent));
- MOCK_METHOD0(repaintEverythingForHWC, void());
MOCK_METHOD1(kernelTimerChanged, void(bool));
MOCK_METHOD0(triggerOnFrameRateOverridesChanged, void());
};
struct NoOpSchedulerCallback final : ISchedulerCallback {
+ void scheduleRefresh(FrameHint) override {}
void setVsyncEnabled(bool) override {}
void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&,
scheduler::RefreshRateConfigEvent) override {}
- void repaintEverythingForHWC() override {}
void kernelTimerChanged(bool) override {}
void triggerOnFrameRateOverridesChanged() {}
};
diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp
index 26052fb..33401d2 100644
--- a/vulkan/libvulkan/api_gen.cpp
+++ b/vulkan/libvulkan/api_gen.cpp
@@ -560,6 +560,7 @@
}
static const char* const known_non_device_names[] = {
+ "vkAcquireDrmDisplayEXT",
"vkCreateAndroidSurfaceKHR",
"vkCreateDebugReportCallbackEXT",
"vkCreateDebugUtilsMessengerEXT",
@@ -581,6 +582,7 @@
"vkEnumeratePhysicalDevices",
"vkGetDisplayModeProperties2KHR",
"vkGetDisplayPlaneCapabilities2KHR",
+ "vkGetDrmDisplayEXT",
"vkGetInstanceProcAddr",
"vkGetPhysicalDeviceCalibrateableTimeDomainsEXT",
"vkGetPhysicalDeviceDisplayPlaneProperties2KHR",
@@ -624,6 +626,8 @@
"vkGetPhysicalDeviceSurfacePresentModesKHR",
"vkGetPhysicalDeviceSurfaceSupportKHR",
"vkGetPhysicalDeviceToolPropertiesEXT",
+ "vkGetPhysicalDeviceVideoCapabilitiesKHR",
+ "vkGetPhysicalDeviceVideoFormatPropertiesKHR",
"vkSubmitDebugUtilsMessageEXT",
};
// clang-format on
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index d7fdab5..cf774fd 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -979,6 +979,8 @@
void QueryPresentationProperties(
VkPhysicalDevice physicalDevice,
VkPhysicalDevicePresentationPropertiesANDROID* presentation_properties) {
+ ATRACE_CALL();
+
// Request the android-specific presentation properties via GPDP2
VkPhysicalDeviceProperties2 properties = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
@@ -994,7 +996,17 @@
presentation_properties->pNext = nullptr;
presentation_properties->sharedImage = VK_FALSE;
- GetPhysicalDeviceProperties2(physicalDevice, &properties);
+ const auto& driver = GetData(physicalDevice).driver;
+
+ if (driver.GetPhysicalDeviceProperties2) {
+ // >= 1.1 driver, supports core GPDP2 entrypoint.
+ driver.GetPhysicalDeviceProperties2(physicalDevice, &properties);
+ } else if (driver.GetPhysicalDeviceProperties2KHR) {
+ // Old driver, but may support presentation properties
+ // if we have the GPDP2 extension. Otherwise, no presentation
+ // properties supported.
+ driver.GetPhysicalDeviceProperties2KHR(physicalDevice, &properties);
+ }
}
VkResult EnumerateDeviceExtensionProperties(
diff --git a/vulkan/scripts/generator_common.py b/vulkan/scripts/generator_common.py
index 72fd4fb..4176509 100644
--- a/vulkan/scripts/generator_common.py
+++ b/vulkan/scripts/generator_common.py
@@ -33,6 +33,7 @@
'VK_EXT_metal_surface',
'VK_FUCHSIA_imagepipe_surface',
'VK_GGP_stream_descriptor_surface',
+ 'VK_HUAWEI_subpass_shading',
'VK_KHR_display',
'VK_KHR_display_swapchain',
'VK_KHR_external_fence_win32',
@@ -47,11 +48,13 @@
'VK_MVK_ios_surface',
'VK_MVK_macos_surface',
'VK_NN_vi_surface',
+ 'VK_NV_acquire_winrt_display',
'VK_NV_cooperative_matrix',
'VK_NV_coverage_reduction_mode',
'VK_NV_external_memory_win32',
'VK_NV_win32_keyed_mutex',
'VK_NVX_image_view_handle',
+ 'VK_QNX_screen_surface',
]
# Extensions having functions exported by the loader.