Merge "Build all of libinput for linux host."
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 2c800c6..1c6583e 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -401,7 +401,7 @@
SectionExists("batterystats", /* bytes= */ 1000);
}
-TEST_F(BugreportSectionTest, WifiSectionGenerated) {
+TEST_F(BugreportSectionTest, DISABLED_WifiSectionGenerated) {
SectionExists("wifi", /* bytes= */ 100000);
}
diff --git a/include/ftl/StaticVector.h b/include/ftl/StaticVector.h
new file mode 100644
index 0000000..b586e91
--- /dev/null
+++ b/include/ftl/StaticVector.h
@@ -0,0 +1,341 @@
+/*
+ * 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 <cassert>
+#include <iterator>
+#include <memory>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+namespace android::ftl {
+
+// 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,
+// and the replace operation that destructively emplaces.
+//
+// StaticVector<T, 1> is analogous to an iterable std::optional, but StaticVector<T, 0> is an error.
+//
+// Example usage:
+//
+// ftl::StaticVector<char, 3> vector;
+// assert(vector.empty());
+//
+// vector = {'a', 'b'};
+// assert(vector.size() == 2u);
+//
+// vector.push_back('c');
+// assert(vector.full());
+//
+// assert(!vector.push_back('d'));
+// assert(vector.size() == 3u);
+//
+// vector.unstable_erase(vector.begin());
+// assert(vector == (ftl::StaticVector{'c', 'b'}));
+//
+// vector.pop_back();
+// assert(vector.back() == 'c');
+//
+// const char array[] = "hi";
+// vector = ftl::StaticVector(array);
+// assert(vector == (ftl::StaticVector{'h', 'i', '\0'}));
+//
+template <typename T, size_t N>
+class 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>;
+
+public:
+ 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>;
+
+ // Creates an empty vector.
+ StaticVector() = default;
+
+ // Copies and moves a vector, respectively.
+ StaticVector(const StaticVector& other) : StaticVector(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()) {}
+
+ // 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)) {}
+
+ // Copies at most N elements from the range [first, last).
+ template <typename Iterator, typename = std::enable_if_t<IsInputIterator<Iterator>{}>>
+ StaticVector(Iterator first, Iterator last)
+ : mSize(std::min(max_size(), static_cast<size_type>(std::distance(first, last)))) {
+ std::uninitialized_copy(first, first + mSize, begin());
+ }
+
+ // Constructs at most N elements. The template arguments T and N are inferred using the
+ // deduction guide defined below. Note that T is determined from the first element, and
+ // subsequent elements must have convertible types:
+ //
+ // ftl::StaticVector vector = {1, 2, 3};
+ // static_assert(std::is_same_v<decltype(vector), ftl::StaticVector<int, 3>>);
+ //
+ // const auto copy = "quince"s;
+ // auto move = "tart"s;
+ // ftl::StaticVector vector = {copy, std::move(move)};
+ //
+ // static_assert(std::is_same_v<decltype(vector), ftl::StaticVector<std::string, 2>>);
+ //
+ template <typename E, typename... Es,
+ typename = std::enable_if_t<std::is_constructible_v<value_type, E>>>
+ StaticVector(E&& element, Es&&... elements)
+ : StaticVector(std::index_sequence<0>{}, std::forward<E>(element),
+ std::forward<Es>(elements)...) {
+ static_assert(sizeof...(elements) < N, "Too many elements");
+ }
+
+ // Constructs at most N elements. The template arguments T and N are inferred using the
+ // deduction guide defined below. Element types must be convertible to the specified T:
+ //
+ // ftl::StaticVector vector(std::in_place_type<std::string>, "red", "velvet", "cake");
+ // static_assert(std::is_same_v<decltype(vector), ftl::StaticVector<std::string, 3>>);
+ //
+ template <typename... Es>
+ explicit StaticVector(std::in_place_type_t<T>, Es... elements)
+ : StaticVector(std::forward<Es>(elements)...) {}
+
+ ~StaticVector() { std::destroy(begin(), end()); }
+
+ StaticVector& operator=(const StaticVector& other) {
+ StaticVector copy(other);
+ swap(copy);
+ return *this;
+ }
+
+ StaticVector& operator=(StaticVector&& other) {
+ std::destroy(begin(), end());
+ mSize = 0;
+ swap<Empty>(other);
+ return *this;
+ }
+
+ template <typename = void>
+ void swap(StaticVector&);
+
+ size_type max_size() const { 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(); }
+
+ reverse_iterator rend() { return std::make_reverse_iterator(begin()); }
+ const_reverse_iterator rend() const { return crend(); }
+ const_reverse_iterator crend() const { return mut().rend(); }
+
+ iterator last() { return end() - 1; }
+ const_iterator last() const { return mut().last(); }
+
+ reference front() { return *begin(); }
+ const_reference front() const { return mut().front(); }
+
+ reference back() { return *last(); }
+ const_reference back() const { return mut().back(); }
+
+ reference operator[](size_type i) { return *(begin() + i); }
+ const_reference operator[](size_type i) const { return mut()[i]; }
+
+ // 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.
+ 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);
+ }
+
+ // 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.
+ template <typename... Args>
+ iterator emplace_back(Args&&... args) {
+ if (full()) return end();
+ const iterator it = construct_at(end(), std::forward<Args>(args)...);
+ ++mSize;
+ return it;
+ }
+
+ // 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.
+ void unstable_erase(const_iterator it) {
+ std::destroy_at(it);
+ if (it != last()) {
+ // Move last element and destroy its source for destructor side effects.
+ 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)
+ : StaticVector(std::index_sequence<I + 1>{}, std::forward<Es>(elements)...) {
+ construct_at(begin() + I, std::forward<E>(element));
+ }
+
+ // Base case for variadic constructor.
+ 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];
+};
+
+// Deduction guide for array constructor.
+template <typename T, size_t N>
+StaticVector(T (&)[N]) -> StaticVector<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> && ...)>>
+StaticVector(T&&, Us&&...) -> StaticVector<V, 1 + sizeof...(Us)>;
+
+// Deduction guide for in-place constructor.
+template <typename T, typename... Us>
+StaticVector(std::in_place_type_t<T>, Us&&...) -> StaticVector<T, sizeof...(Us)>;
+
+template <typename T, size_t N>
+template <typename E>
+void StaticVector<T, N>::swap(StaticVector& other) {
+ auto [to, from] = std::make_pair(this, &other);
+ if (from == this) return;
+
+ // Assume this vector has fewer elements, so the excess of the other vector will be moved to it.
+ auto [min, max] = std::make_pair(size(), other.size());
+
+ // No elements to swap if moving into an empty vector.
+ if constexpr (std::is_same_v<E, Empty>) {
+ assert(min == 0);
+ } else {
+ if (min > max) {
+ std::swap(from, to);
+ std::swap(min, max);
+ }
+
+ // Swap elements [0, min).
+ std::swap_ranges(begin(), begin() + min, other.begin());
+
+ // No elements to move if sizes are equal.
+ if (min == max) return;
+ }
+
+ // Move elements [min, max) and destroy their source for destructor side effects.
+ const auto [first, last] = std::make_pair(from->begin() + min, from->begin() + max);
+ std::uninitialized_move(first, last, to->begin() + min);
+ std::destroy(first, last);
+
+ std::swap(mSize, other.mSize);
+}
+
+template <typename T, size_t N>
+inline void swap(StaticVector<T, N>& lhs, StaticVector<T, N>& rhs) {
+ 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/gfx/.clang-format b/include/gfx/.clang-format
deleted file mode 100644
index 86763a0..0000000
--- a/include/gfx/.clang-format
+++ /dev/null
@@ -1,11 +0,0 @@
-BasedOnStyle: Google
-
-AccessModifierOffset: -2
-AllowShortFunctionsOnASingleLine: Inline
-BinPackParameters: false
-ColumnLimit: 100
-CommentPragmas: NOLINT:.*
-ConstructorInitializerAllOnOneLineOrOnePerLine: true
-ConstructorInitializerIndentWidth: 2
-ContinuationIndentWidth: 8
-IndentWidth: 4
diff --git a/include/input/Input.h b/include/input/Input.h
index 7ec0c9a..d3a9694 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -724,7 +724,7 @@
static const char* getLabel(int32_t axis);
static int32_t getAxisFromLabel(const char* label);
- static const char* actionToString(int32_t action);
+ static std::string actionToString(int32_t action);
protected:
int32_t mAction;
diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp
index e4ea60f..e1cbc19 100644
--- a/libs/binder/MemoryHeapBase.cpp
+++ b/libs/binder/MemoryHeapBase.cpp
@@ -49,7 +49,7 @@
int fd = ashmem_create_region(name == nullptr ? "MemoryHeapBase" : name, size);
ALOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno));
if (fd >= 0) {
- if (mapfd(fd, size) == NO_ERROR) {
+ if (mapfd(fd, true, size) == NO_ERROR) {
if (flags & READ_ONLY) {
ashmem_set_prot_region(fd, PROT_READ);
}
@@ -70,7 +70,7 @@
if (fd >= 0) {
const size_t pagesize = getpagesize();
size = ((size + pagesize-1) & ~(pagesize-1));
- if (mapfd(fd, size) == NO_ERROR) {
+ if (mapfd(fd, false, size) == NO_ERROR) {
mDevice = device;
}
}
@@ -82,7 +82,7 @@
{
const size_t pagesize = getpagesize();
size = ((size + pagesize-1) & ~(pagesize-1));
- mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), size, offset);
+ mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), false, size, offset);
}
status_t MemoryHeapBase::init(int fd, void *base, size_t size, int flags, const char* device)
@@ -98,7 +98,7 @@
return NO_ERROR;
}
-status_t MemoryHeapBase::mapfd(int fd, size_t size, off_t offset)
+status_t MemoryHeapBase::mapfd(int fd, bool writeableByCaller, size_t size, off_t offset)
{
if (size == 0) {
// try to figure out the size automatically
@@ -116,8 +116,12 @@
}
if ((mFlags & DONT_MAP_LOCALLY) == 0) {
+ int prot = PROT_READ;
+ if (writeableByCaller || (mFlags & READ_ONLY) == 0) {
+ prot |= PROT_WRITE;
+ }
void* base = (uint8_t*)mmap(nullptr, size,
- PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
+ prot, MAP_SHARED, fd, offset);
if (base == MAP_FAILED) {
ALOGE("mmap(fd=%d, size=%zu) failed (%s)",
fd, size, strerror(errno));
diff --git a/libs/binder/include/binder/MemoryHeapBase.h b/libs/binder/include/binder/MemoryHeapBase.h
index 52bd5de..0ece121 100644
--- a/libs/binder/include/binder/MemoryHeapBase.h
+++ b/libs/binder/include/binder/MemoryHeapBase.h
@@ -51,6 +51,8 @@
/*
* maps memory from ashmem, with the given name for debugging
+ * if the READ_ONLY flag is set, the memory will be writeable by the calling process,
+ * but not by others. this is NOT the case with the other ctors.
*/
explicit MemoryHeapBase(size_t size, uint32_t flags = 0, char const* name = nullptr);
@@ -78,7 +80,7 @@
int flags = 0, const char* device = nullptr);
private:
- status_t mapfd(int fd, size_t size, off_t offset = 0);
+ status_t mapfd(int fd, bool writeableByCaller, size_t size, off_t offset = 0);
int mFD;
size_t mSize;
diff --git a/libs/binder/parcel_fuzzer/binder_ndk.cpp b/libs/binder/parcel_fuzzer/binder_ndk.cpp
index 29da8f7..008780c 100644
--- a/libs/binder/parcel_fuzzer/binder_ndk.cpp
+++ b/libs/binder/parcel_fuzzer/binder_ndk.cpp
@@ -18,6 +18,7 @@
#include "binder_ndk.h"
#include <android/binder_parcel_utils.h>
+#include <android/binder_parcelable_utils.h>
#include "util.h"
@@ -54,6 +55,25 @@
binder_status_t status = AParcel_readStatusHeader(p.aParcel(), t.getR());
FUZZ_LOG() << "read status header: " << status;
},
+ [](const NdkParcelAdapter& p, uint8_t /*data*/) {
+ FUZZ_LOG() << "about to getDataSize the parcel";
+ AParcel_getDataSize(p.aParcel());
+ FUZZ_LOG() << "getDataSize done";
+ },
+ [](const NdkParcelAdapter& p, uint8_t data) {
+ FUZZ_LOG() << "about to read a ParcelableHolder";
+ ndk::AParcelableHolder ph {(data % 2 == 1) ? ndk::STABILITY_LOCAL : ndk::STABILITY_VINTF};
+ binder_status_t status = AParcel_readParcelable(p.aParcel(), &ph);
+ FUZZ_LOG() << "read the ParcelableHolder: " << status;
+ },
+ [](const NdkParcelAdapter& p, uint8_t data) {
+ FUZZ_LOG() << "about to appendFrom";
+ AParcel* parcel = AParcel_create();
+ binder_status_t status = AParcel_appendFrom(p.aParcel(), parcel, 0, data);
+ AParcel_delete(parcel);
+ FUZZ_LOG() << "appendFrom: " << status;
+ },
+
PARCEL_READ(int32_t, AParcel_readInt32),
PARCEL_READ(uint32_t, AParcel_readUint32),
PARCEL_READ(int64_t, AParcel_readInt64),
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 5e785b6..6058430 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -425,6 +425,7 @@
uint64_t newLastUpdate = lastUpdate ? *lastUpdate : 0;
do {
+ if (key.bucket > (gNCpus - 1) / CPUS_PER_ENTRY) return {};
if (lastUpdate) {
auto uidUpdated = uidUpdatedSince(key.uid, *lastUpdate, &newLastUpdate);
if (!uidUpdated.has_value()) return {};
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index ea2a200..0d5f412 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -387,6 +387,28 @@
}
}
+TEST(TimeInStateTest, AllUidConcurrentTimesFailsOnInvalidBucket) {
+ uint32_t uid = 0;
+ {
+ // Find an unused UID
+ auto map = getUidsConcurrentTimes();
+ ASSERT_TRUE(map.has_value());
+ ASSERT_FALSE(map->empty());
+ for (const auto &kv : *map) uid = std::max(uid, kv.first);
+ ++uid;
+ }
+ android::base::unique_fd fd{
+ bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")};
+ ASSERT_GE(fd, 0);
+ uint32_t nCpus = get_nprocs_conf();
+ uint32_t maxBucket = (nCpus - 1) / CPUS_PER_ENTRY;
+ time_key_t key = {.uid = uid, .bucket = maxBucket + 1};
+ std::vector<concurrent_val_t> vals(nCpus);
+ ASSERT_FALSE(writeToMapEntry(fd, &key, vals.data(), BPF_NOEXIST));
+ EXPECT_FALSE(getUidsConcurrentTimes().has_value());
+ ASSERT_FALSE(deleteMapEntry(fd, &key));
+}
+
TEST(TimeInStateTest, AllUidTimesConsistent) {
auto tisMap = getUidsCpuFreqTimes();
ASSERT_TRUE(tisMap.has_value());
diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp
new file mode 100644
index 0000000..e11be57
--- /dev/null
+++ b/libs/ftl/Android.bp
@@ -0,0 +1,16 @@
+cc_test {
+ name: "ftl_test",
+ test_suites: ["device-tests"],
+ sanitize: {
+ address: true,
+ },
+ srcs: [
+ "StaticVector_test.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ "-Wpedantic",
+ ],
+}
diff --git a/libs/ftl/StaticVector_test.cpp b/libs/ftl/StaticVector_test.cpp
new file mode 100644
index 0000000..06e4659
--- /dev/null
+++ b/libs/ftl/StaticVector_test.cpp
@@ -0,0 +1,347 @@
+/*
+ * 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/StaticVector.h>
+#include <gtest/gtest.h>
+
+#include <algorithm>
+#include <iterator>
+#include <string>
+#include <utility>
+
+using namespace std::string_literals;
+
+namespace android::test {
+
+using ftl::StaticVector;
+
+// Keep in sync with example usage in header file.
+TEST(StaticVector, Example) {
+ ftl::StaticVector<char, 3> vector;
+ EXPECT_TRUE(vector.empty());
+
+ vector = {'a', 'b'};
+ EXPECT_EQ(vector.size(), 2u);
+
+ vector.push_back('c');
+ EXPECT_TRUE(vector.full());
+
+ EXPECT_FALSE(vector.push_back('d'));
+ EXPECT_EQ(vector.size(), 3u);
+
+ vector.unstable_erase(vector.begin());
+ EXPECT_EQ(vector, (ftl::StaticVector{'c', 'b'}));
+
+ vector.pop_back();
+ EXPECT_EQ(vector.back(), 'c');
+
+ const char array[] = "hi";
+ vector = ftl::StaticVector(array);
+ EXPECT_EQ(vector, (ftl::StaticVector{'h', 'i', '\0'}));
+}
+
+TEST(StaticVector, Construct) {
+ {
+ // Default constructor.
+ StaticVector<std::string, 2> vector;
+ EXPECT_TRUE(vector.empty());
+ }
+ {
+ // Array constructor.
+ const float kFloats[] = {.1f, .2f, .3f};
+ StaticVector vector(kFloats);
+ EXPECT_EQ(vector, (StaticVector{.1f, .2f, .3f}));
+ }
+ {
+ // Iterator constructor.
+ const char chars[] = "abcdef";
+ std::string string(chars);
+ StaticVector<char, sizeof(chars)> vector(string.begin(), string.end());
+
+ EXPECT_STREQ(vector.begin(), chars);
+ }
+ {
+ // Variadic constructor with same types.
+ StaticVector vector = {1, 2, 3};
+
+ static_assert(std::is_same_v<decltype(vector), StaticVector<int, 3>>);
+ EXPECT_EQ(vector, (StaticVector{1, 2, 3}));
+ }
+ {
+ // Variadic constructor with different types.
+ const auto copy = "quince"s;
+ auto move = "tart"s;
+ StaticVector vector = {copy, std::move(move)};
+
+ static_assert(std::is_same_v<decltype(vector), StaticVector<std::string, 2>>);
+ EXPECT_EQ(vector, (StaticVector{"quince"s, "tart"s}));
+ }
+ {
+ // In-place constructor with same types.
+ StaticVector vector(std::in_place_type<std::string>, "red", "velvet", "cake");
+
+ static_assert(std::is_same_v<decltype(vector), StaticVector<std::string, 3>>);
+ EXPECT_EQ(vector, (StaticVector{"red"s, "velvet"s, "cake"s}));
+ }
+ {
+ // In-place constructor with different types.
+ const auto copy = "red"s;
+ auto move = "velvet"s;
+ std::initializer_list<char> list = {'c', 'a', 'k', 'e'};
+ StaticVector vector(std::in_place_type<std::string>, copy.c_str(), std::move(move), list);
+
+ static_assert(std::is_same_v<decltype(vector), StaticVector<std::string, 3>>);
+ EXPECT_EQ(vector, (StaticVector{"red"s, "velvet"s, "cake"s}));
+ }
+}
+
+TEST(StaticVector, String) {
+ StaticVector<char, 10> chars;
+ char c = 'a';
+ std::generate_n(std::back_inserter(chars), chars.max_size(), [&c] { return c++; });
+ chars.back() = '\0';
+
+ EXPECT_STREQ(chars.begin(), "abcdefghi");
+
+ // Constructor takes iterator range.
+ const char kString[] = "123456";
+ StaticVector<char, 10> string(std::begin(kString), std::end(kString));
+
+ EXPECT_STREQ(string.begin(), "123456");
+ 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());
+ EXPECT_STREQ(string.begin(), "12345");
+
+ swap(chars, string);
+
+ EXPECT_STREQ(chars.begin(), "12345");
+ EXPECT_STREQ(string.begin(), "abcdefghi");
+}
+
+TEST(StaticVector, CopyableElement) {
+ struct Pair {
+ const int a, b;
+ bool operator==(Pair p) const { return p.a == a && p.b == b; }
+ };
+
+ StaticVector<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;
+ const auto it = pairs.emplace_back(a, a + 1);
+ ASSERT_NE(it, pairs.end());
+ EXPECT_EQ(*it, (Pair{a, a + 1}));
+ }
+
+ EXPECT_TRUE(pairs.full());
+ EXPECT_EQ(pairs.size(), 5u);
+
+ // Insertion fails if the vector is full.
+ const auto it = pairs.emplace_back(10, 11);
+ EXPECT_EQ(it, pairs.end());
+
+ EXPECT_EQ(pairs, (StaticVector{Pair{0, 1}, Pair{2, 3}, Pair{4, 5}, Pair{6, 7}, Pair{8, 9}}));
+
+ // Constructor takes at most N elements.
+ StaticVector<int, 6> sums = {0, 0, 0, 0, 0, -1};
+ EXPECT_TRUE(sums.full());
+
+ // Random-access iterators comply with standard.
+ std::transform(pairs.begin(), pairs.end(), sums.begin(), [](Pair p) { return p.a + p.b; });
+ EXPECT_EQ(sums, (StaticVector{1, 5, 9, 13, 17, -1}));
+
+ sums.pop_back();
+ std::reverse(sums.begin(), sums.end());
+
+ EXPECT_EQ(sums, (StaticVector{17, 13, 9, 5, 1}));
+}
+
+TEST(StaticVector, 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*.
+ StaticVector 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.
+ {
+ 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);
+
+ // Construct std::string from first 4 characters of C-style string.
+ it = strings.emplace_back("cakewalk", 4u);
+ ASSERT_NE(it, strings.end());
+ EXPECT_EQ(*it, "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'};
+ const auto it = strings.replace(rit.base() - 1, list);
+ EXPECT_NE(it, strings.end());
+ }
+
+ strings.front().assign("pie");
+
+ EXPECT_EQ(strings, (StaticVector{"pie"s, "quince"s, "tart"s, "red"s, "velvet"s, "cake"s}));
+}
+
+TEST(StaticVector, ReverseTruncate) {
+ StaticVector<std::string, 10> strings("pie", "quince", "tart", "red", "velvet", "cake");
+ EXPECT_FALSE(strings.full());
+
+ for (auto it = strings.begin(); it != strings.end(); ++it) {
+ strings.replace(it, strings.back());
+ strings.pop_back();
+ }
+
+ EXPECT_EQ(strings, (StaticVector{"cake"s, "velvet"s, "red"s}));
+}
+
+TEST(StaticVector, Sort) {
+ StaticVector<std::string, 7> strings("pie", "quince", "tart", "red", "velvet", "cake");
+ EXPECT_FALSE(strings.full());
+
+ auto sorted = std::move(strings);
+ EXPECT_TRUE(strings.empty());
+
+ std::sort(sorted.begin(), sorted.end());
+ EXPECT_EQ(sorted, (StaticVector{"cake"s, "pie"s, "quince"s, "red"s, "tart"s, "velvet"s}));
+
+ // Constructor takes array reference.
+ {
+ const char* kStrings[] = {"cake", "lie"};
+ strings = StaticVector(kStrings);
+ }
+
+ EXPECT_GT(sorted, strings);
+ swap(sorted, strings);
+ 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);
+
+ EXPECT_NE(sorted, strings);
+
+ sorted.replace(sorted.begin() + 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(StaticVector, Destroy) {
+ int live = 0;
+ int dead = 0;
+
+ { StaticVector<DestroyCounts, 5> counts; }
+ EXPECT_EQ(0, live);
+ EXPECT_EQ(0, dead);
+
+ {
+ StaticVector<DestroyCounts, 5> counts;
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+ }
+ EXPECT_EQ(3, live);
+ EXPECT_EQ(0, dead);
+
+ live = 0;
+ {
+ StaticVector<DestroyCounts, 5> counts;
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+
+ auto copy = counts;
+ }
+ EXPECT_EQ(6, live);
+ EXPECT_EQ(0, dead);
+
+ live = 0;
+ {
+ StaticVector<DestroyCounts, 5> counts;
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+
+ auto move = std::move(counts);
+ }
+ EXPECT_EQ(3, live);
+ EXPECT_EQ(3, dead);
+
+ live = dead = 0;
+ {
+ StaticVector<DestroyCounts, 5> counts1;
+ counts1.emplace_back(live, dead);
+ counts1.emplace_back(live, dead);
+ counts1.emplace_back(live, dead);
+
+ StaticVector<DestroyCounts, 5> counts2;
+ counts2.emplace_back(live, dead);
+
+ swap(counts1, counts2);
+
+ EXPECT_EQ(0, live);
+ EXPECT_EQ(2, dead);
+
+ dead = 0;
+ }
+ EXPECT_EQ(4, live);
+ EXPECT_EQ(0, dead);
+}
+
+} // namespace android::test
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 964195d..6f92233 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -888,7 +888,7 @@
}
virtual status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultConfig,
+ int32_t defaultConfig, bool allowGroupSwitching,
float primaryRefreshRateMin,
float primaryRefreshRateMax,
float appRequestRefreshRateMin,
@@ -909,6 +909,11 @@
ALOGE("setDesiredDisplayConfigSpecs failed to write defaultConfig: %d", result);
return result;
}
+ result = data.writeBool(allowGroupSwitching);
+ if (result != NO_ERROR) {
+ ALOGE("setDesiredDisplayConfigSpecs failed to write allowGroupSwitching: %d", result);
+ return result;
+ }
result = data.writeFloat(primaryRefreshRateMin);
if (result != NO_ERROR) {
ALOGE("setDesiredDisplayConfigSpecs failed to write primaryRefreshRateMin: %d", result);
@@ -943,12 +948,14 @@
virtual status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t* outDefaultConfig,
+ bool* outAllowGroupSwitching,
float* outPrimaryRefreshRateMin,
float* outPrimaryRefreshRateMax,
float* outAppRequestRefreshRateMin,
float* outAppRequestRefreshRateMax) {
- if (!outDefaultConfig || !outPrimaryRefreshRateMin || !outPrimaryRefreshRateMax ||
- !outAppRequestRefreshRateMin || !outAppRequestRefreshRateMax) {
+ if (!outDefaultConfig || !outAllowGroupSwitching || !outPrimaryRefreshRateMin ||
+ !outPrimaryRefreshRateMax || !outAppRequestRefreshRateMin ||
+ !outAppRequestRefreshRateMax) {
return BAD_VALUE;
}
Parcel data, reply;
@@ -973,6 +980,11 @@
ALOGE("getDesiredDisplayConfigSpecs failed to read defaultConfig: %d", result);
return result;
}
+ result = reply.readBool(outAllowGroupSwitching);
+ if (result != NO_ERROR) {
+ ALOGE("getDesiredDisplayConfigSpecs failed to read allowGroupSwitching: %d", result);
+ return result;
+ }
result = reply.readFloat(outPrimaryRefreshRateMin);
if (result != NO_ERROR) {
ALOGE("getDesiredDisplayConfigSpecs failed to read primaryRefreshRateMin: %d", result);
@@ -1829,6 +1841,13 @@
ALOGE("setDesiredDisplayConfigSpecs: failed to read defaultConfig: %d", result);
return result;
}
+ bool allowGroupSwitching;
+ result = data.readBool(&allowGroupSwitching);
+ if (result != NO_ERROR) {
+ ALOGE("setDesiredDisplayConfigSpecs: failed to read allowGroupSwitching: %d",
+ result);
+ return result;
+ }
float primaryRefreshRateMin;
result = data.readFloat(&primaryRefreshRateMin);
if (result != NO_ERROR) {
@@ -1857,10 +1876,10 @@
result);
return result;
}
- result =
- setDesiredDisplayConfigSpecs(displayToken, defaultConfig, primaryRefreshRateMin,
- primaryRefreshRateMax, appRequestRefreshRateMin,
- appRequestRefreshRateMax);
+ result = setDesiredDisplayConfigSpecs(displayToken, defaultConfig, allowGroupSwitching,
+ primaryRefreshRateMin, primaryRefreshRateMax,
+ appRequestRefreshRateMin,
+ appRequestRefreshRateMax);
if (result != NO_ERROR) {
ALOGE("setDesiredDisplayConfigSpecs: failed to call setDesiredDisplayConfigSpecs: "
"%d",
@@ -1874,13 +1893,14 @@
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> displayToken = data.readStrongBinder();
int32_t defaultConfig;
+ bool allowGroupSwitching;
float primaryRefreshRateMin;
float primaryRefreshRateMax;
float appRequestRefreshRateMin;
float appRequestRefreshRateMax;
status_t result =
- getDesiredDisplayConfigSpecs(displayToken, &defaultConfig,
+ getDesiredDisplayConfigSpecs(displayToken, &defaultConfig, &allowGroupSwitching,
&primaryRefreshRateMin, &primaryRefreshRateMax,
&appRequestRefreshRateMin,
&appRequestRefreshRateMax);
@@ -1896,6 +1916,12 @@
ALOGE("getDesiredDisplayConfigSpecs: failed to write defaultConfig: %d", result);
return result;
}
+ result = reply->writeBool(allowGroupSwitching);
+ if (result != NO_ERROR) {
+ ALOGE("getDesiredDisplayConfigSpecs: failed to write allowGroupSwitching: %d",
+ result);
+ return result;
+ }
result = reply->writeFloat(primaryRefreshRateMin);
if (result != NO_ERROR) {
ALOGE("getDesiredDisplayConfigSpecs: failed to write primaryRefreshRateMin: %d",
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 4b7d4b1..32f9695 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1773,27 +1773,24 @@
return ComposerService::getComposerService()->getActiveConfig(display);
}
-status_t SurfaceComposerClient::setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultConfig,
- float primaryRefreshRateMin,
- float primaryRefreshRateMax,
- float appRequestRefreshRateMin,
- float appRequestRefreshRateMax) {
+status_t SurfaceComposerClient::setDesiredDisplayConfigSpecs(
+ const sp<IBinder>& displayToken, int32_t defaultConfig, bool allowGroupSwitching,
+ float primaryRefreshRateMin, float primaryRefreshRateMax, float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax) {
return ComposerService::getComposerService()
- ->setDesiredDisplayConfigSpecs(displayToken, defaultConfig, primaryRefreshRateMin,
- primaryRefreshRateMax, appRequestRefreshRateMin,
- appRequestRefreshRateMax);
+ ->setDesiredDisplayConfigSpecs(displayToken, defaultConfig, allowGroupSwitching,
+ primaryRefreshRateMin, primaryRefreshRateMax,
+ appRequestRefreshRateMin, appRequestRefreshRateMax);
}
-status_t SurfaceComposerClient::getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t* outDefaultConfig,
- float* outPrimaryRefreshRateMin,
- float* outPrimaryRefreshRateMax,
- float* outAppRequestRefreshRateMin,
- float* outAppRequestRefreshRateMax) {
+status_t SurfaceComposerClient::getDesiredDisplayConfigSpecs(
+ const sp<IBinder>& displayToken, int32_t* outDefaultConfig, bool* outAllowGroupSwitching,
+ float* outPrimaryRefreshRateMin, float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin, float* outAppRequestRefreshRateMax) {
return ComposerService::getComposerService()
- ->getDesiredDisplayConfigSpecs(displayToken, outDefaultConfig, outPrimaryRefreshRateMin,
- outPrimaryRefreshRateMax, outAppRequestRefreshRateMin,
+ ->getDesiredDisplayConfigSpecs(displayToken, outDefaultConfig, outAllowGroupSwitching,
+ outPrimaryRefreshRateMin, outPrimaryRefreshRateMax,
+ outAppRequestRefreshRateMin,
outAppRequestRefreshRateMax);
}
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index a416147..5cd9356 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -395,7 +395,7 @@
* returned from getDisplayConfigs().
*/
virtual status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultConfig,
+ int32_t defaultConfig, bool allowGroupSwitching,
float primaryRefreshRateMin,
float primaryRefreshRateMax,
float appRequestRefreshRateMin,
@@ -403,6 +403,7 @@
virtual status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t* outDefaultConfig,
+ bool* outAllowGroupSwitching,
float* outPrimaryRefreshRateMin,
float* outPrimaryRefreshRateMax,
float* outAppRequestRefreshRateMin,
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index fb01dc4..13abed2 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -120,13 +120,15 @@
// Sets the refresh rate boundaries for the display.
static status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultConfig, float primaryRefreshRateMin,
+ int32_t defaultConfig, bool allowGroupSwitching,
+ float primaryRefreshRateMin,
float primaryRefreshRateMax,
float appRequestRefreshRateMin,
float appRequestRefreshRateMax);
// Gets the refresh rate boundaries for the display.
static status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t* outDefaultConfig,
+ bool* outAllowGroupSwitching,
float* outPrimaryRefreshRateMin,
float* outPrimaryRefreshRateMax,
float* outAppRequestRefreshRateMin,
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 5a376da..0cd3962 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -844,7 +844,7 @@
return NO_ERROR;
}
status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& /*displayToken*/,
- int32_t /*defaultConfig*/,
+ int32_t /*defaultConfig*/, bool /*allowGroupSwitching*/,
float /*primaryRefreshRateMin*/,
float /*primaryRefreshRateMax*/,
float /*appRequestRefreshRateMin*/,
@@ -853,6 +853,7 @@
}
status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& /*displayToken*/,
int32_t* /*outDefaultConfig*/,
+ bool* /*outAllowGroupSwitching*/,
float* /*outPrimaryRefreshRateMin*/,
float* /*outPrimaryRefreshRateMax*/,
float* /*outAppRequestRefreshRateMin*/,
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index f3b8832..ad7db75 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -19,9 +19,11 @@
#include <attestation/HmacKeyManager.h>
#include <cutils/compiler.h>
+#include <inttypes.h>
#include <limits.h>
#include <string.h>
+#include <android-base/stringprintf.h>
#include <input/Input.h>
#include <input/InputDevice.h>
#include <input/InputEventLabels.h>
@@ -31,6 +33,8 @@
#include <sys/random.h>
#endif
+using android::base::StringPrintf;
+
namespace android {
const char* motionClassificationToString(MotionClassification classification) {
@@ -696,23 +700,37 @@
return InputEventLookup::getAxisByLabel(label);
}
-const char* MotionEvent::actionToString(int32_t action) {
+std::string MotionEvent::actionToString(int32_t action) {
// Convert MotionEvent action to string
switch (action & AMOTION_EVENT_ACTION_MASK) {
case AMOTION_EVENT_ACTION_DOWN:
return "DOWN";
- case AMOTION_EVENT_ACTION_MOVE:
- return "MOVE";
case AMOTION_EVENT_ACTION_UP:
return "UP";
+ case AMOTION_EVENT_ACTION_MOVE:
+ return "MOVE";
case AMOTION_EVENT_ACTION_CANCEL:
return "CANCEL";
+ case AMOTION_EVENT_ACTION_OUTSIDE:
+ return "OUTSIDE";
case AMOTION_EVENT_ACTION_POINTER_DOWN:
return "POINTER_DOWN";
case AMOTION_EVENT_ACTION_POINTER_UP:
return "POINTER_UP";
+ case AMOTION_EVENT_ACTION_HOVER_MOVE:
+ return "HOVER_MOVE";
+ case AMOTION_EVENT_ACTION_SCROLL:
+ return "SCROLL";
+ case AMOTION_EVENT_ACTION_HOVER_ENTER:
+ return "HOVER_ENTER";
+ case AMOTION_EVENT_ACTION_HOVER_EXIT:
+ return "HOVER_EXIT";
+ case AMOTION_EVENT_ACTION_BUTTON_PRESS:
+ return "BUTTON_PRESS";
+ case AMOTION_EVENT_ACTION_BUTTON_RELEASE:
+ return "BUTTON_RELEASE";
}
- return "UNKNOWN";
+ return android::base::StringPrintf("%" PRId32, action);
}
// --- FocusEvent ---
diff --git a/libs/input/TEST_MAPPING b/libs/input/TEST_MAPPING
new file mode 100644
index 0000000..9626d8d
--- /dev/null
+++ b/libs/input/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "frameworks/native/services/inputflinger"
+ }
+ ]
+}
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 44147a5..b23aade 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -30,7 +30,8 @@
"liblog",
"libui",
"libutils",
- ]
+ ],
+ test_suites: ["device-tests"],
}
// NOTE: This is a compile time test, and does not need to be
diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp
index db81f5d..940a26b 100644
--- a/services/gpuservice/tests/unittests/Android.bp
+++ b/services/gpuservice/tests/unittests/Android.bp
@@ -38,4 +38,5 @@
static_libs: [
"libgmock",
],
+ require_root: true,
}
diff --git a/services/gpuservice/tests/unittests/AndroidTest.xml b/services/gpuservice/tests/unittests/AndroidTest.xml
index 66f51c7..72976a8 100644
--- a/services/gpuservice/tests/unittests/AndroidTest.xml
+++ b/services/gpuservice/tests/unittests/AndroidTest.xml
@@ -18,6 +18,7 @@
<option name="cleanup" value="true" />
<option name="push" value="gpuservice_unittest->/data/local/tmp/gpuservice_unittest" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
<option name="test-suite-tag" value="apct" />
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING
index 824c01e..33520b2 100644
--- a/services/inputflinger/TEST_MAPPING
+++ b/services/inputflinger/TEST_MAPPING
@@ -7,6 +7,18 @@
"include-filter": "android.server.wm.WindowInputTests"
}
]
+ },
+ {
+ "name": "libinput_tests"
+ },
+ {
+ "name": "inputflinger_tests"
+ },
+ {
+ "name": "InputTests"
+ },
+ {
+ "name": "libinputservice_test"
}
]
}
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index 5103b4c..29df00b 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -207,10 +207,10 @@
"buttonState=0x%08x, "
"classification=%s, edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, "
"xCursorPosition=%0.1f, yCursorPosition=%0.1f, pointers=[",
- deviceId, eventTime, source, displayId, MotionEvent::actionToString(action),
- actionButton, flags, metaState, buttonState,
- motionClassificationToString(classification), edgeFlags, xPrecision,
- yPrecision, xCursorPosition, yCursorPosition);
+ deviceId, eventTime, source, displayId,
+ MotionEvent::actionToString(action).c_str(), actionButton, flags, metaState,
+ buttonState, motionClassificationToString(classification), edgeFlags,
+ xPrecision, yPrecision, xCursorPosition, yCursorPosition);
for (uint32_t i = 0; i < pointerCount; i++) {
if (i) {
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 6465cc9..8cb7194 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -48,4 +48,5 @@
"libc++fs"
],
require_root: true,
+ test_suites: ["device-tests"],
}
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index d590f23..3be1cc4 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -167,6 +167,11 @@
const Rect& orientedDisplaySpaceRect) = 0;
// Sets the bounds to use
virtual void setDisplaySize(const ui::Size&) = 0;
+ // Gets the transform hint used in layers that belong to this output. Used to guide
+ // composition orientation so that HW overlay can be used when display isn't in its natural
+ // orientation on some devices. Therefore usually we only use transform hint from display
+ // output.
+ virtual ui::Transform::RotationFlags getTransformHint() const = 0;
// Sets the layer stack filtering settings for this output. See
// belongsInOutput for full details.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 5b832a5..651230c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -42,6 +42,7 @@
const Rect& orientedDisplaySpaceRect) override;
void setDisplaySize(const ui::Size&) override;
void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override;
+ ui::Transform::RotationFlags getTransformHint() const override;
void setColorTransform(const compositionengine::CompositionRefreshArgs&) override;
void setColorProfile(const ColorProfile&) override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index d6fbd7f..95db4da 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -39,6 +39,7 @@
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_METHOD1(setColorTransform, void(const compositionengine::CompositionRefreshArgs&));
MOCK_METHOD1(setColorProfile, void(const ColorProfile&));
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index b420109..c625b2e 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -192,6 +192,10 @@
dirtyEntireOutput();
}
+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;
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 6be0cc2..3dd1839 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -268,6 +268,8 @@
EXPECT_EQ(orientation, state.framebufferSpace.orientation);
EXPECT_EQ(state.displaySpace.content, state.transform.transform(state.layerStackSpace.content));
+
+ EXPECT_EQ(ui::Transform::ROT_90, mOutput->getTransformHint());
}
TEST_F(OutputTest, setProjectionWithSmallFramebufferWorks) {
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 5bd7a1f..cbc201f 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -248,6 +248,10 @@
return mCompositionDisplay->getState().layerStackId;
}
+ui::Transform::RotationFlags DisplayDevice::getTransformHint() const {
+ return mCompositionDisplay->getTransformHint();
+}
+
const ui::Transform& DisplayDevice::getTransform() const {
return mCompositionDisplay->getState().transform;
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index fa684c0..cc38ab0 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -95,10 +95,7 @@
static ui::Transform::RotationFlags getPrimaryDisplayRotationFlags();
- ui::Transform::RotationFlags getTransformHint() const {
- return static_cast<ui::Transform::RotationFlags>(getTransform().getOrientation());
- }
-
+ ui::Transform::RotationFlags getTransformHint() const;
const ui::Transform& getTransform() const;
const Rect& getLayerStackSpaceRect() const;
const Rect& getOrientedDisplaySpaceRect() const;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 50707df..f657a00 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1034,6 +1034,12 @@
mCurrentState.inputInfoChanged = false;
}
+ // Add the callbacks from the drawing state into the current state. This is so when the current
+ // state gets copied to drawing, we don't lose the callback handles that are still in drawing.
+ for (auto& handle : s.callbackHandles) {
+ c.callbackHandles.push_back(handle);
+ }
+
// Commit the transaction
commitTransaction(c);
mPendingStatesSnapshot = mPendingStates;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 8661b6e..7ab49a9 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -48,6 +48,13 @@
}
}
+std::string RefreshRateConfigs::Policy::toString() {
+ return base::StringPrintf("default config ID: %d, allowGroupSwitching = %d"
+ ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]",
+ defaultConfig.value(), allowGroupSwitching, primaryRange.min,
+ primaryRange.max, appRequestRange.min, appRequestRange.max);
+}
+
const RefreshRate& RefreshRateConfigs::getRefreshRateForContent(
const std::vector<LayerRequirement>& layers) const {
std::lock_guard lock(mLock);
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index eed8486..280ed62 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -108,6 +108,10 @@
std::unordered_map<HwcConfigIndexType, std::unique_ptr<const RefreshRate>>;
struct Policy {
+ private:
+ static constexpr int kAllowGroupSwitchingDefault = false;
+
+ public:
struct Range {
float min = 0;
float max = std::numeric_limits<float>::max();
@@ -122,6 +126,8 @@
// The default config, used to ensure we only initiate display config switches within the
// same config group as defaultConfigId's group.
HwcConfigIndexType defaultConfig;
+ // Whether or not we switch config groups to get the best frame rate.
+ bool allowGroupSwitching = kAllowGroupSwitchingDefault;
// The primary refresh rate range represents display manager's general guidance on the
// display configs we'll consider when switching refresh rates. Unless we get an explicit
// signal from an app, we should stay within this range.
@@ -133,15 +139,23 @@
// app request range. The app request range will be greater than or equal to the primary
// refresh rate range, never smaller.
Range appRequestRange;
- // Whether or not we switch config groups to get the best frame rate. Only used by tests.
- bool allowGroupSwitching = false;
Policy() = default;
+
Policy(HwcConfigIndexType defaultConfig, const Range& range)
- : Policy(defaultConfig, range, range) {}
+ : Policy(defaultConfig, kAllowGroupSwitchingDefault, range, range) {}
+
+ Policy(HwcConfigIndexType defaultConfig, bool allowGroupSwitching, const Range& range)
+ : Policy(defaultConfig, allowGroupSwitching, range, range) {}
+
Policy(HwcConfigIndexType defaultConfig, const Range& primaryRange,
const Range& appRequestRange)
+ : Policy(defaultConfig, kAllowGroupSwitchingDefault, primaryRange, appRequestRange) {}
+
+ Policy(HwcConfigIndexType defaultConfig, bool allowGroupSwitching,
+ const Range& primaryRange, const Range& appRequestRange)
: defaultConfig(defaultConfig),
+ allowGroupSwitching(allowGroupSwitching),
primaryRange(primaryRange),
appRequestRange(appRequestRange) {}
@@ -152,6 +166,7 @@
}
bool operator!=(const Policy& other) const { return !(*this == other); }
+ std::string toString();
};
// Return code set*Policy() to indicate the current policy is unchanged.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index b6ed68f..3977e2b 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -357,7 +357,9 @@
hasWideColorDisplay = has_wide_color_display(false);
- useColorManagement = use_color_management(false);
+ // Android 12 and beyond, color management in display pipeline is turned on
+ // by default.
+ useColorManagement = use_color_management(true);
mDefaultCompositionDataspace =
static_cast<ui::Dataspace>(default_composition_dataspace(Dataspace::V0_SRGB));
@@ -1041,7 +1043,12 @@
} else {
const HwcConfigIndexType config(mode);
const float fps = mRefreshRateConfigs->getRefreshRateFromConfigId(config).getFps();
- const scheduler::RefreshRateConfigs::Policy policy{config, {fps, fps}};
+ // Keep the old switching type.
+ const auto allowGroupSwitching =
+ mRefreshRateConfigs->getCurrentPolicy().allowGroupSwitching;
+ const scheduler::RefreshRateConfigs::Policy policy{config,
+ allowGroupSwitching,
+ {fps, fps}};
constexpr bool kOverridePolicy = false;
return setDesiredDisplayConfigSpecsInternal(display, policy, kOverridePolicy);
@@ -1848,16 +1855,18 @@
bool refreshNeeded;
{
- ConditionalLockGuard<std::mutex> lock(mTracingLock, mTracingEnabled);
+ mTracePostComposition = mTracing.flagIsSet(SurfaceTracing::TRACE_COMPOSITION) ||
+ mTracing.flagIsSet(SurfaceTracing::TRACE_SYNC) ||
+ mTracing.flagIsSet(SurfaceTracing::TRACE_BUFFERS);
+ const bool tracePreComposition = mTracingEnabled && !mTracePostComposition;
+ ConditionalLockGuard<std::mutex> lock(mTracingLock, tracePreComposition);
mFrameTimeline->setSfWakeUp(vsyncId, frameStart);
refreshNeeded = handleMessageTransaction();
refreshNeeded |= handleMessageInvalidate();
- if (mTracingEnabled) {
- mAddCompositionStateToTrace =
- mTracing.flagIsSetLocked(SurfaceTracing::TRACE_COMPOSITION);
- if (mVisibleRegionsDirty && !mAddCompositionStateToTrace) {
+ if (tracePreComposition) {
+ if (mVisibleRegionsDirty) {
mTracing.notifyLocked("visibleRegionsDirty");
}
}
@@ -2007,12 +2016,15 @@
modulateVsync(&VsyncModulator::onDisplayRefresh, usedGpuComposition);
mLayersWithQueuedFrames.clear();
- if (mVisibleRegionsDirty) {
- mVisibleRegionsDirty = false;
- if (mTracingEnabled && mAddCompositionStateToTrace) {
+ if (mTracingEnabled && mTracePostComposition) {
+ // This may block if SurfaceTracing is running in sync mode.
+ if (mVisibleRegionsDirty) {
mTracing.notify("visibleRegionsDirty");
+ } else if (mTracing.flagIsSet(SurfaceTracing::TRACE_BUFFERS)) {
+ mTracing.notify("bufferLatched");
}
}
+ mVisibleRegionsDirty = false;
if (mCompositionEngine->needsAnotherUpdate()) {
signalLayerUpdate();
@@ -4277,7 +4289,7 @@
status_t SurfaceFlinger::dumpCritical(int fd, const DumpArgs&, bool asProto) {
if (asProto && mTracing.isEnabled()) {
- mTracing.writeToFileAsync();
+ mTracing.writeToFile();
}
return doDump(fd, DumpArgs(), asProto);
@@ -4361,21 +4373,14 @@
dispSyncPresentTimeOffset, getVsyncPeriodFromHWC());
scheduler::RefreshRateConfigs::Policy policy = mRefreshRateConfigs->getDisplayManagerPolicy();
- StringAppendF(&result,
- "DesiredDisplayConfigSpecs (DisplayManager): default config ID: %d"
- ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]\n\n",
- policy.defaultConfig.value(), policy.primaryRange.min, policy.primaryRange.max,
- policy.appRequestRange.min, policy.appRequestRange.max);
+ StringAppendF(&result, "DesiredDisplayConfigSpecs (DisplayManager): %s\n\n",
+ policy.toString().c_str());
StringAppendF(&result, "(config override by backdoor: %s)\n\n",
mDebugDisplayConfigSetByBackdoor ? "yes" : "no");
scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy();
if (currentPolicy != policy) {
- StringAppendF(&result,
- "DesiredDisplayConfigSpecs (Override): default config ID: %d"
- ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]\n\n",
- currentPolicy.defaultConfig.value(), currentPolicy.primaryRange.min,
- currentPolicy.primaryRange.max, currentPolicy.appRequestRange.min,
- currentPolicy.appRequestRange.max);
+ StringAppendF(&result, "DesiredDisplayConfigSpecs (Override): %s\n\n",
+ currentPolicy.toString().c_str());
}
mScheduler->dump(mAppConnectionHandle, result);
@@ -5101,19 +5106,19 @@
}
case 1025: { // Set layer tracing
n = data.readInt32();
+ bool tracingEnabledChanged;
if (n) {
ALOGD("LayerTracing enabled");
- mTracingEnabledChanged = mTracing.enable();
- reply->writeInt32(NO_ERROR);
+ tracingEnabledChanged = mTracing.enable();
+ if (tracingEnabledChanged) {
+ schedule([&]() MAIN_THREAD { mTracing.notify("start"); }).wait();
+ }
} else {
ALOGD("LayerTracing disabled");
- mTracingEnabledChanged = mTracing.disable();
- if (mTracingEnabledChanged) {
- reply->writeInt32(mTracing.writeToFile());
- } else {
- reply->writeInt32(NO_ERROR);
- }
+ tracingEnabledChanged = mTracing.disable();
}
+ mTracingEnabledChanged = tracingEnabledChanged;
+ reply->writeInt32(NO_ERROR);
return NO_ERROR;
}
case 1026: { // Get layer tracing status
@@ -5969,12 +5974,10 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultConfig,
- float primaryRefreshRateMin,
- float primaryRefreshRateMax,
- float appRequestRefreshRateMin,
- float appRequestRefreshRateMax) {
+status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(
+ const sp<IBinder>& displayToken, int32_t defaultConfig, bool allowGroupSwitching,
+ float primaryRefreshRateMin, float primaryRefreshRateMax, float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax) {
ATRACE_CALL();
if (!displayToken) {
@@ -5993,6 +5996,7 @@
} else {
using Policy = scheduler::RefreshRateConfigs::Policy;
const Policy policy{HwcConfigIndexType(defaultConfig),
+ allowGroupSwitching,
{primaryRefreshRateMin, primaryRefreshRateMax},
{appRequestRefreshRateMin, appRequestRefreshRateMax}};
constexpr bool kOverridePolicy = false;
@@ -6004,12 +6008,10 @@
return future.get();
}
-status_t SurfaceFlinger::getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t* outDefaultConfig,
- float* outPrimaryRefreshRateMin,
- float* outPrimaryRefreshRateMax,
- float* outAppRequestRefreshRateMin,
- float* outAppRequestRefreshRateMax) {
+status_t SurfaceFlinger::getDesiredDisplayConfigSpecs(
+ const sp<IBinder>& displayToken, int32_t* outDefaultConfig, bool* outAllowGroupSwitching,
+ float* outPrimaryRefreshRateMin, float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin, float* outAppRequestRefreshRateMax) {
ATRACE_CALL();
if (!displayToken || !outDefaultConfig || !outPrimaryRefreshRateMin ||
@@ -6027,6 +6029,7 @@
scheduler::RefreshRateConfigs::Policy policy =
mRefreshRateConfigs->getDisplayManagerPolicy();
*outDefaultConfig = policy.defaultConfig.value();
+ *outAllowGroupSwitching = policy.allowGroupSwitching;
*outPrimaryRefreshRateMin = policy.primaryRange.min;
*outPrimaryRefreshRateMax = policy.primaryRange.max;
*outAppRequestRefreshRateMin = policy.appRequestRange.min;
@@ -6037,6 +6040,7 @@
} else {
const auto displayId = display->getPhysicalId();
*outDefaultConfig = getHwComposer().getActiveConfigIndex(displayId);
+ *outAllowGroupSwitching = false;
auto vsyncPeriod = getHwComposer().getActiveConfig(displayId)->getVsyncPeriod();
*outPrimaryRefreshRateMin = 1e9f / vsyncPeriod;
*outPrimaryRefreshRateMax = 1e9f / vsyncPeriod;
@@ -6167,8 +6171,8 @@
// This is a little racy, but not in a way that hurts anything. As we grab the
// defaultConfig from the display manager policy, we could be setting a new display
// manager policy, leaving us using a stale defaultConfig. The defaultConfig doesn't
- // matter for the override policy though, since we set allowGroupSwitching to true, so
- // it's not a problem.
+ // matter for the override policy though, since we set allowGroupSwitching to
+ // true, so it's not a problem.
scheduler::RefreshRateConfigs::Policy overridePolicy;
overridePolicy.defaultConfig =
mRefreshRateConfigs->getDisplayManagerPolicy().defaultConfig;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 5bb5a0d..a821d44 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -583,11 +583,12 @@
const sp<IRegionSamplingListener>& listener) override;
status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override;
status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken, int32_t displayModeId,
- float primaryRefreshRateMin, float primaryRefreshRateMax,
+ bool allowGroupSwitching, float primaryRefreshRateMin,
+ float primaryRefreshRateMax,
float appRequestRefreshRateMin,
float appRequestRefreshRateMax) override;
status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t* outDefaultConfig,
+ int32_t* outDefaultConfig, bool* outAllowGroupSwitching,
float* outPrimaryRefreshRateMin,
float* outPrimaryRefreshRateMax,
float* outAppRequestRefreshRateMin,
@@ -1134,7 +1135,7 @@
SurfaceTracing mTracing{*this};
std::mutex mTracingLock;
bool mTracingEnabled = false;
- bool mAddCompositionStateToTrace = false;
+ bool mTracePostComposition = false;
std::atomic<bool> mTracingEnabledChanged = false;
const std::shared_ptr<TimeStats> mTimeStats;
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index d84ce69..1d1f0c5 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -14,9 +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"
#undef LOG_TAG
#define LOG_TAG "SurfaceTracing"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -32,65 +29,65 @@
namespace android {
-SurfaceTracing::SurfaceTracing(SurfaceFlinger& flinger)
- : mFlinger(flinger), mSfLock(flinger.mTracingLock) {}
+SurfaceTracing::SurfaceTracing(SurfaceFlinger& flinger) : mFlinger(flinger) {}
-void SurfaceTracing::mainLoop() {
- bool enabled = addFirstEntry();
- while (enabled) {
- LayersTraceProto entry = traceWhenNotified();
- enabled = addTraceToBuffer(entry);
- }
-}
-
-bool SurfaceTracing::addFirstEntry() {
- LayersTraceProto entry;
- {
- std::scoped_lock lock(mSfLock);
- entry = traceLayersLocked("tracing.enable");
- }
- return addTraceToBuffer(entry);
-}
-
-LayersTraceProto SurfaceTracing::traceWhenNotified() {
- std::unique_lock<std::mutex> lock(mSfLock);
- mCanStartTrace.wait(lock);
- android::base::ScopedLockAssertion assumeLock(mSfLock);
- LayersTraceProto entry = traceLayersLocked(mWhere);
- mTracingInProgress = false;
- mMissedTraceEntries = 0;
- lock.unlock();
- return entry;
-}
-
-bool SurfaceTracing::addTraceToBuffer(LayersTraceProto& entry) {
+bool SurfaceTracing::enable() {
std::scoped_lock lock(mTraceLock);
- mBuffer.emplace(std::move(entry));
- if (mWriteToFile) {
- writeProtoFileLocked();
- mWriteToFile = false;
+ if (mEnabled) {
+ return false;
}
+
+ if (flagIsSet(TRACE_SYNC)) {
+ runner = std::make_unique<SurfaceTracing::Runner>(mFlinger, mConfig);
+ } else {
+ runner = std::make_unique<SurfaceTracing::AsyncRunner>(mFlinger, mConfig,
+ mFlinger.mTracingLock);
+ }
+ mEnabled = true;
+ return true;
+}
+
+bool SurfaceTracing::disable() {
+ std::scoped_lock lock(mTraceLock);
+ if (!mEnabled) {
+ return false;
+ }
+ mEnabled = false;
+ runner->stop();
+ return true;
+}
+
+bool SurfaceTracing::isEnabled() const {
+ std::scoped_lock lock(mTraceLock);
return mEnabled;
}
+status_t SurfaceTracing::writeToFile() {
+ std::scoped_lock lock(mTraceLock);
+ if (!mEnabled) {
+ return STATUS_OK;
+ }
+ return runner->writeToFile();
+}
+
void SurfaceTracing::notify(const char* where) {
- std::scoped_lock lock(mSfLock);
- notifyLocked(where);
+ if (mEnabled) {
+ runner->notify(where);
+ }
}
void SurfaceTracing::notifyLocked(const char* where) {
- mWhere = where;
- if (mTracingInProgress) {
- mMissedTraceEntries++;
+ if (mEnabled) {
+ runner->notifyLocked(where);
}
- mTracingInProgress = true;
- mCanStartTrace.notify_one();
}
-void SurfaceTracing::writeToFileAsync() {
+void SurfaceTracing::dump(std::string& result) const {
std::scoped_lock lock(mTraceLock);
- mWriteToFile = true;
- mCanStartTrace.notify_one();
+ base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled");
+ if (mEnabled) {
+ runner->dump(result);
+ }
}
void SurfaceTracing::LayersTraceBuffer::reset(size_t newSize) {
@@ -101,12 +98,12 @@
}
void SurfaceTracing::LayersTraceBuffer::emplace(LayersTraceProto&& proto) {
- auto protoSize = proto.ByteSize();
+ size_t protoSize = static_cast<size_t>(proto.ByteSize());
while (mUsedInBytes + protoSize > mSizeInBytes) {
if (mStorage.empty()) {
return;
}
- mUsedInBytes -= mStorage.front().ByteSize();
+ mUsedInBytes -= static_cast<size_t>(mStorage.front().ByteSize());
mStorage.pop();
}
mUsedInBytes += protoSize;
@@ -115,7 +112,7 @@
}
void SurfaceTracing::LayersTraceBuffer::flush(LayersTraceFileProto* fileProto) {
- fileProto->mutable_entry()->Reserve(mStorage.size());
+ fileProto->mutable_entry()->Reserve(static_cast<int>(mStorage.size()));
while (!mStorage.empty()) {
auto entry = fileProto->add_entry();
@@ -124,85 +121,21 @@
}
}
-bool SurfaceTracing::enable() {
- std::scoped_lock lock(mTraceLock);
-
- if (mEnabled) {
- return false;
- }
-
- mBuffer.reset(mBufferSize);
- mEnabled = true;
- mThread = std::thread(&SurfaceTracing::mainLoop, this);
- return true;
+SurfaceTracing::Runner::Runner(SurfaceFlinger& flinger, SurfaceTracing::Config& config)
+ : mFlinger(flinger), mConfig(config) {
+ mBuffer.setSize(mConfig.bufferSize);
}
-status_t SurfaceTracing::writeToFile() {
- std::thread thread;
- {
- std::scoped_lock lock(mTraceLock);
- thread = std::move(mThread);
- }
- thread.join();
- return mLastErr;
+void SurfaceTracing::Runner::notify(const char* where) {
+ LayersTraceProto entry = traceLayers(where);
+ mBuffer.emplace(std::move(entry));
}
-bool SurfaceTracing::disable() {
- std::scoped_lock lock(mTraceLock);
-
- if (!mEnabled) {
- return false;
- }
-
- mEnabled = false;
- mWriteToFile = true;
- mCanStartTrace.notify_all();
- return true;
+status_t SurfaceTracing::Runner::stop() {
+ return writeToFile();
}
-bool SurfaceTracing::isEnabled() const {
- std::scoped_lock lock(mTraceLock);
- return mEnabled;
-}
-
-void SurfaceTracing::setBufferSize(size_t bufferSizeInByte) {
- std::scoped_lock lock(mTraceLock);
- mBufferSize = bufferSizeInByte;
- mBuffer.setSize(bufferSizeInByte);
-}
-
-void SurfaceTracing::setTraceFlags(uint32_t flags) {
- std::scoped_lock lock(mSfLock);
- mTraceFlags = flags;
-}
-
-LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) {
- ATRACE_CALL();
-
- LayersTraceProto entry;
- entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
- entry.set_where(where);
- LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags));
-
- if (flagIsSetLocked(SurfaceTracing::TRACE_EXTRA)) {
- mFlinger.dumpOffscreenLayersProto(layers);
- }
- entry.mutable_layers()->Swap(&layers);
-
- if (mTraceFlags & SurfaceTracing::TRACE_HWC) {
- std::string hwcDump;
- mFlinger.dumpHwc(hwcDump);
- entry.set_hwc_blob(hwcDump);
- }
- if (!flagIsSetLocked(SurfaceTracing::TRACE_COMPOSITION)) {
- entry.set_excludes_composition_state(true);
- }
- entry.set_missed_entries(mMissedTraceEntries);
-
- return entry;
-}
-
-void SurfaceTracing::writeProtoFileLocked() {
+status_t SurfaceTracing::Runner::writeToFile() {
ATRACE_CALL();
LayersTraceFileProto fileProto;
@@ -211,33 +144,114 @@
fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 |
LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L);
mBuffer.flush(&fileProto);
- mBuffer.reset(mBufferSize);
+ mBuffer.reset(mConfig.bufferSize);
if (!fileProto.SerializeToString(&output)) {
ALOGE("Could not save the proto file! Permission denied");
- mLastErr = PERMISSION_DENIED;
+ return PERMISSION_DENIED;
}
// -rw-r--r--
const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
- if (!android::base::WriteStringToFile(output, kDefaultFileName, mode, getuid(), getgid(),
+ if (!android::base::WriteStringToFile(output, DEFAULT_FILE_NAME, mode, getuid(), getgid(),
true)) {
ALOGE("Could not save the proto file! There are missing fields");
- mLastErr = PERMISSION_DENIED;
+ return PERMISSION_DENIED;
}
- mLastErr = NO_ERROR;
+ return NO_ERROR;
}
-void SurfaceTracing::dump(std::string& result) const {
- std::scoped_lock lock(mTraceLock);
- base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled");
+LayersTraceProto SurfaceTracing::Runner::traceLayers(const char* where) {
+ ATRACE_CALL();
+
+ LayersTraceProto entry;
+ entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
+ entry.set_where(where);
+ LayersProto layers(mFlinger.dumpDrawingStateProto(mConfig.flags));
+
+ if (flagIsSet(SurfaceTracing::TRACE_EXTRA)) {
+ mFlinger.dumpOffscreenLayersProto(layers);
+ }
+ entry.mutable_layers()->Swap(&layers);
+
+ if (flagIsSet(SurfaceTracing::TRACE_HWC)) {
+ std::string hwcDump;
+ mFlinger.dumpHwc(hwcDump);
+ entry.set_hwc_blob(hwcDump);
+ }
+ if (!flagIsSet(SurfaceTracing::TRACE_COMPOSITION)) {
+ entry.set_excludes_composition_state(true);
+ }
+ entry.set_missed_entries(mMissedTraceEntries);
+
+ return entry;
+}
+
+void SurfaceTracing::Runner::dump(std::string& result) const {
base::StringAppendF(&result, " number of entries: %zu (%.2fMB / %.2fMB)\n",
mBuffer.frameCount(), float(mBuffer.used()) / float(1_MB),
float(mBuffer.size()) / float(1_MB));
}
-} // namespace android
+SurfaceTracing::AsyncRunner::AsyncRunner(SurfaceFlinger& flinger, SurfaceTracing::Config& config,
+ std::mutex& sfLock)
+ : SurfaceTracing::Runner(flinger, config), mSfLock(sfLock) {
+ mEnabled = true;
+ mThread = std::thread(&AsyncRunner::loop, this);
+}
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+void SurfaceTracing::AsyncRunner::loop() {
+ while (mEnabled) {
+ LayersTraceProto entry;
+ bool entryAdded = traceWhenNotified(&entry);
+ if (entryAdded) {
+ mBuffer.emplace(std::move(entry));
+ }
+ if (mWriteToFile) {
+ Runner::writeToFile();
+ mWriteToFile = false;
+ }
+ }
+}
+
+bool SurfaceTracing::AsyncRunner::traceWhenNotified(LayersTraceProto* outProto) {
+ std::unique_lock<std::mutex> lock(mSfLock);
+ mCanStartTrace.wait(lock);
+ if (!mAddEntry) {
+ return false;
+ }
+ *outProto = traceLayers(mWhere);
+ mAddEntry = false;
+ mMissedTraceEntries = 0;
+ return true;
+}
+
+void SurfaceTracing::AsyncRunner::notify(const char* where) {
+ std::scoped_lock lock(mSfLock);
+ notifyLocked(where);
+}
+
+void SurfaceTracing::AsyncRunner::notifyLocked(const char* where) {
+ mWhere = where;
+ if (mAddEntry) {
+ mMissedTraceEntries++;
+ }
+ mAddEntry = true;
+ mCanStartTrace.notify_one();
+}
+
+status_t SurfaceTracing::AsyncRunner::writeToFile() {
+ mWriteToFile = true;
+ mCanStartTrace.notify_one();
+ return STATUS_OK;
+}
+
+status_t SurfaceTracing::AsyncRunner::stop() {
+ mEnabled = false;
+ mCanStartTrace.notify_one();
+ mThread.join();
+ return Runner::writeToFile();
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index f208eb8..576bba7 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -32,25 +32,31 @@
namespace android {
class SurfaceFlinger;
-
constexpr auto operator""_MB(unsigned long long const num) {
return num * 1024 * 1024;
}
/*
- * SurfaceTracing records layer states during surface flinging.
+ * SurfaceTracing records layer states during surface flinging. Manages tracing state and
+ * configuration.
*/
class SurfaceTracing {
public:
- explicit SurfaceTracing(SurfaceFlinger& flinger);
+ SurfaceTracing(SurfaceFlinger& flinger);
bool enable();
bool disable();
status_t writeToFile();
bool isEnabled() const;
+ /*
+ * Adds a trace entry, must be called from the drawing thread or while holding the
+ * SurfaceFlinger tracing lock.
+ */
void notify(const char* where);
- void notifyLocked(const char* where) NO_THREAD_SAFETY_ANALYSIS /* REQUIRES(mSfLock) */;
+ /*
+ * Adds a trace entry, called while holding the SurfaceFlinger tracing lock.
+ */
+ void notifyLocked(const char* where) /* REQUIRES(mSfLock) */;
- void setBufferSize(size_t bufferSizeInByte);
- void writeToFileAsync();
+ void setBufferSize(size_t bufferSizeInBytes) { mConfig.bufferSize = bufferSizeInBytes; }
void dump(std::string& result) const;
enum : uint32_t {
@@ -59,18 +65,34 @@
TRACE_COMPOSITION = 1 << 2,
TRACE_EXTRA = 1 << 3,
TRACE_HWC = 1 << 4,
- TRACE_ALL = 0xffffffff
+ // Add non-geometry composition changes to the trace.
+ TRACE_BUFFERS = 1 << 5,
+ // Add entries from the drawing thread post composition.
+ TRACE_SYNC = 1 << 6,
+ TRACE_ALL = TRACE_CRITICAL | TRACE_INPUT | TRACE_COMPOSITION | TRACE_EXTRA,
};
- void setTraceFlags(uint32_t flags);
- bool flagIsSetLocked(uint32_t flags) NO_THREAD_SAFETY_ANALYSIS /* REQUIRES(mSfLock) */ {
- return (mTraceFlags & flags) == flags;
- }
+ void setTraceFlags(uint32_t flags) { mConfig.flags = flags; }
+ bool flagIsSet(uint32_t flags) { return (mConfig.flags & flags) == flags; }
private:
- static constexpr auto kDefaultBufferCapInByte = 5_MB;
- static constexpr auto kDefaultFileName = "/data/misc/wmtrace/layers_trace.pb";
+ class Runner;
+ static constexpr auto DEFAULT_BUFFER_SIZE = 5_MB;
+ static constexpr auto DEFAULT_FILE_NAME = "/data/misc/wmtrace/layers_trace.pb";
- class LayersTraceBuffer { // ring buffer
+ SurfaceFlinger& mFlinger;
+ mutable std::mutex mTraceLock;
+ bool mEnabled = false;
+ std::unique_ptr<Runner> runner;
+
+ struct Config {
+ uint32_t flags = TRACE_CRITICAL | TRACE_INPUT;
+ size_t bufferSize = DEFAULT_BUFFER_SIZE;
+ } mConfig;
+
+ /*
+ * ring buffer.
+ */
+ class LayersTraceBuffer {
public:
size_t size() const { return mSizeInBytes; }
size_t used() const { return mUsedInBytes; }
@@ -83,35 +105,59 @@
private:
size_t mUsedInBytes = 0U;
- size_t mSizeInBytes = 0U;
+ size_t mSizeInBytes = DEFAULT_BUFFER_SIZE;
std::queue<LayersTraceProto> mStorage;
};
- void mainLoop();
- bool addFirstEntry();
- LayersTraceProto traceWhenNotified();
- LayersTraceProto traceLayersLocked(const char* where) REQUIRES(mSfLock);
+ /*
+ * Implements a synchronous way of adding trace entries. This must be called
+ * from the drawing thread.
+ */
+ class Runner {
+ public:
+ Runner(SurfaceFlinger& flinger, SurfaceTracing::Config& config);
+ virtual ~Runner() = default;
+ virtual status_t stop();
+ virtual status_t writeToFile();
+ virtual void notify(const char* where);
+ /* Cannot be called with a synchronous runner. */
+ virtual void notifyLocked(const char* /* where */) {}
+ void dump(std::string& result) const;
- // Returns true if trace is enabled.
- bool addTraceToBuffer(LayersTraceProto& entry);
- void writeProtoFileLocked() REQUIRES(mTraceLock);
+ protected:
+ bool flagIsSet(uint32_t flags) { return (mConfig.flags & flags) == flags; }
+ SurfaceFlinger& mFlinger;
+ SurfaceTracing::Config mConfig;
+ SurfaceTracing::LayersTraceBuffer mBuffer;
+ uint32_t mMissedTraceEntries = 0;
+ LayersTraceProto traceLayers(const char* where);
+ };
- SurfaceFlinger& mFlinger;
- status_t mLastErr = NO_ERROR;
- std::thread mThread;
- std::condition_variable mCanStartTrace;
+ /*
+ * Implements asynchronous way to add trace entries called from a separate thread while holding
+ * the SurfaceFlinger tracing lock. Trace entries may be missed if the tracing thread is not
+ * scheduled in time.
+ */
+ class AsyncRunner : public Runner {
+ public:
+ AsyncRunner(SurfaceFlinger& flinger, SurfaceTracing::Config& config, std::mutex& sfLock);
+ virtual ~AsyncRunner() = default;
+ status_t stop() override;
+ status_t writeToFile() override;
+ void notify(const char* where) override;
+ void notifyLocked(const char* where);
- std::mutex& mSfLock;
- uint32_t mTraceFlags GUARDED_BY(mSfLock) = TRACE_CRITICAL | TRACE_INPUT;
- const char* mWhere GUARDED_BY(mSfLock) = "";
- uint32_t mMissedTraceEntries GUARDED_BY(mSfLock) = 0;
- bool mTracingInProgress GUARDED_BY(mSfLock) = false;
-
- mutable std::mutex mTraceLock;
- LayersTraceBuffer mBuffer GUARDED_BY(mTraceLock);
- size_t mBufferSize GUARDED_BY(mTraceLock) = kDefaultBufferCapInByte;
- bool mEnabled GUARDED_BY(mTraceLock) = false;
- bool mWriteToFile GUARDED_BY(mTraceLock) = false;
+ private:
+ std::mutex& mSfLock;
+ std::condition_variable mCanStartTrace;
+ std::thread mThread;
+ const char* mWhere = "";
+ bool mWriteToFile = false;
+ bool mEnabled = false;
+ bool mAddEntry = false;
+ void loop();
+ bool traceWhenNotified(LayersTraceProto* outProto);
+ };
};
} // namespace android
diff --git a/services/surfaceflinger/layerproto/layerstrace.proto b/services/surfaceflinger/layerproto/layerstrace.proto
index acf621e..990f3cf 100644
--- a/services/surfaceflinger/layerproto/layerstrace.proto
+++ b/services/surfaceflinger/layerproto/layerstrace.proto
@@ -42,7 +42,7 @@
/* one window manager trace entry. */
message LayersTraceProto {
/* required: elapsed realtime in nanos since boot of when this entry was logged */
- optional fixed64 elapsed_realtime_nanos = 1;
+ optional sfixed64 elapsed_realtime_nanos = 1;
/* where the trace originated */
optional string where = 2;
@@ -56,5 +56,5 @@
optional bool excludes_composition_state = 5;
/* Number of missed entries since the last entry was recorded. */
- optional int32 missed_entries = 6;
+ optional uint32 missed_entries = 6;
}
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index 7f541e2..9302463 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -218,18 +218,21 @@
TEST_F(CredentialsTest, SetDesiredDisplayConfigsTest) {
const auto display = SurfaceComposerClient::getInternalDisplayToken();
int32_t defaultConfig;
+ bool allowGroupSwitching;
float primaryFpsMin;
float primaryFpsMax;
float appRequestFpsMin;
float appRequestFpsMax;
status_t res =
SurfaceComposerClient::getDesiredDisplayConfigSpecs(display, &defaultConfig,
+ &allowGroupSwitching,
&primaryFpsMin, &primaryFpsMax,
&appRequestFpsMin,
&appRequestFpsMax);
ASSERT_EQ(res, NO_ERROR);
std::function<status_t()> condition = [=]() {
return SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, defaultConfig,
+ allowGroupSwitching,
primaryFpsMin, primaryFpsMax,
appRequestFpsMin,
appRequestFpsMax);
diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
index debfe83..3a8b40f 100644
--- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp
+++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
@@ -14,16 +14,18 @@
* 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 <gtest/gtest.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <private/gui/ComposerService.h>
+#include <ui/DisplayConfig.h>
+#include <utils/Errors.h>
+#include <utils/Vector.h>
-#include <thread>
-#include "LayerTransactionTest.h"
+#include "utils/TransactionUtils.h"
+
namespace android {
-using android::hardware::graphics::common::V1_1::BufferUsage;
-
::testing::Environment* const binderEnv =
::testing::AddGlobalTestEnvironment(new BinderEnvironment());
@@ -31,32 +33,54 @@
* Test class for setting display configs and passing around refresh rate ranges.
*/
class RefreshRateRangeTest : public ::testing::Test {
+private:
+ int32_t initialDefaultConfig;
+ bool initialAllowGroupSwitching;
+ float initialPrimaryMin;
+ float initialPrimaryMax;
+ float initialAppRequestMin;
+ float initialAppRequestMax;
+
protected:
- void SetUp() override { mDisplayToken = SurfaceComposerClient::getInternalDisplayToken(); }
+ void SetUp() override {
+ mDisplayToken = SurfaceComposerClient::getInternalDisplayToken();
+ status_t res =
+ SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken,
+ &initialDefaultConfig,
+ &initialAllowGroupSwitching,
+ &initialPrimaryMin,
+ &initialPrimaryMax,
+ &initialAppRequestMin,
+ &initialAppRequestMax);
+ ASSERT_EQ(res, NO_ERROR);
+ }
+
+ void TearDown() override {
+ status_t res =
+ SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken,
+ initialDefaultConfig,
+ initialAllowGroupSwitching,
+ initialPrimaryMin,
+ initialPrimaryMax,
+ initialAppRequestMin,
+ initialAppRequestMax);
+ ASSERT_EQ(res, NO_ERROR);
+ }
+
+ void testSetAllowGroupSwitching(bool allowGroupSwitching);
sp<IBinder> mDisplayToken;
};
TEST_F(RefreshRateRangeTest, setAllConfigs) {
- int32_t initialDefaultConfig;
- float initialPrimaryMin;
- float initialPrimaryMax;
- float initialAppRequestMin;
- float initialAppRequestMax;
- status_t res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken,
- &initialDefaultConfig,
- &initialPrimaryMin,
- &initialPrimaryMax,
- &initialAppRequestMin,
- &initialAppRequestMax);
- ASSERT_EQ(res, NO_ERROR);
-
Vector<DisplayConfig> configs;
- res = SurfaceComposerClient::getDisplayConfigs(mDisplayToken, &configs);
+ status_t res = SurfaceComposerClient::getDisplayConfigs(mDisplayToken, &configs);
ASSERT_EQ(res, NO_ERROR);
+ ASSERT_GT(configs.size(), 0);
for (size_t i = 0; i < configs.size(); i++) {
- res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, i,
+ res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken,
+ static_cast<int32_t>(i), false,
configs[i].refreshRate,
configs[i].refreshRate,
configs[i].refreshRate,
@@ -64,31 +88,58 @@
ASSERT_EQ(res, NO_ERROR);
int defaultConfig;
+ bool allowGroupSwitching;
float primaryRefreshRateMin;
float primaryRefreshRateMax;
float appRequestRefreshRateMin;
float appRequestRefreshRateMax;
res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfig,
+ &allowGroupSwitching,
&primaryRefreshRateMin,
&primaryRefreshRateMax,
&appRequestRefreshRateMin,
&appRequestRefreshRateMax);
ASSERT_EQ(res, NO_ERROR);
ASSERT_EQ(defaultConfig, i);
+ ASSERT_EQ(allowGroupSwitching, false);
ASSERT_EQ(primaryRefreshRateMin, configs[i].refreshRate);
ASSERT_EQ(primaryRefreshRateMax, configs[i].refreshRate);
ASSERT_EQ(appRequestRefreshRateMin, configs[i].refreshRate);
ASSERT_EQ(appRequestRefreshRateMax, configs[i].refreshRate);
}
+}
- res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, initialDefaultConfig,
- initialPrimaryMin, initialPrimaryMax,
- initialAppRequestMin,
- initialAppRequestMax);
+void RefreshRateRangeTest::testSetAllowGroupSwitching(bool allowGroupSwitching) {
+ status_t res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, 0,
+ allowGroupSwitching, 0.f,
+ 90.f, 0.f, 90.f);
ASSERT_EQ(res, NO_ERROR);
+ int defaultConfig;
+ bool newAllowGroupSwitching;
+ float primaryRefreshRateMin;
+ float primaryRefreshRateMax;
+ float appRequestRefreshRateMin;
+ float appRequestRefreshRateMax;
+
+ res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfig,
+ &newAllowGroupSwitching,
+ &primaryRefreshRateMin,
+ &primaryRefreshRateMax,
+ &appRequestRefreshRateMin,
+ &appRequestRefreshRateMax);
+ ASSERT_EQ(res, NO_ERROR);
+ ASSERT_EQ(defaultConfig, 0);
+ ASSERT_EQ(newAllowGroupSwitching, allowGroupSwitching);
+ ASSERT_EQ(primaryRefreshRateMin, 0.f);
+ ASSERT_EQ(primaryRefreshRateMax, 90.f);
+ ASSERT_EQ(appRequestRefreshRateMin, 0.f);
+ ASSERT_EQ(appRequestRefreshRateMax, 90.f);
+}
+
+TEST_F(RefreshRateRangeTest, setAllowGroupSwitching) {
+ testSetAllowGroupSwitching(true);
+ testSetAllowGroupSwitching(false);
+ testSetAllowGroupSwitching(true);
}
} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h
index 25d3211..da71dad 100644
--- a/services/surfaceflinger/tests/LayerTransactionTest.h
+++ b/services/surfaceflinger/tests/LayerTransactionTest.h
@@ -16,6 +16,10 @@
#pragma once
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <gtest/gtest.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
@@ -300,3 +304,6 @@
};
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 6c654c0..0a70f5c 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -447,7 +447,7 @@
const auto& config = configs[i];
if (config.resolution.getWidth() == 800) {
EXPECT_EQ(NO_ERROR,
- SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+ SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i, false,
config.refreshRate,
config.refreshRate,
config.refreshRate,
@@ -553,7 +553,7 @@
const auto& config = configs[i];
if (config.refreshRate == 1e9f / 11'111'111) {
EXPECT_EQ(NO_ERROR,
- SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+ SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i, false,
config.refreshRate,
config.refreshRate,
config.refreshRate,
@@ -670,7 +670,8 @@
if (config.resolution.getWidth() == 800 && config.refreshRate == 1e9f / 11'111'111) {
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::
- setDesiredDisplayConfigSpecs(display, i, configs[i].refreshRate,
+ setDesiredDisplayConfigSpecs(display, i, false,
+ configs[i].refreshRate,
configs[i].refreshRate,
configs[i].refreshRate,
configs[i].refreshRate));
@@ -716,7 +717,7 @@
const auto& config = configs[i];
if (config.refreshRate == 1e9f / 8'333'333) {
EXPECT_EQ(NO_ERROR,
- SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+ SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i, false,
config.refreshRate,
config.refreshRate,
config.refreshRate,
@@ -763,7 +764,7 @@
const auto& config = configs[i];
if (config.resolution.getWidth() == 1600 && config.refreshRate == 1e9f / 11'111'111) {
EXPECT_EQ(NO_ERROR,
- SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+ SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i, false,
config.refreshRate,
config.refreshRate,
config.refreshRate,
diff --git a/services/surfaceflinger/tests/utils/TransactionUtils.h b/services/surfaceflinger/tests/utils/TransactionUtils.h
index 8e1f943..5c5b18e 100644
--- a/services/surfaceflinger/tests/utils/TransactionUtils.h
+++ b/services/surfaceflinger/tests/utils/TransactionUtils.h
@@ -16,6 +16,9 @@
#pragma once
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <chrono>
#include <android/native_window.h>
@@ -181,3 +184,6 @@
};
} // namespace
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file