diff options
145 files changed, 3777 insertions, 2755 deletions
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp index 783a475829..9a8ec32608 100644 --- a/cmds/atrace/atrace.cpp +++ b/cmds/atrace/atrace.cpp @@ -244,6 +244,7 @@ static const TracingCategory k_categories[] = { { 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/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp index cfd42fec30..3f7c7d6a7b 100644 --- a/cmds/surfacereplayer/replayer/Replayer.cpp +++ b/cmds/surfacereplayer/replayer/Replayer.cpp @@ -528,7 +528,7 @@ void Replayer::setTransparentRegionHint(SurfaceComposerClient::Transaction& t, 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::setDisplaySurface(SurfaceComposerClient::Transaction& t, 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/include/android/input.h b/include/android/input.h index bb98beb41a..f03facb929 100644 --- a/include/android/input.h +++ b/include/android/input.h @@ -169,6 +169,9 @@ enum { /** Drag event */ AINPUT_EVENT_TYPE_DRAG = 5, + + /** TouchMode event */ + AINPUT_EVENT_TYPE_TOUCH_MODE = 6, }; /** diff --git a/include/ftl/cast.h b/include/ftl/cast.h new file mode 100644 index 0000000000..ff1b58ad56 --- /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 0000000000..87b9f1e20a --- /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/small_map.h b/include/ftl/small_map.h index 84c15ebdca..bcaba82934 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 @@ namespace android::ftl { // 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 @@ namespace android::ftl { // 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 @@ class SmallMap final { // 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 @@ class SmallMap final { 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 @@ class SmallMap final { // 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 @@ class SmallMap final { // // 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 @@ class SmallMap final { } 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 @@ bool operator==(const SmallMap<K, V, N>& lhs, const SmallMap<Q, W, M>& rhs) { 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 cb0ae359eb..0341435813 100644 --- a/include/ftl/small_vector.h +++ b/include/ftl/small_vector.h @@ -348,7 +348,7 @@ class SmallVector<T, 0> final : ArrayTraits<T>, 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 0000000000..2d96b06a2f --- /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/Input.h b/include/input/Input.h index cd110e8c39..2e424097e1 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -369,8 +369,6 @@ struct PointerCoords { 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. @@ -888,6 +886,25 @@ protected: 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 +969,7 @@ public: virtual FocusEvent* createFocusEvent() = 0; virtual CaptureEvent* createCaptureEvent() = 0; virtual DragEvent* createDragEvent() = 0; + virtual TouchModeEvent* createTouchModeEvent() = 0; }; /* @@ -968,6 +986,7 @@ public: 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 +994,7 @@ private: FocusEvent mFocusEvent; CaptureEvent mCaptureEvent; DragEvent mDragEvent; + TouchModeEvent mTouchModeEvent; }; /* @@ -990,6 +1010,7 @@ public: virtual FocusEvent* createFocusEvent() override; virtual CaptureEvent* createCaptureEvent() override; virtual DragEvent* createDragEvent() override; + virtual TouchModeEvent* createTouchModeEvent() override; void recycle(InputEvent* event); @@ -1001,6 +1022,7 @@ private: 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; }; } // namespace android diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index a790b5637f..9a150eb0e2 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -72,6 +72,7 @@ struct InputMessage { CAPTURE, DRAG, TIMELINE, + TOUCH_MODE, }; struct Header { @@ -206,6 +207,15 @@ struct InputMessage { 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 +398,15 @@ public: */ 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 +677,7 @@ private: 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/libs/binder/Android.bp b/libs/binder/Android.bp index 2825273333..20bf30122d 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -286,6 +286,9 @@ filegroup { "aidl/android/content/pm/IPackageChangeObserver.aidl", "aidl/android/content/pm/IPackageManagerNative.aidl", "aidl/android/content/pm/PackageChangeEvent.aidl", + "aidl/android/content/pm/IStagedApexObserver.aidl", + "aidl/android/content/pm/ApexStagedEvent.aidl", + "aidl/android/content/pm/StagedApexInfo.aidl", ], path: "aidl", } diff --git a/libs/binder/aidl/android/content/pm/ApexStagedEvent.aidl b/libs/binder/aidl/android/content/pm/ApexStagedEvent.aidl new file mode 100644 index 0000000000..75f87530f9 --- /dev/null +++ b/libs/binder/aidl/android/content/pm/ApexStagedEvent.aidl @@ -0,0 +1,27 @@ +/* + * 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 android.content.pm; + +/** + * This event is designed for notification to native code listener about + * any changes to set of apex packages staged for installation on next boot. + * + * @hide + */ +parcelable ApexStagedEvent { + @utf8InCpp String[] stagedApexModuleNames; +} diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl index c20d9f6645..d71f496bf1 100644 --- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl +++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl @@ -18,6 +18,8 @@ package android.content.pm; import android.content.pm.IPackageChangeObserver; +import android.content.pm.IStagedApexObserver; +import android.content.pm.StagedApexInfo; /** * Parallel implementation of certain {@link PackageManager} APIs that need to @@ -123,4 +125,24 @@ interface IPackageManagerNative { * requested version. */ boolean hasSystemFeature(in String featureName, in int version); + + /** Register a observer for change in set of staged APEX ready for installation */ + void registerStagedApexObserver(in IStagedApexObserver observer); + + /** + * Unregister an existing staged apex observer. + * This does nothing if this observer was not already registered. + */ + void unregisterStagedApexObserver(in IStagedApexObserver observer); + + /** + * Get APEX module names of all APEX that are staged ready for installation + */ + @utf8InCpp String[] getStagedApexModuleNames(); + + /** + * Get information of APEX which is staged ready for installation. + * Returns null if no such APEX is found. + */ + StagedApexInfo getStagedApexInfo(in @utf8InCpp String moduleName); } diff --git a/libs/ui/Size.cpp b/libs/binder/aidl/android/content/pm/IStagedApexObserver.aidl index d2996d164d..9906436acf 100644 --- a/libs/ui/Size.cpp +++ b/libs/binder/aidl/android/content/pm/IStagedApexObserver.aidl @@ -1,5 +1,5 @@ /* - * Copyright 2019 The Android Open Source Project + * 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. @@ -14,11 +14,15 @@ * limitations under the License. */ -#include <ui/Size.h> +package android.content.pm; -namespace android::ui { +import android.content.pm.ApexStagedEvent; -const Size Size::INVALID{-1, -1}; -const Size Size::EMPTY{0, 0}; - -} // namespace android::ui +/** + * This is a non-blocking notification when set of staged apex has changed + * + * @hide + */ +oneway interface IStagedApexObserver { + void onApexStaged(in ApexStagedEvent event); +} diff --git a/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl b/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl new file mode 100644 index 0000000000..ece79895f7 --- /dev/null +++ b/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl @@ -0,0 +1,30 @@ +/* + * 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 android.content.pm; + +/** + * This object is designed for returning information regarding + * staged APEX that are ready to be installed on next reboot. + * + * @hide + */ +parcelable StagedApexInfo { + @utf8InCpp String moduleName; + @utf8InCpp String diskImagePath; + long versionCode; + @utf8InCpp String versionName; +} diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp index 2524c5f6d2..3026921044 100644 --- a/libs/ftl/Android.bp +++ b/libs/ftl/Android.bp @@ -14,12 +14,14 @@ cc_test { address: true, }, srcs: [ + "cast_test.cpp", "Flags_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/cast_test.cpp b/libs/ftl/cast_test.cpp new file mode 100644 index 0000000000..2abcb8fe66 --- /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/small_map_test.cpp b/libs/ftl/small_map_test.cpp index 323b9f91e7..2e81022f38 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 @@ TEST(SmallMap, Example) { 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, Construct) { } } +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 0000000000..f3d85c8319 --- /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/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index d54de4999c..7f0cac5d4f 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -343,80 +343,6 @@ void* GraphicsEnv::loadLibrary(std::string name) { return nullptr; } -bool GraphicsEnv::checkAngleRules(void* so) { - auto manufacturer = base::GetProperty("ro.product.manufacturer", "UNSET"); - auto model = base::GetProperty("ro.product.model", "UNSET"); - - auto ANGLEGetFeatureSupportUtilAPIVersion = - (fpANGLEGetFeatureSupportUtilAPIVersion)dlsym(so, - "ANGLEGetFeatureSupportUtilAPIVersion"); - - if (!ANGLEGetFeatureSupportUtilAPIVersion) { - ALOGW("Cannot find ANGLEGetFeatureSupportUtilAPIVersion function"); - return false; - } - - // Negotiate the interface version by requesting most recent known to the platform - unsigned int versionToUse = CURRENT_ANGLE_API_VERSION; - if (!(ANGLEGetFeatureSupportUtilAPIVersion)(&versionToUse)) { - ALOGW("Cannot use ANGLE feature-support library, it is older than supported by EGL, " - "requested version %u", - versionToUse); - return false; - } - - // Add and remove versions below as needed - bool useAngle = false; - switch (versionToUse) { - case 2: { - ALOGV("Using version %d of ANGLE feature-support library", versionToUse); - void* rulesHandle = nullptr; - int rulesVersion = 0; - void* systemInfoHandle = nullptr; - - // Get the symbols for the feature-support-utility library: -#define GET_SYMBOL(symbol) \ - fp##symbol symbol = (fp##symbol)dlsym(so, #symbol); \ - if (!symbol) { \ - ALOGW("Cannot find " #symbol " in ANGLE feature-support library"); \ - break; \ - } - GET_SYMBOL(ANGLEAndroidParseRulesString); - GET_SYMBOL(ANGLEGetSystemInfo); - GET_SYMBOL(ANGLEAddDeviceInfoToSystemInfo); - GET_SYMBOL(ANGLEShouldBeUsedForApplication); - GET_SYMBOL(ANGLEFreeRulesHandle); - GET_SYMBOL(ANGLEFreeSystemInfoHandle); - - // Parse the rules, obtain the SystemInfo, and evaluate the - // application against the rules: - if (!(ANGLEAndroidParseRulesString)(mRulesBuffer.data(), &rulesHandle, &rulesVersion)) { - ALOGW("ANGLE feature-support library cannot parse rules file"); - break; - } - if (!(ANGLEGetSystemInfo)(&systemInfoHandle)) { - ALOGW("ANGLE feature-support library cannot obtain SystemInfo"); - break; - } - if (!(ANGLEAddDeviceInfoToSystemInfo)(manufacturer.c_str(), model.c_str(), - systemInfoHandle)) { - ALOGW("ANGLE feature-support library cannot add device info to SystemInfo"); - break; - } - useAngle = (ANGLEShouldBeUsedForApplication)(rulesHandle, rulesVersion, - systemInfoHandle, mAngleAppName.c_str()); - (ANGLEFreeRulesHandle)(rulesHandle); - (ANGLEFreeSystemInfoHandle)(systemInfoHandle); - } break; - - default: - ALOGW("Version %u of ANGLE feature-support library is NOT supported.", versionToUse); - } - - ALOGV("Close temporarily-loaded ANGLE opt-in/out logic"); - return useAngle; -} - bool GraphicsEnv::shouldUseAngle(std::string appName) { if (appName != mAngleAppName) { // Make sure we are checking the app we were init'ed for @@ -444,31 +370,20 @@ void GraphicsEnv::updateUseAngle() { const char* ANGLE_PREFER_ANGLE = "angle"; const char* ANGLE_PREFER_NATIVE = "native"; + mUseAngle = NO; if (mAngleDeveloperOptIn == ANGLE_PREFER_ANGLE) { ALOGV("User set \"Developer Options\" to force the use of ANGLE"); mUseAngle = YES; } else if (mAngleDeveloperOptIn == ANGLE_PREFER_NATIVE) { ALOGV("User set \"Developer Options\" to force the use of Native"); - mUseAngle = NO; } else { - // The "Developer Options" value wasn't set to force the use of ANGLE. Need to temporarily - // load ANGLE and call the updatable opt-in/out logic: - void* featureSo = loadLibrary("feature_support"); - if (featureSo) { - ALOGV("loaded ANGLE's opt-in/out logic from namespace"); - mUseAngle = checkAngleRules(featureSo) ? YES : NO; - dlclose(featureSo); - featureSo = nullptr; - } else { - ALOGV("Could not load the ANGLE opt-in/out logic, cannot use ANGLE."); - } + ALOGV("User set invalid \"Developer Options\": '%s'", mAngleDeveloperOptIn.c_str()); } } void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName, const std::string developerOptIn, - const std::vector<std::string> eglFeatures, const int rulesFd, - const long rulesOffset, const long rulesLength) { + const std::vector<std::string> eglFeatures) { if (mUseAngle != UNKNOWN) { // We've already figured out an answer for this app, so just return. ALOGV("Already evaluated the rules file for '%s': use ANGLE = %s", appName.c_str(), @@ -485,22 +400,6 @@ void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName ALOGV("setting ANGLE application opt-in to '%s'", developerOptIn.c_str()); mAngleDeveloperOptIn = developerOptIn; - lseek(rulesFd, rulesOffset, SEEK_SET); - mRulesBuffer = std::vector<char>(rulesLength + 1); - ssize_t numBytesRead = read(rulesFd, mRulesBuffer.data(), rulesLength); - if (numBytesRead < 0) { - ALOGE("Cannot read rules file: numBytesRead = %zd", numBytesRead); - numBytesRead = 0; - } else if (numBytesRead == 0) { - ALOGW("Empty rules file"); - } - if (numBytesRead != rulesLength) { - ALOGW("Did not read all of the necessary bytes from the rules file." - "expected: %ld, got: %zd", - rulesLength, numBytesRead); - } - mRulesBuffer[numBytesRead] = '\0'; - // Update the current status of whether we should use ANGLE or not updateUseAngle(); } diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index 900fc49b59..56d1139f57 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -97,8 +97,7 @@ public: // in the search path must have a '!' after the zip filename, e.g. // /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a void setAngleInfo(const std::string path, const std::string appName, std::string devOptIn, - const std::vector<std::string> eglFeatures, const int rulesFd, - const long rulesOffset, const long rulesLength); + const std::vector<std::string> eglFeatures); // Get the ANGLE driver namespace. android_namespace_t* getAngleNamespace(); // Get the app name for ANGLE debug message. @@ -129,8 +128,6 @@ private: // Load requested ANGLE library. void* loadLibrary(std::string name); - // Check ANGLE support with the rules. - bool checkAngleRules(void* so); // Update whether ANGLE should be used. void updateUseAngle(); // Link updatable driver namespace with llndk and vndk-sp libs. @@ -159,8 +156,6 @@ private: std::string mAngleDeveloperOptIn; // ANGLE EGL features; std::vector<std::string> mAngleEglFeatures; - // ANGLE rules. - std::vector<char> mRulesBuffer; // Use ANGLE flag. UseAngle mUseAngle = UNKNOWN; // Vulkan debug layers libs. diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 2a980bd118..3bf63062f6 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -124,11 +124,11 @@ public: 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 @@ public: 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 @@ status_t BnSurfaceComposer::onTransact( } 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 @@ status_t BnSurfaceComposer::onTransact( } 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 8a7a8711bf..1fd9d13902 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -41,7 +41,6 @@ layer_state_t::layer_state_t() z(0), w(0), h(0), - layerStack(0), alpha(0), flags(0), mask(0), @@ -86,7 +85,7 @@ status_t layer_state_t::write(Parcel& output) const 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 @@ status_t layer_state_t::read(const Parcel& input) 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 @@ status_t ComposerState::read(const Parcel& input) { 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 @@ status_t DisplayState::read(const Parcel& input) { 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 @@ void layer_state_t::merge(const layer_state_t& other) { 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 dc71b6a212..05554cab94 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1095,7 +1095,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAlpha } 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; @@ -1760,7 +1760,7 @@ status_t SurfaceComposerClient::Transaction::setDisplaySurface(const sp<IBinder> } 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; @@ -2184,12 +2184,12 @@ status_t ScreenshotClient::captureDisplay(const DisplayCaptureArgs& captureArgs, 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/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index ad7bcb7d12..b7cd082da0 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -116,6 +116,11 @@ public: 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 @@ public: * 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 8dc8b9a87b..f14127c9de 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 @@ struct layer_state_t { 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 @@ struct DisplayState { 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 @@ struct DisplayState { // 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 1d758e0dde..a980ce24ca 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -456,7 +456,7 @@ public: 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 @@ public: 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 @@ private: 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/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 9082d275a2..26d902d849 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -128,7 +128,7 @@ protected: 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 @@ protected: 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 @@ TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { 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 @@ TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToBufferSize) { 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 @@ TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToWindowSize) { 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 @@ TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) { 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/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index a02970c9bc..d1ad478dd1 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -752,21 +752,19 @@ public: } 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/input/Input.cpp b/libs/input/Input.cpp index 35209f7a07..1e8ff945ef 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -170,6 +170,9 @@ const char* inputEventTypeToString(int32_t type) { case AINPUT_EVENT_TYPE_DRAG: { return "DRAG"; } + case AINPUT_EVENT_TYPE_TOUCH_MODE: { + return "TOUCH_MODE"; + } } return "UNKNOWN"; } @@ -330,10 +333,6 @@ void PointerCoords::scale(float globalScaleFactor, float windowXScale, float win 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); @@ -899,6 +898,19 @@ void DragEvent::initialize(const DragEvent& from) { 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 @@ DragEvent* PooledInputEventFactory::createDragEvent() { 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/InputTransport.cpp b/libs/input/InputTransport.cpp index ea8b9a7ec8..1e93dfb488 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -116,6 +116,7 @@ bool InputMessage::isValid(size_t actualSize) const { 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 @@ size_t InputMessage::size() const { 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 @@ void InputMessage::getSanitizedCopy(InputMessage* msg) const { 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 @@ status_t InputPublisher::publishDragEvent(uint32_t seq, int32_t eventId, float x 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__); @@ -866,6 +889,16 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consum *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 @@ void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage 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]; @@ -1476,6 +1513,11 @@ std::string InputConsumer::dump() const { 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/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index 5d1f2c3bfc..8db5bf1289 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -56,6 +56,7 @@ protected: void PublishAndConsumeFocusEvent(); void PublishAndConsumeCaptureEvent(); void PublishAndConsumeDragEvent(); + void PublishAndConsumeTouchModeEvent(); }; TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) { @@ -413,6 +414,46 @@ void InputPublisherAndConsumerTest::PublishAndConsumeDragEvent() { << "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 @@ TEST_F(InputPublisherAndConsumerTest, PublishDragEvent_EndToEnd) { 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 @@ TEST_F(InputPublisherAndConsumerTest, PublishMultipleEvents_EndToEnd) { 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 59fed1fb41..18289a5f11 100644 --- a/libs/input/tests/StructLayout_test.cpp +++ b/libs/input/tests/StructLayout_test.cpp @@ -102,6 +102,10 @@ void TestInputMessageAlignment() { 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 @@ void TestBodySize() { 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 2dd6c4fcaa..6a14d4f3d1 100644 --- a/libs/nativedisplay/AChoreographer.cpp +++ b/libs/nativedisplay/AChoreographer.cpp @@ -305,8 +305,9 @@ void Choreographer::scheduleLatestConfigRequest() { // 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 6eaa84e225..bac44c978a 100644 --- a/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h +++ b/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h @@ -272,10 +272,11 @@ public: 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 85fe42f6fd..e85009c206 100644 --- a/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h +++ b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h @@ -84,10 +84,11 @@ typedef int (*ASurfaceTexture_fenceWait)(int fence, void* fencePassThroughHandle */ 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 62db6d069f..3535e67895 100644 --- a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp +++ b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp @@ -464,10 +464,11 @@ void SurfaceTexture::dumpLocked(String8& result, const char* prefix) const { } 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 @@ sp<GraphicBuffer> SurfaceTexture::dequeueBuffer(int* outSlotid, android_dataspac 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 c214ab7718..cc0a12d2c6 100644 --- a/libs/nativedisplay/surfacetexture/surface_texture.cpp +++ b/libs/nativedisplay/surfacetexture/surface_texture.cpp @@ -194,15 +194,18 @@ void ASurfaceTexture_releaseConsumerOwnership(ASurfaceTexture* texture) { 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 d93a84cd25..d5e7cb299b 100644 --- a/libs/nativewindow/include/android/hardware_buffer.h +++ b/libs/nativewindow/include/android/hardware_buffer.h @@ -556,6 +556,7 @@ int AHardwareBuffer_lockAndGetInfo(AHardwareBuffer* _Nonnull buffer, uint64_t us int32_t* _Nonnull outBytesPerPixel, int32_t* _Nonnull outBytesPerStride) __INTRODUCED_IN(29); + /** * Get the system wide unique id for an AHardwareBuffer. * diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index 467f848237..b1e1014fe4 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -1156,10 +1156,6 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, 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) diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h index 53fa622ad8..d395d06b95 100644 --- a/libs/renderengine/include/renderengine/DisplaySettings.h +++ b/libs/renderengine/include/renderengine/DisplaySettings.h @@ -51,10 +51,6 @@ struct DisplaySettings { // 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 @@ struct DisplaySettings { 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 @@ static inline void PrintTo(const DisplaySettings& settings, ::std::ostream* os) 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/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp index ae8f2384c4..01df6a69e5 100644 --- a/libs/renderengine/skia/Cache.cpp +++ b/libs/renderengine/skia/Cache.cpp @@ -95,25 +95,28 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin .alpha = 1, }; + base::unique_fd drawFence; 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(), &drawFence); } } @@ -138,6 +141,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting }}, }; + base::unique_fd drawFence; auto layers = std::vector<const LayerSettings*>{&layer}; for (auto dataspace : {kDestDataSpace, kOtherDataSpace}) { layer.sourceDataspace = dataspace; @@ -151,7 +155,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting for (auto alpha : {half(.2f), half(1.0f)}) { layer.alpha = alpha; renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, - base::unique_fd(), nullptr); + base::unique_fd(), &drawFence); } } } @@ -174,13 +178,14 @@ static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySetting .alpha = 0.5, }; + base::unique_fd drawFence; auto layers = std::vector<const LayerSettings*>{&layer}; for (auto transform : {mat4(), kScaleAndTranslate}) { layer.geometry.positionTransform = transform; for (float roundedCornersRadius : {0.0f, 50.f}) { layer.geometry.roundedCornersRadius = roundedCornersRadius; renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, - base::unique_fd(), nullptr); + base::unique_fd(), &drawFence); } } } @@ -199,12 +204,13 @@ static void drawBlurLayers(SkiaRenderEngine* renderengine, const DisplaySettings .skipContentDraw = true, }; + base::unique_fd drawFence; auto layers = std::vector<const LayerSettings*>{&layer}; // Different blur code is invoked for radii less and greater than 30 pixels for (int radius : {9, 60}) { layer.backgroundBlurRadius = radius; renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, - base::unique_fd(), nullptr); + base::unique_fd(), &drawFence); } } @@ -240,6 +246,7 @@ static void drawClippedLayers(SkiaRenderEngine* renderengine, const DisplaySetti }, }; + base::unique_fd drawFence; auto layers = std::vector<const LayerSettings*>{&layer}; for (auto pixelSource : {bufferSource, bufferOpaque, colorSource}) { layer.source = pixelSource; @@ -251,7 +258,7 @@ static void drawClippedLayers(SkiaRenderEngine* renderengine, const DisplaySetti for (float alpha : {0.5f, 1.f}) { layer.alpha = alpha, renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, - base::unique_fd(), nullptr); + base::unique_fd(), &drawFence); } } } @@ -287,9 +294,10 @@ static void drawPIPImageLayer(SkiaRenderEngine* renderengine, const DisplaySetti }; + base::unique_fd drawFence; auto layers = std::vector<const LayerSettings*>{&layer}; renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, - base::unique_fd(), nullptr); + base::unique_fd(), &drawFence); } static void drawHolePunchLayer(SkiaRenderEngine* renderengine, const DisplaySettings& display, @@ -316,9 +324,10 @@ static void drawHolePunchLayer(SkiaRenderEngine* renderengine, const DisplaySett }; + base::unique_fd drawFence; auto layers = std::vector<const LayerSettings*>{&layer}; renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, - base::unique_fd(), nullptr); + base::unique_fd(), &drawFence); } // @@ -381,6 +390,7 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { ExternalTexture::Usage::WRITEABLE); drawHolePunchLayer(renderengine, display, dstTexture); drawSolidLayers(renderengine, display, dstTexture); + drawShadowLayers(renderengine, display, srcTexture); drawShadowLayers(renderengine, p3Display, srcTexture); @@ -421,6 +431,14 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { 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}; + renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, + base::unique_fd(), nullptr); // null drawFence makes it synchronous + 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 f4b07d06a5..9fbbdc34ba 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -812,28 +812,6 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, 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()); @@ -1149,6 +1127,73 @@ inline SkRect SkiaGLRenderEngine::getSkRect(const Rect& rect) { 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) { @@ -1166,66 +1211,20 @@ inline std::pair<SkRRect, SkRRect> SkiaGLRenderEngine::getBoundsAndClip(const Fl // 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/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index 33e3773d50..33053a0a61 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -524,10 +524,6 @@ public: void fillGreenColorBufferThenClearRegion(); - void clearLeftRegion(); - - void clearRegion(); - template <typename SourceVariant> void drawShadow(const renderengine::LayerSettings& castingLayer, const renderengine::ShadowSettings& shadow, const ubyte4& casterColor, @@ -1195,28 +1191,6 @@ void RenderEngineTest::fillBufferWithoutPremultiplyAlpha() { 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, @@ -1647,11 +1621,6 @@ TEST_P(RenderEngineTest, drawLayers_fillBuffer_withoutPremultiplyingAlpha) { fillBufferWithoutPremultiplyAlpha(); } -TEST_P(RenderEngineTest, drawLayers_clearRegion) { - initializeRenderEngine(); - clearRegion(); -} - TEST_P(RenderEngineTest, drawLayers_fillShadow_castsWithoutCasterLayer) { initializeRenderEngine(); @@ -1900,6 +1869,40 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCrop) { 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/ui/Android.bp b/libs/ui/Android.bp index eed58c5715..ba5a64f317 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -137,7 +137,6 @@ cc_library_shared { "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 f196ab901a..9120972a42 100644 --- a/libs/ui/include/ui/DisplayId.h +++ b/libs/ui/include/ui/DisplayId.h @@ -38,12 +38,22 @@ struct DisplayId { 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 @@ struct PhysicalDisplayId : DisplayId { // 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 @@ private: 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 @@ private: 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 70a0d50611..98ee35652a 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 0000000000..d6ffeb7fad --- /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 f1e825286e..ecc192dcae 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; } + // Valid means non-negative width and height + bool isValid() const { return width >= 0 && height >= 0; } + + // Empty means zero width and height + bool isEmpty() const; + template <typename T> - void setWidth(T&& v) { - width = Size::clamp<int32_t, T>(std::forward<T>(v)); + void setWidth(T v) { + width = clamp<int32_t>(v); } + template <typename T> - void setHeight(T&& v) { - height = Size::clamp<int32_t, T>(std::forward<T>(v)); + void setHeight(T v) { + height = clamp<int32_t>(v); } - // ------------------------------------------------------------------------ - // Assignment - // ------------------------------------------------------------------------ + void set(Size size) { *this = size; } - 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))); + void set(T w, T h) { + set(Size(w, h)); } - // Sets the value to INVALID - void makeInvalid() { set(INVALID); } + // Sets the value to kInvalidSize + void makeInvalid(); - // Sets the value to EMPTY - void clear() { set(EMPTY); } + // Sets the value to kEmptySize + void clear(); - // ------------------------------------------------------------------------ - // 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; } - - // ------------------------------------------------------------------------ - // 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] + // TODO: Replace with std::remove_cvref_t in C++20. template <typename T> - using remove_cv_reference_t = - typename std::remove_cv<typename std::remove_reference<T>::type>::type; + 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 @@ struct Size { // 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 @@ struct Size { // 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 void Size::makeInvalid() { + set(kInvalidSize); +} -inline bool operator==(const Size& lhs, const Size& rhs) { +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!=(Size lhs, Size rhs) { + return !(lhs == rhs); } -inline bool operator<(const Size& lhs, const Size& 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 1d908b8ef1..8ddee7e740 100644 --- a/libs/ui/tests/DisplayId_test.cpp +++ b/libs/ui/tests/DisplayId_test.cpp @@ -32,6 +32,9 @@ TEST(DisplayIdTest, createPhysicalIdFromEdid) { 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 @@ TEST(DisplayIdTest, createPhysicalIdFromPort) { 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 @@ TEST(DisplayIdTest, createGpuVirtualId) { 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 @@ TEST(DisplayIdTest, createHalVirtualId) { 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 5f75aeabeb..acef47fb97 100644 --- a/libs/ui/tests/Size_test.cpp +++ b/libs/ui/tests/Size_test.cpp @@ -93,9 +93,8 @@ TEST(SizeTest, ValidAndEmpty) { } { - 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 @@ TEST(SizeTest, ValidAndEmpty) { } { - 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 d6fc69562b..d205231033 100644 --- a/services/automotive/display/AutomotiveDisplayProxyService.cpp +++ b/services/automotive/display/AutomotiveDisplayProxyService.cpp @@ -34,7 +34,10 @@ AutomotiveDisplayProxyService::getIGraphicBufferProducer(uint64_t id) { 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 @@ Return<void> AutomotiveDisplayProxyService::getDisplayInfo(uint64_t id, getDispl 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/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index b5ed0640cd..288068f584 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -176,10 +176,11 @@ std::string KeyEntry::getDescription() const { } 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() { @@ -318,17 +319,4 @@ uint32_t DispatchEntry::nextSeq() { return seq; } -// --- CommandEntry --- - -CommandEntry::CommandEntry(Command command) - : command(command), - eventTime(0), - keyEntry(nullptr), - userActivityEventType(0), - seq(0), - handled(false), - enabled(false) {} - -CommandEntry::~CommandEntry() {} - } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index 1b7fcf2f75..8feb98243b 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -245,55 +245,6 @@ private: 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; - bool enabled; - 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/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 3dea9ce14c..59cb419d2b 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> @@ -94,9 +66,50 @@ using com::android::internal::compat::IPlatformCompatNative; 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 +149,27 @@ constexpr size_t RECENT_QUEUE_MAX_SIZE = 10; 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 +179,7 @@ static bool isValidKeyAction(int32_t action) { } } -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 +187,7 @@ static bool validateKeyEvent(int32_t action) { 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 +212,12 @@ static bool isValidMotionAction(int32_t action, int32_t actionButton, int32_t po } } -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 +244,7 @@ static bool validateMotionEvent(int32_t action, int32_t actionButton, size_t poi return true; } -static std::string dumpRegion(const Region& region) { +std::string dumpRegion(const Region& region) { if (region.isEmpty()) { return "<empty>"; } @@ -252,7 +265,7 @@ static std::string dumpRegion(const Region& region) { 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 +304,12 @@ static std::string dumpQueue(const std::deque<DispatchEntry*>& queue, nsecs_t cu * 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 +321,7 @@ static bool haveSameToken(const sp<WindowInfoHandle>& first, const sp<WindowInfo 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 +329,13 @@ static bool haveSameApplicationToken(const WindowInfo* first, const WindowInfo* 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 +412,9 @@ static std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inp 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 +424,8 @@ static void addGestureMonitors(const std::vector<Monitor>& monitors, } } -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 +434,7 @@ static status_t openInputChannelPair(const std::string& name, } 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 +444,7 @@ static bool sharedPointersEqual(const std::shared_ptr<T>& lhs, const std::shared 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 +453,7 @@ static sp<IPlatformCompatNative> getCompatService() { 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 +461,7 @@ static KeyEvent createKeyEvent(const KeyEntry& entry) { 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 +475,7 @@ static std::optional<int32_t> findMonitorPidByToken( 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 +488,7 @@ static bool shouldReportMetricsForConnection(const Connection& connection) { 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 +524,22 @@ static bool shouldReportFinishedEvent(const DispatchEntry& dispatchEntry, 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) @@ -546,17 +573,17 @@ InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& polic } 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 */); } } @@ -596,7 +623,7 @@ void InputDispatcher::dispatchOnce() { // 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; } @@ -911,8 +938,7 @@ bool InputDispatcher::shouldPruneInboundQueueLocked(const MotionEntry& motionEnt } // 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()); @@ -957,9 +983,9 @@ bool InputDispatcher::enqueueInboundEventLocked(std::unique_ptr<EventEntry> newE 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; @@ -1006,11 +1032,9 @@ void InputDispatcher::addRecentEventLocked(std::shared_ptr<EventEntry> entry) { 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); @@ -1027,16 +1051,6 @@ sp<WindowInfoHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayI 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; } @@ -1054,17 +1068,11 @@ sp<WindowInfoHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayI } 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; } @@ -1072,9 +1080,9 @@ void InputDispatcher::dropInboundEventLocked(const EventEntry& entry, DropReason 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: @@ -1158,37 +1166,35 @@ bool InputDispatcher::isAppSwitchPendingLocked() { 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() { @@ -1210,9 +1216,9 @@ void InputDispatcher::releasePendingEventLocked() { 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) { @@ -1247,27 +1253,28 @@ std::shared_ptr<KeyEntry> InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t cur 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) { @@ -1408,9 +1415,9 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, std::shared_ptr<Key } 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(); } @@ -1441,13 +1448,13 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, std::shared_ptr<Key // 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; @@ -1489,47 +1496,42 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, std::shared_ptr<Key } 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, + NamedEnum::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, + NamedEnum::string(sensorType).c_str()); + } { // acquire lock std::scoped_lock _l(mLock); @@ -1600,23 +1602,6 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr< // 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, @@ -1657,42 +1642,43 @@ void InputDispatcher::dispatchDragLocked(nsecs_t currentTime, std::shared_ptr<Dr } 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); - - 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 + 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); + + 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)); + } + } } 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); @@ -2004,12 +1990,11 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( 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. @@ -2057,7 +2042,7 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( 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); @@ -2174,10 +2159,10 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( 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)); } @@ -2187,10 +2172,10 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( 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)); @@ -2380,13 +2365,12 @@ Failed: 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(); } @@ -2415,8 +2399,7 @@ void InputDispatcher::addDragEventLocked(const MotionEntry& entry) { 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)) { @@ -2433,7 +2416,7 @@ void InputDispatcher::addDragEventLocked(const MotionEntry& entry) { } 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(); } } @@ -2721,9 +2704,9 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry& eventEntry) { 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; } } @@ -2761,12 +2744,12 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry& eventEntry) { } } - 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, @@ -2779,21 +2762,21 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, 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; } @@ -2892,10 +2875,11 @@ void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connectio 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; @@ -2925,11 +2909,11 @@ void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connectio 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; @@ -2945,11 +2929,11 @@ void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connectio 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 } @@ -3081,10 +3065,11 @@ void InputDispatcher::dispatchPointerDownOutsideFocus(uint32_t source, int32_t a 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, @@ -3094,9 +3079,9 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, 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(); @@ -3234,11 +3219,11 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, } 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, " @@ -3305,10 +3290,10 @@ const std::array<uint8_t, 32> InputDispatcher::getSignature( 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) { @@ -3316,16 +3301,19 @@ void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, } // 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); @@ -3340,7 +3328,15 @@ void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime, 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)); } } } @@ -3407,7 +3403,7 @@ int InputDispatcher::handleReceiveCallback(int events, sp<IBinder> connectionTok gotOne = true; } if (gotOne) { - runCommandsLockedInterruptible(); + runCommandsLockedInterruptable(); if (status == WOULD_BLOCK) { return 1; } @@ -3484,12 +3480,12 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( 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 = @@ -3553,10 +3549,10 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( 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 = @@ -3699,9 +3695,9 @@ std::unique_ptr<MotionEntry> InputDispatcher::splitMotionEvent( } 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 @@ -3755,14 +3751,14 @@ void InputDispatcher::accelerateMetaShortcuts(const int32_t deviceId, const int3 } 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; } @@ -3833,33 +3829,33 @@ bool InputDispatcher::shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args } 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)); - } -#endif + 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 (!validateMotionEvent(args->action, args->actionButton, args->pointerCount, args->pointerProperties)) { return; @@ -3912,6 +3908,13 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { 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 @@ -3922,12 +3925,12 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { } 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, + NamedEnum::string(args->sensorType).c_str()); + } bool needWake; { // acquire lock @@ -3950,10 +3953,10 @@ void InputDispatcher::notifySensor(const NotifySensorArgs* args) { } 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); } @@ -3962,11 +3965,11 @@ bool InputDispatcher::shouldSendMotionToInputFilterLocked(const NotifyMotionArgs } 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; @@ -3974,10 +3977,10 @@ void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) { } 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 @@ -3994,10 +3997,10 @@ void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) { } void InputDispatcher::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) { -#if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifyPointerCaptureChanged - eventTime=%" PRId64 ", enabled=%s", args->eventTime, - args->enabled ? "true" : "false"); -#endif + if (DEBUG_INBOUND_EVENT_DETAILS) { + ALOGD("notifyPointerCaptureChanged - eventTime=%" PRId64 ", enabled=%s", args->eventTime, + args->enabled ? "true" : "false"); + } bool needWake; { // acquire lock @@ -4015,11 +4018,11 @@ void InputDispatcher::notifyPointerCaptureChanged(const NotifyPointerCaptureChan 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; @@ -4197,10 +4200,10 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( 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; } @@ -4211,16 +4214,16 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( 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; } @@ -4233,10 +4236,10 @@ InputEventInjectionResult InputDispatcher::injectInputEvent( 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; } @@ -4283,11 +4286,11 @@ void InputDispatcher::setInjectionResult(EventEntry& entry, 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. @@ -4447,8 +4450,7 @@ void InputDispatcher::updateWindowHandlesForDisplayLocked( 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) || @@ -4693,7 +4695,7 @@ void InputDispatcher::setFocusedDisplay(int32_t displayId) { // 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); @@ -5000,14 +5002,6 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { } 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"; @@ -5029,7 +5023,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { 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, " @@ -5037,8 +5031,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { "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, @@ -5135,6 +5128,12 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { 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) { @@ -5201,9 +5200,9 @@ private: }; 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; @@ -5484,46 +5483,92 @@ void InputDispatcher::removeConnectionLocked(const sp<Connection>& connection) { 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); + } + } -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()); + // Start the next dispatch cycle for this connection. + startDispatchCycleLocked(now(), connection); +} - 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) { @@ -5566,17 +5611,11 @@ void InputDispatcher::onAnrLocked(std::shared_ptr<InputApplicationHandle> applic 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, @@ -5607,109 +5646,24 @@ void InputDispatcher::updateLastAnrStateLocked(const std::string& windowLabel, 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; @@ -5717,122 +5671,37 @@ void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( } } -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)); } /** @@ -5880,7 +5749,7 @@ void InputDispatcher::processConnectionResponsiveLocked(const Connection& connec 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) { @@ -5905,11 +5774,12 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con // 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); @@ -5937,21 +5807,21 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con // 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(); @@ -5985,19 +5855,19 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con // 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"); @@ -6011,18 +5881,18 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con } } -#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. @@ -6038,16 +5908,16 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con 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); @@ -6056,21 +5926,12 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con 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()); @@ -6182,7 +6043,7 @@ void InputDispatcher::onFocusChangedLocked(const FocusResolver::FocusChanges& ch disablePointerCaptureForcedLocked(); if (mFocusedDisplayId == changes.displayId) { - notifyFocusChangedLocked(changes.oldFocus, changes.newFocus); + sendFocusChangedCommandLocked(changes.oldFocus, changes.newFocus); } } @@ -6216,19 +6077,11 @@ void InputDispatcher::disablePointerCaptureForcedLocked() { } void InputDispatcher::setPointerCaptureLocked(bool enabled) { - std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>( - &InputDispatcher::doSetPointerCaptureLockedInterruptible); - commandEntry->enabled = enabled; - postCommandLocked(std::move(commandEntry)); -} - -void InputDispatcher::doSetPointerCaptureLockedInterruptible( - android::inputdispatcher::CommandEntry* commandEntry) { - mLock.unlock(); - - mPolicy->setPointerCapture(commandEntry->enabled); - - mLock.lock(); + auto command = [this, enabled]() REQUIRES(mLock) { + scoped_unlock unlock(mLock); + mPolicy->setPointerCapture(enabled); + }; + postCommandLocked(std::move(command)); } void InputDispatcher::displayRemoved(int32_t displayId) { diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 2436e73367..6df333a154 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -171,7 +171,26 @@ private: 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 +234,6 @@ private: 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 +314,8 @@ private: // 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); @@ -405,7 +423,7 @@ private: DropReason& dropReason) 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); @@ -452,24 +470,11 @@ private: */ 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. @@ -497,9 +502,7 @@ private: 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); @@ -605,53 +608,30 @@ private: 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) - REQUIRES(mLock); - void onDispatchCycleBrokenLocked(nsecs_t currentTime, const sp<Connection>& connection) + void doDispatchCycleFinishedCommand(nsecs_t finishTime, const sp<Connection>& connection, + uint32_t seq, bool handled, nsecs_t consumeTime) 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); // Statistics gathering. LatencyAggregator mLatencyAggregator GUARDED_BY(mLock); diff --git a/services/inputflinger/dispatcher/LatencyTracker.cpp b/services/inputflinger/dispatcher/LatencyTracker.cpp index d634dcda1d..52f189c5c5 100644 --- a/services/inputflinger/dispatcher/LatencyTracker.cpp +++ b/services/inputflinger/dispatcher/LatencyTracker.cpp @@ -50,13 +50,12 @@ static bool isMatureEvent(nsecs_t eventTime, nsecs_t now) { * 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 @@ void LatencyTracker::trackListener(int32_t inputEventId, bool isDown, nsecs_t ev // 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 @@ void LatencyTracker::trackFinishedEvent(int32_t inputEventId, const sp<IBinder>& 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 @@ void LatencyTracker::trackGraphicsLatency( 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::reportAndPruneMatureRecords(nsecs_t newEventTime) { } } -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 289b8ed6c4..4b0c618590 100644 --- a/services/inputflinger/dispatcher/LatencyTracker.h +++ b/services/inputflinger/dispatcher/LatencyTracker.h @@ -43,6 +43,12 @@ public: 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 @@ public: 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 20b6eadf5b..b7ed658777 100644 --- a/services/inputflinger/dispatcher/TouchState.cpp +++ b/services/inputflinger/dispatcher/TouchState.cpp @@ -37,7 +37,6 @@ void TouchState::reset() { source = 0; displayId = ADISPLAY_ID_NONE; windows.clear(); - portalWindows.clear(); gestureMonitors.clear(); } @@ -48,7 +47,6 @@ void TouchState::copyFrom(const TouchState& other) { source = other.source; displayId = other.displayId; windows = other.windows; - portalWindows = other.portalWindows; gestureMonitors = other.gestureMonitors; } @@ -77,16 +75,6 @@ void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle, int 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::filterNonAsIsTouchWindows() { void TouchState::filterNonMonitors() { windows.clear(); - portalWindows.clear(); } sp<WindowInfoHandle> TouchState::getFirstForegroundWindowHandle() const { diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h index a4e52b0d83..579b868443 100644 --- a/services/inputflinger/dispatcher/TouchState.h +++ b/services/inputflinger/dispatcher/TouchState.h @@ -36,11 +36,6 @@ struct TouchState { 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(); diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 50e185469f..0fc4708548 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> @@ -678,7 +679,11 @@ TEST_F(InputDispatcherTest, NotifySwitch_CallsPolicy) { // --- 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: diff --git a/services/inputflinger/tests/LatencyTracker_test.cpp b/services/inputflinger/tests/LatencyTracker_test.cpp index e7e1937235..89c0741dfd 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 @@ protected: } 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 @@ private: 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 @@ void LatencyTrackerTest::assertReceivedTimeline(const InputEventTimeline& timeli * 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 @@ void LatencyTrackerTest::assertReceivedTimelines(const std::vector<InputEventTim */ 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, TrackListener_DoesNotTriggerReporting) { TEST_F(LatencyTrackerTest, TrackFinishedEvent_DoesNotTriggerReporting) { mTracker->trackFinishedEvent(1 /*inputEventId*/, connection1, 2 /*deliveryTime*/, 3 /*consumeTime*/, 4 /*finishTime*/); + triggerEventReporting(4 /*eventTime*/); assertReceivedTimelines({}); } @@ -141,6 +159,7 @@ TEST_F(LatencyTrackerTest, TrackGraphicsLatency_DoesNotTriggerReporting) { 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 @@ TEST_F(LatencyTrackerTest, TrackAllParameters_ReportsFullTimeline) { 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 @@ TEST_F(LatencyTrackerTest, MultipleEvents_AreReportedConsistently) { mTracker->trackGraphicsLatency(inputEventId2, connection2, connectionTimeline2.graphicsTimeline); // Now both events should be completed + triggerEventReporting(timeline2.eventTime); assertReceivedTimelines({timeline1, timeline2}); } @@ -228,6 +269,7 @@ TEST_F(LatencyTrackerTest, IncompleteEvents_AreHandledConsistently) { mTracker->trackGraphicsLatency(1 /*inputEventId*/, token, expectedCT.graphicsTimeline); expectedTimelines[0].connectionTimelines.emplace(token, std::move(expectedCT)); + triggerEventReporting(timeline.eventTime); assertReceivedTimelines(expectedTimelines); } @@ -246,6 +288,7 @@ TEST_F(LatencyTrackerTest, EventsAreTracked_WhenTrackListenerIsCalledFirst) { 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 0000000000..df4db199f8 --- /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 0000000000..4f066ad513 --- /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/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp index c233bf06cf..c351676b1d 100644 --- a/services/sensorservice/SensorDevice.cpp +++ b/services/sensorservice/SensorDevice.cpp @@ -168,7 +168,7 @@ void SensorDevice::initializeSensorList() { } } - // 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 9ce8d9bb18..c58e992643 100644 --- a/services/sensorservice/SensorEventConnection.cpp +++ b/services/sensorservice/SensorEventConnection.cpp @@ -867,7 +867,7 @@ int SensorService::SensorEventConnection::handleEvent(int fd, int events, void* } 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 726fe8ea84..3081b1abef 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -1197,7 +1197,7 @@ int32_t SensorService::getIdFromUuid(const Sensor::uuid_t &uuid) const { // 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 @@ int32_t SensorService::getIdFromUuid(const Sensor::uuid_t &uuid) const { 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/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 71db330f01..b600fad66d 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -152,39 +152,10 @@ std::optional<compositionengine::LayerFE::LayerSettings> BufferLayer::prepareCli 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); diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 99e470dfe6..81254ac64e 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -153,11 +153,12 @@ bool BufferQueueLayer::fenceHasSignaled() const { } 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; } @@ -269,13 +270,15 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t // 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 +308,7 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t return BAD_VALUE; } + bool more_frames_pending = false; if (queuedBuffer) { // Autolock scope auto currentFrameNumber = mConsumer->getFrameNumber(); @@ -313,7 +317,7 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t // 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 +338,12 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t 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 cd531d6afc..4d86598e1c 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 @@ bool BufferStateLayer::setTransparentRegionHint(const Region& transparent) { 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 @@ Rect BufferStateLayer::getBufferSize(const State& s) const { } } - 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 { @@ -817,7 +812,7 @@ void BufferStateLayer::HwcSlotGenerator::bufferErased(const client_cache_t& clie 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 @@ uint32_t BufferStateLayer::HwcSlotGenerator::getHwcCacheSlot(const client_cache_ 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 @@ uint32_t BufferStateLayer::HwcSlotGenerator::addCachedBuffer(const client_cache_ 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 @@ bool BufferStateLayer::bufferNeedsFiltering() const { 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 @@ Rect BufferStateLayer::getInputBounds() const { } } // 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 0a0527c1a9..124e91ac61 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -178,19 +178,19 @@ private: 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 @@ private: 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 aac6c913cf..8da2e24aa4 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 @@ status_t Client::getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outSt // --------------------------------------------------------------------------- }; // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h index 554e2f4868..95d553d02f 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h @@ -47,9 +47,6 @@ struct CompositionRefreshArgs { // 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 14eddb1861..98c4af487e 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h @@ -36,18 +36,12 @@ class CompositionEngine; 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 @@ public: 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 @@ public: 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 e51019ae99..6d1017f678 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -115,10 +115,6 @@ public: // 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 @@ using LayerFESet = std::unordered_set<sp<LayerFE>, LayerFESpHash>; 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 @@ static inline void PrintTo(const LayerFE::ClientCompositionTargetSettings& setti *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 a45be8a7a2..ecb4e6d79d 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 @@ struct LayerFECompositionState { /* * 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}; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 0ef0b995c3..a33b57d668 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 @@ public: // 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 @@ public: 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 @@ protected: 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/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index bb540ea7ee..b407267560 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -83,9 +83,8 @@ public: 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 6b9597b2d5..7521324756 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 @@ void dumpVal(std::string& out, const char* name, const std::string& valueName, E 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 ddcc907a91..6d49ce6965 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 @@ public: 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 @@ public: 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 @@ protected: 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 f34cb94079..44f754f936 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 @@ struct OutputCompositionState { // 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/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index 8fdf3ae887..344b2f9456 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -40,9 +40,12 @@ public: 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 @@ public: 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 @@ public: 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 2f2c686805..6b9ea87df5 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -51,12 +51,9 @@ Display::~Display() = default; 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); setName(args.name); } @@ -73,7 +70,7 @@ bool Display::isSecure() const { } bool Display::isVirtual() const { - return mIsVirtual; + return VirtualDisplayId::tryCast(mId).has_value(); } std::optional<DisplayId> Display::getDisplayId() const { @@ -117,8 +114,8 @@ void Display::setColorProfile(const ColorProfile& colorProfile) { 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 @@ void Display::dump(std::string& out) const { 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 @@ void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refre // 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 5565396922..01c368de88 100644 --- a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp +++ b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp @@ -63,6 +63,18 @@ void dumpVal(std::string& out, const char* name, const std::string& valueName, i 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 @@ void dumpVal(std::string& out, const char* name, const ui::Transform& transform) 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 3310a71c79..0ff5eca2d4 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -227,11 +227,8 @@ ui::Transform::RotationFlags Output::getTransformHint() const { 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(); } @@ -371,26 +368,18 @@ void Output::setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSu 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.content); } -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( @@ -496,8 +485,8 @@ void Output::ensureOutputLayerIfVisible(sp<compositionengine::LayerFE>& layerFE, 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; } @@ -908,7 +897,7 @@ compositionengine::Output::ColorProfile Output::pickColorProfile( 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; @@ -960,14 +949,9 @@ void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& } 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()); } } @@ -1075,13 +1059,9 @@ std::optional<base::unique_fd> Output::composeSurfaces( 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); @@ -1126,7 +1106,7 @@ std::optional<base::unique_fd> Output::composeSurfaces( // 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; + const bool useFramebufferCache = outputState.layerFilter.toInternalDisplay; status_t status = renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, tex, useFramebufferCache, std::move(fd), &readyFence); @@ -1149,15 +1129,13 @@ std::optional<base::unique_fd> Output::composeSurfaces( } 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); bool firstLayer = true; - // Used when a layer clears part of the buffer. - Region stubRegion; bool disableBlurs = false; sp<GraphicBuffer> previousOverrideBuffer = nullptr; @@ -1219,7 +1197,6 @@ std::vector<LayerFE::LayerSettings> Output::generateClientCompositionRequests( outputState.needsFiltering, .isSecure = outputState.isSecure, .supportsProtectedContent = supportsProtectedContent, - .clearRegion = clientComposition ? clearRegion : stubRegion, .viewport = outputState.layerStackSpace.content, .dataspace = outputDataspace, .realContentIsVisible = realContentIsVisible, diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp index ee30ad8583..acc92162ac 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp @@ -28,9 +28,7 @@ void OutputCompositionState::dump(std::string& out) const { 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/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp index c1cd5ab5fd..ccacdfb19b 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp @@ -171,13 +171,11 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& te .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, diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index c037cc6173..f2978f904d 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -60,8 +60,7 @@ constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(123 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 @@ struct DisplayTestCommon : public testing::Test { 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 @@ struct DisplayTestCommon : public testing::Test { .setId(GPU_VIRTUAL_DISPLAY_ID) .setPixels(DEFAULT_RESOLUTION) .setIsSecure(false) - .setLayerStackId(DEFAULT_LAYER_STACK) .setPowerAdvisor(&mPowerAdvisor) .build(); } @@ -193,14 +189,13 @@ struct PartialMockDisplayTestCommon : public DisplayTestCommon { 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 @@ struct DisplayWithLayersTestCommon : public FullDisplayImplTestCommon { LayerNoHWC2Layer mLayer3; StrictMock<HWC2::mock::Layer> hwc2LayerUnknown; std::shared_ptr<Display> mDisplay = - createDisplay<Display>(mCompositionEngine, - getDisplayCreationArgsForPhysicalHWCDisplay()); + createDisplay<Display>(mCompositionEngine, getDisplayCreationArgsForPhysicalDisplay()); }; /* @@ -232,7 +226,7 @@ struct DisplayCreationTest : public DisplayTestCommon { 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 @@ TEST_F(DisplayCreationTest, createGpuVirtualDisplay) { 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 @@ TEST_F(DisplaySetConfigurationTest, configuresInternalSecurePhysicalDisplay) { 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 @@ TEST_F(DisplaySetConfigurationTest, configuresHalVirtualDisplay) { .setId(HAL_VIRTUAL_DISPLAY_ID) .setPixels(DEFAULT_RESOLUTION) .setIsSecure(false) - .setLayerStackId(DEFAULT_LAYER_STACK) .setPowerAdvisor(&mPowerAdvisor) .setName(getDisplayNameFromCurrentTest()) .build()); @@ -303,9 +277,11 @@ TEST_F(DisplaySetConfigurationTest, configuresHalVirtualDisplay) { 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 @@ TEST_F(DisplaySetConfigurationTest, configuresGpuVirtualDisplay) { .setId(GPU_VIRTUAL_DISPLAY_ID) .setPixels(DEFAULT_RESOLUTION) .setIsSecure(false) - .setLayerStackId(DEFAULT_LAYER_STACK) .setPowerAdvisor(&mPowerAdvisor) .setName(getDisplayNameFromCurrentTest()) .build()); @@ -321,9 +296,11 @@ TEST_F(DisplaySetConfigurationTest, configuresGpuVirtualDisplay) { 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); } /* @@ -902,10 +879,7 @@ TEST_F(DisplayFinishFrameTest, doesNotSkipCompositionIfNotDirtyOnHwcDisplay) { mDisplay->editState().layerStackSpace.content = 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) { @@ -923,10 +897,7 @@ TEST_F(DisplayFinishFrameTest, skipsCompositionIfNotDirty) { gpuDisplay->editState().layerStackSpace.content = 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) { @@ -944,31 +915,7 @@ TEST_F(DisplayFinishFrameTest, performsCompositionIfDirty) { gpuDisplay->editState().layerStackSpace.content = 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 +945,8 @@ struct DisplayFunctionalTest : public testing::Test { 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 ada5adfa12..224dad1647 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -49,6 +49,7 @@ public: 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 @@ public: 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/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index ee73cfc0c1..6c510eb99a 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -403,17 +403,18 @@ TEST_F(OutputTest, setDisplaySpaceSizeUpdatesOutputStateAndDirtiesEntireOutput) } /* - * 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))); } /* @@ -567,126 +568,100 @@ TEST_F(OutputTest, setRenderSurfaceResetsBounds) { * Output::getDirtyRegion() */ -TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingTrue) { - const Rect viewport{100, 200}; - mOutput->editState().layerStackSpace.content = viewport; - mOutput->editState().dirtyRegion.set(50, 300); - - { - Region result = mOutput->getDirtyRegion(true); - - EXPECT_THAT(result, RegionEq(Region(viewport))); - } -} - -TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingFalse) { +TEST_F(OutputTest, getDirtyRegion) { 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)); } /* @@ -1268,14 +1243,15 @@ struct OutputEnsureOutputLayerIfVisibleTest : public testing::Test { 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)) @@ -1326,8 +1302,8 @@ const Region OutputEnsureOutputLayerIfVisibleTest::kLowerHalfBoundsNoRotation = 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 +1313,8 @@ TEST_F(OutputEnsureOutputLayerIfVisibleTest, performsGeomLatchBeforeCheckingIfLa } 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(); } @@ -2530,7 +2506,7 @@ struct OutputBeginFrameTest : public ::testing::Test { 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 +2518,7 @@ struct OutputBeginFrameTest : public ::testing::Test { 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 +2658,7 @@ struct OutputDevOptRepaintFlashTest : public testing::Test { 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 +2686,6 @@ const Region OutputDevOptRepaintFlashTest::kNotEmptyRegion{Rect{0, 0, 1, 1}}; TEST_F(OutputDevOptRepaintFlashTest, doesNothingIfFlashDelayNotSet) { mRefreshArgs.devOptFlashDirtyRegionsDelay = {}; - mRefreshArgs.repaintEverything = true; mOutput.mState.isEnabled = true; mOutput.devOptRepaintFlash(mRefreshArgs); @@ -2719,7 +2693,6 @@ TEST_F(OutputDevOptRepaintFlashTest, doesNothingIfFlashDelayNotSet) { TEST_F(OutputDevOptRepaintFlashTest, postsAndPreparesANewFrameIfNotEnabled) { mRefreshArgs.devOptFlashDirtyRegionsDelay = std::chrono::microseconds(1); - mRefreshArgs.repaintEverything = true; mOutput.mState.isEnabled = false; InSequence seq; @@ -2729,13 +2702,12 @@ TEST_F(OutputDevOptRepaintFlashTest, postsAndPreparesANewFrameIfNotEnabled) { 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 +2716,10 @@ TEST_F(OutputDevOptRepaintFlashTest, postsAndPreparesANewFrameIfNotDirty) { 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 +2963,8 @@ struct OutputComposeSurfacesTest : public testing::Test { // 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)); @@ -3142,7 +3113,7 @@ TEST_F(OutputComposeSurfacesTest, handlesZeroCompositionRequests) { 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()); @@ -3165,7 +3136,7 @@ TEST_F(OutputComposeSurfacesTest, buildsAndRendersRequestList) { 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( @@ -3188,14 +3159,13 @@ TEST_F(OutputComposeSurfacesTest, 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( @@ -3223,7 +3193,7 @@ TEST_F(OutputComposeSurfacesTest, renderDuplicateClientCompositionRequestsWithou 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()); @@ -3252,7 +3222,7 @@ TEST_F(OutputComposeSurfacesTest, skipDuplicateClientCompositionRequests) { 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()); @@ -3281,7 +3251,7 @@ TEST_F(OutputComposeSurfacesTest, clientCompositionIfBufferChanges) { 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()); @@ -3316,7 +3286,7 @@ TEST_F(OutputComposeSurfacesTest, clientCompositionIfRequestChanges) { 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), _)) @@ -3339,7 +3309,7 @@ struct OutputComposeSurfacesTest_UsesExpectedDisplaySettings : public OutputComp 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()); @@ -3391,7 +3361,7 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrMixedComposi .andIfSkipColorTransform(false) .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport, kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(), - Region::INVALID_REGION, kDefaultOutputOrientationFlags}) + kDefaultOutputOrientationFlags}) .execute() .expectAFenceWasReturned(); } @@ -3402,7 +3372,7 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrMixedComp .andIfSkipColorTransform(false) .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport, kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(), - Region::INVALID_REGION, kDefaultOutputOrientationFlags}) + kDefaultOutputOrientationFlags}) .execute() .expectAFenceWasReturned(); } @@ -3413,7 +3383,7 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrOnlyClientCo .andIfSkipColorTransform(false) .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport, kDefaultMaxLuminance, kDefaultOutputDataspace, - kDefaultColorTransformMat, Region::INVALID_REGION, + kDefaultColorTransformMat, kDefaultOutputOrientationFlags}) .execute() .expectAFenceWasReturned(); @@ -3425,7 +3395,7 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrOnlyClien .andIfSkipColorTransform(false) .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport, kDefaultMaxLuminance, kDefaultOutputDataspace, - kDefaultColorTransformMat, Region::INVALID_REGION, + kDefaultColorTransformMat, kDefaultOutputOrientationFlags}) .execute() .expectAFenceWasReturned(); @@ -3438,7 +3408,7 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, .andIfSkipColorTransform(true) .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport, kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(), - Region::INVALID_REGION, kDefaultOutputOrientationFlags}) + kDefaultOutputOrientationFlags}) .execute() .expectAFenceWasReturned(); } @@ -3469,7 +3439,7 @@ struct OutputComposeSurfacesTest_HandlesProtectedContent : public OutputComposeS 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()); @@ -3590,7 +3560,7 @@ struct OutputComposeSurfacesTest_SetsExpensiveRendering : public OutputComposeSu 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. @@ -3612,7 +3582,7 @@ struct OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur 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(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1u)); @@ -3652,10 +3622,9 @@ struct GenerateClientCompositionRequestsTest : public testing::Test { 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); } }; @@ -3739,11 +3708,9 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, handlesNoClientCompost 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) { @@ -3751,11 +3718,9 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, requiresVisibleRegionA 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) { @@ -3770,16 +3735,13 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, gathersClientCompositi .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); @@ -3810,16 +3772,13 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, overridesBlur) { .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); @@ -3843,13 +3802,10 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, 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, @@ -3869,13 +3825,10 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, 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) { @@ -3896,15 +3849,12 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, clearsHWCLayersIfOpaqu 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 */, @@ -3916,7 +3866,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, clearsHWCLayersIfOpaqu false, /* needs filtering */ false, /* secure */ false, /* supports protected content */ - accumClearRegion, kDisplayViewport, kDisplayDataspace, true /* realContentIsVisible */, @@ -3936,15 +3885,13 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, clearsHWCLayersIfOpaqu .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, @@ -3953,14 +3900,11 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, 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 */, @@ -3972,7 +3916,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* needs filtering */ false, /* secure */ false, /* supports protected content */ - accumClearRegion, kDisplayViewport, kDisplayDataspace, true /* realContentIsVisible */, @@ -3984,7 +3927,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* needs filtering */ false, /* secure */ false, /* supports protected content */ - accumClearRegion, kDisplayViewport, kDisplayDataspace, true /* realContentIsVisible */, @@ -4001,7 +3943,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, static_cast<void>( mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */, - accumClearRegion, kDisplayDataspace)); + kDisplayDataspace)); } TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, @@ -4009,14 +3951,11 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, 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 */, @@ -4028,7 +3967,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* needs filtering */ false, /* secure */ false, /* supports protected content */ - accumClearRegion, kDisplayViewport, kDisplayDataspace, true /* realContentIsVisible */, @@ -4040,7 +3978,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* needs filtering */ false, /* secure */ false, /* supports protected content */ - accumClearRegion, kDisplayViewport, kDisplayDataspace, true /* realContentIsVisible */, @@ -4057,7 +3994,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, static_cast<void>( mOutput.generateClientCompositionRequests(false /* supportsProtectedContent */, - accumClearRegion, kDisplayDataspace)); + kDisplayDataspace)); } TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, @@ -4065,14 +4002,11 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, 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 */, @@ -4085,7 +4019,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, true, /* needs filtering */ false, /* secure */ false, /* supports protected content */ - accumClearRegion, kDisplayViewport, kDisplayDataspace, true /* realContentIsVisible */, @@ -4097,7 +4030,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, true, /* needs filtering */ false, /* secure */ false, /* supports protected content */ - accumClearRegion, kDisplayViewport, kDisplayDataspace, true /* realContentIsVisible */, @@ -4114,21 +4046,18 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, 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 */, @@ -4140,7 +4069,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* needs filtering */ true, /* secure */ false, /* supports protected content */ - accumClearRegion, kDisplayViewport, kDisplayDataspace, true /* realContentIsVisible */, @@ -4152,7 +4080,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* needs filtering */ true, /* secure */ false, /* supports protected content */ - accumClearRegion, kDisplayViewport, kDisplayDataspace, true /* realContentIsVisible */, @@ -4169,19 +4096,17 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, 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 */, @@ -4193,7 +4118,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* needs filtering */ false, /* secure */ true, /* supports protected content */ - accumClearRegion, kDisplayViewport, kDisplayDataspace, true /* realContentIsVisible */, @@ -4205,7 +4129,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, false, /* needs filtering */ false, /* secure */ true, /* supports protected content */ - accumClearRegion, kDisplayViewport, kDisplayDataspace, true /* realContentIsVisible */, @@ -4221,7 +4144,6 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, .WillOnce(Return(std::vector<LayerFE::LayerSettings>())); static_cast<void>(mOutput.generateClientCompositionRequests(true /* supportsProtectedContent */, - accumClearRegion, kDisplayDataspace)); } @@ -4336,14 +4258,11 @@ TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenReq 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 */, @@ -4361,7 +4280,6 @@ TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenReq false, /* needs filtering */ true, /* secure */ true, /* supports protected content */ - accumClearRegion, kPortraitViewport, kOutputDataspace, true /* realContentIsVisible */, @@ -4375,8 +4293,8 @@ TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenReq .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]); @@ -4389,13 +4307,11 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, 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 */, @@ -4415,7 +4331,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, .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]); @@ -4435,13 +4351,11 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, 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 */, @@ -4456,7 +4370,7 @@ TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, {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/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp index 5090bb280f..431cc93514 100644 --- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp @@ -35,7 +35,7 @@ namespace { 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/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 4445eea604..802a17d981 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -232,7 +232,7 @@ ui::Dataspace DisplayDevice::getCompositionDataSpace() const { } void DisplayDevice::setLayerStack(ui::LayerStack stack) { - mCompositionDisplay->setLayerStackFilter(stack, isInternal()); + mCompositionDisplay->setLayerFilter({stack, isInternal()}); if (mRefreshRateOverlay) { mRefreshRateOverlay->setLayerStack(stack); } @@ -349,7 +349,7 @@ bool DisplayDevice::needsFiltering() const { } ui::LayerStack DisplayDevice::getLayerStack() const { - return mCompositionDisplay->getState().layerStackId; + return mCompositionDisplay->getState().layerFilter.layerStack; } ui::Transform::RotationFlags DisplayDevice::getTransformHint() const { diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 4d435c7e47..43a6bd540a 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -86,9 +86,7 @@ public: 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. @@ -273,7 +271,7 @@ private: 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 +309,7 @@ struct DisplayDeviceState { 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 +352,4 @@ struct DisplayDeviceCreationArgs { 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 a790b4c11e..256bca9570 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -212,8 +212,6 @@ bool HWComposer::onVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp) { 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 @@ bool HWComposer::allocateVirtualDisplay(HalVirtualDisplayId displayId, ui::Size display->setConnected(true); auto& displayData = mDisplayData[displayId]; displayData.hwcDisplay = std::move(display); - displayData.isVirtual = true; return true; } @@ -279,10 +276,8 @@ void HWComposer::allocatePhysicalDisplay(hal::HWDisplayId hwcDisplayId, 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 HWComposer::getDisplayConnectionType(PhysicalDisplayId 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 @@ void HWComposer::setVsyncEnabled(PhysicalDisplayId displayId, hal::Vsync enabled 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::presentAndGetReleaseFences( 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 @@ void HWComposer::disconnectDisplay(HalDisplayId displayId) { 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 @@ status_t HWComposer::setOutputBuffer(HalVirtualDisplayId displayId, const sp<Fen 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<PhysicalDisplayId> HWComposer::toPhysicalDisplayId( 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 @@ bool HWComposer::shouldIgnoreHotplugConnect(hal::HWDisplayId hwcDisplayId, 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 @@ std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect( } 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 @@ std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect( } 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::onHotplugConnect( 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 @@ std::optional<DisplayIdentificationInfo> HWComposer::onHotplugDisconnect( 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 49f96d9614..0a090da01e 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 @@ public: 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 @@ public: 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 @@ private: 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 @@ private: 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 @@ private: } // namespace impl } // namespace android - -#endif // ANDROID_SF_HWCOMPOSER_H diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 140436aafa..b872c85861 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -107,7 +107,7 @@ Layer::Layer(const LayerCreationArgs& args) 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; @@ -391,7 +391,6 @@ void Layer::setupRoundedCornersCropCoordinates(Rect win, 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; @@ -403,9 +402,7 @@ void Layer::prepareBasicGeometryCompositionState() { } 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; @@ -728,14 +725,14 @@ void Layer::commitTransaction(State&) { 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) { @@ -1005,7 +1002,7 @@ bool Layer::setMetadata(const LayerMetadata& data) { 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; @@ -1052,12 +1049,11 @@ bool Layer::isLayerFocusedBasedOnPriority(int32_t priority) { 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) { @@ -1371,7 +1367,7 @@ LayerDebugInfo Layer::getLayerDebugInfo(const DisplayDevice* display) const { 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; @@ -2088,7 +2084,7 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet 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(), @@ -2135,7 +2131,7 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet if (traceFlags & SurfaceTracing::TRACE_INPUT) { WindowInfo info; if (useDrawing) { - info = fillInputInfo({nullptr}); + info = fillInputInfo(nullptr); } else { info = state.inputInfo; } @@ -2164,7 +2160,7 @@ Rect Layer::getInputBounds() const { 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 @@ -2184,13 +2180,13 @@ void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& toNonRotat 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(); @@ -2269,26 +2265,28 @@ void Layer::fillTouchOcclusionMode(WindowInfo& info) { } } -WindowInfo Layer::fillInputInfo(const sp<DisplayDevice>& display) { +WindowInfo Layer::fillInputInfo(const DisplayDevice* display) { 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; + // Transform that maps from LayerStack space to display space, e.g. rotated to non-rotated. + // Used when InputFlinger operates in display space. + ui::Transform displayTransform; 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. + // 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 - display->getPhysicalOrientation(); auto width = display->getWidth(); @@ -2297,9 +2295,10 @@ WindowInfo Layer::fillInputInfo(const sp<DisplayDevice>& display) { 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(); + const ui::Transform undoPhysicalOrientation(ui::Transform::toRotationFlags( + inversePhysicalOrientation), + width, height); + displayTransform = undoPhysicalOrientation * display->getTransform(); // Send the inverse of the display orientation so that input can transform points back to // the rotated display space. @@ -2309,7 +2308,7 @@ WindowInfo Layer::fillInputInfo(const sp<DisplayDevice>& display) { 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 @@ -2325,15 +2324,11 @@ WindowInfo Layer::fillInputInfo(const sp<DisplayDevice>& display) { 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 @@ -2344,9 +2339,8 @@ WindowInfo Layer::fillInputInfo(const sp<DisplayDevice>& display) { // 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); } } @@ -2542,14 +2536,14 @@ scheduler::Seamlessness Layer::FrameRate::convertChangeFrameRateStrategy(int8_t } } -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 470103c784..4200be4898 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -151,12 +151,7 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: */ 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 @@ public: gui::WindowInfo::Type getWindowType() const { return mWindowType; } - bool getPrimaryDisplayOnly() const; - void updateMirrorInfo(); /* @@ -851,7 +851,8 @@ public: bool getPremultipledAlpha() const; void setInputInfo(const gui::WindowInfo& info); - gui::WindowInfo fillInputInfo(const sp<DisplayDevice>& display); + gui::WindowInfo fillInputInfo(const DisplayDevice*); + /** * Returns whether this layer has an explicitly set input-info. */ @@ -1072,8 +1073,8 @@ private: // 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 aee820a88c..f52e60deda 100644 --- a/services/surfaceflinger/LayerVector.cpp +++ b/services/surfaceflinger/LayerVector.cpp @@ -45,8 +45,8 @@ int LayerVector::do_compare(const void* lhs, const void* rhs) const 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 bc32a1d66c..0789e8dcb4 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>> RefreshRateOverlay::SevenSegmentDrawer::drawNumbe 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 @@ bool RefreshRateOverlay::createLayer() { 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 @@ RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) { 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 @@ RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) { 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 @@ void RefreshRateOverlay::setViewport(ui::Size viewport) { 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 f9baa898dc..63ae383c8c 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 @@ class RefreshRateOverlay { 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 @@ public: 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 @@ private: 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 9a6c8533ea..5fea521f18 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 @@ float RenderArea::getCaptureFillValue(CaptureFill captureFill) { } } // 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 c38cd68cd7..e922d46a40 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -140,6 +140,8 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye 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 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye 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] = @@ -421,7 +433,7 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( const auto layerScore = calculateLayerScoreLocked(layer, *scores[i].refreshRate, isSeamlessSwitch); - ALOGV("%s gives %s score of %.2f", formatLayerInfo(layer, weight).c_str(), + ALOGV("%s gives %s score of %.4f", formatLayerInfo(layer, weight).c_str(), scores[i].refreshRate->getName().c_str(), layerScore); scores[i].score += weight * layerScore; } @@ -582,7 +594,7 @@ RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverr template <typename Iter> const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) const { - constexpr auto EPSILON = 0.001f; + constexpr auto kEpsilon = 0.0001f; const RefreshRate* bestRefreshRate = begin->refreshRate; float max = begin->score; for (auto i = begin; i != end; ++i) { @@ -591,7 +603,7 @@ const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) ATRACE_INT(refreshRate->getName().c_str(), round<int>(score * 100)); - if (score > max * (1 + EPSILON)) { + if (score > max * (1 + kEpsilon)) { max = score; bestRefreshRate = refreshRate; } @@ -910,7 +922,10 @@ RefreshRateConfigs::KernelIdleTimerAction RefreshRateConfigs::getIdleTimerAction int RefreshRateConfigs::getFrameRateDivider(Fps displayFrameRate, Fps layerFrameRate) { // This calculation needs to be in sync with the java code // in DisplayManagerService.getDisplayInfoForFrameRateOverride - constexpr float kThreshold = 0.1f; + + // The threshold must be smaller than 0.001 in order to differentiate + // between the fractional pairs (e.g. 59.94 and 60). + constexpr float kThreshold = 0.0009f; const auto numPeriods = displayFrameRate.getValue() / layerFrameRate.getValue(); const auto numPeriodsRounded = std::round(numPeriods); if (std::abs(numPeriods - numPeriodsRounded) > kThreshold) { @@ -920,6 +935,17 @@ int RefreshRateConfigs::getFrameRateDivider(Fps displayFrameRate, Fps layerFrame return static_cast<int>(numPeriodsRounded); } +bool RefreshRateConfigs::isFractionalPairOrMultiple(Fps smaller, Fps bigger) { + if (smaller.getValue() > bigger.getValue()) { + return isFractionalPairOrMultiple(bigger, smaller); + } + + const auto multiplier = std::round(bigger.getValue() / smaller.getValue()); + constexpr float kCoef = 1000.f / 1001.f; + return bigger.equalsWithMargin(Fps(smaller.getValue() * multiplier / kCoef)) || + bigger.equalsWithMargin(Fps(smaller.getValue() * multiplier * kCoef)); +} + void RefreshRateConfigs::dump(std::string& result) const { std::lock_guard lock(mLock); base::StringAppendF(&result, "DesiredDisplayModeSpecs (DisplayManager): %s\n\n", diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 4a9a1fd9fc..0d75689546 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -335,6 +335,10 @@ public: // layer refresh rate. static int getFrameRateDivider(Fps displayFrameRate, Fps layerFrameRate); + // Returns if the provided frame rates have a ratio t*1000/1001 or t*1001/1000 + // for an integer t. + static bool isFractionalPairOrMultiple(Fps, Fps); + using UidToFrameRateOverride = std::map<uid_t, Fps>; // Returns the frame rate override for each uid. // diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index f808981d0f..534efeeb4a 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -669,7 +669,7 @@ void Scheduler::resetIdleTimer() { } } -void Scheduler::notifyTouchEvent() { +void Scheduler::onTouchHint() { if (mTouchTimer) { mTouchTimer->reset(); @@ -878,7 +878,7 @@ DisplayModePtr Scheduler::getPreferredDisplayMode() { void Scheduler::onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline) { if (timeline.refreshRequired) { - mSchedulerCallback.repaintEverythingForHWC(); + mSchedulerCallback.scheduleRefresh(FrameHint::kNone); } std::lock_guard<std::mutex> lock(mVsyncTimelineLock); @@ -891,21 +891,21 @@ void Scheduler::onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimel } 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; } + + mLastVsyncPeriodChangeTimeline->refreshRequired = false; } - } + return false; + }(); - if (callRepaint) { - mSchedulerCallback.repaintEverythingForHWC(); + if (refresh) { + mSchedulerCallback.scheduleRefresh(FrameHint::kNone); } } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 4b6905bc6d..420ba61a14 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -56,10 +56,13 @@ class TokenManager; } // 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 @@ public: 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 @@ public: 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 0f7fada31d..5d8d79b11b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -415,10 +415,7 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI 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"); @@ -618,17 +615,14 @@ void SurfaceFlinger::releaseVirtualDisplay(VirtualDisplayId displayId) { } std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIdsLocked() const { - const auto internalDisplayId = getInternalDisplayIdLocked(); - if (!internalDisplayId) { - return {}; - } - std::vector<PhysicalDisplayId> displayIds; displayIds.reserve(mPhysicalDisplayTokens.size()); - displayIds.push_back(*internalDisplayId); + + const auto internalDisplayId = getInternalDisplayIdLocked(); + displayIds.push_back(internalDisplayId); for (const auto& [id, token] : mPhysicalDisplayTokens) { - if (id != *internalDisplayId) { + if (id != internalDisplayId) { displayIds.push_back(id); } } @@ -795,10 +789,10 @@ void SurfaceFlinger::init() { // 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; @@ -967,6 +961,11 @@ status_t SurfaceFlinger::getDynamicDisplayInfo(const sp<IBinder>& displayToken, 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(); @@ -1026,18 +1025,18 @@ status_t SurfaceFlinger::getDynamicDisplayInfo(const sp<IBinder>& displayToken, } 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; } @@ -1064,8 +1063,8 @@ void SurfaceFlinger::setDesiredActiveMode(const ActiveModeInfo& info) { } 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()); @@ -1261,15 +1260,15 @@ void SurfaceFlinger::disableExpensiveRendering() { }).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()); } @@ -1293,34 +1292,41 @@ status_t SurfaceFlinger::getDisplayNativePrimaries(const sp<IBinder>& displayTok } 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; } @@ -1640,7 +1646,7 @@ status_t SurfaceFlinger::notifyPowerBoost(int32_t boostId) { Boost powerBoost = static_cast<Boost>(boostId); if (powerBoost == Boost::INTERACTION) { - mScheduler->notifyTouchEvent(); + mScheduler->onTouchHint(); } return NO_ERROR; @@ -1657,16 +1663,26 @@ sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection( 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() { @@ -1737,8 +1753,8 @@ void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate, 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 @@ -1769,7 +1785,7 @@ void SurfaceFlinger::onComposerHalSeamlessPossible(hal::HWDisplayId) { void SurfaceFlinger::onComposerHalRefresh(hal::HWDisplayId) { Mutex::Autolock lock(mStateLock); - repaintEverythingForHWC(); + scheduleRefresh(FrameHint::kNone); } void SurfaceFlinger::setVsyncEnabled(bool enabled) { @@ -1930,17 +1946,13 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT } 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) || @@ -1950,8 +1962,9 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT mFrameTimeline->setSfWakeUp(vsyncId, frameStart, Fps::fromPeriodNsecs(stats.vsyncPeriod)); - refreshNeeded = handleMessageTransaction(); + refreshNeeded |= flushAndCommitTransactions(); refreshNeeded |= handleMessageInvalidate(); + if (tracePreComposition) { if (mVisibleRegionsDirty) { mTracing.notifyLocked("visibleRegionsDirty"); @@ -1973,7 +1986,6 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT 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 @@ -1995,25 +2007,23 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT 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() { @@ -2037,7 +2047,6 @@ void SurfaceFlinger::onMessageRefresh() { refreshArgs.layersWithQueuedFrames.push_back(layerFE); } - refreshArgs.repaintEverything = mRepaintEverything.exchange(false); refreshArgs.outputColorSetting = useColorManagement ? mDisplayColorSetting : compositionengine::OutputColorSetting::kUnmanaged; @@ -2045,7 +2054,7 @@ void SurfaceFlinger::onMessageRefresh() { refreshArgs.forceOutputColorMode = mForceColorMode; refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty; - refreshArgs.updatingGeometryThisFrame = mGeometryInvalid || mVisibleRegionsDirty; + refreshArgs.updatingGeometryThisFrame = mGeometryDirty.exchange(false) || mVisibleRegionsDirty; refreshArgs.blursAreExpensive = mBlursAreExpensive; refreshArgs.internalDisplayRotationFlags = DisplayDevice::getPrimaryDisplayRotationFlags(); @@ -2054,11 +2063,11 @@ void SurfaceFlinger::onMessageRefresh() { 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); @@ -2067,8 +2076,6 @@ void SurfaceFlinger::onMessageRefresh() { 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(); @@ -2290,7 +2297,7 @@ void SurfaceFlinger::postComposition() { 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 || @@ -2421,8 +2428,8 @@ void SurfaceFlinger::computeLayerBounds() { const auto& displayDevice = pair.second; const auto display = displayDevice->getCompositionDisplay(); for (const auto& layer : mDrawingState.layersSortedByZ) { - // only consider the layers on the given layer stack - if (!display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) { + // Only consider the layers on this display. + if (!display->includesLayer(layer->getOutputFilter())) { continue; } @@ -2442,29 +2449,26 @@ void SurfaceFlinger::postFrame() { } } -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, @@ -2727,14 +2731,12 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, 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()); @@ -2840,7 +2842,7 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, 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); } } @@ -2920,8 +2922,8 @@ void SurfaceFlinger::processDisplayChangesLocked() { 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(); @@ -2935,18 +2937,9 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { 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. @@ -2957,30 +2950,29 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { // (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; } } @@ -2994,20 +2986,10 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { 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. @@ -3029,7 +3011,9 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { }); } - commitTransaction(); + doCommitTransactions(); + signalSynchronousTransactions(CountDownLatch::eSyncTransaction); + mAnimTransactionPending = false; } void SurfaceFlinger::updateInputFlinger() { @@ -3064,9 +3048,12 @@ void SurfaceFlinger::notifyWindowInfos() { 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)); @@ -3175,14 +3162,9 @@ void SurfaceFlinger::setVsyncConfig(const VsyncModulator::VsyncConfig& config, 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) { @@ -3226,11 +3208,10 @@ void SurfaceFlinger::commitTransactionLocked() { 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(); + } }); } } @@ -3238,7 +3219,7 @@ void SurfaceFlinger::commitOffscreenLayers() { 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); } } @@ -3266,14 +3247,14 @@ bool SurfaceFlinger::handlePageFlip() { // 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); @@ -3281,7 +3262,7 @@ bool SurfaceFlinger::handlePageFlip() { ATRACE_NAME("!layer->shouldPresentNow()"); layer->useEmptyDamage(); } - } else { + } else { layer->useEmptyDamage(); } }); @@ -3334,10 +3315,6 @@ bool SurfaceFlinger::handlePageFlip() { 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, @@ -3384,23 +3361,23 @@ void SurfaceFlinger::removeGraphicBufferProducerAsync(const wp<IBinder>& binder) })); } -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; } @@ -4459,7 +4436,7 @@ void SurfaceFlinger::onInitializeDisplays() { 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(); @@ -4490,23 +4467,22 @@ void SurfaceFlinger::initializeDisplays() { } 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) { @@ -4551,7 +4527,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: mVisibleRegionsDirty = true; mHasPoweredOff = true; - repaintEverything(); + scheduleRefresh(FrameHint::kActive); } else if (mode == hal::PowerMode::OFF) { // Turn off the display if (SurfaceFlinger::setSchedFifo(false) != NO_ERROR) { @@ -5143,7 +5119,7 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co 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); @@ -5352,9 +5328,8 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { 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); @@ -5371,47 +5346,43 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } int n; switch (code) { - case 1000: // SHOW_CPU, NOT SUPPORTED ANYMORE - case 1001: // SHOW_FPS, NOT SUPPORTED ANYMORE - return NO_ERROR; - case 1002: // SHOW_UPDATES - n = data.readInt32(); - mDebugRegion = n ? n : (mDebugRegion ? 0 : 1); - invalidateHwcGeometry(); - repaintEverything(); + 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 1004:{ // repaint everything - repaintEverything(); + case 1004: // Force refresh ahead of next VSYNC. + scheduleRefresh(FrameHint::kActive); return NO_ERROR; - } - case 1005:{ // force transaction - Mutex::Autolock _l(mStateLock); - setTransactionFlags( - eTransactionNeeded| - eDisplayTransactionNeeded| - eTraversalNeeded); + case 1005: { // Force commit ahead of next VSYNC. + Mutex::Autolock lock(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; @@ -5466,12 +5437,15 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r 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; @@ -5525,8 +5499,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r 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. @@ -5657,37 +5630,24 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } 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 (!displayId) { - ALOGE("No display found"); - return NO_ERROR; - } - - status_t result = setActiveMode(getPhysicalDisplayToken(*displayId), modeId); - if (result != NO_ERROR) { - return result; - } + if (const auto id = DisplayId::fromValue<PhysicalDisplayId>(value)) { + return getPhysicalDisplayToken(*id); + } - mDebugDisplayModeSetByBackdoor = true; + ALOGE("Invalid physical display ID"); + return nullptr; + }(); - return NO_ERROR; + const status_t result = setActiveMode(display, modeId); + mDebugDisplayModeSetByBackdoor = result == NO_ERROR; + return result; } case 1036: { if (data.readInt32() > 0) { @@ -5704,12 +5664,10 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r // 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 @@ -5750,14 +5708,11 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r 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); @@ -5774,8 +5729,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r if (error != OK) { return error; } - invalidateHwcGeometry(); - repaintEverything(); + scheduleRepaint(); return NO_ERROR; } } @@ -5783,17 +5737,6 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r 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); @@ -6015,7 +5958,7 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, 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; @@ -6023,21 +5966,14 @@ status_t SurfaceFlinger::captureDisplay(uint64_t displayIdOrLayerStack, 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 = @@ -6122,7 +6058,11 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, } } - 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; } @@ -6337,7 +6277,6 @@ status_t SurfaceFlinger::renderScreenImplLocked( 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; @@ -6349,7 +6288,6 @@ status_t SurfaceFlinger::renderScreenImplLocked( renderArea.needsFiltering(), renderArea.isSecure(), useProtected, - clearRegion, layerStackSpaceRect, clientCompositionDisplay.outputDataspace, true, /* realContentIsVisible */ @@ -6387,7 +6325,6 @@ status_t SurfaceFlinger::renderScreenImplLocked( 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; @@ -6436,12 +6373,12 @@ void SurfaceFlinger::traverseLayersInLayerStack(ui::LayerStack layerStack, const // 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()) { @@ -6800,33 +6737,29 @@ int SurfaceFlinger::calculateMaxAcquiredBufferCount(Fps refreshRate, } 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 ebc3e4a95a..33bc17ba73 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -285,8 +285,12 @@ public: 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 +352,6 @@ protected: uint32_t permissions, std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks) REQUIRES(mStateLock); - virtual void commitTransactionLocked(); // Used internally by computeLayerBounds() to gets the clip rectangle to use for the // root layers on a particular display in layer-coordinate space. The @@ -635,12 +638,10 @@ private: 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*) @@ -753,8 +754,6 @@ private: 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. @@ -773,8 +772,6 @@ private: * 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(); @@ -806,8 +803,12 @@ private: // 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 @@ -816,9 +817,6 @@ private: // 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); @@ -850,18 +848,23 @@ private: 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, @@ -944,7 +947,7 @@ private: return width > mMaxRenderTargetSize || height > mMaxRenderTargetSize; } - int getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const; + uint32_t getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const; /* * Display and layer stack management @@ -1035,8 +1038,6 @@ private: /* * Compositing */ - void invalidateHwcGeometry(); - void postComposition(); void getCompositorTiming(CompositorTiming* compositorTiming); void updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime, @@ -1120,15 +1121,19 @@ private: 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. @@ -1207,8 +1212,7 @@ private: /* * 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); @@ -1250,7 +1254,8 @@ private: 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(); @@ -1277,7 +1282,6 @@ private: bool mSomeDataspaceChanged = false; bool mForceTransactionDisplayChange = false; - bool mGeometryInvalid = false; bool mAnimCompositionPending = false; // Tracks layers that have pending frames which are candidates for being @@ -1312,13 +1316,13 @@ private: 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; diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp index 9be3abefab..0782fef8ea 100644 --- a/services/surfaceflinger/SurfaceInterceptor.cpp +++ b/services/surfaceflinger/SurfaceInterceptor.cpp @@ -323,11 +323,10 @@ void SurfaceInterceptor::addFlagsLocked(Transaction* transaction, int32_t layerI } 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::addDisplaySurfaceLocked(Transaction* transaction, int32 } } -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 9a3ce2c58d..970c3e5c27 100644 --- a/services/surfaceflinger/SurfaceInterceptor.h +++ b/services/surfaceflinger/SurfaceInterceptor.h @@ -48,7 +48,7 @@ using SurfaceChange = surfaceflinger::SurfaceChange; using Increment = surfaceflinger::Increment; using DisplayChange = surfaceflinger::DisplayChange; -constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.pb"; +constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.winscope"; class SurfaceInterceptor : public IBinder::DeathRecipient { public: @@ -160,7 +160,7 @@ private: 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 @@ private: 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/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h index 15a503d834..42a16c64a4 100644 --- a/services/surfaceflinger/SurfaceTracing.h +++ b/services/surfaceflinger/SurfaceTracing.h @@ -77,7 +77,7 @@ public: private: class Runner; static constexpr auto DEFAULT_BUFFER_SIZE = 5_MB; - static constexpr auto DEFAULT_FILE_NAME = "/data/misc/wmtrace/layers_trace.pb"; + static constexpr auto DEFAULT_FILE_NAME = "/data/misc/wmtrace/layers_trace.winscope"; SurfaceFlinger& mFlinger; mutable std::mutex mTraceLock; diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp index fa3f0e7239..d33bc1080c 100644 --- a/services/surfaceflinger/tests/Credentials_test.cpp +++ b/services/surfaceflinger/tests/Credentials_test.cpp @@ -93,7 +93,7 @@ protected: 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 af00ec7fc9..1361ded67d 100644 --- a/services/surfaceflinger/tests/EffectLayer_test.cpp +++ b/services/surfaceflinger/tests/EffectLayer_test.cpp @@ -33,7 +33,7 @@ protected: 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 9fa3d4c417..8d7e175cec 100644 --- a/services/surfaceflinger/tests/IPC_test.cpp +++ b/services/surfaceflinger/tests/IPC_test.cpp @@ -159,7 +159,7 @@ public: {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 @@ public: mDisplayHeight = mode.resolution.getHeight(); Transaction setupTransaction; - setupTransaction.setDisplayLayerStack(mPrimaryDisplay, 0); + setupTransaction.setDisplayLayerStack(mPrimaryDisplay, ui::DEFAULT_LAYER_STACK); setupTransaction.apply(); } @@ -310,7 +310,7 @@ TEST_F(IPCTest, MergeBasic) { 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 0bc8fe7aa0..6bd7920a62 100644 --- a/services/surfaceflinger/tests/LayerTransactionTest.h +++ b/services/surfaceflinger/tests/LayerTransactionTest.h @@ -266,7 +266,7 @@ protected: 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 @@ private: // 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 43d957cf7a..407625313c 100644 --- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp @@ -643,7 +643,8 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetLayerStackBasic) { 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 ee4d367f3d..e1a7ecc03b 100644 --- a/services/surfaceflinger/tests/LayerUpdate_test.cpp +++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp @@ -63,7 +63,7 @@ protected: 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 d02786504e..3ec6da9ff4 100644 --- a/services/surfaceflinger/tests/MirrorLayer_test.cpp +++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp @@ -36,7 +36,7 @@ protected: 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 08de01cdfb..1ed6c65afb 100644 --- a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp +++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp @@ -52,7 +52,7 @@ protected: 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 @@ protected: }); } - 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 @@ protected: }; 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 @@ TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInMirroredVirtualDisplay) { // 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 fde6e6eff8..50a4092ddb 100644 --- a/services/surfaceflinger/tests/RelativeZ_test.cpp +++ b/services/surfaceflinger/tests/RelativeZ_test.cpp @@ -43,7 +43,7 @@ protected: 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 ab2064efd0..95301b3a37 100644 --- a/services/surfaceflinger/tests/ScreenCapture_test.cpp +++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp @@ -53,7 +53,7 @@ protected: 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 @@ TEST_F(ScreenCaptureTest, CaptureSecureLayer) { Transaction() .show(redLayer) .show(secureLayer) - .setLayerStack(redLayer, 0) + .setLayerStack(redLayer, ui::DEFAULT_LAYER_STACK) .setLayer(redLayer, INT32_MAX) .apply(); @@ -655,7 +655,7 @@ TEST_F(ScreenCaptureTest, CaptureDisplayPrimaryDisplayOnly) { 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 @@ TEST_F(ScreenCaptureTest, CaptureDisplayChildPrimaryDisplayOnly) { .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 d5890ffa79..ee16f40b6d 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -61,7 +61,7 @@ constexpr auto UNIQUE_TEST_FG_SURFACE_NAME = "FG Interceptor Test Surface#0"; constexpr auto LAYER_NAME = "Layer Create and Delete Test"; constexpr auto UNIQUE_LAYER_NAME = "Layer Create and Delete Test#0"; -constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.pb"; +constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.winscope"; // Fill an RGBA_8888 formatted surface with a single color. static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b) { @@ -283,7 +283,7 @@ void SurfaceInterceptorTest::setupBackgroundSurface() { 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::transparentRegionHintUpdate(Transaction& t) { } 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 89f608645d..60cffb19df 100644 --- a/services/surfaceflinger/tests/TransactionTestHarnesses.h +++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h @@ -65,7 +65,7 @@ public: 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 89228d55e5..de116f29ca 100644 --- a/services/surfaceflinger/tests/WindowInfosListener_test.cpp +++ b/services/surfaceflinger/tests/WindowInfosListener_test.cpp @@ -84,7 +84,7 @@ TEST_F(WindowInfosListenerTest, WindowInfoAddedAndRemoved) { ISurfaceComposerClient::eFXSurfaceBufferState); Transaction() - .setLayerStack(surfaceControl, 0) + .setLayerStack(surfaceControl, ui::DEFAULT_LAYER_STACK) .show(surfaceControl) .setLayer(surfaceControl, INT32_MAX - 1) .setInputWindowInfo(surfaceControl, windowInfo) @@ -112,7 +112,7 @@ TEST_F(WindowInfosListenerTest, WindowInfoChanged) { 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 162711d6f5..b3b4ec15cd 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -279,7 +279,7 @@ protected: } 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 @@ protected: } 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 @@ protected: { 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 @@ protected: { 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 @@ protected: { 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 @@ protected: { 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 @@ protected: { 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 @@ protected: { 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 @@ protected: { 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 @@ protected: { 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 @@ protected: { 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 @@ protected: 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 @@ protected: 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 9e704c32fc..200ecbd894 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -23,7 +23,10 @@ package { 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 @@ -67,10 +70,10 @@ cc_test { "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", diff --git a/services/surfaceflinger/tests/unittests/CachingTest.cpp b/services/surfaceflinger/tests/unittests/CachingTest.cpp index 6a7ec9b553..6f85498670 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 @@ TEST_F(SlotGenerationTest, getHwcCacheSlot_Invalid) { 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 @@ TEST_F(SlotGenerationTest, getHwcCacheSlot_Basic) { 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 @@ TEST_F(SlotGenerationTest, getHwcCacheSlot_Reuse) { 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 52a36a2719..93a4ce2fae 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -77,12 +77,12 @@ constexpr hal::HWDisplayId HWC_DISPLAY = FakeHwcDisplayInjector::DEFAULT_HWC_DIS 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 @@ public: // pain) // mFlinger.mutableVisibleRegionsDirty() = true; - mFlinger.mutableGeometryInvalid() = true; + mFlinger.mutableGeometryDirty() = true; } template <typename Case> @@ -287,10 +287,8 @@ struct BaseDisplayVariant { 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 +307,7 @@ struct BaseDisplayVariant { .setPowerMode(Derived::INIT_POWER_MODE) .inject(); Mock::VerifyAndClear(test->mNativeWindow); - test->mDisplay->setLayerStack(DEFAULT_LAYER_STACK); + test->mDisplay->setLayerStack(LAYER_STACK); } template <typename Case> @@ -834,7 +832,7 @@ struct BaseLayerVariant { 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/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index cc24323c98..5a21e7be5b 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -122,7 +122,7 @@ void DisplayTransactionTest::injectFakeNativeWindowSurfaceFactory() { 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 @@ sp<DisplayDevice> DisplayTransactionTest::injectDefaultInternalDisplay( 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 de058a4f68..0f1cc6765d 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -267,11 +267,6 @@ struct DisplayVariant { .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 @@ struct DisplayVariant { auto injector = TestableSurfaceFlinger::FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay, - connectionType, + CONNECTION_TYPE::value, HWC_DISPLAY_ID_OPT::value, static_cast<bool>(PRIMARY)); @@ -388,7 +383,6 @@ struct HwcDisplayVariant { 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 4ff7592b71..28d0222829 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -41,10 +41,13 @@ namespace android { 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/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index 02ec7fc493..bb21ad63db 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -118,13 +118,15 @@ protected: 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 691676420c..597e5e71a2 100644 --- a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp +++ b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp @@ -72,7 +72,8 @@ TEST_F(OneShotTimerTest, startStopTest) { 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 @@ TEST_F(OneShotTimerTest, resetTest) { 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 @@ TEST_F(OneShotTimerTest, startNotCalledTest) { 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 @@ TEST_F(OneShotTimerTest, idleTimerIdlesTest) { 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 6870fd45fb..a6bfde791b 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -98,9 +98,15 @@ protected: static inline const DisplayModeId HWC_CONFIG_ID_30 = DisplayModeId(4); static inline const DisplayModeId HWC_CONFIG_ID_25 = DisplayModeId(5); static inline const DisplayModeId HWC_CONFIG_ID_50 = DisplayModeId(6); + static inline const DisplayModeId HWC_CONFIG_ID_24 = DisplayModeId(7); + static inline const DisplayModeId HWC_CONFIG_ID_24_FRAC = DisplayModeId(8); + static inline const DisplayModeId HWC_CONFIG_ID_30_FRAC = DisplayModeId(9); + static inline const DisplayModeId HWC_CONFIG_ID_60_FRAC = DisplayModeId(10); // Test configs DisplayModePtr mConfig60 = createDisplayMode(HWC_CONFIG_ID_60, 0, Fps(60.0f).getPeriodNsecs()); + DisplayModePtr mConfig60Frac = + createDisplayMode(HWC_CONFIG_ID_60_FRAC, 0, Fps(59.94f).getPeriodNsecs()); DisplayModePtr mConfig90 = createDisplayMode(HWC_CONFIG_ID_90, 0, Fps(90.0f).getPeriodNsecs()); DisplayModePtr mConfig90DifferentGroup = createDisplayMode(HWC_CONFIG_ID_90, 1, Fps(90.0f).getPeriodNsecs()); @@ -116,9 +122,15 @@ protected: DisplayModePtr mConfig30 = createDisplayMode(HWC_CONFIG_ID_30, 0, Fps(30.0f).getPeriodNsecs()); DisplayModePtr mConfig30DifferentGroup = createDisplayMode(HWC_CONFIG_ID_30, 1, Fps(30.0f).getPeriodNsecs()); + DisplayModePtr mConfig30Frac = + createDisplayMode(HWC_CONFIG_ID_30_FRAC, 0, Fps(29.97f).getPeriodNsecs()); + DisplayModePtr mConfig25 = createDisplayMode(HWC_CONFIG_ID_25, 0, Fps(25.0f).getPeriodNsecs()); DisplayModePtr mConfig25DifferentGroup = createDisplayMode(HWC_CONFIG_ID_25, 1, Fps(25.0f).getPeriodNsecs()); DisplayModePtr mConfig50 = createDisplayMode(HWC_CONFIG_ID_50, 0, Fps(50.0f).getPeriodNsecs()); + DisplayModePtr mConfig24 = createDisplayMode(HWC_CONFIG_ID_24, 0, Fps(24.0f).getPeriodNsecs()); + DisplayModePtr mConfig24Frac = + createDisplayMode(HWC_CONFIG_ID_24_FRAC, 0, Fps(23.976f).getPeriodNsecs()); // Test device configurations // The positions of the configs in the arrays below MUST match their IDs. For example, @@ -145,6 +157,11 @@ protected: mConfig50}; DisplayModes m60_120Device = {mConfig60, mConfig120}; + // This is a typical TV configuration. + DisplayModes m24_25_30_50_60WithFracDevice = {mConfig24, mConfig24Frac, mConfig25, + mConfig30, mConfig30Frac, mConfig50, + mConfig60, mConfig60Frac}; + // Expected RefreshRate objects RefreshRate mExpected60Config = {mConfig60, RefreshRate::ConstructorTag(0)}; RefreshRate mExpectedAlmost60Config = {createDisplayMode(HWC_CONFIG_ID_60, 0, 16666665), @@ -181,7 +198,7 @@ DisplayModePtr RefreshRateConfigsTest::createDisplayMode(DisplayModeId modeId, i 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) @@ -1230,7 +1247,109 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitDefault) { const auto& refreshRate = refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}); EXPECT_TRUE(refreshRate.getFps().equalsWithMargin(Fps(test.second))) - << "Expecting " << test.first << "fps => " << test.second << "Hz"; + << "Expecting " << test.first << "fps => " << test.second << "Hz" + << " but it was " << refreshRate.getFps(); + } +} + +TEST_F(RefreshRateConfigsTest, + getBestRefreshRate_ExplicitExactOrMultiple_WithFractionalRefreshRates) { + auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}}; + auto& lr = layers[0]; + + // Test that 23.976 will choose 24 if 23.976 is not supported + { + android::DisplayModes modes = {mConfig24, mConfig25, mConfig30, + mConfig30Frac, mConfig60, mConfig60Frac}; + auto refreshRateConfigs = + std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60); + + lr.vote = LayerVoteType::ExplicitExactOrMultiple; + lr.desiredRefreshRate = Fps(23.976f); + lr.name = "ExplicitExactOrMultiple 23.976 fps"; + EXPECT_EQ(HWC_CONFIG_ID_24, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getModeId()); + } + + // Test that 24 will choose 23.976 if 24 is not supported + { + android::DisplayModes modes = {mConfig24Frac, mConfig25, mConfig30, + mConfig30Frac, mConfig60, mConfig60Frac}; + auto refreshRateConfigs = + std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60); + lr.desiredRefreshRate = Fps(24.f); + lr.name = "ExplicitExactOrMultiple 24 fps"; + EXPECT_EQ(HWC_CONFIG_ID_24_FRAC, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getModeId()); + } + + // Test that 29.97 will prefer 59.94 over 60 and 30 + { + android::DisplayModes modes = {mConfig24, mConfig24Frac, mConfig25, + mConfig30, mConfig60, mConfig60Frac}; + auto refreshRateConfigs = + std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60); + lr.desiredRefreshRate = Fps(29.97f); + lr.name = "ExplicitExactOrMultiple 29.97f fps"; + EXPECT_EQ(HWC_CONFIG_ID_60_FRAC, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getModeId()); + } +} + +TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExact_WithFractionalRefreshRates) { + auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}}; + auto& lr = layers[0]; + + // Test that voting for supported refresh rate will select this refresh rate + { + auto refreshRateConfigs = + std::make_unique<RefreshRateConfigs>(m24_25_30_50_60WithFracDevice, + /*currentConfigId=*/HWC_CONFIG_ID_60); + + for (auto desiredRefreshRate : {23.976f, 24.f, 25.f, 29.97f, 30.f, 50.f, 59.94f, 60.f}) { + lr.vote = LayerVoteType::ExplicitExact; + lr.desiredRefreshRate = Fps(desiredRefreshRate); + std::stringstream ss; + ss << "ExplicitExact " << desiredRefreshRate << " fps"; + lr.name = ss.str(); + + auto selecteRefreshRate = + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}); + + EXPECT_TRUE(selecteRefreshRate.getFps().equalsWithMargin(lr.desiredRefreshRate)) + << "Expecting " << lr.desiredRefreshRate << " but it was " + << selecteRefreshRate.getFps(); + } + } + + // Test that 23.976 will choose 24 if 23.976 is not supported + { + android::DisplayModes modes = {mConfig24, mConfig25, mConfig30, + mConfig30Frac, mConfig60, mConfig60Frac}; + auto refreshRateConfigs = + std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60); + lr.vote = LayerVoteType::ExplicitExact; + lr.desiredRefreshRate = Fps(23.976f); + lr.name = "ExplicitExact 23.976 fps"; + EXPECT_EQ(HWC_CONFIG_ID_24, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getModeId()); + } + + // Test that 24 will choose 23.976 if 24 is not supported + { + android::DisplayModes modes = {mConfig24Frac, mConfig25, mConfig30, + mConfig30Frac, mConfig60, mConfig60Frac}; + auto refreshRateConfigs = + std::make_unique<RefreshRateConfigs>(modes, /*currentConfigId=*/HWC_CONFIG_ID_60); + lr.desiredRefreshRate = Fps(24.f); + lr.name = "ExplicitExact 24 fps"; + EXPECT_EQ(HWC_CONFIG_ID_24_FRAC, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getModeId()); } } @@ -2028,6 +2147,29 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExactTouchBoost) { refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false})); } +TEST_F(RefreshRateConfigsTest, getBestRefreshRate_FractionalRefreshRates_ExactAndDefault) { + RefreshRateConfigs::Config config = {.enableFrameRateOverride = true}; + auto refreshRateConfigs = + std::make_unique<RefreshRateConfigs>(m24_25_30_50_60WithFracDevice, + /*currentConfigId=*/HWC_CONFIG_ID_60, config); + + auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 0.5f}, + LayerRequirement{.weight = 0.5f}}; + auto& explicitDefaultLayer = layers[0]; + auto& explicitExactOrMultipleLayer = layers[1]; + + explicitExactOrMultipleLayer.vote = LayerVoteType::ExplicitExactOrMultiple; + explicitExactOrMultipleLayer.name = "ExplicitExactOrMultiple"; + explicitExactOrMultipleLayer.desiredRefreshRate = Fps(60); + + explicitDefaultLayer.vote = LayerVoteType::ExplicitDefault; + explicitDefaultLayer.name = "ExplicitDefault"; + explicitDefaultLayer.desiredRefreshRate = Fps(59.94f); + + EXPECT_EQ(mExpected60Config, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); +} + TEST_F(RefreshRateConfigsTest, testComparisonOperator) { EXPECT_TRUE(mExpected60Config < mExpected90Config); EXPECT_FALSE(mExpected60Config < mExpected60Config); @@ -2116,7 +2258,38 @@ TEST_F(RefreshRateConfigsTest, getFrameRateDivider) { refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_90); displayRefreshRate = refreshRateConfigs->getCurrentRefreshRate().getFps(); EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, Fps(22.5f))); - EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, Fps(22.6f))); + + EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(Fps(24.f), Fps(25.f))); + EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(Fps(24.f), Fps(23.976f))); + EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(Fps(30.f), Fps(29.97f))); + 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) { diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp index 12b155bd2c..0a8759de66 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp @@ -81,7 +81,7 @@ DisplayModePtr RefreshRateStatsTest::createDisplayMode(DisplayModeId modeId, int 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 5713c2f64a..e2b3993211 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -34,7 +34,7 @@ using testing::Return; 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 @@ protected: 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 index b713334f99..6959ee35c3 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 @@ public: }; template <typename Case> -void HandleTransactionLockedTest::setupCommonPreconditions() { +void DisplayTransactionCommitTest::setupCommonPreconditions() { // Wide color displays support is configured appropriately Case::WideColorSupport::injectConfigChange(this); @@ -68,7 +67,7 @@ void HandleTransactionLockedTest::setupCommonPreconditions() { } 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 @@ void HandleTransactionLockedTest::expectHotplugReceived(mock::EventThread* event } template <typename Case> -void HandleTransactionLockedTest::setupCommonCallExpectationsForConnectProcessing() { +void DisplayTransactionCommitTest::setupCommonCallExpectationsForConnectProcessing() { Case::Display::setupHwcHotplugCallExpectations(this); Case::Display::setupFramebufferConsumerBufferQueueCallExpectations(this); @@ -97,7 +96,7 @@ void HandleTransactionLockedTest::setupCommonCallExpectationsForConnectProcessin } template <typename Case> -void HandleTransactionLockedTest::setupCommonCallExpectationsForDisconnectProcessing() { +void DisplayTransactionCommitTest::setupCommonCallExpectationsForDisconnectProcessing() { EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1); expectHotplugReceived<Case, false>(mEventThread); @@ -105,7 +104,7 @@ void HandleTransactionLockedTest::setupCommonCallExpectationsForDisconnectProces } 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 @@ void HandleTransactionLockedTest::verifyDisplayIsConnected(const sp<IBinder>& di } 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 @@ void HandleTransactionLockedTest::verifyPhysicalDisplayIsConnected() { 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 @@ void HandleTransactionLockedTest::processesHotplugConnectCommon() { // -------------------------------------------------------------------- // Invocation - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); // -------------------------------------------------------------------- // Postconditions @@ -191,7 +190,7 @@ void HandleTransactionLockedTest::processesHotplugConnectCommon() { } template <typename Case> -void HandleTransactionLockedTest::ignoresHotplugConnectCommon() { +void DisplayTransactionCommitTest::ignoresHotplugConnectCommon() { // -------------------------------------------------------------------- // Preconditions @@ -203,7 +202,7 @@ void HandleTransactionLockedTest::ignoresHotplugConnectCommon() { // -------------------------------------------------------------------- // Invocation - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); // -------------------------------------------------------------------- // Postconditions @@ -213,7 +212,7 @@ void HandleTransactionLockedTest::ignoresHotplugConnectCommon() { } template <typename Case> -void HandleTransactionLockedTest::processesHotplugDisconnectCommon() { +void DisplayTransactionCommitTest::processesHotplugDisconnectCommon() { // -------------------------------------------------------------------- // Preconditions @@ -238,7 +237,7 @@ void HandleTransactionLockedTest::processesHotplugDisconnectCommon() { // -------------------------------------------------------------------- // Invocation - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); // -------------------------------------------------------------------- // Postconditions @@ -255,18 +254,18 @@ void HandleTransactionLockedTest::processesHotplugDisconnectCommon() { 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 @@ TEST_F(HandleTransactionLockedTest, ignoresHotplugConnectIfPrimaryAndExternalAlr 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 @@ TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAdded) { // -------------------------------------------------------------------- // Invocation - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); // -------------------------------------------------------------------- // Postconditions @@ -453,7 +463,7 @@ TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAdded) { mFlinger.mutableDrawingState().displays.removeItem(displayToken); } -TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAddedWithNoSurface) { +TEST_F(DisplayTransactionCommitTest, processesVirtualDisplayAddedWithNoSurface) { using Case = HwcVirtualDisplayCase; // -------------------------------------------------------------------- @@ -479,7 +489,7 @@ TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAddedWithNoSurface) { // -------------------------------------------------------------------- // Invocation - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); // -------------------------------------------------------------------- // Postconditions @@ -493,7 +503,7 @@ TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAddedWithNoSurface) { 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 @@ TEST_F(HandleTransactionLockedTest, processesVirtualDisplayRemoval) { // -------------------------------------------------------------------- // Invocation - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); // -------------------------------------------------------------------- // Postconditions @@ -520,11 +530,11 @@ TEST_F(HandleTransactionLockedTest, processesVirtualDisplayRemoval) { 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 @@ TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackChanges) { // -------------------------------------------------------------------- // Invocation - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); // -------------------------------------------------------------------- // Postconditions @@ -548,7 +558,7 @@ TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackChanges) { 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 @@ TEST_F(HandleTransactionLockedTest, processesDisplayTransformChanges) { // -------------------------------------------------------------------- // Invocation - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); // -------------------------------------------------------------------- // Postconditions @@ -576,7 +586,7 @@ TEST_F(HandleTransactionLockedTest, processesDisplayTransformChanges) { 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 @@ TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackRectChanges) { // -------------------------------------------------------------------- // Invocation - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); // -------------------------------------------------------------------- // Postconditions @@ -604,7 +614,7 @@ TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackRectChanges) { 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 @@ TEST_F(HandleTransactionLockedTest, processesDisplayRectChanges) { // -------------------------------------------------------------------- // Invocation - mFlinger.handleTransactionLocked(eDisplayTransactionNeeded); + mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded); // -------------------------------------------------------------------- // Postconditions @@ -632,7 +642,7 @@ TEST_F(HandleTransactionLockedTest, processesDisplayRectChanges) { 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 @@ TEST_F(HandleTransactionLockedTest, processesDisplayWidthChanges) { // -------------------------------------------------------------------- // 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 @@ TEST_F(HandleTransactionLockedTest, processesDisplayHeightChanges) { // -------------------------------------------------------------------- // 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 @@ TEST_F(HandleTransactionLockedTest, processesDisplaySizeDisplayRectAndLayerStack // -------------------------------------------------------------------- // 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 ef8b1493ae..bafa910270 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp @@ -63,15 +63,11 @@ TEST_F(OnInitializeDisplaysTest, onInitializeDisplaysSetsUpPrimaryDisplay) { // 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 - EXPECT_EQ(ui::ROTATION_0, primaryDisplayState.orientation); - // The orientedDisplaySpaceRect state should be set to INVALID + // The primary display state should be reset + EXPECT_EQ(ui::DEFAULT_LAYER_STACK, primaryDisplayState.layerStack); + EXPECT_EQ(ui::ROTATION_0, primaryDisplayState.orientation); 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 @@ TEST_F(OnInitializeDisplaysTest, onInitializeDisplaysSetsUpPrimaryDisplay) { } } // 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 fc40818ad1..7d9e22b23e 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 @@ TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingWithUnknownDis DisplayState state; state.what = DisplayState::eLayerStackChanged; state.token = displayToken; - state.layerStack = 456; + state.layerStack = LAYER_STACK; // -------------------------------------------------------------------- // Invocation @@ -167,13 +169,13 @@ TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingIfLayerStackDi 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 @@ TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingIfLayerStackDi 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 @@ TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfLayerStac 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 @@ TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfLayerStac 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 e32c4bf145..7ead0af26d 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp @@ -292,7 +292,9 @@ TEST_F(SetupNewDisplayDeviceInternalTest, createSimplePrimaryDisplay) { } 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 40c881e902..d8352ed9d4 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -209,7 +209,7 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: } auto setDisplayStateLocked(const DisplayState& s) { - Mutex::Autolock _l(mFlinger->mStateLock); + Mutex::Autolock lock(mFlinger->mStateLock); return mFlinger->setDisplayStateLocked(s); } @@ -426,7 +426,7 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: }; 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 7de187207e..20d41e6072 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 ab19886755..291559f2f9 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 26052fba63..33401d24d6 100644 --- a/vulkan/libvulkan/api_gen.cpp +++ b/vulkan/libvulkan/api_gen.cpp @@ -560,6 +560,7 @@ VKAPI_ATTR PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pNa } static const char* const known_non_device_names[] = { + "vkAcquireDrmDisplayEXT", "vkCreateAndroidSurfaceKHR", "vkCreateDebugReportCallbackEXT", "vkCreateDebugUtilsMessengerEXT", @@ -581,6 +582,7 @@ VKAPI_ATTR PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pNa "vkEnumeratePhysicalDevices", "vkGetDisplayModeProperties2KHR", "vkGetDisplayPlaneCapabilities2KHR", + "vkGetDrmDisplayEXT", "vkGetInstanceProcAddr", "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT", "vkGetPhysicalDeviceDisplayPlaneProperties2KHR", @@ -624,6 +626,8 @@ VKAPI_ATTR PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pNa "vkGetPhysicalDeviceSurfacePresentModesKHR", "vkGetPhysicalDeviceSurfaceSupportKHR", "vkGetPhysicalDeviceToolPropertiesEXT", + "vkGetPhysicalDeviceVideoCapabilitiesKHR", + "vkGetPhysicalDeviceVideoFormatPropertiesKHR", "vkSubmitDebugUtilsMessageEXT", }; // clang-format on diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index d7fdab5586..cf774fd9b8 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -979,6 +979,8 @@ VkResult EnumerateInstanceExtensionProperties( 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 @@ void QueryPresentationProperties( 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 72fd4fbc9c..4176509447 100644 --- a/vulkan/scripts/generator_common.py +++ b/vulkan/scripts/generator_common.py @@ -33,6 +33,7 @@ _BLOCKED_EXTENSIONS = [ '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 @@ _BLOCKED_EXTENSIONS = [ '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. |