Merge "SurfaceFlinger: call setFrameTimelineVsyncForTransaction with valid id"
diff --git a/include/ftl/ArrayTraits.h b/include/ftl/ArrayTraits.h
new file mode 100644
index 0000000..28f717a
--- /dev/null
+++ b/include/ftl/ArrayTraits.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <iterator>
+#include <new>
+
+#define FTL_ARRAY_TRAIT(T, U) using U = typename ArrayTraits<T>::U
+
+namespace android::ftl {
+
+template <typename T>
+struct ArrayTraits {
+ using value_type = T;
+ using size_type = size_t;
+ using difference_type = ptrdiff_t;
+
+ using pointer = value_type*;
+ using reference = value_type&;
+ using iterator = pointer;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+
+ using const_pointer = const value_type*;
+ using const_reference = const value_type&;
+ using const_iterator = const_pointer;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ // TODO: Replace with std::construct_at in C++20.
+ template <typename... Args>
+ static pointer construct_at(const_iterator it, Args&&... args) {
+ void* const ptr = const_cast<void*>(static_cast<const void*>(it));
+ return new (ptr) value_type{std::forward<Args>(args)...};
+ }
+};
+
+// CRTP mixin to define iterator functions in terms of non-const Self::begin and Self::end.
+template <typename Self, typename T>
+class ArrayIterators {
+ FTL_ARRAY_TRAIT(T, size_type);
+
+ FTL_ARRAY_TRAIT(T, reference);
+ FTL_ARRAY_TRAIT(T, iterator);
+ FTL_ARRAY_TRAIT(T, reverse_iterator);
+
+ FTL_ARRAY_TRAIT(T, const_reference);
+ FTL_ARRAY_TRAIT(T, const_iterator);
+ FTL_ARRAY_TRAIT(T, const_reverse_iterator);
+
+ Self& self() const { return *const_cast<Self*>(static_cast<const Self*>(this)); }
+
+public:
+ const_iterator begin() const { return cbegin(); }
+ const_iterator cbegin() const { return self().begin(); }
+
+ const_iterator end() const { return cend(); }
+ const_iterator cend() const { return self().end(); }
+
+ reverse_iterator rbegin() { return std::make_reverse_iterator(self().end()); }
+ const_reverse_iterator rbegin() const { return crbegin(); }
+ const_reverse_iterator crbegin() const { return self().rbegin(); }
+
+ reverse_iterator rend() { return std::make_reverse_iterator(self().begin()); }
+ const_reverse_iterator rend() const { return crend(); }
+ const_reverse_iterator crend() const { return self().rend(); }
+
+ iterator last() { return self().end() - 1; }
+ const_iterator last() const { return self().last(); }
+
+ reference front() { return *self().begin(); }
+ const_reference front() const { return self().front(); }
+
+ reference back() { return *last(); }
+ const_reference back() const { return self().back(); }
+
+ reference operator[](size_type i) { return *(self().begin() + i); }
+ const_reference operator[](size_type i) const { return self()[i]; }
+};
+
+// Mixin to define comparison operators for an array-like template.
+// TODO: Replace with operator<=> in C++20.
+template <template <typename, size_t> class Array>
+struct ArrayComparators {
+ template <typename T, size_t N, size_t M>
+ friend bool operator==(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+ return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+ }
+
+ template <typename T, size_t N, size_t M>
+ friend bool operator<(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+ return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+ }
+
+ template <typename T, size_t N, size_t M>
+ friend bool operator>(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+ return rhs < lhs;
+ }
+
+ template <typename T, size_t N, size_t M>
+ friend bool operator!=(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+ return !(lhs == rhs);
+ }
+
+ template <typename T, size_t N, size_t M>
+ friend bool operator>=(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+ return !(lhs < rhs);
+ }
+
+ template <typename T, size_t N, size_t M>
+ friend bool operator<=(const Array<T, N>& lhs, const Array<T, M>& rhs) {
+ return !(lhs > rhs);
+ }
+};
+
+} // namespace android::ftl
diff --git a/include/ftl/SmallVector.h b/include/ftl/SmallVector.h
new file mode 100644
index 0000000..cecec7f
--- /dev/null
+++ b/include/ftl/SmallVector.h
@@ -0,0 +1,380 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ftl/ArrayTraits.h>
+#include <ftl/StaticVector.h>
+
+#include <algorithm>
+#include <iterator>
+#include <type_traits>
+#include <utility>
+#include <variant>
+#include <vector>
+
+namespace android::ftl {
+
+template <typename>
+struct IsSmallVector;
+
+// ftl::StaticVector that promotes to std::vector when full. SmallVector is a drop-in replacement
+// for std::vector with statically allocated storage for N elements, whose goal is to improve run
+// time by avoiding heap allocation and increasing probability of cache hits. The standard API is
+// augmented by an unstable_erase operation that does not preserve order, and a replace operation
+// that destructively emplaces.
+//
+// SmallVector<T, 0> is a specialization that thinly wraps std::vector.
+//
+// Example usage:
+//
+// ftl::SmallVector<char, 3> vector;
+// assert(vector.empty());
+// assert(!vector.dynamic());
+//
+// vector = {'a', 'b', 'c'};
+// assert(vector.size() == 3u);
+// assert(!vector.dynamic());
+//
+// vector.push_back('d');
+// assert(vector.dynamic());
+//
+// vector.unstable_erase(vector.begin());
+// assert(vector == (ftl::SmallVector{'d', 'b', 'c'}));
+//
+// vector.pop_back();
+// assert(vector.back() == 'b');
+// assert(vector.dynamic());
+//
+// const char array[] = "hi";
+// vector = ftl::SmallVector(array);
+// assert(vector == (ftl::SmallVector{'h', 'i', '\0'}));
+// assert(!vector.dynamic());
+//
+template <typename T, size_t N>
+class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> {
+ using Static = StaticVector<T, N>;
+ using Dynamic = SmallVector<T, 0>;
+
+ // TODO: Replace with std::remove_cvref_t in C++20.
+ template <typename U>
+ using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<U>>;
+
+public:
+ FTL_ARRAY_TRAIT(T, value_type);
+ FTL_ARRAY_TRAIT(T, size_type);
+ FTL_ARRAY_TRAIT(T, difference_type);
+
+ FTL_ARRAY_TRAIT(T, pointer);
+ FTL_ARRAY_TRAIT(T, reference);
+ FTL_ARRAY_TRAIT(T, iterator);
+ FTL_ARRAY_TRAIT(T, reverse_iterator);
+
+ FTL_ARRAY_TRAIT(T, const_pointer);
+ FTL_ARRAY_TRAIT(T, const_reference);
+ FTL_ARRAY_TRAIT(T, const_iterator);
+ FTL_ARRAY_TRAIT(T, const_reverse_iterator);
+
+ // Creates an empty vector.
+ SmallVector() = default;
+
+ // Constructs at most N elements. See StaticVector for underlying constructors.
+ template <typename Arg, typename... Args,
+ typename = std::enable_if_t<!IsSmallVector<remove_cvref_t<Arg>>{}>>
+ SmallVector(Arg&& arg, Args&&... args)
+ : mVector(std::in_place_type<Static>, std::forward<Arg>(arg),
+ std::forward<Args>(args)...) {}
+
+ // Copies at most N elements from a smaller convertible vector.
+ template <typename U, size_t M, typename = std::enable_if_t<M <= N>>
+ SmallVector(const SmallVector<U, M>& other)
+ : SmallVector(IteratorRange, other.begin(), other.end()) {}
+
+ void swap(SmallVector& other) { mVector.swap(other.mVector); }
+
+ // Returns whether the vector is backed by static or dynamic storage.
+ bool dynamic() const { return std::holds_alternative<Dynamic>(mVector); }
+
+ // Avoid std::visit as it generates a dispatch table.
+#define DISPATCH(T, F, ...) \
+ T F() __VA_ARGS__ { \
+ return dynamic() ? std::get<Dynamic>(mVector).F() : std::get<Static>(mVector).F(); \
+ }
+
+ DISPATCH(size_type, max_size, const)
+ DISPATCH(size_type, size, const)
+ DISPATCH(bool, empty, const)
+
+ // noexcept to suppress warning about zero variadic macro arguments.
+ DISPATCH(iterator, begin, noexcept)
+ DISPATCH(const_iterator, begin, const)
+ DISPATCH(const_iterator, cbegin, const)
+
+ DISPATCH(iterator, end, noexcept)
+ DISPATCH(const_iterator, end, const)
+ DISPATCH(const_iterator, cend, const)
+
+ DISPATCH(reverse_iterator, rbegin, noexcept)
+ DISPATCH(const_reverse_iterator, rbegin, const)
+ DISPATCH(const_reverse_iterator, crbegin, const)
+
+ DISPATCH(reverse_iterator, rend, noexcept)
+ DISPATCH(const_reverse_iterator, rend, const)
+ DISPATCH(const_reverse_iterator, crend, const)
+
+ DISPATCH(iterator, last, noexcept)
+ DISPATCH(const_iterator, last, const)
+
+ DISPATCH(reference, front, noexcept)
+ DISPATCH(const_reference, front, const)
+
+ DISPATCH(reference, back, noexcept)
+ DISPATCH(const_reference, back, const)
+
+#undef DISPATCH
+
+ reference operator[](size_type i) {
+ return dynamic() ? std::get<Dynamic>(mVector)[i] : std::get<Static>(mVector)[i];
+ }
+
+ const_reference operator[](size_type i) const { return const_cast<SmallVector&>(*this)[i]; }
+
+ // Replaces an element, and returns a reference to it. The iterator must be dereferenceable, so
+ // replacing at end() is erroneous.
+ //
+ // The element is emplaced via move constructor, so type T 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 element being replaced.
+ //
+ // Iterators to the replaced element point to its replacement, and others remain valid.
+ //
+ template <typename... Args>
+ reference replace(const_iterator it, Args&&... args) {
+ if (dynamic()) {
+ return std::get<Dynamic>(mVector).replace(it, std::forward<Args>(args)...);
+ } else {
+ return std::get<Static>(mVector).replace(it, std::forward<Args>(args)...);
+ }
+ }
+
+ // Appends an element, and returns a reference to it.
+ //
+ // If the vector reaches its static or dynamic capacity, then all iterators are invalidated.
+ // Otherwise, only the end() iterator is invalidated.
+ //
+ template <typename... Args>
+ reference emplace_back(Args&&... args) {
+ constexpr auto insertStatic = &Static::template emplace_back<Args...>;
+ constexpr auto insertDynamic = &Dynamic::template emplace_back<Args...>;
+ return *insert<insertStatic, insertDynamic>(std::forward<Args>(args)...);
+ }
+
+ // Appends an element.
+ //
+ // If the vector reaches its static or dynamic capacity, then all iterators are invalidated.
+ // Otherwise, only the end() iterator is invalidated.
+ //
+ void push_back(const value_type& v) {
+ constexpr auto insertStatic =
+ static_cast<bool (Static::*)(const value_type&)>(&Static::push_back);
+ constexpr auto insertDynamic =
+ static_cast<bool (Dynamic::*)(const value_type&)>(&Dynamic::push_back);
+ insert<insertStatic, insertDynamic>(v);
+ }
+
+ void push_back(value_type&& v) {
+ constexpr auto insertStatic =
+ static_cast<bool (Static::*)(value_type&&)>(&Static::push_back);
+ constexpr auto insertDynamic =
+ static_cast<bool (Dynamic::*)(value_type&&)>(&Dynamic::push_back);
+ insert<insertStatic, insertDynamic>(std::move(v));
+ }
+
+ // Removes the last element. The vector must not be empty, or the call is erroneous.
+ //
+ // The last() and end() iterators are invalidated.
+ //
+ void pop_back() {
+ if (dynamic()) {
+ std::get<Dynamic>(mVector).pop_back();
+ } else {
+ std::get<Static>(mVector).pop_back();
+ }
+ }
+
+ // Erases an element, but does not preserve order. Rather than shifting subsequent elements,
+ // this moves the last element to the slot of the erased element.
+ //
+ // The last() and end() iterators, as well as those to the erased element, are invalidated.
+ //
+ void unstable_erase(iterator it) {
+ if (dynamic()) {
+ std::get<Dynamic>(mVector).unstable_erase(it);
+ } else {
+ std::get<Static>(mVector).unstable_erase(it);
+ }
+ }
+
+private:
+ template <auto insertStatic, auto insertDynamic, typename... Args>
+ auto insert(Args&&... args) {
+ if (Dynamic* const vector = std::get_if<Dynamic>(&mVector)) {
+ return (vector->*insertDynamic)(std::forward<Args>(args)...);
+ }
+
+ auto& vector = std::get<Static>(mVector);
+ if (vector.full()) {
+ return (promote(vector).*insertDynamic)(std::forward<Args>(args)...);
+ } else {
+ return (vector.*insertStatic)(std::forward<Args>(args)...);
+ }
+ }
+
+ Dynamic& promote(Static& staticVector) {
+ assert(staticVector.full());
+
+ // Allocate double capacity to reduce probability of reallocation.
+ Dynamic vector;
+ vector.reserve(Static::max_size() * 2);
+ std::move(staticVector.begin(), staticVector.end(), std::back_inserter(vector));
+
+ return mVector.template emplace<Dynamic>(std::move(vector));
+ }
+
+ std::variant<Static, Dynamic> mVector;
+};
+
+// Partial specialization without static storage.
+template <typename T>
+class SmallVector<T, 0> final : ArrayTraits<T>,
+ ArrayIterators<SmallVector<T, 0>, T>,
+ std::vector<T> {
+ using ArrayTraits<T>::construct_at;
+
+ using Iter = ArrayIterators<SmallVector, T>;
+ using Impl = std::vector<T>;
+
+ friend Iter;
+
+public:
+ FTL_ARRAY_TRAIT(T, value_type);
+ FTL_ARRAY_TRAIT(T, size_type);
+ FTL_ARRAY_TRAIT(T, difference_type);
+
+ FTL_ARRAY_TRAIT(T, pointer);
+ FTL_ARRAY_TRAIT(T, reference);
+ FTL_ARRAY_TRAIT(T, iterator);
+ FTL_ARRAY_TRAIT(T, reverse_iterator);
+
+ FTL_ARRAY_TRAIT(T, const_pointer);
+ FTL_ARRAY_TRAIT(T, const_reference);
+ FTL_ARRAY_TRAIT(T, const_iterator);
+ FTL_ARRAY_TRAIT(T, const_reverse_iterator);
+
+ using Impl::Impl;
+
+ using Impl::empty;
+ using Impl::max_size;
+ using Impl::size;
+
+ using Impl::reserve;
+
+ // std::vector iterators are not necessarily raw pointers.
+ iterator begin() { return Impl::data(); }
+ iterator end() { return Impl::data() + size(); }
+
+ using Iter::begin;
+ using Iter::end;
+
+ using Iter::cbegin;
+ using Iter::cend;
+
+ using Iter::rbegin;
+ using Iter::rend;
+
+ using Iter::crbegin;
+ using Iter::crend;
+
+ using Iter::last;
+
+ using Iter::back;
+ using Iter::front;
+
+ using Iter::operator[];
+
+ template <typename... Args>
+ reference replace(const_iterator it, Args&&... args) {
+ value_type element{std::forward<Args>(args)...};
+ std::destroy_at(it);
+ // This is only safe because exceptions are disabled.
+ return *construct_at(it, std::move(element));
+ }
+
+ template <typename... Args>
+ iterator emplace_back(Args&&... args) {
+ return &Impl::emplace_back(std::forward<Args>(args)...);
+ }
+
+ bool push_back(const value_type& v) {
+ Impl::push_back(v);
+ return true;
+ }
+
+ bool push_back(value_type&& v) {
+ Impl::push_back(std::move(v));
+ return true;
+ }
+
+ using Impl::pop_back;
+
+ void unstable_erase(iterator it) {
+ if (it != last()) std::iter_swap(it, last());
+ pop_back();
+ }
+
+ void swap(SmallVector& other) { Impl::swap(other); }
+};
+
+template <typename>
+struct IsSmallVector : std::false_type {};
+
+template <typename T, size_t N>
+struct IsSmallVector<SmallVector<T, N>> : std::true_type {};
+
+// Deduction guide for array constructor.
+template <typename T, size_t N>
+SmallVector(T (&)[N]) -> SmallVector<std::remove_cv_t<T>, N>;
+
+// Deduction guide for variadic constructor.
+template <typename T, typename... Us, typename V = std::decay_t<T>,
+ typename = std::enable_if_t<(std::is_constructible_v<V, Us> && ...)>>
+SmallVector(T&&, Us&&...) -> SmallVector<V, 1 + sizeof...(Us)>;
+
+// Deduction guide for in-place constructor.
+template <typename T, typename... Us>
+SmallVector(std::in_place_type_t<T>, Us&&...) -> SmallVector<T, sizeof...(Us)>;
+
+// Deduction guide for StaticVector conversion.
+template <typename T, size_t N>
+SmallVector(StaticVector<T, N>&&) -> SmallVector<T, N>;
+
+template <typename T, size_t N>
+inline void swap(SmallVector<T, N>& lhs, SmallVector<T, N>& rhs) {
+ lhs.swap(rhs);
+}
+
+} // namespace android::ftl
diff --git a/include/ftl/StaticVector.h b/include/ftl/StaticVector.h
index b586e91..457095d 100644
--- a/include/ftl/StaticVector.h
+++ b/include/ftl/StaticVector.h
@@ -16,22 +16,25 @@
#pragma once
+#include <ftl/ArrayTraits.h>
+
#include <algorithm>
#include <cassert>
#include <iterator>
#include <memory>
-#include <new>
#include <type_traits>
#include <utility>
namespace android::ftl {
+constexpr struct IteratorRangeTag {} IteratorRange;
+
// Fixed-capacity, statically allocated counterpart of std::vector. Akin to std::array, StaticVector
// allocates contiguous storage for N elements of type T at compile time, but stores at most (rather
// than exactly) N elements. Unlike std::array, its default constructor does not require T to have a
// default constructor, since elements are constructed in-place as the vector grows. Operations that
-// insert an element, such as push_back and emplace, fail when the vector is full. The API otherwise
-// adheres to standard containers, except the unstable_erase operation that does not shift elements,
+// insert an element (emplace_back, push_back, etc.) fail when the vector is full. The API otherwise
+// adheres to standard containers, except the unstable_erase operation that does not preserve order,
// and the replace operation that destructively emplaces.
//
// StaticVector<T, 1> is analogous to an iterable std::optional, but StaticVector<T, 0> is an error.
@@ -61,46 +64,70 @@
// assert(vector == (ftl::StaticVector{'h', 'i', '\0'}));
//
template <typename T, size_t N>
-class StaticVector {
+class StaticVector final : ArrayTraits<T>,
+ ArrayIterators<StaticVector<T, N>, T>,
+ ArrayComparators<StaticVector> {
static_assert(N > 0);
- template <typename I>
- using IsInputIterator = std::is_base_of<std::input_iterator_tag,
- typename std::iterator_traits<I>::iterator_category>;
+ using ArrayTraits<T>::construct_at;
+
+ using Iter = ArrayIterators<StaticVector, T>;
+ friend Iter;
+
+ // There is ambiguity when constructing from two iterator-like elements like pointers:
+ // they could be an iterator range, or arguments for in-place construction. Assume the
+ // latter unless they are input iterators and cannot be used to construct elements. If
+ // the former is intended, the caller can pass an IteratorRangeTag to disambiguate.
+ template <typename I, typename Traits = std::iterator_traits<I>>
+ using IsInputIterator = std::conjunction<
+ std::is_base_of<std::input_iterator_tag, typename Traits::iterator_category>,
+ std::negation<std::is_constructible<T, I>>>;
public:
- using value_type = T;
- using size_type = size_t;
- using difference_type = ptrdiff_t;
+ FTL_ARRAY_TRAIT(T, value_type);
+ FTL_ARRAY_TRAIT(T, size_type);
+ FTL_ARRAY_TRAIT(T, difference_type);
- using pointer = value_type*;
- using reference = value_type&;
- using iterator = pointer;
- using reverse_iterator = std::reverse_iterator<iterator>;
+ FTL_ARRAY_TRAIT(T, pointer);
+ FTL_ARRAY_TRAIT(T, reference);
+ FTL_ARRAY_TRAIT(T, iterator);
+ FTL_ARRAY_TRAIT(T, reverse_iterator);
- using const_pointer = const value_type*;
- using const_reference = const value_type&;
- using const_iterator = const_pointer;
- using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+ FTL_ARRAY_TRAIT(T, const_pointer);
+ FTL_ARRAY_TRAIT(T, const_reference);
+ FTL_ARRAY_TRAIT(T, const_iterator);
+ FTL_ARRAY_TRAIT(T, const_reverse_iterator);
// Creates an empty vector.
StaticVector() = default;
// Copies and moves a vector, respectively.
- StaticVector(const StaticVector& other) : StaticVector(other.begin(), other.end()) {}
+ StaticVector(const StaticVector& other)
+ : StaticVector(IteratorRange, other.begin(), other.end()) {}
StaticVector(StaticVector&& other) { swap<Empty>(other); }
// Copies at most N elements from a smaller convertible vector.
template <typename U, size_t M, typename = std::enable_if_t<M <= N>>
- StaticVector(const StaticVector<U, M>& other) : StaticVector(other.begin(), other.end()) {}
+ StaticVector(const StaticVector<U, M>& other)
+ : StaticVector(IteratorRange, other.begin(), other.end()) {}
// Copies at most N elements from an array.
template <typename U, size_t M>
- explicit StaticVector(U (&array)[M]) : StaticVector(std::begin(array), std::end(array)) {}
+ explicit StaticVector(U (&array)[M])
+ : StaticVector(IteratorRange, std::begin(array), std::end(array)) {}
// Copies at most N elements from the range [first, last).
+ //
+ // IteratorRangeTag disambiguates with initialization from two iterator-like elements.
+ //
template <typename Iterator, typename = std::enable_if_t<IsInputIterator<Iterator>{}>>
- StaticVector(Iterator first, Iterator last)
+ StaticVector(Iterator first, Iterator last) : StaticVector(IteratorRange, first, last) {
+ using V = typename std::iterator_traits<Iterator>::value_type;
+ static_assert(std::is_constructible_v<value_type, V>, "Incompatible iterator range");
+ }
+
+ template <typename Iterator>
+ StaticVector(IteratorRangeTag, Iterator first, Iterator last)
: mSize(std::min(max_size(), static_cast<size_type>(std::distance(first, last)))) {
std::uninitialized_copy(first, first + mSize, begin());
}
@@ -154,53 +181,57 @@
template <typename = void>
void swap(StaticVector&);
- size_type max_size() const { return N; }
+ static constexpr size_type max_size() { return N; }
size_type size() const { return mSize; }
bool empty() const { return size() == 0; }
bool full() const { return size() == max_size(); }
iterator begin() { return std::launder(reinterpret_cast<pointer>(mData)); }
- const_iterator begin() const { return cbegin(); }
- const_iterator cbegin() const { return mut().begin(); }
-
iterator end() { return begin() + size(); }
- const_iterator end() const { return cend(); }
- const_iterator cend() const { return mut().end(); }
- reverse_iterator rbegin() { return std::make_reverse_iterator(end()); }
- const_reverse_iterator rbegin() const { return crbegin(); }
- const_reverse_iterator crbegin() const { return mut().rbegin(); }
+ using Iter::begin;
+ using Iter::end;
- reverse_iterator rend() { return std::make_reverse_iterator(begin()); }
- const_reverse_iterator rend() const { return crend(); }
- const_reverse_iterator crend() const { return mut().rend(); }
+ using Iter::cbegin;
+ using Iter::cend;
- iterator last() { return end() - 1; }
- const_iterator last() const { return mut().last(); }
+ using Iter::rbegin;
+ using Iter::rend;
- reference front() { return *begin(); }
- const_reference front() const { return mut().front(); }
+ using Iter::crbegin;
+ using Iter::crend;
- reference back() { return *last(); }
- const_reference back() const { return mut().back(); }
+ using Iter::last;
- reference operator[](size_type i) { return *(begin() + i); }
- const_reference operator[](size_type i) const { return mut()[i]; }
+ using Iter::back;
+ using Iter::front;
- // Replaces an element, and returns an iterator to it. If the vector is full, the element is not
- // replaced, and the end iterator is returned.
+ using Iter::operator[];
+
+ // Replaces an element, and returns a reference to it. The iterator must be dereferenceable, so
+ // replacing at end() is erroneous.
+ //
+ // The element is emplaced via move constructor, so type T 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 element being replaced.
+ //
+ // Iterators to the replaced element point to its replacement, and others remain valid.
+ //
template <typename... Args>
- iterator replace(const_iterator cit, Args&&... args) {
- if (full()) return end();
- // Append element, and move into place if not last.
- emplace_back(std::forward<Args>(args)...);
- if (cit != last()) unstable_erase(cit);
- return const_cast<iterator>(cit);
+ reference replace(const_iterator it, Args&&... args) {
+ value_type element{std::forward<Args>(args)...};
+ std::destroy_at(it);
+ // This is only safe because exceptions are disabled.
+ return *construct_at(it, std::move(element));
}
// Appends an element, and returns an iterator to it. If the vector is full, the element is not
- // inserted, and the end iterator is returned.
+ // inserted, and the end() iterator is returned.
+ //
+ // On success, the end() iterator is invalidated.
+ //
template <typename... Args>
iterator emplace_back(Args&&... args) {
if (full()) return end();
@@ -209,31 +240,47 @@
return it;
}
+ // Appends an element unless the vector is full, and returns whether the element was inserted.
+ //
+ // On success, the end() iterator is invalidated.
+ //
+ bool push_back(const value_type& v) {
+ // Two statements for sequence point.
+ const iterator it = emplace_back(v);
+ return it != end();
+ }
+
+ bool push_back(value_type&& v) {
+ // Two statements for sequence point.
+ const iterator it = emplace_back(std::move(v));
+ return it != end();
+ }
+
+ // Removes the last element. The vector must not be empty, or the call is erroneous.
+ //
+ // The last() and end() iterators are invalidated.
+ //
+ void pop_back() { unstable_erase(last()); }
+
// Erases an element, but does not preserve order. Rather than shifting subsequent elements,
// this moves the last element to the slot of the erased element.
+ //
+ // The last() and end() iterators, as well as those to the erased element, are invalidated.
+ //
void unstable_erase(const_iterator it) {
std::destroy_at(it);
if (it != last()) {
- // Move last element and destroy its source for destructor side effects.
+ // Move last element and destroy its source for destructor side effects. This is only
+ // safe because exceptions are disabled.
construct_at(it, std::move(back()));
std::destroy_at(last());
}
--mSize;
}
- bool push_back(value_type v) {
- // Two statements for sequence point.
- const iterator it = emplace_back(std::move(v));
- return it != end();
- }
-
- void pop_back() { unstable_erase(last()); }
-
private:
struct Empty {};
- StaticVector& mut() const { return *const_cast<StaticVector*>(this); }
-
// Recursion for variadic constructor.
template <size_t I, typename E, typename... Es>
StaticVector(std::index_sequence<I>, E&& element, Es&&... elements)
@@ -245,13 +292,6 @@
template <size_t I>
explicit StaticVector(std::index_sequence<I>) : mSize(I) {}
- // TODO: Replace with std::construct_at in C++20.
- template <typename... Args>
- static pointer construct_at(const_iterator it, Args&&... args) {
- void* const ptr = const_cast<void*>(static_cast<const void*>(it));
- return new (ptr) value_type{std::forward<Args>(args)...};
- }
-
size_type mSize = 0;
std::aligned_storage_t<sizeof(value_type), alignof(value_type)> mData[N];
};
@@ -307,35 +347,4 @@
lhs.swap(rhs);
}
-// TODO: Replace with operator<=> in C++20.
-template <typename T, size_t N, size_t M>
-inline bool operator==(const StaticVector<T, N>& lhs, const StaticVector<T, M>& rhs) {
- return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
-}
-
-template <typename T, size_t N, size_t M>
-inline bool operator<(const StaticVector<T, N>& lhs, const StaticVector<T, M>& rhs) {
- return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
-}
-
-template <typename T, size_t N, size_t M>
-inline bool operator>(const StaticVector<T, N>& lhs, const StaticVector<T, M>& rhs) {
- return rhs < lhs;
-}
-
-template <typename T, size_t N, size_t M>
-inline bool operator!=(const StaticVector<T, N>& lhs, const StaticVector<T, M>& rhs) {
- return !(lhs == rhs);
-}
-
-template <typename T, size_t N, size_t M>
-inline bool operator>=(const StaticVector<T, N>& lhs, const StaticVector<T, M>& rhs) {
- return !(lhs < rhs);
-}
-
-template <typename T, size_t N, size_t M>
-inline bool operator<=(const StaticVector<T, N>& lhs, const StaticVector<T, M>& rhs) {
- return !(rhs < lhs);
-}
-
} // namespace android::ftl
diff --git a/include/input/Input.h b/include/input/Input.h
index d3a9694..3facfa5 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -177,7 +177,9 @@
namespace android {
+#ifdef __linux__
class Parcel;
+#endif
const char* inputEventTypeToString(int32_t type);
@@ -344,8 +346,10 @@
return getAxisValue(AMOTION_EVENT_AXIS_Y);
}
+#ifdef __linux__
status_t readFromParcel(Parcel* parcel);
status_t writeToParcel(Parcel* parcel) const;
+#endif
bool operator==(const PointerCoords& other) const;
inline bool operator!=(const PointerCoords& other) const {
@@ -704,8 +708,10 @@
// Matrix is in row-major form and compatible with SkMatrix.
void transform(const std::array<float, 9>& matrix);
+#ifdef __linux__
status_t readFromParcel(Parcel* parcel);
status_t writeToParcel(Parcel* parcel) const;
+#endif
static bool isTouchEvent(uint32_t source, int32_t action);
inline bool isTouchEvent() const {
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index 339c7eb..23f8ddf 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -19,7 +19,9 @@
#include <stdint.h>
+#ifdef __linux__
#include <binder/IBinder.h>
+#endif
#include <android-base/result.h>
#include <input/Input.h>
@@ -42,27 +44,27 @@
*/
class KeyCharacterMap {
public:
- enum KeyboardType {
- KEYBOARD_TYPE_UNKNOWN = 0,
- KEYBOARD_TYPE_NUMERIC = 1,
- KEYBOARD_TYPE_PREDICTIVE = 2,
- KEYBOARD_TYPE_ALPHA = 3,
- KEYBOARD_TYPE_FULL = 4,
+ enum class KeyboardType : int32_t {
+ UNKNOWN = 0,
+ NUMERIC = 1,
+ PREDICTIVE = 2,
+ ALPHA = 3,
+ FULL = 4,
/**
* Deprecated. Set 'keyboard.specialFunction' to '1' in the device's IDC file instead.
*/
- KEYBOARD_TYPE_SPECIAL_FUNCTION = 5,
- KEYBOARD_TYPE_OVERLAY = 6,
+ SPECIAL_FUNCTION = 5,
+ OVERLAY = 6,
};
- enum Format {
+ enum class Format {
// Base keyboard layout, may contain device-specific options, such as "type" declaration.
- FORMAT_BASE = 0,
+ BASE = 0,
// Overlay keyboard layout, more restrictive, may be published by applications,
// cannot override device-specific options.
- FORMAT_OVERLAY = 1,
+ OVERLAY = 1,
// Either base or overlay layout ok.
- FORMAT_ANY = 2,
+ ANY = 2,
};
// Substitute key code and meta state for fallback action.
@@ -86,7 +88,7 @@
void combine(const KeyCharacterMap& overlay);
/* Gets the keyboard type. */
- int32_t getKeyboardType() const;
+ KeyboardType getKeyboardType() const;
/* Gets the primary character for this key as in the label physically printed on it.
* Returns 0 if none (eg. for non-printing keys). */
@@ -132,11 +134,13 @@
void tryRemapKey(int32_t scanCode, int32_t metaState,
int32_t* outKeyCode, int32_t* outMetaState) const;
+#ifdef __linux__
/* Reads a key map from a parcel. */
static std::shared_ptr<KeyCharacterMap> readFromParcel(Parcel* parcel);
/* Writes a key map to a parcel. */
void writeToParcel(Parcel* parcel) const;
+#endif
KeyCharacterMap(const KeyCharacterMap& other);
@@ -222,7 +226,7 @@
};
KeyedVector<int32_t, Key*> mKeys;
- int mType;
+ KeyboardType mType;
std::string mLoadFileName;
KeyedVector<int32_t, int32_t> mKeysByScanCode;
diff --git a/libs/android_runtime_lazy/Android.bp b/libs/android_runtime_lazy/Android.bp
index 09a5f39..cdd7764 100644
--- a/libs/android_runtime_lazy/Android.bp
+++ b/libs/android_runtime_lazy/Android.bp
@@ -35,6 +35,11 @@
vendor_available: true,
double_loadable: true,
host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ }
+ },
cflags: [
"-Wall",
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index d363ee9..e6071a0 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -31,6 +31,11 @@
"libutils_headers",
],
min_sdk_version: "29",
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
}
// These interfaces are android-specific implementation unrelated to binder
@@ -122,6 +127,9 @@
vendor: {
exclude_srcs: libbinder_device_interface_sources,
},
+ darwin: {
+ enabled: false,
+ },
},
aidl: {
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index ddd9f9b..4381386 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -1068,6 +1068,7 @@
{
if (str == nullptr) return writeInt32(-1);
+ // NOTE: Keep this logic in sync with android_os_Parcel.cpp
status_t err = writeInt32(len);
if (err == NO_ERROR) {
uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char));
@@ -1108,6 +1109,7 @@
{
if (str == nullptr) return writeInt32(-1);
+ // NOTE: Keep this logic in sync with android_os_Parcel.cpp
status_t err = writeInt32(len);
if (err == NO_ERROR) {
len *= sizeof(char16_t);
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index e4d86ae..cecc759 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -26,6 +26,9 @@
"-D__ANDROID_API__=10000",
],
},
+ darwin: {
+ enabled: false,
+ },
},
}
@@ -84,6 +87,9 @@
linux: {
version_script: "libbinder_ndk.map.txt",
},
+ darwin: {
+ enabled: false,
+ },
},
stubs: {
symbol_file: "libbinder_ndk.map.txt",
diff --git a/libs/binder/parcel_fuzzer/Android.bp b/libs/binder/parcel_fuzzer/Android.bp
index c5b3d80..3e6fe99 100644
--- a/libs/binder/parcel_fuzzer/Android.bp
+++ b/libs/binder/parcel_fuzzer/Android.bp
@@ -52,6 +52,11 @@
cc_library_static {
name: "libbinder_random_parcel",
host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ }
+ },
srcs: [
"random_fd.cpp",
"random_parcel.cpp",
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index dc8270e..fd5f2f5 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -10,6 +10,11 @@
"libbinder_ndk_sys",
],
host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ }
+ }
}
rust_library {
@@ -23,6 +28,11 @@
"libbinder_ndk",
],
host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ }
+ }
}
rust_bindgen {
@@ -64,6 +74,9 @@
"-D__ANDROID_API__=10000",
],
},
+ darwin: {
+ enabled: false,
+ },
},
}
diff --git a/libs/binder/tests/fuzzers/Android.bp b/libs/binder/tests/fuzzers/Android.bp
index 46379fc..c465bed 100644
--- a/libs/binder/tests/fuzzers/Android.bp
+++ b/libs/binder/tests/fuzzers/Android.bp
@@ -26,6 +26,11 @@
"libutils",
"libbase",
],
+ target: {
+ darwin: {
+ enabled: false,
+ }
+ }
}
cc_fuzz {
diff --git a/libs/binderthreadstate/Android.bp b/libs/binderthreadstate/Android.bp
index 88752ee..08c62df 100644
--- a/libs/binderthreadstate/Android.bp
+++ b/libs/binderthreadstate/Android.bp
@@ -19,6 +19,11 @@
double_loadable: true,
vendor_available: true,
host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ }
+ },
shared_libs: [
"libbinder",
diff --git a/libs/fakeservicemanager/Android.bp b/libs/fakeservicemanager/Android.bp
index 6909637..76518c1 100644
--- a/libs/fakeservicemanager/Android.bp
+++ b/libs/fakeservicemanager/Android.bp
@@ -9,6 +9,11 @@
"libbinder",
"libutils",
],
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
}
cc_library {
diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp
index e11be57..fb32382 100644
--- a/libs/ftl/Android.bp
+++ b/libs/ftl/Android.bp
@@ -5,6 +5,7 @@
address: true,
},
srcs: [
+ "SmallVector_test.cpp",
"StaticVector_test.cpp",
],
cflags: [
diff --git a/libs/ftl/SmallVector_test.cpp b/libs/ftl/SmallVector_test.cpp
new file mode 100644
index 0000000..c41e622
--- /dev/null
+++ b/libs/ftl/SmallVector_test.cpp
@@ -0,0 +1,455 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ftl/SmallVector.h>
+#include <gtest/gtest.h>
+
+#include <algorithm>
+#include <iterator>
+#include <string>
+#include <utility>
+
+using namespace std::string_literals;
+
+namespace android::test {
+
+using ftl::SmallVector;
+
+// Keep in sync with example usage in header file.
+TEST(SmallVector, Example) {
+ ftl::SmallVector<char, 3> vector;
+ EXPECT_TRUE(vector.empty());
+ EXPECT_FALSE(vector.dynamic());
+
+ vector = {'a', 'b', 'c'};
+ EXPECT_EQ(vector.size(), 3u);
+ EXPECT_FALSE(vector.dynamic());
+
+ vector.push_back('d');
+ EXPECT_TRUE(vector.dynamic());
+
+ vector.unstable_erase(vector.begin());
+ EXPECT_EQ(vector, (ftl::SmallVector{'d', 'b', 'c'}));
+
+ vector.pop_back();
+ EXPECT_EQ(vector.back(), 'b');
+ EXPECT_TRUE(vector.dynamic());
+
+ const char array[] = "hi";
+ vector = ftl::SmallVector(array);
+ EXPECT_EQ(vector, (ftl::SmallVector{'h', 'i', '\0'}));
+ EXPECT_FALSE(vector.dynamic());
+}
+
+TEST(SmallVector, Construct) {
+ {
+ // Default constructor.
+ SmallVector<std::string, 2> vector;
+
+ EXPECT_TRUE(vector.empty());
+ EXPECT_FALSE(vector.dynamic());
+ }
+ {
+ // Array constructor.
+ const float kFloats[] = {.1f, .2f, .3f};
+ SmallVector vector(kFloats);
+
+ EXPECT_EQ(vector, (SmallVector{.1f, .2f, .3f}));
+ EXPECT_FALSE(vector.dynamic());
+ }
+ {
+ // Iterator constructor.
+ const char chars[] = "abcdef";
+ std::string string(chars);
+ SmallVector<char, sizeof(chars)> vector(string.begin(), string.end());
+
+ EXPECT_STREQ(vector.begin(), chars);
+ EXPECT_FALSE(vector.dynamic());
+ }
+ {
+ // Variadic constructor with same types.
+ SmallVector vector = {1, 2, 3};
+
+ static_assert(std::is_same_v<decltype(vector), SmallVector<int, 3>>);
+ EXPECT_EQ(vector, (SmallVector{1, 2, 3}));
+ EXPECT_FALSE(vector.dynamic());
+ }
+ {
+ // Variadic constructor with different types.
+ const auto copy = "quince"s;
+ auto move = "tart"s;
+ SmallVector vector = {copy, std::move(move)};
+
+ static_assert(std::is_same_v<decltype(vector), SmallVector<std::string, 2>>);
+ EXPECT_EQ(vector, (SmallVector{"quince"s, "tart"s}));
+ EXPECT_FALSE(vector.dynamic());
+ }
+ {
+ // In-place constructor with same types.
+ SmallVector vector(std::in_place_type<std::string>, "red", "velvet", "cake");
+
+ static_assert(std::is_same_v<decltype(vector), SmallVector<std::string, 3>>);
+ EXPECT_EQ(vector, (SmallVector{"red"s, "velvet"s, "cake"s}));
+ EXPECT_FALSE(vector.dynamic());
+ }
+ {
+ // In-place constructor with different types.
+ const auto copy = "red"s;
+ auto move = "velvet"s;
+ std::initializer_list<char> list = {'c', 'a', 'k', 'e'};
+ SmallVector vector(std::in_place_type<std::string>, copy.c_str(), std::move(move), list);
+
+ static_assert(std::is_same_v<decltype(vector), SmallVector<std::string, 3>>);
+ EXPECT_EQ(vector, (SmallVector{"red"s, "velvet"s, "cake"s}));
+ EXPECT_FALSE(vector.dynamic());
+ }
+ {
+ // Conversion from StaticVector.
+ ftl::StaticVector doubles = {.1, .2, .3};
+ SmallVector vector = std::move(doubles);
+ EXPECT_TRUE(doubles.empty());
+
+ static_assert(std::is_same_v<decltype(vector), SmallVector<double, 3>>);
+ EXPECT_EQ(vector, (SmallVector{.1, .2, .3}));
+ EXPECT_FALSE(vector.dynamic());
+ }
+}
+
+TEST(SmallVector, String) {
+ SmallVector<char, 10> chars;
+ char c = 'a';
+ std::generate_n(std::back_inserter(chars), chars.max_size(), [&c] { return c++; });
+ chars.push_back('\0');
+
+ EXPECT_TRUE(chars.dynamic());
+ EXPECT_EQ(chars.size(), 11u);
+ EXPECT_STREQ(chars.begin(), "abcdefghij");
+
+ // Constructor takes iterator range.
+ const char kString[] = "123456";
+ SmallVector<char, 10> string(std::begin(kString), std::end(kString));
+
+ EXPECT_FALSE(string.dynamic());
+ EXPECT_STREQ(string.begin(), "123456");
+ EXPECT_EQ(string.size(), 7u);
+
+ // Similar to emplace, but replaces rather than inserts.
+ string.replace(string.begin() + 5, '\0');
+ EXPECT_STREQ(string.begin(), "12345");
+
+ swap(chars, string);
+
+ EXPECT_STREQ(chars.begin(), "12345");
+ EXPECT_STREQ(string.begin(), "abcdefghij");
+
+ EXPECT_FALSE(chars.dynamic());
+ EXPECT_TRUE(string.dynamic());
+}
+
+TEST(SmallVector, CopyableElement) {
+ struct Pair {
+ // Needed because std::vector emplace does not use uniform initialization.
+ Pair(int a, int b) : a(a), b(b) {}
+
+ const int a, b;
+ bool operator==(Pair p) const { return p.a == a && p.b == b; }
+ };
+
+ SmallVector<Pair, 5> pairs;
+
+ EXPECT_TRUE(pairs.empty());
+ EXPECT_EQ(pairs.max_size(), 5u);
+
+ for (size_t i = 0; i < pairs.max_size(); ++i) {
+ EXPECT_EQ(pairs.size(), i);
+
+ const int a = static_cast<int>(i) * 2;
+ EXPECT_EQ(pairs.emplace_back(a, a + 1), Pair(a, a + 1));
+ }
+
+ EXPECT_EQ(pairs.size(), 5u);
+ EXPECT_FALSE(pairs.dynamic());
+
+ // The vector is promoted when full.
+ EXPECT_EQ(pairs.emplace_back(10, 11), Pair(10, 11));
+ EXPECT_TRUE(pairs.dynamic());
+
+ EXPECT_EQ(pairs,
+ (SmallVector{Pair{0, 1}, Pair{2, 3}, Pair{4, 5}, Pair{6, 7}, Pair{8, 9},
+ Pair{10, 11}}));
+
+ // Constructor takes at most N elements.
+ SmallVector<int, 6> sums = {0, 0, 0, 0, 0, 0};
+ EXPECT_FALSE(sums.dynamic());
+
+ // Random-access iterators comply with standard.
+ std::transform(pairs.begin(), pairs.end(), sums.begin(), [](Pair p) { return p.a + p.b; });
+ EXPECT_EQ(sums, (SmallVector{1, 5, 9, 13, 17, 21}));
+
+ sums.pop_back();
+ std::reverse(sums.begin(), sums.end());
+
+ EXPECT_EQ(sums, (SmallVector{17, 13, 9, 5, 1}));
+}
+
+TEST(SmallVector, MovableElement) {
+ // Construct std::string elements in-place from C-style strings. Without std::in_place_type, the
+ // element type would be deduced from the first element, i.e. const char*.
+ SmallVector strings(std::in_place_type<std::string>, "", "", "", "cake", "velvet", "red", "");
+ strings.pop_back();
+
+ EXPECT_EQ(strings.max_size(), 7u);
+ EXPECT_EQ(strings.size(), 6u);
+
+ // Erase "cake" and append a substring copy.
+ {
+ const auto it = std::find_if(strings.begin(), strings.end(),
+ [](const auto& s) { return !s.empty(); });
+ ASSERT_FALSE(it == strings.end());
+ EXPECT_EQ(*it, "cake");
+
+ strings.unstable_erase(it);
+ EXPECT_EQ(strings.emplace_back("cakewalk", 4u), "cake"s);
+ }
+
+ strings[1] = "quince"s;
+
+ // Replace last empty string with "tart".
+ {
+ const auto rit = std::find(strings.rbegin(), strings.rend(), std::string());
+ ASSERT_FALSE(rit == strings.rend());
+
+ std::initializer_list<char> list = {'t', 'a', 'r', 't'};
+ strings.replace(rit.base() - 1, list);
+ }
+
+ strings.front().assign("pie");
+
+ EXPECT_EQ(strings, (SmallVector{"pie"s, "quince"s, "tart"s, "red"s, "velvet"s, "cake"s}));
+
+ strings.push_back("nougat");
+ strings.push_back("oreo");
+ EXPECT_TRUE(strings.dynamic());
+
+ std::rotate(strings.begin(), strings.end() - 2, strings.end());
+
+ EXPECT_EQ(strings,
+ (SmallVector{"nougat"s, "oreo"s, "pie"s, "quince"s, "tart"s, "red"s, "velvet"s,
+ "cake"s}));
+}
+
+TEST(SmallVector, Replace) {
+ // Replacing does not require a copy/move assignment operator.
+ struct Word {
+ explicit Word(std::string str) : str(std::move(str)) {}
+ const std::string str;
+
+ bool operator==(const Word& other) const { return other.str == str; }
+ };
+
+ SmallVector words(std::in_place_type<Word>, "colored", "velour");
+
+ // The replaced element can be referenced by the replacement.
+ {
+ const Word& word = words.replace(words.last(), words.back().str.substr(0, 3) + "vet");
+ EXPECT_EQ(word, Word("velvet"));
+ }
+
+ // The vector is not promoted if replacing while full.
+ EXPECT_FALSE(words.dynamic());
+
+ words.emplace_back("cake");
+ EXPECT_TRUE(words.dynamic());
+
+ {
+ const Word& word = words.replace(words.begin(), words.front().str.substr(4));
+ EXPECT_EQ(word, Word("red"));
+ }
+
+ EXPECT_EQ(words, (SmallVector{Word("red"), Word("velvet"), Word("cake")}));
+}
+
+TEST(SmallVector, ReverseAppend) {
+ SmallVector strings = {"red"s, "velvet"s, "cake"s};
+ EXPECT_FALSE(strings.dynamic());
+
+ auto rit = strings.rbegin();
+ while (rit != strings.rend()) {
+ // Iterator and reference are invalidated on insertion.
+ const auto i = std::distance(strings.begin(), rit.base());
+ std::string s = *rit;
+
+ strings.push_back(std::move(s));
+ rit = std::make_reverse_iterator(strings.begin() + i) + 1;
+ }
+
+ EXPECT_EQ(strings, (SmallVector{"red"s, "velvet"s, "cake"s, "cake"s, "velvet"s, "red"s}));
+ EXPECT_TRUE(strings.dynamic());
+}
+
+TEST(SmallVector, Sort) {
+ SmallVector strings(std::in_place_type<std::string>, "pie", "quince", "tart", "red", "velvet");
+ strings.push_back("cake"s);
+
+ auto sorted = std::move(strings);
+ EXPECT_TRUE(strings.empty());
+
+ EXPECT_TRUE(sorted.dynamic());
+ EXPECT_TRUE(strings.dynamic());
+
+ std::sort(sorted.begin(), sorted.end());
+ EXPECT_EQ(sorted, (SmallVector{"cake"s, "pie"s, "quince"s, "red"s, "tart"s, "velvet"s}));
+
+ // Constructor takes array reference.
+ {
+ const char* kStrings[] = {"cake", "lie"};
+ strings = SmallVector(kStrings);
+ EXPECT_FALSE(strings.dynamic());
+ }
+
+ EXPECT_GT(sorted, strings);
+ swap(sorted, strings);
+ EXPECT_LT(sorted, strings);
+
+ EXPECT_FALSE(sorted.dynamic());
+ EXPECT_TRUE(strings.dynamic());
+
+ // Append remaining elements, such that "pie" is the only difference.
+ for (const char* str : {"quince", "red", "tart", "velvet"}) {
+ sorted.emplace_back(str);
+ }
+ EXPECT_TRUE(sorted.dynamic());
+
+ EXPECT_NE(sorted, strings);
+
+ // Replace second element with "pie".
+ const auto it = sorted.begin() + 1;
+ EXPECT_EQ(sorted.replace(it, 'p' + it->substr(1)), "pie");
+
+ EXPECT_EQ(sorted, strings);
+}
+
+namespace {
+
+struct DestroyCounts {
+ DestroyCounts(int& live, int& dead) : counts{live, dead} {}
+ DestroyCounts(const DestroyCounts& other) : counts(other.counts) {}
+ DestroyCounts(DestroyCounts&& other) : counts(other.counts) { other.alive = false; }
+ ~DestroyCounts() { ++(alive ? counts.live : counts.dead); }
+
+ struct {
+ int& live;
+ int& dead;
+ } counts;
+
+ bool alive = true;
+};
+
+void swap(DestroyCounts& lhs, DestroyCounts& rhs) {
+ std::swap(lhs.alive, rhs.alive);
+}
+
+} // namespace
+
+TEST(SmallVector, Destroy) {
+ int live = 0;
+ int dead = 0;
+
+ { SmallVector<DestroyCounts, 3> counts; }
+ EXPECT_EQ(0, live);
+ EXPECT_EQ(0, dead);
+
+ {
+ SmallVector<DestroyCounts, 3> counts;
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+
+ EXPECT_FALSE(counts.dynamic());
+ }
+ EXPECT_EQ(3, live);
+ EXPECT_EQ(0, dead);
+
+ live = 0;
+ {
+ SmallVector<DestroyCounts, 3> counts;
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+
+ EXPECT_TRUE(counts.dynamic());
+ }
+ EXPECT_EQ(4, live);
+ EXPECT_EQ(3, dead);
+
+ live = dead = 0;
+ {
+ SmallVector<DestroyCounts, 2> counts;
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+
+ auto copy = counts;
+ EXPECT_TRUE(copy.dynamic());
+ }
+ EXPECT_EQ(6, live);
+ EXPECT_EQ(2, dead);
+
+ live = dead = 0;
+ {
+ SmallVector<DestroyCounts, 2> counts;
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+
+ auto move = std::move(counts);
+ EXPECT_TRUE(move.dynamic());
+ }
+ EXPECT_EQ(3, live);
+ EXPECT_EQ(2, dead);
+
+ live = dead = 0;
+ {
+ SmallVector<DestroyCounts, 2> counts1;
+ counts1.emplace_back(live, dead);
+ counts1.emplace_back(live, dead);
+ counts1.emplace_back(live, dead);
+
+ EXPECT_TRUE(counts1.dynamic());
+ EXPECT_EQ(2, dead);
+ dead = 0;
+
+ SmallVector<DestroyCounts, 2> counts2;
+ counts2.emplace_back(live, dead);
+
+ EXPECT_FALSE(counts2.dynamic());
+
+ swap(counts1, counts2);
+
+ EXPECT_FALSE(counts1.dynamic());
+ EXPECT_TRUE(counts2.dynamic());
+
+ EXPECT_EQ(0, live);
+ EXPECT_EQ(1, dead);
+
+ dead = 0;
+ }
+ EXPECT_EQ(4, live);
+ EXPECT_EQ(0, dead);
+}
+
+} // namespace android::test
diff --git a/libs/ftl/StaticVector_test.cpp b/libs/ftl/StaticVector_test.cpp
index 06e4659..dd5ce35 100644
--- a/libs/ftl/StaticVector_test.cpp
+++ b/libs/ftl/StaticVector_test.cpp
@@ -106,6 +106,33 @@
static_assert(std::is_same_v<decltype(vector), StaticVector<std::string, 3>>);
EXPECT_EQ(vector, (StaticVector{"red"s, "velvet"s, "cake"s}));
}
+ {
+ struct String {
+ explicit String(const char* str) : str(str) {}
+ explicit String(const char** ptr) : str(*ptr) {}
+ const char* str;
+ };
+
+ const char* kStrings[] = {"a", "b", "c", "d"};
+
+ {
+ // Two iterator-like elements.
+ StaticVector<String, 3> vector(kStrings, kStrings + 3);
+ ASSERT_EQ(vector.size(), 2u);
+
+ EXPECT_STREQ(vector[0].str, "a");
+ EXPECT_STREQ(vector[1].str, "d");
+ }
+ {
+ // Disambiguating iterator constructor.
+ StaticVector<String, 3> vector(ftl::IteratorRange, kStrings, kStrings + 3);
+ ASSERT_EQ(vector.size(), 3u);
+
+ EXPECT_STREQ(vector[0].str, "a");
+ EXPECT_STREQ(vector[1].str, "b");
+ EXPECT_STREQ(vector[2].str, "c");
+ }
+ }
}
TEST(StaticVector, String) {
@@ -124,8 +151,7 @@
EXPECT_EQ(string.size(), 7u);
// Similar to emplace, but replaces rather than inserts.
- const auto it = string.replace(string.begin() + 5, '\0');
- EXPECT_NE(it, string.end());
+ string.replace(string.begin() + 5, '\0');
EXPECT_STREQ(string.begin(), "12345");
swap(chars, string);
@@ -209,8 +235,7 @@
ASSERT_FALSE(rit == strings.rend());
std::initializer_list<char> list = {'t', 'a', 'r', 't'};
- const auto it = strings.replace(rit.base() - 1, list);
- EXPECT_NE(it, strings.end());
+ strings.replace(rit.base() - 1, list);
}
strings.front().assign("pie");
@@ -218,6 +243,21 @@
EXPECT_EQ(strings, (StaticVector{"pie"s, "quince"s, "tart"s, "red"s, "velvet"s, "cake"s}));
}
+TEST(StaticVector, Replace) {
+ // Replacing does not require a copy/move assignment operator.
+ struct Word {
+ explicit Word(std::string str) : str(std::move(str)) {}
+ const std::string str;
+ };
+
+ StaticVector words(std::in_place_type<Word>, "red", "velour", "cake");
+
+ // The replaced element can be referenced by the replacement.
+ const auto it = words.begin() + 1;
+ const Word& word = words.replace(it, it->str.substr(0, 3) + "vet");
+ EXPECT_EQ(word.str, "velvet");
+}
+
TEST(StaticVector, ReverseTruncate) {
StaticVector<std::string, 10> strings("pie", "quince", "tart", "red", "velvet", "cake");
EXPECT_FALSE(strings.full());
@@ -251,12 +291,16 @@
EXPECT_LT(sorted, strings);
// Append remaining elements, such that "pie" is the only difference.
- sorted.replace(sorted.end(), "quince");
- for (const char* str : {"red", "tart", "velvet"}) sorted.emplace_back(str);
+ for (const char* str : {"quince", "red", "tart", "velvet"}) {
+ sorted.emplace_back(str);
+ }
EXPECT_NE(sorted, strings);
- sorted.replace(sorted.begin() + 1, "pie");
+ // Replace second element with "pie".
+ const auto it = sorted.begin() + 1;
+ EXPECT_EQ(sorted.replace(it, 'p' + it->substr(1)), "pie");
+
EXPECT_EQ(sorted, strings);
}
diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp
index cc31cd5..243d7f1 100644
--- a/libs/gralloc/types/Android.bp
+++ b/libs/gralloc/types/Android.bp
@@ -21,6 +21,11 @@
"-Wno-enum-compare",
],
host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ }
+ },
vendor_available: true,
vndk: {
diff --git a/libs/gralloc/types/fuzzer/Android.bp b/libs/gralloc/types/fuzzer/Android.bp
index 8444883..8933dc3 100644
--- a/libs/gralloc/types/fuzzer/Android.bp
+++ b/libs/gralloc/types/fuzzer/Android.bp
@@ -2,6 +2,11 @@
name: "libgralloctypes_fuzzer",
defaults: ["libbinder_ndk_host_user"],
host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ }
+ },
fuzz_config: {
cc: ["marissaw@google.com"],
diff --git a/libs/gui/view/Surface.cpp b/libs/gui/view/Surface.cpp
index 3e49de6..1bfe462 100644
--- a/libs/gui/view/Surface.cpp
+++ b/libs/gui/view/Surface.cpp
@@ -75,13 +75,9 @@
}
String16 Surface::readMaybeEmptyString16(const Parcel* parcel) {
- size_t len;
- const char16_t* str = parcel->readString16Inplace(&len);
- if (str != nullptr) {
- return String16(str, len);
- } else {
- return String16();
- }
+ std::optional<String16> str;
+ parcel->readString16(&str);
+ return str.value_or(String16());
}
} // namespace view
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index ad7db75..0ea3889 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -28,7 +28,9 @@
#include <input/InputDevice.h>
#include <input/InputEventLabels.h>
+#ifdef __linux__
#include <binder/Parcel.h>
+#endif
#ifdef __ANDROID__
#include <sys/random.h>
#endif
@@ -254,6 +256,7 @@
setAxisValue(AMOTION_EVENT_AXIS_Y, getY() + yOffset);
}
+#ifdef __linux__
status_t PointerCoords::readFromParcel(Parcel* parcel) {
bits = parcel->readInt64();
@@ -277,6 +280,7 @@
}
return OK;
}
+#endif
void PointerCoords::tooManyAxes(int axis) {
ALOGW("Could not set value for axis %d because the PointerCoords structure is full and "
@@ -538,6 +542,7 @@
}
}
+#ifdef __linux__
static status_t readFromParcel(ui::Transform& transform, const Parcel& parcel) {
float dsdx, dtdx, tx, dtdy, dsdy, ty;
status_t status = parcel.readFloat(&dsdx);
@@ -674,6 +679,7 @@
}
return OK;
}
+#endif
bool MotionEvent::isTouchEvent(uint32_t source, int32_t action) {
if (source & AINPUT_SOURCE_CLASS_POINTER) {
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index 2623ecd..f5432ad 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -19,7 +19,9 @@
#include <stdlib.h>
#include <string.h>
+#ifdef __linux__
#include <binder/Parcel.h>
+#endif
#include <android/keycodes.h>
#include <attestation/HmacKeyManager.h>
#include <input/InputEventLabels.h>
@@ -83,9 +85,7 @@
// --- KeyCharacterMap ---
-KeyCharacterMap::KeyCharacterMap() :
- mType(KEYBOARD_TYPE_UNKNOWN) {
-}
+KeyCharacterMap::KeyCharacterMap() : mType(KeyboardType::UNKNOWN) {}
KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other)
: mType(other.mType),
@@ -184,7 +184,7 @@
mLoadFileName = overlay.mLoadFileName;
}
-int32_t KeyCharacterMap::getKeyboardType() const {
+KeyCharacterMap::KeyboardType KeyCharacterMap::getKeyboardType() const {
return mType;
}
@@ -587,13 +587,14 @@
}
}
+#ifdef __linux__
std::shared_ptr<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) {
if (parcel == nullptr) {
ALOGE("%s: Null parcel", __func__);
return nullptr;
}
std::shared_ptr<KeyCharacterMap> map = std::shared_ptr<KeyCharacterMap>(new KeyCharacterMap());
- map->mType = parcel->readInt32();
+ map->mType = static_cast<KeyCharacterMap::KeyboardType>(parcel->readInt32());
size_t numKeys = parcel->readInt32();
if (parcel->errorCheck()) {
return nullptr;
@@ -651,7 +652,7 @@
ALOGE("%s: Null parcel", __func__);
return;
}
- parcel->writeInt32(mType);
+ parcel->writeInt32(static_cast<int32_t>(mType));
size_t numKeys = mKeys.size();
parcel->writeInt32(numKeys);
@@ -672,7 +673,7 @@
parcel->writeInt32(0);
}
}
-
+#endif // __linux__
// --- KeyCharacterMap::Key ---
@@ -776,20 +777,20 @@
return BAD_VALUE;
}
- if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) {
+ if (mMap->mType == KeyboardType::UNKNOWN) {
ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.",
mTokenizer->getLocation().string());
return BAD_VALUE;
}
- if (mFormat == FORMAT_BASE) {
- if (mMap->mType == KEYBOARD_TYPE_OVERLAY) {
+ if (mFormat == Format::BASE) {
+ if (mMap->mType == KeyboardType::OVERLAY) {
ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.",
mTokenizer->getLocation().string());
return BAD_VALUE;
}
- } else if (mFormat == FORMAT_OVERLAY) {
- if (mMap->mType != KEYBOARD_TYPE_OVERLAY) {
+ } else if (mFormat == Format::OVERLAY) {
+ if (mMap->mType != KeyboardType::OVERLAY) {
ALOGE("%s: Overlay keyboard layout missing required keyboard "
"'type OVERLAY' declaration.",
mTokenizer->getLocation().string());
@@ -801,7 +802,7 @@
}
status_t KeyCharacterMap::Parser::parseType() {
- if (mMap->mType != KEYBOARD_TYPE_UNKNOWN) {
+ if (mMap->mType != KeyboardType::UNKNOWN) {
ALOGE("%s: Duplicate keyboard 'type' declaration.",
mTokenizer->getLocation().string());
return BAD_VALUE;
@@ -810,20 +811,20 @@
KeyboardType type;
String8 typeToken = mTokenizer->nextToken(WHITESPACE);
if (typeToken == "NUMERIC") {
- type = KEYBOARD_TYPE_NUMERIC;
+ type = KeyboardType::NUMERIC;
} else if (typeToken == "PREDICTIVE") {
- type = KEYBOARD_TYPE_PREDICTIVE;
+ type = KeyboardType::PREDICTIVE;
} else if (typeToken == "ALPHA") {
- type = KEYBOARD_TYPE_ALPHA;
+ type = KeyboardType::ALPHA;
} else if (typeToken == "FULL") {
- type = KEYBOARD_TYPE_FULL;
+ type = KeyboardType::FULL;
} else if (typeToken == "SPECIAL_FUNCTION") {
ALOGW("The SPECIAL_FUNCTION type is now declared in the device's IDC file, please set "
"the property 'keyboard.specialFunction' to '1' there instead.");
// TODO: return BAD_VALUE here in Q
- type = KEYBOARD_TYPE_SPECIAL_FUNCTION;
+ type = KeyboardType::SPECIAL_FUNCTION;
} else if (typeToken == "OVERLAY") {
- type = KEYBOARD_TYPE_OVERLAY;
+ type = KeyboardType::OVERLAY;
} else {
ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(),
typeToken.string());
diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp
index 38a68b3..14dc9e5 100644
--- a/libs/input/Keyboard.cpp
+++ b/libs/input/Keyboard.cpp
@@ -128,7 +128,7 @@
}
base::Result<std::shared_ptr<KeyCharacterMap>> ret =
- KeyCharacterMap::load(path, KeyCharacterMap::FORMAT_BASE);
+ KeyCharacterMap::load(path, KeyCharacterMap::Format::BASE);
if (!ret) {
return ret.error().code();
}
@@ -159,9 +159,9 @@
bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier,
const PropertyMap* deviceConfiguration, const KeyMap* keyMap) {
// TODO: remove the third OR statement (SPECIAL_FUNCTION) in Q
- if (!keyMap->haveKeyCharacterMap() || isKeyboardSpecialFunction(deviceConfiguration)
- || keyMap->keyCharacterMap->getKeyboardType()
- == KeyCharacterMap::KEYBOARD_TYPE_SPECIAL_FUNCTION) {
+ if (!keyMap->haveKeyCharacterMap() || isKeyboardSpecialFunction(deviceConfiguration) ||
+ keyMap->keyCharacterMap->getKeyboardType() ==
+ KeyCharacterMap::KeyboardType::SPECIAL_FUNCTION) {
return false;
}
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 03c8e80..e5f7539 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -560,6 +560,10 @@
}
auto texMatrix = getSkM44(item.textureTransform).asM33();
+
+ // b/171404534, scale to fix the layer
+ matrix.postScale(bounds.getWidth() / bufferWidth, bounds.getHeight() / bufferHeight);
+
// textureTansform was intended to be passed directly into a shader, so when
// building the total matrix with the textureTransform we need to first
// normalize it, then apply the textureTransform, then scale back up.
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 7094c74..7191487 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2272,17 +2272,18 @@
std::string InputDispatcher::dumpWindowForTouchOcclusion(const InputWindowInfo* info,
bool isTouchedWindow) const {
- return StringPrintf(INDENT2
- "* %stype=%s, package=%s/%" PRId32 ", mode=%s, alpha=%.2f, "
- "frame=[%" PRId32 ",%" PRId32 "][%" PRId32 ",%" PRId32
- "], touchableRegion=%s, window=%s, applicationInfo=%s, flags={%s}\n",
+ return StringPrintf(INDENT2 "* %stype=%s, package=%s/%" PRId32 ", mode=%s, alpha=%.2f, "
+ "frame=[%" PRId32 ",%" PRId32 "][%" PRId32 ",%" PRId32
+ "], touchableRegion=%s, window={%s}, applicationInfo=%s, "
+ "flags={%s}, inputFeatures={%s}, hasToken=%s\n",
(isTouchedWindow) ? "[TOUCHED] " : "",
NamedEnum::string(info->type, "%" PRId32).c_str(),
info->packageName.c_str(), info->ownerUid,
toString(info->touchOcclusionMode).c_str(), info->alpha, info->frameLeft,
info->frameTop, info->frameRight, info->frameBottom,
dumpRegion(info->touchableRegion).c_str(), info->name.c_str(),
- info->applicationInfo.name.c_str(), info->flags.string().c_str());
+ info->applicationInfo.name.c_str(), info->flags.string().c_str(),
+ info->inputFeatures.string().c_str(), toString(info->token != nullptr));
}
bool InputDispatcher::isTouchTrustedLocked(const TouchOcclusionInfo& occlusionInfo) const {
@@ -4403,6 +4404,24 @@
return dump;
}
+std::string InputDispatcher::dumpPendingFocusRequestsLocked() {
+ if (mPendingFocusRequests.empty()) {
+ return INDENT "mPendingFocusRequests: <none>\n";
+ }
+
+ std::string dump;
+ dump += INDENT "mPendingFocusRequests:\n";
+ for (const auto& [displayId, focusRequest] : mPendingFocusRequests) {
+ // Rather than printing raw values for focusRequest.token and focusRequest.focusedToken,
+ // try to resolve them to actual windows.
+ std::string windowName = getConnectionNameLocked(focusRequest.token);
+ std::string focusedWindowName = getConnectionNameLocked(focusRequest.focusedToken);
+ dump += StringPrintf(INDENT2 "displayId=%" PRId32 ", token->%s, focusedToken->%s\n",
+ displayId, windowName.c_str(), focusedWindowName.c_str());
+ }
+ return dump;
+}
+
void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
dump += StringPrintf(INDENT "DispatchEnabled: %s\n", toString(mDispatchEnabled));
dump += StringPrintf(INDENT "DispatchFrozen: %s\n", toString(mDispatchFrozen));
@@ -4425,6 +4444,7 @@
}
dump += dumpFocusedWindowsLocked();
+ dump += dumpPendingFocusRequestsLocked();
if (!mTouchStatesByDisplay.empty()) {
dump += StringPrintf(INDENT "TouchStatesByDisplay:\n");
@@ -4491,9 +4511,11 @@
dump += StringPrintf(", inputFeatures=%s",
windowInfo->inputFeatures.string().c_str());
dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%" PRId64
- "ms\n",
+ "ms, trustedOverlay=%s, hasToken=%s\n",
windowInfo->ownerPid, windowInfo->ownerUid,
- millis(windowInfo->dispatchingTimeout));
+ millis(windowInfo->dispatchingTimeout),
+ toString(windowInfo->trustedOverlay),
+ toString(windowInfo->token != nullptr));
windowInfo->transform.dump(dump, "transform", INDENT4);
}
} else {
@@ -4830,6 +4852,14 @@
return nullptr;
}
+std::string InputDispatcher::getConnectionNameLocked(const sp<IBinder>& connectionToken) const {
+ sp<Connection> connection = getConnectionLocked(connectionToken);
+ if (connection == nullptr) {
+ return "<nullptr>";
+ }
+ return connection->getInputChannelName();
+}
+
void InputDispatcher::removeConnectionLocked(const sp<Connection>& connection) {
mAnrTracker.eraseToken(connection->inputChannel->getConnectionToken());
removeByValue(mConnectionsByFd, connection);
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 4565151..5387c40 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -210,6 +210,8 @@
sp<Connection> getConnectionLocked(const sp<IBinder>& inputConnectionToken) const
REQUIRES(mLock);
+ std::string getConnectionNameLocked(const sp<IBinder>& connectionToken) const REQUIRES(mLock);
+
void removeConnectionLocked(const sp<Connection>& connection) REQUIRES(mLock);
struct IBinderHash {
@@ -532,6 +534,7 @@
void dumpMonitors(std::string& dump, const std::vector<Monitor>& monitors);
void logDispatchStateLocked() REQUIRES(mLock);
std::string dumpFocusedWindowsLocked() REQUIRES(mLock);
+ std::string dumpPendingFocusRequestsLocked() REQUIRES(mLock);
// Registration.
void removeMonitorChannelLocked(const sp<IBinder>& connectionToken) REQUIRES(mLock);
diff --git a/services/surfaceflinger/TEST_MAPPING b/services/surfaceflinger/TEST_MAPPING
index e530ff9..cab33ae 100644
--- a/services/surfaceflinger/TEST_MAPPING
+++ b/services/surfaceflinger/TEST_MAPPING
@@ -5,14 +5,6 @@
},
{
"name": "libcompositionengine_test"
- },
- {
- "name": "SurfaceFlinger_test"
- }
- ],
- "postsubmit": [
- {
- "name": "sffakehwc_test"
}
]
}