Merge "Revert "Respect LayerSettings::alpha in Skia-RE for buffer layers""
diff --git a/include/android/input.h b/include/android/input.h
index b04775b..38af89a 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -163,6 +163,9 @@
/** Focus event */
AINPUT_EVENT_TYPE_FOCUS = 3,
+
+ /** Capture event */
+ AINPUT_EVENT_TYPE_CAPTURE = 4,
};
/**
diff --git a/include/ftl/ArrayTraits.h b/include/ftl/ArrayTraits.h
index 28f717a..ff685c5 100644
--- a/include/ftl/ArrayTraits.h
+++ b/include/ftl/ArrayTraits.h
@@ -19,6 +19,7 @@
#include <algorithm>
#include <iterator>
#include <new>
+#include <type_traits>
#define FTL_ARRAY_TRAIT(T, U) using U = typename ArrayTraits<T>::U
@@ -40,11 +41,16 @@
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)...};
+ if constexpr (std::is_constructible_v<value_type, Args...>) {
+ // TODO: Replace with std::construct_at in C++20.
+ return new (ptr) value_type(std::forward<Args>(args)...);
+ } else {
+ // Fall back to list initialization.
+ return new (ptr) value_type{std::forward<Args>(args)...};
+ }
}
};
diff --git a/include/ftl/InitializerList.h b/include/ftl/InitializerList.h
new file mode 100644
index 0000000..bb99280
--- /dev/null
+++ b/include/ftl/InitializerList.h
@@ -0,0 +1,110 @@
+/*
+ * 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 <tuple>
+#include <utility>
+
+namespace android::ftl {
+
+// Compile-time counterpart of std::initializer_list<T> that stores per-element constructor
+// arguments with heterogeneous types. For a container with elements of type T, given Sizes
+// (S0, S1, ..., SN), N elements are initialized: the first element is initialized with the
+// first S0 arguments, the second element is initialized with the next S1 arguments, and so
+// on. The list of Types (T0, ..., TM) is flattened, so M is equal to the sum of the Sizes.
+//
+// The InitializerList is created using ftl::init::list, and is consumed by constructors of
+// containers. The function call operator is overloaded such that arguments are accumulated
+// in a tuple with each successive call. For instance, the following calls initialize three
+// strings using different constructors, i.e. string literal, default, and count/character:
+//
+// ... = ftl::init::list<std::string>("abc")()(3u, '?');
+//
+// The following syntax is a shorthand for key-value pairs, where the first argument is the
+// key, and the rest construct the value. The types of the key and value are deduced if the
+// first pair contains exactly two arguments:
+//
+// ... = ftl::init::map<int, std::string>(-1, "abc")(-2)(-3, 3u, '?');
+//
+// ... = ftl::init::map(0, 'a')(1, 'b')(2, 'c');
+//
+// WARNING: The InitializerList returned by an ftl::init::list expression must be consumed
+// immediately, since temporary arguments are destroyed after the full expression. Storing
+// an InitializerList results in dangling references.
+//
+template <typename T, typename Sizes = std::index_sequence<>, typename... Types>
+struct InitializerList;
+
+template <typename T, size_t... Sizes, typename... Types>
+struct InitializerList<T, std::index_sequence<Sizes...>, Types...> {
+ // Creates a superset InitializerList by appending the number of arguments to Sizes, and
+ // expanding Types with forwarding references for each argument.
+ template <typename... Args>
+ [[nodiscard]] constexpr auto operator()(Args&&... args) && -> InitializerList<
+ T, std::index_sequence<Sizes..., sizeof...(Args)>, Types..., Args&&...> {
+ return {std::tuple_cat(std::move(tuple),
+ std::forward_as_tuple(std::forward<Args>(args)...))};
+ }
+
+ // The temporary InitializerList returned by operator() is bound to an rvalue reference in
+ // container constructors, which extends the lifetime of any temporary arguments that this
+ // tuple refers to until the completion of the full expression containing the construction.
+ std::tuple<Types...> tuple;
+};
+
+template <typename K, typename V>
+struct KeyValue {};
+
+// Shorthand for key-value pairs that assigns the first argument to the key, and the rest to the
+// value. The specialization is on KeyValue rather than std::pair, so that ftl::init::list works
+// with the latter.
+template <typename K, typename V, size_t... Sizes, typename... Types>
+struct InitializerList<KeyValue<K, V>, std::index_sequence<Sizes...>, Types...> {
+ // Accumulate the three arguments to std::pair's piecewise constructor.
+ template <typename... Args>
+ [[nodiscard]] constexpr auto operator()(K&& k, Args&&... args) && -> InitializerList<
+ KeyValue<K, V>, std::index_sequence<Sizes..., 3>, Types..., std::piecewise_construct_t,
+ std::tuple<K&&>, std::tuple<Args&&...>> {
+ return {std::tuple_cat(std::move(tuple),
+ std::forward_as_tuple(std::piecewise_construct,
+ std::forward_as_tuple(std::forward<K>(k)),
+ std::forward_as_tuple(
+ std::forward<Args>(args)...)))};
+ }
+
+ std::tuple<Types...> tuple;
+};
+
+namespace init {
+
+template <typename T, typename... Args>
+[[nodiscard]] constexpr auto list(Args&&... args) {
+ return InitializerList<T>{}(std::forward<Args>(args)...);
+}
+
+template <typename K, typename V, typename... Args>
+[[nodiscard]] constexpr auto map(Args&&... args) {
+ return list<KeyValue<K, V>>(std::forward<Args>(args)...);
+}
+
+template <typename K, typename V>
+[[nodiscard]] constexpr auto map(K&& k, V&& v) {
+ return list<KeyValue<K, V>>(std::forward<K>(k), std::forward<V>(v));
+}
+
+} // namespace init
+} // namespace android::ftl
diff --git a/include/ftl/SmallMap.h b/include/ftl/SmallMap.h
new file mode 100644
index 0000000..87ae99c
--- /dev/null
+++ b/include/ftl/SmallMap.h
@@ -0,0 +1,205 @@
+/*
+ * 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/InitializerList.h>
+#include <ftl/SmallVector.h>
+
+#include <functional>
+#include <optional>
+#include <type_traits>
+#include <utility>
+
+namespace android::ftl {
+
+// Associative container with unique, unordered keys. Unlike std::unordered_map, key-value pairs are
+// stored in contiguous storage for cache efficiency. The map is allocated statically until its size
+// exceeds N, at which point mappings are relocated to dynamic memory.
+//
+// SmallMap<K, V, 0> unconditionally allocates on the heap.
+//
+// Example usage:
+//
+// ftl::SmallMap<int, std::string, 3> map;
+// assert(map.empty());
+// assert(!map.dynamic());
+//
+// map = ftl::init::map<int, std::string>(123, "abc")(-1)(42, 3u, '?');
+// assert(map.size() == 3u);
+// assert(!map.dynamic());
+//
+// assert(map.contains(123));
+// assert(map.find(42, [](const std::string& s) { return s.size(); }) == 3u);
+//
+// const auto opt = map.find(-1);
+// assert(opt);
+//
+// std::string& ref = *opt;
+// assert(ref.empty());
+// ref = "xyz";
+//
+// assert(map == SmallMap(ftl::init::map(-1, "xyz")(42, "???")(123, "abc")));
+//
+template <typename K, typename V, size_t N>
+class SmallMap final {
+ using Map = SmallVector<std::pair<const K, V>, N>;
+
+public:
+ using key_type = K;
+ using mapped_type = V;
+
+ using value_type = typename Map::value_type;
+ using size_type = typename Map::size_type;
+ using difference_type = typename Map::difference_type;
+
+ using reference = typename Map::reference;
+ using iterator = typename Map::iterator;
+
+ using const_reference = typename Map::const_reference;
+ using const_iterator = typename Map::const_iterator;
+
+ // Creates an empty map.
+ SmallMap() = default;
+
+ // Constructs at most N key-value pairs in place by forwarding per-pair constructor arguments.
+ // The template arguments K, V, and N are inferred using the deduction guide defined below.
+ // The syntax for listing pairs is as follows:
+ //
+ // ftl::SmallMap map = ftl::init::map<int, std::string>(123, "abc")(-1)(42, 3u, '?');
+ //
+ // static_assert(std::is_same_v<decltype(map), ftl::SmallMap<int, std::string, 3>>);
+ // assert(map.size() == 3u);
+ // assert(map.contains(-1) && map.find(-1)->get().empty());
+ // assert(map.contains(42) && map.find(42)->get() == "???");
+ // assert(map.contains(123) && map.find(123)->get() == "abc");
+ //
+ // The types of the key and value are deduced if the first pair contains exactly two arguments:
+ //
+ // ftl::SmallMap map = ftl::init::map(0, 'a')(1, 'b')(2, 'c');
+ // static_assert(std::is_same_v<decltype(map), ftl::SmallMap<int, char, 3>>);
+ //
+ template <typename U, size_t... Sizes, typename... Types>
+ SmallMap(InitializerList<U, std::index_sequence<Sizes...>, Types...>&& init)
+ : mMap(std::move(init)) {
+ // TODO: Enforce unique keys.
+ }
+
+ size_type max_size() const { return mMap.max_size(); }
+ size_type size() const { return mMap.size(); }
+ bool empty() const { return mMap.empty(); }
+
+ // Returns whether the map is backed by static or dynamic storage.
+ bool dynamic() const { return mMap.dynamic(); }
+
+ iterator begin() { return mMap.begin(); }
+ const_iterator begin() const { return cbegin(); }
+ const_iterator cbegin() const { return mMap.cbegin(); }
+
+ iterator end() { return mMap.end(); }
+ const_iterator end() const { return cend(); }
+ const_iterator cend() const { return mMap.cend(); }
+
+ // Returns whether a mapping exists for the given key.
+ bool contains(const key_type& key) const {
+ return find(key, [](const mapped_type&) {});
+ }
+
+ // Returns a reference to the value for the given key, or std::nullopt if the key was not found.
+ //
+ // ftl::SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C');
+ //
+ // const auto opt = map.find('c');
+ // assert(opt == 'C');
+ //
+ // char d = 'd';
+ // const auto ref = map.find('d').value_or(std::ref(d));
+ // ref.get() = 'D';
+ // assert(d == 'D');
+ //
+ auto find(const key_type& key) const
+ -> std::optional<std::reference_wrapper<const mapped_type>> {
+ return find(key, [](const mapped_type& v) { return std::cref(v); });
+ }
+
+ auto find(const key_type& key) -> std::optional<std::reference_wrapper<mapped_type>> {
+ return find(key, [](mapped_type& v) { return std::ref(v); });
+ }
+
+ // Returns the result R of a unary operation F on (a constant or mutable reference to) the value
+ // for the given key, or std::nullopt if the key was not found. If F has a return type of void,
+ // then the Boolean result indicates whether the key was found.
+ //
+ // ftl::SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z');
+ //
+ // assert(map.find('c', [](char c) { return std::toupper(c); }) == 'Z');
+ // assert(map.find('c', [](char& c) { c = std::toupper(c); }));
+ //
+ template <typename F, typename R = std::invoke_result_t<F, const mapped_type&>>
+ auto find(const key_type& key, F f) const
+ -> std::conditional_t<std::is_void_v<R>, bool, std::optional<R>> {
+ for (auto& [k, v] : *this) {
+ if (k == key) {
+ if constexpr (std::is_void_v<R>) {
+ f(v);
+ return true;
+ } else {
+ return f(v);
+ }
+ }
+ }
+
+ return {};
+ }
+
+ template <typename F>
+ auto find(const key_type& key, F f) {
+ return std::as_const(*this).find(key, [&f](const mapped_type& v) {
+ return f(const_cast<mapped_type&>(v));
+ });
+ }
+
+private:
+ Map mMap;
+};
+
+// Deduction guide for in-place constructor.
+template <typename K, typename V, size_t... Sizes, typename... Types>
+SmallMap(InitializerList<KeyValue<K, V>, std::index_sequence<Sizes...>, Types...>&&)
+ -> SmallMap<K, V, sizeof...(Sizes)>;
+
+// Returns whether the key-value pairs of two maps are equal.
+template <typename K, typename V, size_t N, typename Q, typename W, size_t M>
+bool operator==(const SmallMap<K, V, N>& lhs, const SmallMap<Q, W, M>& rhs) {
+ if (lhs.size() != rhs.size()) return false;
+
+ for (const auto& [k, v] : lhs) {
+ const auto& lv = v;
+ if (!rhs.find(k, [&lv](const auto& rv) { return lv == rv; }).value_or(false)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// TODO: Remove in C++20.
+template <typename K, typename V, size_t N, typename Q, typename W, size_t M>
+inline bool operator!=(const SmallMap<K, V, N>& lhs, const SmallMap<Q, W, M>& rhs) {
+ return !(lhs == rhs);
+}
+
+} // namespace android::ftl
diff --git a/include/ftl/SmallVector.h b/include/ftl/SmallVector.h
index cecec7f..2f05a9b 100644
--- a/include/ftl/SmallVector.h
+++ b/include/ftl/SmallVector.h
@@ -64,6 +64,16 @@
// assert(vector == (ftl::SmallVector{'h', 'i', '\0'}));
// assert(!vector.dynamic());
//
+// ftl::SmallVector strings = ftl::init::list<std::string>("abc")
+// ("123456", 3u)
+// (3u, '?');
+// assert(strings.size() == 3u);
+// assert(!strings.dynamic());
+//
+// assert(strings[0] == "abc");
+// assert(strings[1] == "123");
+// assert(strings[2] == "???");
+//
template <typename T, size_t N>
class SmallVector final : ArrayTraits<T>, ArrayComparators<SmallVector> {
using Static = StaticVector<T, N>;
@@ -365,8 +375,9 @@
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)>;
+template <typename T, size_t... Sizes, typename... Types>
+SmallVector(InitializerList<T, std::index_sequence<Sizes...>, Types...>&&)
+ -> SmallVector<T, sizeof...(Sizes)>;
// Deduction guide for StaticVector conversion.
template <typename T, size_t N>
diff --git a/include/ftl/StaticVector.h b/include/ftl/StaticVector.h
index 457095d..c132556 100644
--- a/include/ftl/StaticVector.h
+++ b/include/ftl/StaticVector.h
@@ -17,6 +17,7 @@
#pragma once
#include <ftl/ArrayTraits.h>
+#include <ftl/InitializerList.h>
#include <algorithm>
#include <cassert>
@@ -32,7 +33,7 @@
// 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
+// default constructor, since elements are constructed in place as the vector grows. Operations that
// 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.
@@ -63,6 +64,14 @@
// vector = ftl::StaticVector(array);
// assert(vector == (ftl::StaticVector{'h', 'i', '\0'}));
//
+// ftl::StaticVector strings = ftl::init::list<std::string>("abc")
+// ("123456", 3u)
+// (3u, '?');
+// assert(strings.size() == 3u);
+// assert(strings[0] == "abc");
+// assert(strings[1] == "123");
+// assert(strings[2] == "???");
+//
template <typename T, size_t N>
class StaticVector final : ArrayTraits<T>,
ArrayIterators<StaticVector<T, N>, T>,
@@ -153,15 +162,22 @@
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:
+ // Constructs at most N elements in place by forwarding per-element constructor arguments. The
+ // template arguments T and N are inferred using the deduction guide defined below. The syntax
+ // for listing arguments is as follows:
//
- // ftl::StaticVector vector(std::in_place_type<std::string>, "red", "velvet", "cake");
+ // ftl::StaticVector vector = ftl::init::list<std::string>("abc")()(3u, '?');
+ //
// static_assert(std::is_same_v<decltype(vector), ftl::StaticVector<std::string, 3>>);
+ // assert(vector.full());
+ // assert(vector[0] == "abc");
+ // assert(vector[1].empty());
+ // assert(vector[2] == "???");
//
- template <typename... Es>
- explicit StaticVector(std::in_place_type_t<T>, Es... elements)
- : StaticVector(std::forward<Es>(elements)...) {}
+ template <typename U, size_t Size, size_t... Sizes, typename... Types>
+ StaticVector(InitializerList<U, std::index_sequence<Size, Sizes...>, Types...>&& init)
+ : StaticVector(std::index_sequence<0, 0, Size>{}, std::make_index_sequence<Size>{},
+ std::index_sequence<Sizes...>{}, init.tuple) {}
~StaticVector() { std::destroy(begin(), end()); }
@@ -292,6 +308,32 @@
template <size_t I>
explicit StaticVector(std::index_sequence<I>) : mSize(I) {}
+ // Recursion for in-place constructor.
+ //
+ // Construct element I by extracting its arguments from the InitializerList tuple. ArgIndex
+ // is the position of its first argument in Args, and ArgCount is the number of arguments.
+ // The Indices sequence corresponds to [0, ArgCount).
+ //
+ // The Sizes sequence lists the argument counts for elements after I, so Size is the ArgCount
+ // for the next element. The recursion stops when Sizes is empty for the last element.
+ //
+ template <size_t I, size_t ArgIndex, size_t ArgCount, size_t... Indices, size_t Size,
+ size_t... Sizes, typename... Args>
+ StaticVector(std::index_sequence<I, ArgIndex, ArgCount>, std::index_sequence<Indices...>,
+ std::index_sequence<Size, Sizes...>, std::tuple<Args...>& tuple)
+ : StaticVector(std::index_sequence<I + 1, ArgIndex + ArgCount, Size>{},
+ std::make_index_sequence<Size>{}, std::index_sequence<Sizes...>{}, tuple) {
+ construct_at(begin() + I, std::move(std::get<ArgIndex + Indices>(tuple))...);
+ }
+
+ // Base case for in-place constructor.
+ template <size_t I, size_t ArgIndex, size_t ArgCount, size_t... Indices, typename... Args>
+ StaticVector(std::index_sequence<I, ArgIndex, ArgCount>, std::index_sequence<Indices...>,
+ std::index_sequence<>, std::tuple<Args...>& tuple)
+ : mSize(I + 1) {
+ construct_at(begin() + I, std::move(std::get<ArgIndex + Indices>(tuple))...);
+ }
+
size_type mSize = 0;
std::aligned_storage_t<sizeof(value_type), alignof(value_type)> mData[N];
};
@@ -306,8 +348,9 @@
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... Sizes, typename... Types>
+StaticVector(InitializerList<T, std::index_sequence<Sizes...>, Types...>&&)
+ -> StaticVector<T, sizeof...(Sizes)>;
template <typename T, size_t N>
template <typename E>
diff --git a/include/input/Input.h b/include/input/Input.h
index 3facfa5..aa42db8 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -773,6 +773,25 @@
bool mInTouchMode;
};
+/*
+ * Capture events.
+ */
+class CaptureEvent : public InputEvent {
+public:
+ virtual ~CaptureEvent() {}
+
+ virtual int32_t getType() const override { return AINPUT_EVENT_TYPE_CAPTURE; }
+
+ inline bool getPointerCaptureEnabled() const { return mPointerCaptureEnabled; }
+
+ void initialize(int32_t id, bool pointerCaptureEnabled);
+
+ void initialize(const CaptureEvent& from);
+
+protected:
+ bool mPointerCaptureEnabled;
+};
+
/**
* Base class for verified events.
* Do not create a VerifiedInputEvent explicitly.
@@ -835,6 +854,7 @@
virtual KeyEvent* createKeyEvent() = 0;
virtual MotionEvent* createMotionEvent() = 0;
virtual FocusEvent* createFocusEvent() = 0;
+ virtual CaptureEvent* createCaptureEvent() = 0;
};
/*
@@ -849,11 +869,13 @@
virtual KeyEvent* createKeyEvent() override { return &mKeyEvent; }
virtual MotionEvent* createMotionEvent() override { return &mMotionEvent; }
virtual FocusEvent* createFocusEvent() override { return &mFocusEvent; }
+ virtual CaptureEvent* createCaptureEvent() override { return &mCaptureEvent; }
private:
KeyEvent mKeyEvent;
MotionEvent mMotionEvent;
FocusEvent mFocusEvent;
+ CaptureEvent mCaptureEvent;
};
/*
@@ -867,6 +889,7 @@
virtual KeyEvent* createKeyEvent() override;
virtual MotionEvent* createMotionEvent() override;
virtual FocusEvent* createFocusEvent() override;
+ virtual CaptureEvent* createCaptureEvent() override;
void recycle(InputEvent* event);
@@ -876,6 +899,7 @@
std::queue<std::unique_ptr<KeyEvent>> mKeyEventPool;
std::queue<std::unique_ptr<MotionEvent>> mMotionEventPool;
std::queue<std::unique_ptr<FocusEvent>> mFocusEventPool;
+ std::queue<std::unique_ptr<CaptureEvent>> mCaptureEventPool;
};
} // namespace android
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index ad0a14e..8744ef7 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -67,6 +67,7 @@
MOTION,
FINISHED,
FOCUS,
+ CAPTURE,
};
struct Header {
@@ -166,6 +167,13 @@
inline size_t size() const { return sizeof(Focus); }
} focus;
+
+ struct Capture {
+ int32_t eventId;
+ uint32_t pointerCaptureEnabled; // actually a bool, but we maintain 8-byte alignment
+
+ inline size_t size() const { return sizeof(Capture); }
+ } capture;
} __attribute__((aligned(8))) body;
bool isValid(size_t actualSize) const;
@@ -182,6 +190,8 @@
return "FINISHED";
case Type::FOCUS:
return "FOCUS";
+ case Type::CAPTURE:
+ return "CAPTURE";
}
}
};
@@ -341,6 +351,15 @@
*/
status_t publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus, bool inTouchMode);
+ /* Publishes a capture event to the input channel.
+ *
+ * Returns OK on success.
+ * Returns WOULD_BLOCK if the channel is full.
+ * Returns DEAD_OBJECT if the channel's peer has been closed.
+ * Other errors probably indicate that the channel is broken.
+ */
+ status_t publishCaptureEvent(uint32_t seq, int32_t eventId, bool pointerCaptureEnabled);
+
/* Receives the finished signal from the consumer in reply to the original dispatch signal.
* If a signal was received, returns the message sequence number,
* and whether the consumer handled the message.
@@ -576,6 +595,7 @@
static void initializeKeyEvent(KeyEvent* event, const InputMessage* msg);
static void initializeMotionEvent(MotionEvent* event, const InputMessage* msg);
static void initializeFocusEvent(FocusEvent* event, const InputMessage* msg);
+ static void initializeCaptureEvent(CaptureEvent* event, const InputMessage* msg);
static void addSample(MotionEvent* event, const InputMessage* msg);
static bool canAddSample(const Batch& batch, const InputMessage* msg);
static ssize_t findSampleNoLaterThan(const Batch& batch, nsecs_t time);
diff --git a/libs/binder/ActivityManager.cpp b/libs/binder/ActivityManager.cpp
index 727ea60..e45a656 100644
--- a/libs/binder/ActivityManager.cpp
+++ b/libs/binder/ActivityManager.cpp
@@ -62,23 +62,27 @@
return service != nullptr ? service->openContentUri(stringUri) : -1;
}
-void ActivityManager::registerUidObserver(const sp<IUidObserver>& observer,
+status_t ActivityManager::registerUidObserver(const sp<IUidObserver>& observer,
const int32_t event,
const int32_t cutpoint,
const String16& callingPackage)
{
sp<IActivityManager> service = getService();
if (service != nullptr) {
- service->registerUidObserver(observer, event, cutpoint, callingPackage);
+ return service->registerUidObserver(observer, event, cutpoint, callingPackage);
}
+ // ActivityManagerService appears dead. Return usual error code for dead service.
+ return DEAD_OBJECT;
}
-void ActivityManager::unregisterUidObserver(const sp<IUidObserver>& observer)
+status_t ActivityManager::unregisterUidObserver(const sp<IUidObserver>& observer)
{
sp<IActivityManager> service = getService();
if (service != nullptr) {
- service->unregisterUidObserver(observer);
+ return service->unregisterUidObserver(observer);
}
+ // ActivityManagerService appears dead. Return usual error code for dead service.
+ return DEAD_OBJECT;
}
bool ActivityManager::isUidActive(const uid_t uid, const String16& callingPackage)
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 8264154..bf4387a 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -137,8 +137,8 @@
}
BpBinder::BpBinder(int32_t handle, int32_t trackedUid)
- : mHandle(handle)
- , mStability(0)
+ : mStability(0)
+ , mHandle(handle)
, mAlive(1)
, mObitsSent(0)
, mObituaries(nullptr)
diff --git a/libs/binder/Debug.cpp b/libs/binder/Debug.cpp
index da342ff..3a62059 100644
--- a/libs/binder/Debug.cpp
+++ b/libs/binder/Debug.cpp
@@ -208,7 +208,7 @@
}
for (offset = 0; ; offset += bytesPerLine, pos += bytesPerLine) {
- size_t remain = length;
+ ssize_t remain = length;
char* c = buffer;
if (!oneLine && !cStyle) {
diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp
index e9f5aae..cf9bb46 100644
--- a/libs/binder/IActivityManager.cpp
+++ b/libs/binder/IActivityManager.cpp
@@ -59,7 +59,7 @@
return fd;
}
- virtual void registerUidObserver(const sp<IUidObserver>& observer,
+ virtual status_t registerUidObserver(const sp<IUidObserver>& observer,
const int32_t event,
const int32_t cutpoint,
const String16& callingPackage)
@@ -70,15 +70,23 @@
data.writeInt32(event);
data.writeInt32(cutpoint);
data.writeString16(callingPackage);
- remote()->transact(REGISTER_UID_OBSERVER_TRANSACTION, data, &reply);
+ status_t err = remote()->transact(REGISTER_UID_OBSERVER_TRANSACTION, data, &reply);
+ if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) {
+ return err;
+ }
+ return OK;
}
- virtual void unregisterUidObserver(const sp<IUidObserver>& observer)
+ virtual status_t unregisterUidObserver(const sp<IUidObserver>& observer)
{
Parcel data, reply;
data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor());
data.writeStrongBinder(IInterface::asBinder(observer));
- remote()->transact(UNREGISTER_UID_OBSERVER_TRANSACTION, data, &reply);
+ status_t err = remote()->transact(UNREGISTER_UID_OBSERVER_TRANSACTION, data, &reply);
+ if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) {
+ return err;
+ }
+ return OK;
}
virtual bool isUidActive(const uid_t uid, const String16& callingPackage)
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 61a611d..dafc879 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -50,6 +50,14 @@
"exclude-filter": "android.os.cts.StrictModeTest#testNonSdkApiUsage"
}
]
+ },
+ {
+ "name": "libbinder_rs-internal_test"
+ }
+ ],
+ "postsubmit": [
+ {
+ "name": "rustBinderTest"
}
]
}
diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h
index 0240858..830971b 100644
--- a/libs/binder/include/binder/ActivityManager.h
+++ b/libs/binder/include/binder/ActivityManager.h
@@ -74,11 +74,11 @@
ActivityManager();
int openContentUri(const String16& stringUri);
- void registerUidObserver(const sp<IUidObserver>& observer,
+ status_t registerUidObserver(const sp<IUidObserver>& observer,
const int32_t event,
const int32_t cutpoint,
const String16& callingPackage);
- void unregisterUidObserver(const sp<IUidObserver>& observer);
+ status_t unregisterUidObserver(const sp<IUidObserver>& observer);
bool isUidActive(const uid_t uid, const String16& callingPackage);
int getUidProcessState(const uid_t uid, const String16& callingPackage);
status_t checkPermission(const String16& permission, const pid_t pid, const uid_t uid, int32_t* outResult);
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index 64d0657..a0e28d2 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -109,19 +109,18 @@
KeyedVector<const void*, entry_t> mObjects;
};
-protected:
+private:
BpBinder(int32_t handle,int32_t trackedUid);
virtual ~BpBinder();
virtual void onFirstRef();
virtual void onLastStrongRef(const void* id);
virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
-private:
- const int32_t mHandle;
-
friend ::android::internal::Stability;
int32_t mStability;
+ const int32_t mHandle;
+
struct Obituary {
wp<DeathRecipient> recipient;
void* cookie;
diff --git a/libs/binder/include/binder/IActivityManager.h b/libs/binder/include/binder/IActivityManager.h
index e2081ff..2d58c46 100644
--- a/libs/binder/include/binder/IActivityManager.h
+++ b/libs/binder/include/binder/IActivityManager.h
@@ -31,11 +31,11 @@
DECLARE_META_INTERFACE(ActivityManager)
virtual int openContentUri(const String16& stringUri) = 0;
- virtual void registerUidObserver(const sp<IUidObserver>& observer,
+ virtual status_t registerUidObserver(const sp<IUidObserver>& observer,
const int32_t event,
const int32_t cutpoint,
const String16& callingPackage) = 0;
- virtual void unregisterUidObserver(const sp<IUidObserver>& observer) = 0;
+ virtual status_t unregisterUidObserver(const sp<IUidObserver>& observer) = 0;
virtual bool isUidActive(const uid_t uid, const String16& callingPackage) = 0;
virtual int32_t getUidProcessState(const uid_t uid, const String16& callingPackage) = 0;
virtual status_t checkPermission(const String16& permission,
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index ece25a0..4b2d50d 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -210,6 +210,8 @@
template<typename T>
status_t writeParcelableVector(const std::shared_ptr<std::vector<std::unique_ptr<T>>>& val);
template<typename T>
+ status_t writeParcelableVector(const std::shared_ptr<std::vector<std::optional<T>>>& val);
+ template<typename T>
status_t writeParcelableVector(const std::vector<T>& val);
template<typename T>
@@ -1229,6 +1231,16 @@
return unsafeWriteTypedVector<NullableT, const NullableT&>(*val, &Parcel::writeNullableParcelable);
}
+template<typename T>
+status_t Parcel::writeParcelableVector(const std::shared_ptr<std::vector<std::optional<T>>>& val) {
+ if (val.get() == nullptr) {
+ return this->writeInt32(-1);
+ }
+
+ using NullableT = std::optional<T>;
+ return unsafeWriteTypedVector<NullableT, const NullableT&>(*val, &Parcel::writeNullableParcelable);
+}
+
template<typename T, std::enable_if_t<std::is_same_v<typename std::underlying_type_t<T>,int32_t>, bool>>
status_t Parcel::writeEnum(const T& val) {
return writeInt32(static_cast<int32_t>(val));
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index 3e3eda1..ec7c7d8 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -261,7 +261,7 @@
}
binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd) {
- std::unique_ptr<ParcelFileDescriptor> parcelFd;
+ std::optional<ParcelFileDescriptor> parcelFd;
status_t status = parcel->get()->readParcelable(&parcelFd);
if (status != STATUS_OK) return PruneStatusT(status);
diff --git a/libs/binder/rust/TEST_MAPPING b/libs/binder/rust/TEST_MAPPING
deleted file mode 100644
index 50c474c..0000000
--- a/libs/binder/rust/TEST_MAPPING
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "presubmit": [
- {
- "name": "libbinder_rs-internal_test"
- }
- ],
- "postsubmit": [
- {
- "name": "rustBinderTest"
- }
- ]
-}
diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp
index fb32382..eb8e57a 100644
--- a/libs/ftl/Android.bp
+++ b/libs/ftl/Android.bp
@@ -5,6 +5,7 @@
address: true,
},
srcs: [
+ "SmallMap_test.cpp",
"SmallVector_test.cpp",
"StaticVector_test.cpp",
],
diff --git a/libs/ftl/SmallMap_test.cpp b/libs/ftl/SmallMap_test.cpp
new file mode 100644
index 0000000..fa00c06
--- /dev/null
+++ b/libs/ftl/SmallMap_test.cpp
@@ -0,0 +1,131 @@
+/*
+ * 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/SmallMap.h>
+#include <gtest/gtest.h>
+
+#include <cctype>
+
+namespace android::test {
+
+using ftl::SmallMap;
+
+// Keep in sync with example usage in header file.
+TEST(SmallMap, Example) {
+ ftl::SmallMap<int, std::string, 3> map;
+ EXPECT_TRUE(map.empty());
+ EXPECT_FALSE(map.dynamic());
+
+ map = ftl::init::map<int, std::string>(123, "abc")(-1)(42, 3u, '?');
+ EXPECT_EQ(map.size(), 3u);
+ EXPECT_FALSE(map.dynamic());
+
+ EXPECT_TRUE(map.contains(123));
+
+ EXPECT_EQ(map.find(42, [](const std::string& s) { return s.size(); }), 3u);
+
+ const auto opt = map.find(-1);
+ ASSERT_TRUE(opt);
+
+ std::string& ref = *opt;
+ EXPECT_TRUE(ref.empty());
+ ref = "xyz";
+
+ EXPECT_EQ(map, SmallMap(ftl::init::map(-1, "xyz")(42, "???")(123, "abc")));
+}
+
+TEST(SmallMap, Construct) {
+ {
+ // Default constructor.
+ SmallMap<int, std::string, 2> map;
+
+ EXPECT_TRUE(map.empty());
+ EXPECT_FALSE(map.dynamic());
+ }
+ {
+ // In-place constructor with same types.
+ SmallMap<int, std::string, 5> map =
+ ftl::init::map<int, std::string>(123, "abc")(456, "def")(789, "ghi");
+
+ EXPECT_EQ(map.size(), 3u);
+ EXPECT_EQ(map.max_size(), 5u);
+ EXPECT_FALSE(map.dynamic());
+
+ EXPECT_EQ(map, SmallMap(ftl::init::map(123, "abc")(456, "def")(789, "ghi")));
+ }
+ {
+ // In-place constructor with different types.
+ SmallMap<int, std::string, 5> map =
+ ftl::init::map<int, std::string>(123, "abc")(-1)(42, 3u, '?');
+
+ EXPECT_EQ(map.size(), 3u);
+ EXPECT_EQ(map.max_size(), 5u);
+ EXPECT_FALSE(map.dynamic());
+
+ EXPECT_EQ(map, SmallMap(ftl::init::map(42, "???")(123, "abc")(-1, "\0\0\0")));
+ }
+ {
+ // In-place constructor with implicit size.
+ SmallMap map = ftl::init::map<int, std::string>(123, "abc")(-1)(42, 3u, '?');
+
+ static_assert(std::is_same_v<decltype(map), SmallMap<int, std::string, 3>>);
+ EXPECT_EQ(map.size(), 3u);
+ EXPECT_EQ(map.max_size(), 3u);
+ EXPECT_FALSE(map.dynamic());
+
+ EXPECT_EQ(map, SmallMap(ftl::init::map(-1, "\0\0\0")(42, "???")(123, "abc")));
+ }
+}
+
+TEST(SmallMap, Find) {
+ {
+ // Constant reference.
+ const ftl::SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C');
+
+ const auto opt = map.find('b');
+ EXPECT_EQ(opt, 'B');
+
+ const char d = 'D';
+ const auto ref = map.find('d').value_or(std::cref(d));
+ EXPECT_EQ(ref.get(), 'D');
+ }
+ {
+ // Mutable reference.
+ ftl::SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C');
+
+ const auto opt = map.find('c');
+ EXPECT_EQ(opt, 'C');
+
+ char d = 'd';
+ const auto ref = map.find('d').value_or(std::ref(d));
+ ref.get() = 'D';
+ EXPECT_EQ(d, 'D');
+ }
+ {
+ // Constant unary operation.
+ const ftl::SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z');
+ EXPECT_EQ(map.find('c', [](char c) { return std::toupper(c); }), 'Z');
+ }
+ {
+ // Mutable unary operation.
+ ftl::SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z');
+ EXPECT_TRUE(map.find('c', [](char& c) { c = std::toupper(c); }));
+
+ EXPECT_EQ(map, SmallMap(ftl::init::map('c', 'Z')('b', 'y')('a', 'x')));
+ }
+}
+
+} // namespace android::test
diff --git a/libs/ftl/SmallVector_test.cpp b/libs/ftl/SmallVector_test.cpp
index c41e622..d0c2858 100644
--- a/libs/ftl/SmallVector_test.cpp
+++ b/libs/ftl/SmallVector_test.cpp
@@ -52,6 +52,14 @@
vector = ftl::SmallVector(array);
EXPECT_EQ(vector, (ftl::SmallVector{'h', 'i', '\0'}));
EXPECT_FALSE(vector.dynamic());
+
+ ftl::SmallVector strings = ftl::init::list<std::string>("abc")("123456", 3u)(3u, '?');
+ ASSERT_EQ(strings.size(), 3u);
+ EXPECT_FALSE(strings.dynamic());
+
+ EXPECT_EQ(strings[0], "abc");
+ EXPECT_EQ(strings[1], "123");
+ EXPECT_EQ(strings[2], "???");
}
TEST(SmallVector, Construct) {
@@ -99,7 +107,8 @@
}
{
// In-place constructor with same types.
- SmallVector vector(std::in_place_type<std::string>, "red", "velvet", "cake");
+ SmallVector vector =
+ ftl::init::list<std::string>("redolent", 3u)("velveteen", 6u)("cakewalk", 4u);
static_assert(std::is_same_v<decltype(vector), SmallVector<std::string, 3>>);
EXPECT_EQ(vector, (SmallVector{"red"s, "velvet"s, "cake"s}));
@@ -110,9 +119,10 @@
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);
+ SmallVector vector = ftl::init::list<std::string>(copy.c_str())(std::move(move))(list);
static_assert(std::is_same_v<decltype(vector), SmallVector<std::string, 3>>);
+ EXPECT_TRUE(move.empty());
EXPECT_EQ(vector, (SmallVector{"red"s, "velvet"s, "cake"s}));
EXPECT_FALSE(vector.dynamic());
}
@@ -206,9 +216,8 @@
}
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", "");
+ // Construct std::string elements in place from per-element arguments.
+ SmallVector strings = ftl::init::list<std::string>()()()("cake")("velvet")("red")();
strings.pop_back();
EXPECT_EQ(strings.max_size(), 7u);
@@ -221,6 +230,7 @@
ASSERT_FALSE(it == strings.end());
EXPECT_EQ(*it, "cake");
+ // Construct std::string from first 4 characters of string literal.
strings.unstable_erase(it);
EXPECT_EQ(strings.emplace_back("cakewalk", 4u), "cake"s);
}
@@ -260,7 +270,7 @@
bool operator==(const Word& other) const { return other.str == str; }
};
- SmallVector words(std::in_place_type<Word>, "colored", "velour");
+ SmallVector words = ftl::init::list<Word>("colored")("velour");
// The replaced element can be referenced by the replacement.
{
@@ -301,7 +311,7 @@
}
TEST(SmallVector, Sort) {
- SmallVector strings(std::in_place_type<std::string>, "pie", "quince", "tart", "red", "velvet");
+ SmallVector strings = ftl::init::list<std::string>("pie")("quince")("tart")("red")("velvet");
strings.push_back("cake"s);
auto sorted = std::move(strings);
diff --git a/libs/ftl/StaticVector_test.cpp b/libs/ftl/StaticVector_test.cpp
index dd5ce35..db42d23 100644
--- a/libs/ftl/StaticVector_test.cpp
+++ b/libs/ftl/StaticVector_test.cpp
@@ -51,6 +51,13 @@
const char array[] = "hi";
vector = ftl::StaticVector(array);
EXPECT_EQ(vector, (ftl::StaticVector{'h', 'i', '\0'}));
+
+ ftl::StaticVector strings = ftl::init::list<std::string>("abc")("123456", 3u)(3u, '?');
+ ASSERT_EQ(strings.size(), 3u);
+
+ EXPECT_EQ(strings[0], "abc");
+ EXPECT_EQ(strings[1], "123");
+ EXPECT_EQ(strings[2], "???");
}
TEST(StaticVector, Construct) {
@@ -91,7 +98,8 @@
}
{
// In-place constructor with same types.
- StaticVector vector(std::in_place_type<std::string>, "red", "velvet", "cake");
+ StaticVector vector =
+ ftl::init::list<std::string>("redolent", 3u)("velveteen", 6u)("cakewalk", 4u);
static_assert(std::is_same_v<decltype(vector), StaticVector<std::string, 3>>);
EXPECT_EQ(vector, (StaticVector{"red"s, "velvet"s, "cake"s}));
@@ -101,9 +109,10 @@
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);
+ StaticVector vector = ftl::init::list<std::string>(copy.c_str())(std::move(move))(list);
static_assert(std::is_same_v<decltype(vector), StaticVector<std::string, 3>>);
+ EXPECT_TRUE(move.empty());
EXPECT_EQ(vector, (StaticVector{"red"s, "velvet"s, "cake"s}));
}
{
@@ -204,9 +213,8 @@
}
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", "");
+ // Construct std::string elements in place from per-element arguments.
+ StaticVector strings = ftl::init::list<std::string>()()()("cake")("velvet")("red")();
strings.pop_back();
EXPECT_EQ(strings.max_size(), 7u);
@@ -221,7 +229,7 @@
strings.unstable_erase(it);
- // Construct std::string from first 4 characters of C-style string.
+ // Construct std::string from first 4 characters of string literal.
it = strings.emplace_back("cakewalk", 4u);
ASSERT_NE(it, strings.end());
EXPECT_EQ(*it, "cake"s);
@@ -250,7 +258,7 @@
const std::string str;
};
- StaticVector words(std::in_place_type<Word>, "red", "velour", "cake");
+ StaticVector words = ftl::init::list<Word>("red")("velour")("cake");
// The replaced element can be referenced by the replacement.
const auto it = words.begin() + 1;
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index ac1c736..e6aa02a 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -111,8 +111,8 @@
int width, int height, bool enableTripleBuffering)
: mName(name),
mSurfaceControl(surface),
- mWidth(width),
- mHeight(height),
+ mSize(width, height),
+ mRequestedSize(mSize),
mNextTransaction(nullptr) {
BufferQueue::createBufferQueue(&mProducer, &mConsumer);
// since the adapter is in the client process, set dequeue timeout
@@ -130,7 +130,7 @@
mBufferItemConsumer->setName(String8(consumerName.c_str()));
mBufferItemConsumer->setFrameAvailableListener(this);
mBufferItemConsumer->setBufferFreedListener(this);
- mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
+ mBufferItemConsumer->setDefaultBufferSize(mSize.width, mSize.height);
mBufferItemConsumer->setDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888);
mTransformHint = mSurfaceControl->getTransformHint();
@@ -146,10 +146,10 @@
std::unique_lock _lock{mMutex};
mSurfaceControl = surface;
- if (mWidth != width || mHeight != height) {
- mWidth = width;
- mHeight = height;
- mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
+ ui::Size newSize(width, height);
+ if (mRequestedSize != newSize) {
+ mRequestedSize.set(newSize);
+ mBufferItemConsumer->setDefaultBufferSize(mRequestedSize.width, mRequestedSize.height);
}
}
@@ -218,6 +218,7 @@
// number of buffers.
if (mNumFrameAvailable == 0 || maxBuffersAcquired()) {
BQA_LOGV("processNextBufferLocked waiting for frame available or callback");
+ mCallbackCV.notify_all();
return;
}
@@ -252,10 +253,13 @@
}
if (rejectBuffer(bufferItem)) {
- BQA_LOGE("rejecting buffer:configured size=%dx%d, buffer{size=%dx%d transform=%d}", mWidth,
- mHeight, buffer->getWidth(), buffer->getHeight(), bufferItem.mTransform);
- // TODO(b/168917217) temporarily don't reject buffers until we can synchronize buffer size
- // changes from ViewRootImpl.
+ BQA_LOGE("rejecting buffer:active_size=%dx%d, requested_size=%dx%d"
+ "buffer{size=%dx%d transform=%d}",
+ mSize.width, mSize.height, mRequestedSize.width, mRequestedSize.height,
+ buffer->getWidth(), buffer->getHeight(), bufferItem.mTransform);
+ mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE);
+ processNextBufferLocked(useNextTransaction);
+ return;
}
mNumAcquired++;
@@ -278,26 +282,31 @@
t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this));
t->setFrame(mSurfaceControl,
- {0, 0, static_cast<int32_t>(mWidth), static_cast<int32_t>(mHeight)});
+ {0, 0, static_cast<int32_t>(mSize.width), static_cast<int32_t>(mSize.height)});
t->setCrop(mSurfaceControl, computeCrop(bufferItem));
t->setTransform(mSurfaceControl, bufferItem.mTransform);
t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse);
t->setDesiredPresentTime(bufferItem.mTimestamp);
t->setFrameNumber(mSurfaceControl, bufferItem.mFrameNumber);
+ if (mAutoRefresh != bufferItem.mAutoRefresh) {
+ t->setAutoRefresh(mSurfaceControl, bufferItem.mAutoRefresh);
+ mAutoRefresh = bufferItem.mAutoRefresh;
+ }
+
if (applyTransaction) {
t->apply();
}
BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64
" applyTransaction=%s mTimestamp=%" PRId64,
- mWidth, mHeight, bufferItem.mFrameNumber, toString(applyTransaction),
+ mSize.width, mSize.height, bufferItem.mFrameNumber, toString(applyTransaction),
bufferItem.mTimestamp);
}
Rect BLASTBufferQueue::computeCrop(const BufferItem& item) {
if (item.mScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
- return GLConsumer::scaleDownCrop(item.mCrop, mWidth, mHeight);
+ return GLConsumer::scaleDownCrop(item.mCrop, mSize.width, mSize.height);
}
return item.mCrop;
}
@@ -332,8 +341,9 @@
mNextTransaction = t;
}
-bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) const {
+bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) {
if (item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) {
+ mSize = mRequestedSize;
// Only reject buffers if scaling mode is freeze.
return false;
}
@@ -345,9 +355,14 @@
if (item.mTransform & ui::Transform::ROT_90) {
std::swap(bufWidth, bufHeight);
}
+ ui::Size bufferSize(bufWidth, bufHeight);
+ if (mRequestedSize != mSize && mRequestedSize == bufferSize) {
+ mSize = mRequestedSize;
+ return false;
+ }
// reject buffers if the buffer size doesn't match.
- return bufWidth != mWidth || bufHeight != mHeight;
+ return mSize != bufferSize;
}
// Check if we have acquired the maximum number of buffers.
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 90999fa..7d2c7b8 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -61,7 +61,9 @@
frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT),
shouldBeSeamless(true),
fixedTransformHint(ui::Transform::ROT_INVALID),
- frameNumber(0) {
+ frameNumber(0),
+ frameTimelineVsyncId(ISurfaceComposer::INVALID_VSYNC_ID),
+ autoRefresh(false) {
matrix.dsdx = matrix.dtdy = 1.0f;
matrix.dsdy = matrix.dtdx = 0.0f;
hdrMetadata.validTypes = 0;
@@ -149,6 +151,7 @@
SAFE_PARCEL(output.writeUint32, fixedTransformHint);
SAFE_PARCEL(output.writeUint64, frameNumber);
SAFE_PARCEL(output.writeInt64, frameTimelineVsyncId);
+ SAFE_PARCEL(output.writeBool, autoRefresh);
SAFE_PARCEL(output.writeUint32, blurRegions.size());
for (auto region : blurRegions) {
@@ -269,6 +272,7 @@
fixedTransformHint = static_cast<ui::Transform::RotationFlags>(tmpUint32);
SAFE_PARCEL(input.readUint64, &frameNumber);
SAFE_PARCEL(input.readInt64, &frameTimelineVsyncId);
+ SAFE_PARCEL(input.readBool, &autoRefresh);
uint32_t numRegions = 0;
SAFE_PARCEL(input.readUint32, &numRegions);
@@ -534,6 +538,20 @@
what |= eFrameNumberChanged;
frameNumber = other.frameNumber;
}
+ if (other.what & eFrameTimelineVsyncChanged) {
+ // When merging vsync Ids we take the oldest valid one
+ if (frameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID &&
+ other.frameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID) {
+ frameTimelineVsyncId = std::max(frameTimelineVsyncId, other.frameTimelineVsyncId);
+ } else if (frameTimelineVsyncId == ISurfaceComposer::INVALID_VSYNC_ID) {
+ frameTimelineVsyncId = other.frameTimelineVsyncId;
+ }
+ what |= eFrameTimelineVsyncChanged;
+ }
+ if (other.what & eAutoRefreshChanged) {
+ what |= eAutoRefreshChanged;
+ autoRefresh = other.autoRefresh;
+ }
if ((other.what & what) != other.what) {
ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
"other.what=0x%" PRIu64 " what=0x%" PRIu64,
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index a822598..47a08ab 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1527,6 +1527,19 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAutoRefresh(
+ const sp<SurfaceControl>& sc, bool autoRefresh) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+
+ s->what |= layer_state_t::eAutoRefreshChanged;
+ s->autoRefresh = autoRefresh;
+ return *this;
+}
+
// ---------------------------------------------------------------------------
DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 7741d8c..9fb7d6f 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -100,7 +100,7 @@
void processNextBufferLocked(bool useNextTransaction) REQUIRES(mMutex);
Rect computeCrop(const BufferItem& item) REQUIRES(mMutex);
// Return true if we need to reject the buffer based on the scaling mode and the buffer size.
- bool rejectBuffer(const BufferItem& item) const REQUIRES(mMutex);
+ bool rejectBuffer(const BufferItem& item) REQUIRES(mMutex);
bool maxBuffersAcquired() const REQUIRES(mMutex);
std::string mName;
@@ -126,8 +126,8 @@
// is ready to be presented.
PendingReleaseItem mPendingReleaseItem GUARDED_BY(mMutex);
- uint32_t mWidth GUARDED_BY(mMutex);
- uint32_t mHeight GUARDED_BY(mMutex);
+ ui::Size mSize GUARDED_BY(mMutex);
+ ui::Size mRequestedSize GUARDED_BY(mMutex);
uint32_t mTransformHint GUARDED_BY(mMutex);
@@ -139,6 +139,10 @@
// If set to true, the next queue buffer will wait until the shadow queue has been processed by
// the adapter.
bool mFlushShadowQueue = false;
+ // Last requested auto refresh state set by the producer. The state indicates that the consumer
+ // should acquire the next frame as soon as it can and not wait for a frame to become available.
+ // This is only relevant for shared buffer mode.
+ bool mAutoRefresh GUARDED_BY(mMutex) = false;
};
} // namespace android
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index d9f2806..f1c5d67 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -130,6 +130,7 @@
eFrameNumberChanged = 0x400'00000000,
eFrameTimelineVsyncChanged = 0x800'00000000,
eBlurRegionsChanged = 0x1000'00000000,
+ eAutoRefreshChanged = 0x2000'00000000,
};
layer_state_t();
@@ -234,6 +235,11 @@
uint64_t frameNumber;
int64_t frameTimelineVsyncId;
+
+ // Indicates that the consumer should acquire the next frame as soon as it
+ // can and not wait for a frame to become available. This is only relevant
+ // in shared buffer mode.
+ bool autoRefresh;
};
struct ComposerState {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 6289c6a..2eb97f2 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -541,6 +541,11 @@
Transaction& setFrameTimelineVsync(const sp<SurfaceControl>& sc,
int64_t frameTimelineVsyncId);
+ // Indicates that the consumer should acquire the next frame as soon as it
+ // can and not wait for a frame to become available. This is only relevant
+ // in shared buffer mode.
+ Transaction& setAutoRefresh(const sp<SurfaceControl>& sc, bool autoRefresh);
+
status_t setDisplaySurface(const sp<IBinder>& token,
const sp<IGraphicBufferProducer>& bufferProducer);
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index f3559fa..4282ef9 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -55,9 +55,9 @@
mBlastBufferQueueAdapter->setNextTransaction(next);
}
- int getWidth() { return mBlastBufferQueueAdapter->mWidth; }
+ int getWidth() { return mBlastBufferQueueAdapter->mSize.width; }
- int getHeight() { return mBlastBufferQueueAdapter->mHeight; }
+ int getHeight() { return mBlastBufferQueueAdapter->mSize.height; }
Transaction* getNextTransaction() { return mBlastBufferQueueAdapter->mNextTransaction; }
@@ -250,8 +250,15 @@
PIXEL_FORMAT_RGBA_8888);
adapter.update(updateSurface, mDisplayWidth / 2, mDisplayHeight / 2);
ASSERT_EQ(updateSurface, adapter.getSurfaceControl());
- ASSERT_EQ(mDisplayWidth / 2, adapter.getWidth());
- ASSERT_EQ(mDisplayHeight / 2, adapter.getHeight());
+ sp<IGraphicBufferProducer> igbProducer;
+ setUpProducer(adapter, igbProducer);
+
+ int32_t width;
+ igbProducer->query(NATIVE_WINDOW_WIDTH, &width);
+ ASSERT_EQ(mDisplayWidth / 2, width);
+ int32_t height;
+ igbProducer->query(NATIVE_WINDOW_HEIGHT, &height);
+ ASSERT_EQ(mDisplayHeight / 2, height);
}
TEST_F(BLASTBufferQueueTest, SetNextTransaction) {
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 0ea3889..0a00d68 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -89,6 +89,9 @@
case AINPUT_EVENT_TYPE_FOCUS: {
return "FOCUS";
}
+ case AINPUT_EVENT_TYPE_CAPTURE: {
+ return "CAPTURE";
+ }
}
return "UNKNOWN";
}
@@ -754,6 +757,19 @@
mInTouchMode = from.mInTouchMode;
}
+// --- CaptureEvent ---
+
+void CaptureEvent::initialize(int32_t id, bool pointerCaptureEnabled) {
+ InputEvent::initialize(id, ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID, AINPUT_SOURCE_UNKNOWN,
+ ADISPLAY_ID_NONE, INVALID_HMAC);
+ mPointerCaptureEnabled = pointerCaptureEnabled;
+}
+
+void CaptureEvent::initialize(const CaptureEvent& from) {
+ InputEvent::initialize(from);
+ mPointerCaptureEnabled = from.mPointerCaptureEnabled;
+}
+
// --- PooledInputEventFactory ---
PooledInputEventFactory::PooledInputEventFactory(size_t maxPoolSize) :
@@ -790,6 +806,15 @@
return event;
}
+CaptureEvent* PooledInputEventFactory::createCaptureEvent() {
+ if (mCaptureEventPool.empty()) {
+ return new CaptureEvent();
+ }
+ CaptureEvent* event = mCaptureEventPool.front().release();
+ mCaptureEventPool.pop();
+ return event;
+}
+
void PooledInputEventFactory::recycle(InputEvent* event) {
switch (event->getType()) {
case AINPUT_EVENT_TYPE_KEY:
@@ -810,6 +835,13 @@
return;
}
break;
+ case AINPUT_EVENT_TYPE_CAPTURE:
+ if (mCaptureEventPool.size() < mMaxPoolSize) {
+ mCaptureEventPool.push(
+ std::unique_ptr<CaptureEvent>(static_cast<CaptureEvent*>(event)));
+ return;
+ }
+ break;
}
delete event;
}
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 85df405..acea473 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -105,6 +105,8 @@
return true;
case Type::FOCUS:
return true;
+ case Type::CAPTURE:
+ return true;
}
}
return false;
@@ -120,6 +122,8 @@
return sizeof(Header) + body.finished.size();
case Type::FOCUS:
return sizeof(Header) + body.focus.size();
+ case Type::CAPTURE:
+ return sizeof(Header) + body.capture.size();
}
return sizeof(Header);
}
@@ -238,6 +242,11 @@
msg->body.focus.inTouchMode = body.focus.inTouchMode;
break;
}
+ case InputMessage::Type::CAPTURE: {
+ msg->body.capture.eventId = body.capture.eventId;
+ msg->body.capture.pointerCaptureEnabled = body.capture.pointerCaptureEnabled;
+ break;
+ }
}
}
@@ -571,6 +580,23 @@
return mChannel->sendMessage(&msg);
}
+status_t InputPublisher::publishCaptureEvent(uint32_t seq, int32_t eventId,
+ bool pointerCaptureEnabled) {
+ if (ATRACE_ENABLED()) {
+ std::string message =
+ StringPrintf("publishCaptureEvent(inputChannel=%s, pointerCaptureEnabled=%s)",
+ mChannel->getName().c_str(), toString(pointerCaptureEnabled));
+ ATRACE_NAME(message.c_str());
+ }
+
+ InputMessage msg;
+ msg.header.type = InputMessage::Type::CAPTURE;
+ msg.header.seq = seq;
+ msg.body.capture.eventId = eventId;
+ msg.body.capture.pointerCaptureEnabled = pointerCaptureEnabled ? 1 : 0;
+ return mChannel->sendMessage(&msg);
+}
+
status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {
if (DEBUG_TRANSPORT_ACTIONS) {
ALOGD("channel '%s' publisher ~ receiveFinishedSignal", mChannel->getName().c_str());
@@ -739,6 +765,16 @@
*outEvent = focusEvent;
break;
}
+
+ case InputMessage::Type::CAPTURE: {
+ CaptureEvent* captureEvent = factory->createCaptureEvent();
+ if (!captureEvent) return NO_MEMORY;
+
+ initializeCaptureEvent(captureEvent, &mMsg);
+ *outSeq = mMsg.header.seq;
+ *outEvent = captureEvent;
+ break;
+ }
}
}
return OK;
@@ -1171,6 +1207,10 @@
msg->body.focus.inTouchMode == 1);
}
+void InputConsumer::initializeCaptureEvent(CaptureEvent* event, const InputMessage* msg) {
+ event->initialize(msg->body.capture.eventId, msg->body.capture.pointerCaptureEnabled == 1);
+}
+
void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) {
uint32_t pointerCount = msg->body.motion.pointerCount;
PointerProperties pointerProperties[pointerCount];
@@ -1274,6 +1314,12 @@
toString(msg.body.focus.inTouchMode));
break;
}
+ case InputMessage::Type::CAPTURE: {
+ out += android::base::StringPrintf("hasCapture=%s",
+ toString(msg.body.capture
+ .pointerCaptureEnabled));
+ break;
+ }
}
out += "\n";
}
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 4f53dc9..9da7b69 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -51,6 +51,7 @@
void PublishAndConsumeKeyEvent();
void PublishAndConsumeMotionEvent();
void PublishAndConsumeFocusEvent();
+ void PublishAndConsumeCaptureEvent();
};
TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) {
@@ -309,6 +310,43 @@
<< "publisher receiveFinishedSignal should have set handled to consumer's reply";
}
+void InputPublisherAndConsumerTest::PublishAndConsumeCaptureEvent() {
+ status_t status;
+
+ constexpr uint32_t seq = 42;
+ int32_t eventId = InputEvent::nextId();
+ constexpr bool captureEnabled = true;
+
+ status = mPublisher->publishCaptureEvent(seq, eventId, captureEnabled);
+ ASSERT_EQ(OK, status) << "publisher publishKeyEvent should return OK";
+
+ uint32_t consumeSeq;
+ InputEvent* event;
+ status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
+ ASSERT_EQ(OK, status) << "consumer consume should return OK";
+
+ ASSERT_TRUE(event != nullptr) << "consumer should have returned non-NULL event";
+ ASSERT_EQ(AINPUT_EVENT_TYPE_CAPTURE, event->getType())
+ << "consumer should have returned a capture event";
+
+ const CaptureEvent* captureEvent = static_cast<CaptureEvent*>(event);
+ EXPECT_EQ(seq, consumeSeq);
+ EXPECT_EQ(eventId, captureEvent->getId());
+ EXPECT_EQ(captureEnabled, captureEvent->getPointerCaptureEnabled());
+
+ status = mConsumer->sendFinishedSignal(seq, true);
+ ASSERT_EQ(OK, status) << "consumer sendFinishedSignal should return OK";
+
+ uint32_t finishedSeq = 0;
+ bool handled = false;
+ status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);
+ ASSERT_EQ(OK, status) << "publisher receiveFinishedSignal should return OK";
+ ASSERT_EQ(seq, finishedSeq)
+ << "publisher receiveFinishedSignal should have returned the original sequence number";
+ ASSERT_TRUE(handled)
+ << "publisher receiveFinishedSignal should have set handled to consumer's reply";
+}
+
TEST_F(InputPublisherAndConsumerTest, PublishKeyEvent_EndToEnd) {
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
}
@@ -321,6 +359,10 @@
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeFocusEvent());
}
+TEST_F(InputPublisherAndConsumerTest, PublishCaptureEvent_EndToEnd) {
+ ASSERT_NO_FATAL_FAILURE(PublishAndConsumeCaptureEvent());
+}
+
TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenSequenceNumberIsZero_ReturnsError) {
status_t status;
const size_t pointerCount = 1;
@@ -385,6 +427,9 @@
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeFocusEvent());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
+ ASSERT_NO_FATAL_FAILURE(PublishAndConsumeCaptureEvent());
+ ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
+ ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
}
} // namespace android
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 3c5fb22..4107d61 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -79,6 +79,9 @@
CHECK_OFFSET(InputMessage::Body::Focus, hasFocus, 4);
CHECK_OFFSET(InputMessage::Body::Focus, inTouchMode, 6);
+ CHECK_OFFSET(InputMessage::Body::Capture, eventId, 0);
+ CHECK_OFFSET(InputMessage::Body::Capture, pointerCaptureEnabled, 4);
+
CHECK_OFFSET(InputMessage::Body::Finished, handled, 4);
}
@@ -99,6 +102,7 @@
sizeof(InputMessage::Body::Motion::Pointer) * MAX_POINTERS);
static_assert(sizeof(InputMessage::Body::Finished) == 8);
static_assert(sizeof(InputMessage::Body::Focus) == 8);
+ static_assert(sizeof(InputMessage::Body::Capture) == 8);
}
// --- VerifiedInputEvent ---
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 1ec73ce..a375d43 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -397,6 +397,16 @@
return 0;
}
+int AHardwareBuffer_getId(const AHardwareBuffer* buffer, uint64_t* outId) {
+ if (!buffer || !outId) return BAD_VALUE;
+
+ const GraphicBuffer* gb = AHardwareBuffer_to_GraphicBuffer(buffer);
+ if (!gb) return BAD_VALUE;
+
+ *outId = gb->getId();
+
+ return OK;
+}
// ----------------------------------------------------------------------------
// VNDK functions
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index ae5e47b..4fcca9e 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -45,14 +45,14 @@
#ifndef ANDROID_HARDWARE_BUFFER_H
#define ANDROID_HARDWARE_BUFFER_H
+#include <android/rect.h>
#include <inttypes.h>
-
#include <sys/cdefs.h>
-#include <android/rect.h>
-
__BEGIN_DECLS
+// clang-format off
+
/**
* Buffer pixel formats.
*/
@@ -201,9 +201,9 @@
AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK = 0xFUL << 4,
/// The buffer will be read from by the GPU as a texture.
- AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE = 1UL << 8,
+ AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE = 1UL << 8,
/// The buffer will be written to by the GPU as a framebuffer attachment.
- AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER = 1UL << 9,
+ AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER = 1UL << 9,
/**
* The buffer will be written to by the GPU as a framebuffer
* attachment.
@@ -214,7 +214,7 @@
* attachment should also have this flag. Use the equivalent flag
* AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER to avoid this confusion.
*/
- AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER,
+ AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER,
/**
* The buffer will be used as a composer HAL overlay layer.
*
@@ -225,7 +225,7 @@
* directly through AHardwareBuffer_allocate instead of buffers allocated
* by the framework.
*/
- AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY = 1ULL << 11,
+ AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY = 1ULL << 11,
/**
* The buffer is protected from direct CPU access or being read by
* non-secure hardware, such as video encoders.
@@ -236,19 +236,19 @@
* GL_EXT_protected_textures for more information on how these
* buffers are expected to behave.
*/
- AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT = 1UL << 14,
+ AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT = 1UL << 14,
/// The buffer will be read by a hardware video encoder.
- AHARDWAREBUFFER_USAGE_VIDEO_ENCODE = 1UL << 16,
+ AHARDWAREBUFFER_USAGE_VIDEO_ENCODE = 1UL << 16,
/**
* The buffer will be used for direct writes from sensors.
* When this flag is present, the format must be AHARDWAREBUFFER_FORMAT_BLOB.
*/
- AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA = 1UL << 23,
+ AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA = 1UL << 23,
/**
* The buffer will be used as a shader storage or uniform buffer object.
* When this flag is present, the format must be AHARDWAREBUFFER_FORMAT_BLOB.
*/
- AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER = 1UL << 24,
+ AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER = 1UL << 24,
/**
* The buffer will be used as a cube map texture.
* When this flag is present, the buffer must have a layer count
@@ -256,13 +256,13 @@
* bound to OpenGL textures using the extension
* GL_EXT_EGL_image_storage instead of GL_KHR_EGL_image.
*/
- AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP = 1UL << 25,
+ AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP = 1UL << 25,
/**
* The buffer contains a complete mipmap hierarchy.
* Note that buffers with this flag must be bound to OpenGL textures using
* the extension GL_EXT_EGL_image_storage instead of GL_KHR_EGL_image.
*/
- AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE = 1UL << 26,
+ AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE = 1UL << 26,
AHARDWAREBUFFER_USAGE_VENDOR_0 = 1ULL << 28,
AHARDWAREBUFFER_USAGE_VENDOR_1 = 1ULL << 29,
@@ -291,8 +291,8 @@
* parameters of existing ones.
*/
typedef struct AHardwareBuffer_Desc {
- uint32_t width; ///< Width in pixels.
- uint32_t height; ///< Height in pixels.
+ uint32_t width; ///< Width in pixels.
+ uint32_t height; ///< Height in pixels.
/**
* Number of images in an image array. AHardwareBuffers with one
* layer correspond to regular 2D textures. AHardwareBuffers with
@@ -301,21 +301,21 @@
* AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP is present, the buffer is
* a cube map or a cube map array.
*/
- uint32_t layers;
- uint32_t format; ///< One of AHardwareBuffer_Format.
- uint64_t usage; ///< Combination of AHardwareBuffer_UsageFlags.
- uint32_t stride; ///< Row stride in pixels, ignored for AHardwareBuffer_allocate()
- uint32_t rfu0; ///< Initialize to zero, reserved for future use.
- uint64_t rfu1; ///< Initialize to zero, reserved for future use.
+ uint32_t layers;
+ uint32_t format; ///< One of AHardwareBuffer_Format.
+ uint64_t usage; ///< Combination of AHardwareBuffer_UsageFlags.
+ uint32_t stride; ///< Row stride in pixels, ignored for AHardwareBuffer_allocate()
+ uint32_t rfu0; ///< Initialize to zero, reserved for future use.
+ uint64_t rfu1; ///< Initialize to zero, reserved for future use.
} AHardwareBuffer_Desc;
/**
* Holds data for a single image plane.
*/
typedef struct AHardwareBuffer_Plane {
- void* data; ///< Points to first byte in plane
- uint32_t pixelStride; ///< Distance in bytes from the color channel of one pixel to the next
- uint32_t rowStride; ///< Distance in bytes from the first value of one row of the image to
+ void* _Nullable data; ///< Points to first byte in plane
+ uint32_t pixelStride; ///< Distance in bytes from the color channel of one pixel to the next
+ uint32_t rowStride; ///< Distance in bytes from the first value of one row of the image to
/// the first value of the next row.
} AHardwareBuffer_Plane;
@@ -323,8 +323,8 @@
* Holds all image planes that contain the pixel data.
*/
typedef struct AHardwareBuffer_Planes {
- uint32_t planeCount; ///< Number of distinct planes
- AHardwareBuffer_Plane planes[4]; ///< Array of image planes
+ uint32_t planeCount; ///< Number of distinct planes
+ AHardwareBuffer_Plane planes[4]; ///< Array of image planes
} AHardwareBuffer_Planes;
/**
@@ -332,6 +332,8 @@
*/
typedef struct AHardwareBuffer AHardwareBuffer;
+// clang-format on
+
#if __ANDROID_API__ >= 26
/**
@@ -347,8 +349,8 @@
* \return 0 on success, or an error number of the allocation fails for
* any reason. The returned buffer has a reference count of 1.
*/
-int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc,
- AHardwareBuffer** outBuffer) __INTRODUCED_IN(26);
+int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* _Nonnull desc,
+ AHardwareBuffer* _Nullable* _Nonnull outBuffer) __INTRODUCED_IN(26);
/**
* Acquire a reference on the given AHardwareBuffer object.
*
@@ -357,7 +359,7 @@
*
* Available since API level 26.
*/
-void AHardwareBuffer_acquire(AHardwareBuffer* buffer) __INTRODUCED_IN(26);
+void AHardwareBuffer_acquire(AHardwareBuffer* _Nonnull buffer) __INTRODUCED_IN(26);
/**
* Remove a reference that was previously acquired with
@@ -365,7 +367,7 @@
*
* Available since API level 26.
*/
-void AHardwareBuffer_release(AHardwareBuffer* buffer) __INTRODUCED_IN(26);
+void AHardwareBuffer_release(AHardwareBuffer* _Nonnull buffer) __INTRODUCED_IN(26);
/**
* Return a description of the AHardwareBuffer in the passed
@@ -373,8 +375,8 @@
*
* Available since API level 26.
*/
-void AHardwareBuffer_describe(const AHardwareBuffer* buffer,
- AHardwareBuffer_Desc* outDesc) __INTRODUCED_IN(26);
+void AHardwareBuffer_describe(const AHardwareBuffer* _Nonnull buffer,
+ AHardwareBuffer_Desc* _Nonnull outDesc) __INTRODUCED_IN(26);
/**
* Lock the AHardwareBuffer for direct CPU access.
@@ -428,8 +430,57 @@
* has more than one layer. Error number if the lock fails for any other
* reason.
*/
-int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage,
- int32_t fence, const ARect* rect, void** outVirtualAddress) __INTRODUCED_IN(26);
+int AHardwareBuffer_lock(AHardwareBuffer* _Nonnull buffer, uint64_t usage, int32_t fence,
+ const ARect* _Nullable rect, void* _Nullable* _Nonnull outVirtualAddress)
+ __INTRODUCED_IN(26);
+
+/**
+ * Unlock the AHardwareBuffer from direct CPU access.
+ *
+ * Must be called after all changes to the buffer are completed by the
+ * caller. If \a fence is NULL, the function will block until all work
+ * is completed. Otherwise, \a fence will be set either to a valid file
+ * descriptor or to -1. The file descriptor will become signaled once
+ * the unlocking is complete and buffer contents are updated.
+ * The caller is responsible for closing the file descriptor once it's
+ * no longer needed. The value -1 indicates that unlocking has already
+ * completed before the function returned and no further operations are
+ * necessary.
+ *
+ * Available since API level 26.
+ *
+ * \return 0 on success. -EINVAL if \a buffer is NULL. Error number if
+ * the unlock fails for any reason.
+ */
+int AHardwareBuffer_unlock(AHardwareBuffer* _Nonnull buffer, int32_t* _Nullable fence)
+ __INTRODUCED_IN(26);
+
+/**
+ * Send the AHardwareBuffer to an AF_UNIX socket.
+ *
+ * Available since API level 26.
+ *
+ * \return 0 on success, -EINVAL if \a buffer is NULL, or an error
+ * number if the operation fails for any reason.
+ */
+int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* _Nonnull buffer, int socketFd)
+ __INTRODUCED_IN(26);
+
+/**
+ * Receive an AHardwareBuffer from an AF_UNIX socket.
+ *
+ * Available since API level 26.
+ *
+ * \return 0 on success, -EINVAL if \a outBuffer is NULL, or an error
+ * number if the operation fails for any reason.
+ */
+int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd,
+ AHardwareBuffer* _Nullable* _Nonnull outBuffer)
+ __INTRODUCED_IN(26);
+
+#endif // __ANDROID_API__ >= 26
+
+#if __ANDROID_API__ >= 29
/**
* Lock a potentially multi-planar AHardwareBuffer for direct CPU access.
@@ -458,52 +509,9 @@
* has more than one layer. Error number if the lock fails for any other
* reason.
*/
-int AHardwareBuffer_lockPlanes(AHardwareBuffer* buffer, uint64_t usage,
- int32_t fence, const ARect* rect, AHardwareBuffer_Planes* outPlanes) __INTRODUCED_IN(29);
-
-/**
- * Unlock the AHardwareBuffer from direct CPU access.
- *
- * Must be called after all changes to the buffer are completed by the
- * caller. If \a fence is NULL, the function will block until all work
- * is completed. Otherwise, \a fence will be set either to a valid file
- * descriptor or to -1. The file descriptor will become signaled once
- * the unlocking is complete and buffer contents are updated.
- * The caller is responsible for closing the file descriptor once it's
- * no longer needed. The value -1 indicates that unlocking has already
- * completed before the function returned and no further operations are
- * necessary.
- *
- * Available since API level 26.
- *
- * \return 0 on success. -EINVAL if \a buffer is NULL. Error number if
- * the unlock fails for any reason.
- */
-int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) __INTRODUCED_IN(26);
-
-/**
- * Send the AHardwareBuffer to an AF_UNIX socket.
- *
- * Available since API level 26.
- *
- * \return 0 on success, -EINVAL if \a buffer is NULL, or an error
- * number if the operation fails for any reason.
- */
-int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int socketFd) __INTRODUCED_IN(26);
-
-/**
- * Receive an AHardwareBuffer from an AF_UNIX socket.
- *
- * Available since API level 26.
- *
- * \return 0 on success, -EINVAL if \a outBuffer is NULL, or an error
- * number if the operation fails for any reason.
- */
-int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** outBuffer) __INTRODUCED_IN(26);
-
-#endif // __ANDROID_API__ >= 26
-
-#if __ANDROID_API__ >= 29
+int AHardwareBuffer_lockPlanes(AHardwareBuffer* _Nonnull buffer, uint64_t usage, int32_t fence,
+ const ARect* _Nullable rect,
+ AHardwareBuffer_Planes* _Nonnull outPlanes) __INTRODUCED_IN(29);
/**
* Test whether the given format and usage flag combination is
@@ -524,7 +532,7 @@
* \return 1 if the format and usage flag combination is allocatable,
* 0 otherwise.
*/
-int AHardwareBuffer_isSupported(const AHardwareBuffer_Desc* desc) __INTRODUCED_IN(29);
+int AHardwareBuffer_isSupported(const AHardwareBuffer_Desc* _Nonnull desc) __INTRODUCED_IN(29);
/**
* Lock an AHardwareBuffer for direct CPU access.
@@ -537,11 +545,29 @@
*
* Available since API level 29.
*/
-int AHardwareBuffer_lockAndGetInfo(AHardwareBuffer* buffer, uint64_t usage,
- int32_t fence, const ARect* rect, void** outVirtualAddress,
- int32_t* outBytesPerPixel, int32_t* outBytesPerStride) __INTRODUCED_IN(29);
+int AHardwareBuffer_lockAndGetInfo(AHardwareBuffer* _Nonnull buffer, uint64_t usage, int32_t fence,
+ const ARect* _Nullable rect,
+ void* _Nullable* _Nonnull outVirtualAddress,
+ int32_t* _Nonnull outBytesPerPixel,
+ int32_t* _Nonnull outBytesPerStride) __INTRODUCED_IN(29);
+
#endif // __ANDROID_API__ >= 29
+#if __ANDROID_API__ >= 31
+
+/**
+ * Get the system wide unique id for an AHardwareBuffer.
+ *
+ * Available since API level 31.
+ *
+ * \return 0 on success, -EINVAL if \a buffer or \a outId is NULL, or an error number if the
+ * operation fails for any reason.
+ */
+int AHardwareBuffer_getId(const AHardwareBuffer* _Nonnull buffer, uint64_t* _Nonnull outId)
+ __INTRODUCED_IN(31);
+
+#endif // __ANDROID_API__ >= 31
+
__END_DECLS
#endif // ANDROID_HARDWARE_BUFFER_H
diff --git a/libs/nativewindow/include/vndk/hardware_buffer.h b/libs/nativewindow/include/vndk/hardware_buffer.h
index 3392d7f..50fe0b7 100644
--- a/libs/nativewindow/include/vndk/hardware_buffer.h
+++ b/libs/nativewindow/include/vndk/hardware_buffer.h
@@ -24,7 +24,14 @@
__BEGIN_DECLS
-const native_handle_t* AHardwareBuffer_getNativeHandle(const AHardwareBuffer* buffer);
+/**
+ * Get the native handle from an AHardwareBuffer.
+ *
+ * \return a non-NULL native handle on success, NULL if \a buffer is nullptr or the operation fails
+ * for any reason.
+ */
+const native_handle_t* _Nullable AHardwareBuffer_getNativeHandle(
+ const AHardwareBuffer* _Nonnull buffer);
enum CreateFromHandleMethod {
// enum values chosen to match internal GraphicBuffer::HandleWrapMethod
@@ -33,9 +40,9 @@
};
/**
- * Create a AHardwareBuffer from a native handle.
+ * Create an AHardwareBuffer from a native handle.
*
- * This function wraps a native handle in a AHardwareBuffer suitable for use by applications or
+ * This function wraps a native handle in an AHardwareBuffer suitable for use by applications or
* other parts of the system. The contents of desc will be returned by AHardwareBuffer_describe().
*
* If method is AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_REGISTER, the handle is assumed to be
@@ -44,10 +51,13 @@
*
* If method is AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE, the handle will be cloned and the
* clone registered. The AHardwareBuffer will own the cloned handle but not the original.
+ *
+ * \return 0 on success, -EINVAL if \a desc or \a handle or outBuffer is NULL, or an error number if
+ * the operation fails for any reason.
*/
-int AHardwareBuffer_createFromHandle(const AHardwareBuffer_Desc* desc,
- const native_handle_t* handle, int32_t method,
- AHardwareBuffer** outBuffer);
+int AHardwareBuffer_createFromHandle(const AHardwareBuffer_Desc* _Nonnull desc,
+ const native_handle_t* _Nonnull handle, int32_t method,
+ AHardwareBuffer* _Nullable* _Nonnull outBuffer);
/**
* Buffer pixel formats.
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index de48ec2..24d0e3b 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -4,6 +4,7 @@
AHardwareBuffer_allocate;
AHardwareBuffer_createFromHandle; # llndk # apex
AHardwareBuffer_describe;
+ AHardwareBuffer_getId; # introduced=31
AHardwareBuffer_getNativeHandle; # llndk # apex
AHardwareBuffer_isSupported; # introduced=29
AHardwareBuffer_lock;
diff --git a/libs/nativewindow/tests/AHardwareBufferTest.cpp b/libs/nativewindow/tests/AHardwareBufferTest.cpp
index 71b1f9f..ef863b6 100644
--- a/libs/nativewindow/tests/AHardwareBufferTest.cpp
+++ b/libs/nativewindow/tests/AHardwareBufferTest.cpp
@@ -17,12 +17,11 @@
#define LOG_TAG "AHardwareBuffer_test"
//#define LOG_NDEBUG 0
-#include <android/hardware_buffer.h>
-#include <private/android/AHardwareBufferHelpers.h>
#include <android/hardware/graphics/common/1.0/types.h>
-#include <vndk/hardware_buffer.h>
-
#include <gtest/gtest.h>
+#include <private/android/AHardwareBufferHelpers.h>
+#include <ui/GraphicBuffer.h>
+#include <vndk/hardware_buffer.h>
using namespace android;
using android::hardware::graphics::common::V1_0::BufferUsage;
@@ -131,3 +130,43 @@
AHardwareBuffer_release(buffer);
AHardwareBuffer_release(otherBuffer);
}
+
+TEST(AHardwareBufferTest, GetIdTest) {
+ const uint32_t testWidth = 4;
+ const uint32_t testHeight = 4;
+ const uint32_t testLayers = 1;
+
+ AHardwareBuffer* ahb1 = nullptr;
+ uint64_t id1 = 0;
+ const AHardwareBuffer_Desc desc = {
+ .width = testWidth,
+ .height = testHeight,
+ .layers = testLayers,
+ .format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+ .usage = AHARDWAREBUFFER_USAGE_CPU_READ_RARELY,
+ };
+ int res = AHardwareBuffer_allocate(&desc, &ahb1);
+ EXPECT_EQ(NO_ERROR, res);
+ EXPECT_NE(nullptr, ahb1);
+ EXPECT_EQ(0, AHardwareBuffer_getId(ahb1, &id1));
+ const GraphicBuffer* gb1 = AHardwareBuffer_to_GraphicBuffer(ahb1);
+ EXPECT_NE(nullptr, gb1);
+ EXPECT_EQ(id1, gb1->getId());
+ EXPECT_NE(id1, 0);
+
+ sp<GraphicBuffer> gb2(new GraphicBuffer(testWidth,
+ testHeight,
+ PIXEL_FORMAT_RGBA_8888,
+ testLayers,
+ GraphicBuffer::USAGE_SW_READ_RARELY,
+ std::string("test")));
+ EXPECT_NE(nullptr, gb2.get());
+ const AHardwareBuffer* ahb2 = AHardwareBuffer_from_GraphicBuffer(gb2.get());
+ EXPECT_NE(nullptr, ahb2);
+ uint64_t id2 = 0;
+ EXPECT_EQ(0, AHardwareBuffer_getId(ahb2, &id2));
+ EXPECT_EQ(id2, gb2->getId());
+ EXPECT_NE(id2, 0);
+
+ EXPECT_NE(id1, id2);
+}
diff --git a/libs/nativewindow/tests/Android.bp b/libs/nativewindow/tests/Android.bp
index cdb3d20..2e4bd99 100644
--- a/libs/nativewindow/tests/Android.bp
+++ b/libs/nativewindow/tests/Android.bp
@@ -24,6 +24,7 @@
"liblog",
"libnativewindow",
"libsync",
+ "libui",
"libutils",
"android.hardware.graphics.common@1.0",
],
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index aefedb4..07be0b6 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -486,7 +486,7 @@
}
auto grContext = mInProtectedContext ? mProtectedGrContext : mGrContext;
- auto cache = mInProtectedContext ? mProtectedSurfaceCache : mSurfaceCache;
+ auto& cache = mInProtectedContext ? mProtectedSurfaceCache : mSurfaceCache;
AHardwareBuffer_Desc bufferDesc;
AHardwareBuffer_describe(buffer->toAHardwareBuffer(), &bufferDesc);
LOG_ALWAYS_FATAL_IF(!hasUsage(bufferDesc, AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE),
@@ -550,7 +550,6 @@
screenTransform.preRotate(toDegrees(display.orientation));
screenTransform.preTranslate(-clipWidth / 2, -clipHeight / 2);
screenTransform.preTranslate(-display.clip.left, -display.clip.top);
- // Traverse all layers.
for (const auto& layer : layers) {
const SkMatrix drawTransform = getDrawTransform(layer, screenTransform);
@@ -653,16 +652,7 @@
matrix.postConcat(texMatrix);
matrix.postScale(rotatedBufferWidth, rotatedBufferHeight);
- sk_sp<SkShader> shader;
-
- if (layer->source.buffer.useTextureFiltering) {
- shader = image->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
- SkSamplingOptions(
- {SkSamplingMode::kLinear, SkMipmapMode::kNone}),
- &matrix);
- } else {
- shader = image->makeShader(matrix);
- }
+ sk_sp<SkShader> shader = image->makeShader(matrix);
if (mUseColorManagement &&
needsToneMapping(layer->sourceDataspace, display.outputDataspace)) {
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp
index a514825..c6b8d3a 100644
--- a/libs/renderengine/skia/filters/BlurFilter.cpp
+++ b/libs/renderengine/skia/filters/BlurFilter.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include "BlurFilter.h"
#include <SkCanvas.h>
#include <SkData.h>
@@ -38,11 +40,11 @@
half4 main(float2 xy) {
float2 scaled_xy = float2(xy.x * in_inverseScale, xy.y * in_inverseScale);
- float4 c = float4(sample(input, scaled_xy));
- c += float4(sample(input, scaled_xy + float2( in_blurOffset.x, in_blurOffset.y)));
- c += float4(sample(input, scaled_xy + float2( in_blurOffset.x, -in_blurOffset.y)));
- c += float4(sample(input, scaled_xy + float2(-in_blurOffset.x, in_blurOffset.y)));
- c += float4(sample(input, scaled_xy + float2(-in_blurOffset.x, -in_blurOffset.y)));
+ half4 c = sample(input, scaled_xy);
+ c += sample(input, scaled_xy + float2( in_blurOffset.x, in_blurOffset.y));
+ c += sample(input, scaled_xy + float2( in_blurOffset.x, -in_blurOffset.y));
+ c += sample(input, scaled_xy + float2(-in_blurOffset.x, in_blurOffset.y));
+ c += sample(input, scaled_xy + float2(-in_blurOffset.x, -in_blurOffset.y));
return half4(c.rgb * 0.2, 1.0);
}
@@ -57,8 +59,6 @@
sk_sp<SkSurface> BlurFilter::generate(SkCanvas* canvas, const sk_sp<SkSurface> input,
const uint32_t blurRadius, SkRect rect) const {
- ATRACE_CALL();
-
// Kawase is an approximation of Gaussian, but it behaves differently from it.
// A radius transformation is required for approximating them, and also to introduce
// non-integer steps, necessary to smoothly interpolate large radii.
@@ -77,7 +77,7 @@
const float stepY = radiusByPasses;
// start by drawing and downscaling and doing the first blur pass
- SkFilterOptions linear = {SkSamplingMode::kLinear, SkMipmapMode::kNone};
+ SkSamplingOptions linear(SkFilterMode::kLinear, SkMipmapMode::kNone);
SkRuntimeShaderBuilder blurBuilder(mBlurEffect);
blurBuilder.child("input") =
input->makeImageSnapshot()->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear);
@@ -126,7 +126,11 @@
}
lastDrawTarget = readSurface;
}
- lastDrawTarget->flushAndSubmit();
+
+ {
+ ATRACE_NAME("Flush Offscreen Surfaces");
+ lastDrawTarget->flushAndSubmit();
+ }
return lastDrawTarget;
}
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index 340d7bf..d5a19d3 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -80,6 +80,7 @@
cc_library_shared {
name: "libdvr.google",
+ system_ext_specific: true,
owner: "google",
cflags: cflags,
header_libs: ["libdvr_headers"],
diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp
index 1ce9c99..b3534de 100644
--- a/libs/vr/libpdx_default_transport/Android.bp
+++ b/libs/vr/libpdx_default_transport/Android.bp
@@ -45,6 +45,7 @@
cc_binary {
name: "pdx_tool",
+ system_ext_specific: true,
defaults: ["pdx_default_transport_compiler_defaults"],
srcs: [
"pdx_tool.cpp",
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index 77a0716..eafb5ab 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -405,6 +405,11 @@
mListener->notifyDeviceReset(args);
}
+void InputClassifier::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
+ // pass through
+ mListener->notifyPointerCaptureChanged(args);
+}
+
void InputClassifier::setMotionClassifier(
std::unique_ptr<MotionClassifierInterface> motionClassifier) {
std::scoped_lock lock(mLock);
diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h
index 03510a6..6965940 100644
--- a/services/inputflinger/InputClassifier.h
+++ b/services/inputflinger/InputClassifier.h
@@ -230,6 +230,7 @@
virtual void notifyMotion(const NotifyMotionArgs* args) override;
virtual void notifySwitch(const NotifySwitchArgs* args) override;
virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
+ void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
virtual void dump(std::string& dump) override;
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 84838ec..49a813e 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -48,7 +48,6 @@
listener->notifyConfigurationChanged(this);
}
-
// --- NotifyKeyArgs ---
NotifyKeyArgs::NotifyKeyArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source,
@@ -90,7 +89,6 @@
listener->notifyKey(this);
}
-
// --- NotifyMotionArgs ---
NotifyMotionArgs::NotifyMotionArgs(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source,
@@ -189,7 +187,6 @@
listener->notifyMotion(this);
}
-
// --- NotifySwitchArgs ---
NotifySwitchArgs::NotifySwitchArgs(int32_t id, nsecs_t eventTime, uint32_t policyFlags,
@@ -214,7 +211,6 @@
listener->notifySwitch(this);
}
-
// --- NotifyDeviceResetArgs ---
NotifyDeviceResetArgs::NotifyDeviceResetArgs(int32_t id, nsecs_t eventTime, int32_t deviceId)
@@ -231,6 +227,23 @@
listener->notifyDeviceReset(this);
}
+// --- NotifyPointerCaptureChangedArgs ---
+
+NotifyPointerCaptureChangedArgs::NotifyPointerCaptureChangedArgs(int32_t id, nsecs_t eventTime,
+ bool enabled)
+ : NotifyArgs(id, eventTime), enabled(enabled) {}
+
+NotifyPointerCaptureChangedArgs::NotifyPointerCaptureChangedArgs(
+ const NotifyPointerCaptureChangedArgs& other)
+ : NotifyArgs(other.id, other.eventTime), enabled(other.enabled) {}
+
+bool NotifyPointerCaptureChangedArgs::operator==(const NotifyPointerCaptureChangedArgs& rhs) const {
+ return id == rhs.id && eventTime == rhs.eventTime && enabled == rhs.enabled;
+}
+
+void NotifyPointerCaptureChangedArgs::notify(const sp<InputListenerInterface>& listener) const {
+ listener->notifyPointerCaptureChanged(this);
+}
// --- QueuedInputListener ---
@@ -278,6 +291,11 @@
mArgsQueue.push_back(new NotifyDeviceResetArgs(*args));
}
+void QueuedInputListener::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
+ traceEvent(__func__, args->id);
+ mArgsQueue.push_back(new NotifyPointerCaptureChangedArgs(*args));
+}
+
void QueuedInputListener::flush() {
size_t count = mArgsQueue.size();
for (size_t i = 0; i < count; i++) {
@@ -288,5 +306,4 @@
mArgsQueue.clear();
}
-
} // namespace android
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index b28bff2..91e9536 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -3542,6 +3542,15 @@
}
}
+void InputDispatcher::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
+#if DEBUG_INBOUND_EVENT_DETAILS
+ ALOGD("notifyPointerCaptureChanged - eventTime=%" PRId64 ", enabled=%s", args->eventTime,
+ args->enabled ? "true" : "false");
+#endif
+
+ // TODO(prabirmsp): Implement.
+}
+
InputEventInjectionResult InputDispatcher::injectInputEvent(
const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
InputEventInjectionSync syncMode, std::chrono::milliseconds timeout, uint32_t policyFlags) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 5704a5a..9aaae74 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -94,6 +94,7 @@
virtual void notifyMotion(const NotifyMotionArgs* args) override;
virtual void notifySwitch(const NotifySwitchArgs* args) override;
virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
+ virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
virtual android::os::InputEventInjectionResult injectInputEvent(
const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h
index 8317b05..58eb915 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -181,6 +181,22 @@
virtual void notify(const sp<InputListenerInterface>& listener) const;
};
+/* Describes a change in the state of Pointer Capture. */
+struct NotifyPointerCaptureChangedArgs : public NotifyArgs {
+ bool enabled;
+
+ inline NotifyPointerCaptureChangedArgs() {}
+
+ NotifyPointerCaptureChangedArgs(int32_t id, nsecs_t eventTime, bool enabled);
+
+ NotifyPointerCaptureChangedArgs(const NotifyPointerCaptureChangedArgs& other);
+
+ bool operator==(const NotifyPointerCaptureChangedArgs& rhs) const;
+
+ virtual ~NotifyPointerCaptureChangedArgs() {}
+
+ virtual void notify(const sp<InputListenerInterface>& listener) const;
+};
/*
* The interface used by the InputReader to notify the InputListener about input events.
@@ -196,6 +212,7 @@
virtual void notifyMotion(const NotifyMotionArgs* args) = 0;
virtual void notifySwitch(const NotifySwitchArgs* args) = 0;
virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0;
+ virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) = 0;
};
@@ -210,11 +227,12 @@
public:
explicit QueuedInputListener(const sp<InputListenerInterface>& innerListener);
- virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
- virtual void notifyKey(const NotifyKeyArgs* args);
- virtual void notifyMotion(const NotifyMotionArgs* args);
- virtual void notifySwitch(const NotifySwitchArgs* args);
- virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
+ virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
+ virtual void notifyKey(const NotifyKeyArgs* args) override;
+ virtual void notifyMotion(const NotifyMotionArgs* args) override;
+ virtual void notifySwitch(const NotifySwitchArgs* args) override;
+ virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
+ void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
void flush();
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 2028b91..e263f01 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -338,24 +338,30 @@
mPolicy->getReaderConfiguration(&mConfig);
mEventHub->setExcludedDevices(mConfig.excludedDeviceNames);
- if (changes) {
- ALOGI("Reconfiguring input devices, changes=%s",
- InputReaderConfiguration::changesToString(changes).c_str());
- nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+ if (!changes) return;
- if (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO) {
- updatePointerDisplayLocked();
- }
+ ALOGI("Reconfiguring input devices, changes=%s",
+ InputReaderConfiguration::changesToString(changes).c_str());
+ nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) {
- mEventHub->requestReopenDevices();
- } else {
- for (auto& devicePair : mDevices) {
- std::shared_ptr<InputDevice>& device = devicePair.second;
- device->configure(now, &mConfig, changes);
- }
+ if (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO) {
+ updatePointerDisplayLocked();
+ }
+
+ if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) {
+ mEventHub->requestReopenDevices();
+ } else {
+ for (auto& devicePair : mDevices) {
+ std::shared_ptr<InputDevice>& device = devicePair.second;
+ device->configure(now, &mConfig, changes);
}
}
+
+ if (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE) {
+ const NotifyPointerCaptureChangedArgs args(mContext.getNextId(), now,
+ mConfig.pointerCapture);
+ mQueuedListener->notifyPointerCaptureChanged(&args);
+ }
}
void InputReader::updateGlobalMetaStateLocked() {
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index a72d5c3..99eaac6 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -1792,6 +1792,29 @@
mReader->getKeyCodeState(deviceId, AINPUT_SOURCE_KEYBOARD, AKEYCODE_C));
}
+TEST_F(InputReaderTest, ChangingPointerCaptureNotifiesInputListener) {
+ NotifyPointerCaptureChangedArgs args;
+
+ mFakePolicy->setPointerCapture(true);
+ mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+ mReader->loopOnce();
+ mFakeListener->assertNotifyCaptureWasCalled(&args);
+ ASSERT_TRUE(args.enabled) << "Pointer Capture should be enabled.";
+
+ mFakePolicy->setPointerCapture(false);
+ mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+ mReader->loopOnce();
+ mFakeListener->assertNotifyCaptureWasCalled(&args);
+ ASSERT_FALSE(args.enabled) << "Pointer Capture should be disabled.";
+
+ // Verify that the Pointer Capture state is re-configured correctly when the configuration value
+ // does not change.
+ mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+ mReader->loopOnce();
+ mFakeListener->assertNotifyCaptureWasCalled(&args);
+ ASSERT_FALSE(args.enabled) << "Pointer Capture should be disabled.";
+}
+
// --- InputReaderIntegrationTest ---
// These tests create and interact with the InputReader only through its interface.
diff --git a/services/inputflinger/tests/TestInputListener.cpp b/services/inputflinger/tests/TestInputListener.cpp
index 9bff166..352995c 100644
--- a/services/inputflinger/tests/TestInputListener.cpp
+++ b/services/inputflinger/tests/TestInputListener.cpp
@@ -82,6 +82,14 @@
"Expected notifySwitch() to have been called."));
}
+void TestInputListener::assertNotifyCaptureWasCalled(
+ NotifyPointerCaptureChangedArgs* outEventArgs) {
+ ASSERT_NO_FATAL_FAILURE(
+ assertCalled<NotifyPointerCaptureChangedArgs>(outEventArgs,
+ "Expected notifyPointerCaptureChanged() "
+ "to have been called."));
+}
+
template <class NotifyArgsType>
void TestInputListener::assertCalled(NotifyArgsType* outEventArgs, std::string message) {
std::unique_lock<std::mutex> lock(mLock);
@@ -145,4 +153,8 @@
notify<NotifySwitchArgs>(args);
}
+void TestInputListener::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
+ notify<NotifyPointerCaptureChangedArgs>(args);
+}
+
} // namespace android
diff --git a/services/inputflinger/tests/TestInputListener.h b/services/inputflinger/tests/TestInputListener.h
index d50c6bc..887d4ea 100644
--- a/services/inputflinger/tests/TestInputListener.h
+++ b/services/inputflinger/tests/TestInputListener.h
@@ -54,6 +54,8 @@
void assertNotifySwitchWasCalled(NotifySwitchArgs* outEventArgs = nullptr);
+ void assertNotifyCaptureWasCalled(NotifyPointerCaptureChangedArgs* outEventArgs = nullptr);
+
private:
template <class NotifyArgsType>
void assertCalled(NotifyArgsType* outEventArgs, std::string message);
@@ -74,16 +76,19 @@
virtual void notifySwitch(const NotifySwitchArgs* args) override;
+ virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
+
std::mutex mLock;
std::condition_variable mCondition;
const std::chrono::milliseconds mEventHappenedTimeout;
const std::chrono::milliseconds mEventDidNotHappenTimeout;
- std::tuple<std::vector<NotifyConfigurationChangedArgs>, //
- std::vector<NotifyDeviceResetArgs>, //
- std::vector<NotifyKeyArgs>, //
- std::vector<NotifyMotionArgs>, //
- std::vector<NotifySwitchArgs>> //
+ std::tuple<std::vector<NotifyConfigurationChangedArgs>, //
+ std::vector<NotifyDeviceResetArgs>, //
+ std::vector<NotifyKeyArgs>, //
+ std::vector<NotifyMotionArgs>, //
+ std::vector<NotifySwitchArgs>, //
+ std::vector<NotifyPointerCaptureChangedArgs>> //
mQueues GUARDED_BY(mLock);
};
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index deaf846..63dfe5f 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -178,13 +178,17 @@
/// the mStateLock.
ui::Transform::RotationFlags mTransformHint = ui::Transform::ROT_0;
+ bool getAutoRefresh() const { return mAutoRefresh; }
+ bool getSidebandStreamChanged() const { return mSidebandStreamChanged; }
+
+ std::atomic<bool> mAutoRefresh{false};
+ std::atomic<bool> mSidebandStreamChanged{false};
+
private:
virtual bool fenceHasSignaled() const = 0;
virtual bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const = 0;
virtual uint64_t getFrameNumber(nsecs_t expectedPresentTime) const = 0;
- virtual bool getAutoRefresh() const = 0;
- virtual bool getSidebandStreamChanged() const = 0;
// Latch sideband stream and returns true if the dirty region should be updated.
virtual bool latchSidebandStream(bool& recomputeVisibleRegions) = 0;
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 71b05fd..dc99986 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -196,14 +196,6 @@
return frameNumber;
}
-bool BufferQueueLayer::getAutoRefresh() const {
- return mAutoRefresh;
-}
-
-bool BufferQueueLayer::getSidebandStreamChanged() const {
- return mSidebandStreamChanged;
-}
-
bool BufferQueueLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
// We need to update the sideband stream if the layer has both a buffer and a sideband stream.
const bool updateSidebandStream = hasFrameUpdate() && mSidebandStream.get();
@@ -265,8 +257,10 @@
const uint64_t maxFrameNumberToAcquire =
std::min(mLastFrameNumberReceived.load(), lastSignaledFrameNumber);
- status_t updateResult = mConsumer->updateTexImage(&r, expectedPresentTime, &mAutoRefresh,
+ bool autoRefresh;
+ status_t updateResult = mConsumer->updateTexImage(&r, expectedPresentTime, &autoRefresh,
&queuedBuffer, maxFrameNumberToAcquire);
+ mAutoRefresh = autoRefresh;
if (updateResult == BufferQueue::PRESENT_LATER) {
// Producer doesn't want buffer to be displayed yet. Signal a
// layer update so we check again at the next opportunity.
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index fb8a0c2..b45900e 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -90,9 +90,6 @@
private:
uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override;
- bool getAutoRefresh() const override;
- bool getSidebandStreamChanged() const override;
-
bool latchSidebandStream(bool& recomputeVisibleRegions) override;
void setTransformHint(ui::Transform::RotationFlags displayTransformHint) override;
@@ -140,11 +137,8 @@
std::vector<BufferData> mQueueItems;
std::atomic<uint64_t> mLastFrameNumberReceived{0};
- bool mAutoRefresh{false};
-
// thread-safe
std::atomic<int32_t> mQueuedFrames{0};
- std::atomic<bool> mSidebandStreamChanged{false};
sp<ContentsChangedListener> mContentsChangedListener;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index a64b243..963e541 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -482,13 +482,10 @@
return mCurrentState.frameNumber;
}
-bool BufferStateLayer::getAutoRefresh() const {
- // TODO(marissaw): support shared buffer mode
- return false;
-}
-
-bool BufferStateLayer::getSidebandStreamChanged() const {
- return mSidebandStreamChanged.load();
+void BufferStateLayer::setAutoRefresh(bool autoRefresh) {
+ if (!mAutoRefresh.exchange(autoRefresh)) {
+ mFlinger->signalLayerUpdate();
+ }
}
bool BufferStateLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
@@ -526,37 +523,12 @@
return NO_ERROR;
}
- const int32_t layerId = getSequence();
-
- // Reject if the layer is invalid
- uint32_t bufferWidth = s.buffer->width;
- uint32_t bufferHeight = s.buffer->height;
-
- if (s.transform & ui::Transform::ROT_90) {
- std::swap(bufferWidth, bufferHeight);
- }
-
- if (s.transformToDisplayInverse) {
- uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
- if (invTransform & ui::Transform::ROT_90) {
- std::swap(bufferWidth, bufferHeight);
- }
- }
-
- if (getEffectiveScalingMode() == NATIVE_WINDOW_SCALING_MODE_FREEZE &&
- (s.active.w != bufferWidth || s.active.h != bufferHeight)) {
- ALOGE("[%s] rejecting buffer: "
- "bufferWidth=%d, bufferHeight=%d, front.active.{w=%d, h=%d}",
- getDebugName(), bufferWidth, bufferHeight, s.active.w, s.active.h);
- mFlinger->mTimeStats->removeTimeRecord(layerId, mDrawingState.frameNumber);
- return BAD_VALUE;
- }
-
for (auto& handle : mDrawingState.callbackHandles) {
handle->latchTime = latchTime;
handle->frameNumber = mDrawingState.frameNumber;
}
+ const int32_t layerId = getSequence();
mFlinger->mTimeStats->setAcquireFence(layerId, mDrawingState.frameNumber,
std::make_shared<FenceTime>(mDrawingState.acquireFence));
mFlinger->mTimeStats->setLatchTime(layerId, mDrawingState.frameNumber, latchTime);
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 104a13b..42be62a 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -100,6 +100,7 @@
Rect getBufferSize(const State& s) const override;
FloatRect computeSourceBounds(const FloatRect& parentBounds) const override;
Layer::RoundedCornerState getRoundedCornerState() const override;
+ void setAutoRefresh(bool autoRefresh) override;
// -----------------------------------------------------------------------
@@ -123,9 +124,6 @@
uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override;
- bool getAutoRefresh() const override;
- bool getSidebandStreamChanged() const override;
-
bool latchSidebandStream(bool& recomputeVisibleRegions) override;
bool hasFrameUpdate() const override;
@@ -149,8 +147,6 @@
std::unique_ptr<renderengine::Image> mTextureImage;
- std::atomic<bool> mSidebandStreamChanged{false};
-
mutable uint64_t mFrameNumber{0};
uint64_t mFrameCounter{0};
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 4b4c050..901e19a 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -64,7 +64,7 @@
PowerAdvisor::PowerAdvisor()
: mUseUpdateImminentTimer(getUpdateTimeout() > 0),
mUpdateImminentTimer(
- OneShotTimer::Interval(getUpdateTimeout()),
+ "UpdateImminentTimer", OneShotTimer::Interval(getUpdateTimeout()),
/* resetCallback */ [this] { mSendUpdateImminent.store(false); },
/* timeoutCallback */ [this] { mSendUpdateImminent.store(true); }) {
if (mUseUpdateImminentTimer) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 1a784aa..8d67ce5 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -444,6 +444,7 @@
virtual bool setColorSpaceAgnostic(const bool agnostic);
virtual bool setFrameRateSelectionPriority(int32_t priority);
virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint);
+ virtual void setAutoRefresh(bool /* autoRefresh */) {}
// If the variable is not set on the layer, it traverses up the tree to inherit the frame
// rate priority from its parent.
virtual int32_t getFrameRateSelectionPriority() const;
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index b7b7e46..2511eb3 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -175,6 +175,7 @@
mScheduler(scheduler),
mTunables(tunables),
mIdleTimer(
+ "RegionSamplingIdleTimer",
std::chrono::duration_cast<std::chrono::milliseconds>(
mTunables.mSamplingTimerTimeout),
[] {}, [this] { checkForStaleLuma(); }),
diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.cpp b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
index 2783800..ce3b0c6 100644
--- a/services/surfaceflinger/Scheduler/OneShotTimer.cpp
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
@@ -16,6 +16,8 @@
#include "OneShotTimer.h"
+#include <utils/Log.h>
+#include <utils/Timers.h>
#include <chrono>
#include <sstream>
#include <thread>
@@ -29,25 +31,30 @@
// (tv_sec) is the whole count of seconds. The second (tv_nsec) is the
// nanosecond part of the count. This function takes care of translation.
void calculateTimeoutTime(std::chrono::nanoseconds timestamp, timespec* spec) {
- clock_gettime(CLOCK_MONOTONIC, spec);
- spec->tv_sec += static_cast<__kernel_time_t>(timestamp.count() / kNsToSeconds);
- spec->tv_nsec += timestamp.count() % kNsToSeconds;
+ const nsecs_t timeout = systemTime(CLOCK_MONOTONIC) + timestamp.count();
+ spec->tv_sec = static_cast<__kernel_time_t>(timeout / kNsToSeconds);
+ spec->tv_nsec = timeout % kNsToSeconds;
}
} // namespace
namespace android {
namespace scheduler {
-OneShotTimer::OneShotTimer(const Interval& interval, const ResetCallback& resetCallback,
+OneShotTimer::OneShotTimer(std::string name, const Interval& interval,
+ const ResetCallback& resetCallback,
const TimeoutCallback& timeoutCallback)
- : mInterval(interval), mResetCallback(resetCallback), mTimeoutCallback(timeoutCallback) {}
+ : mName(std::move(name)),
+ mInterval(interval),
+ mResetCallback(resetCallback),
+ mTimeoutCallback(timeoutCallback) {}
OneShotTimer::~OneShotTimer() {
stop();
}
void OneShotTimer::start() {
- sem_init(&mSemaphore, 0, 0);
+ int result = sem_init(&mSemaphore, 0, 0);
+ LOG_ALWAYS_FATAL_IF(result, "sem_init failed");
if (!mThread.joinable()) {
// Only create thread if it has not been created.
@@ -57,15 +64,21 @@
void OneShotTimer::stop() {
mStopTriggered = true;
- sem_post(&mSemaphore);
+ int result = sem_post(&mSemaphore);
+ LOG_ALWAYS_FATAL_IF(result, "sem_post failed");
if (mThread.joinable()) {
mThread.join();
- sem_destroy(&mSemaphore);
+ result = sem_destroy(&mSemaphore);
+ LOG_ALWAYS_FATAL_IF(result, "sem_destroy failed");
}
}
void OneShotTimer::loop() {
+ if (pthread_setname_np(pthread_self(), mName.c_str())) {
+ ALOGW("Failed to set thread name on dispatch thread");
+ }
+
TimerState state = TimerState::RESET;
while (true) {
bool triggerReset = false;
@@ -77,7 +90,12 @@
}
if (state == TimerState::IDLE) {
- sem_wait(&mSemaphore);
+ int result = sem_wait(&mSemaphore);
+ if (result && errno != EINTR) {
+ std::stringstream ss;
+ ss << "sem_wait failed (" << errno << ")";
+ LOG_ALWAYS_FATAL("%s", ss.str().c_str());
+ }
continue;
}
@@ -101,7 +119,12 @@
// Wait for mInterval time for semaphore signal.
struct timespec ts;
calculateTimeoutTime(std::chrono::nanoseconds(mInterval), &ts);
- sem_clockwait(&mSemaphore, CLOCK_MONOTONIC, &ts);
+ int result = sem_clockwait(&mSemaphore, CLOCK_MONOTONIC, &ts);
+ if (result && errno != ETIMEDOUT && errno != EINTR) {
+ std::stringstream ss;
+ ss << "sem_clockwait failed (" << errno << ")";
+ LOG_ALWAYS_FATAL("%s", ss.str().c_str());
+ }
state = checkForResetAndStop(state);
if (state == TimerState::RESET) {
@@ -135,7 +158,8 @@
void OneShotTimer::reset() {
mResetTriggered = true;
- sem_post(&mSemaphore);
+ int result = sem_post(&mSemaphore);
+ LOG_ALWAYS_FATAL_IF(result, "sem_post failed");
}
std::string OneShotTimer::dump() const {
diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.h b/services/surfaceflinger/Scheduler/OneShotTimer.h
index 8bbd4f5..3690ce7 100644
--- a/services/surfaceflinger/Scheduler/OneShotTimer.h
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.h
@@ -36,7 +36,7 @@
using ResetCallback = std::function<void()>;
using TimeoutCallback = std::function<void()>;
- OneShotTimer(const Interval& interval, const ResetCallback& resetCallback,
+ OneShotTimer(std::string name, const Interval& interval, const ResetCallback& resetCallback,
const TimeoutCallback& timeoutCallback);
~OneShotTimer();
@@ -81,6 +81,9 @@
// Semaphore to keep mThread synchronized.
sem_t mSemaphore;
+ // Timer's name.
+ std::string mName;
+
// Interval after which timer expires.
const Interval mInterval;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index a14019e..3706631 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -135,7 +135,7 @@
const auto callback = mOptions.supportKernelTimer ? &Scheduler::kernelIdleTimerCallback
: &Scheduler::idleTimerCallback;
mIdleTimer.emplace(
- std::chrono::milliseconds(millis),
+ "IdleTimer", std::chrono::milliseconds(millis),
[this, callback] { std::invoke(callback, this, TimerState::Reset); },
[this, callback] { std::invoke(callback, this, TimerState::Expired); });
mIdleTimer->start();
@@ -144,7 +144,7 @@
if (const int64_t millis = set_touch_timer_ms(0); millis > 0) {
// Touch events are coming to SF every 100ms, so the timer needs to be higher than that
mTouchTimer.emplace(
- std::chrono::milliseconds(millis),
+ "TouchTimer", std::chrono::milliseconds(millis),
[this] { touchTimerCallback(TimerState::Reset); },
[this] { touchTimerCallback(TimerState::Expired); });
mTouchTimer->start();
@@ -152,7 +152,7 @@
if (const int64_t millis = set_display_power_timer_ms(0); millis > 0) {
mDisplayPowerTimer.emplace(
- std::chrono::milliseconds(millis),
+ "DisplayPowerTimer", std::chrono::milliseconds(millis),
[this] { displayPowerTimerCallback(TimerState::Reset); },
[this] { displayPowerTimerCallback(TimerState::Expired); });
mDisplayPowerTimer->start();
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 75d1e6f..a28ed92 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -77,8 +77,12 @@
if (!validate(timestamp)) {
// VSR could elect to ignore the incongruent timestamp or resetModel(). If ts is ignored,
- // don't insert this ts into mTimestamps ringbuffer.
- if (!mTimestamps.empty()) {
+ // don't insert this ts into mTimestamps ringbuffer. If we are still
+ // in the learning phase we should just clear all timestamps and start
+ // over.
+ if (mTimestamps.size() < kMinimumSamplesForPrediction) {
+ clearTimestamps();
+ } else if (!mTimestamps.empty()) {
mKnownTimestamp =
std::max(timestamp, *std::max_element(mTimestamps.begin(), mTimestamps.end()));
} else {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 91f050c..604a83a 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -330,7 +330,7 @@
: mFactory(factory),
mInterceptor(mFactory.createSurfaceInterceptor()),
mTimeStats(std::make_shared<impl::TimeStats>()),
- mFrameTracer(std::make_unique<FrameTracer>()),
+ mFrameTracer(mFactory.createFrameTracer()),
mFrameTimeline(std::make_unique<frametimeline::impl::FrameTimeline>(mTimeStats)),
mEventQueue(mFactory.createMessageQueue()),
mCompositionEngine(mFactory.createCompositionEngine()),
@@ -3796,6 +3796,9 @@
flags |= eTraversalNeeded | eTransformHintUpdateNeeded;
}
}
+ if (what & layer_state_t::eAutoRefreshChanged) {
+ layer->setAutoRefresh(s.autoRefresh);
+ }
// This has to happen after we reparent children because when we reparent to null we remove
// child layers from current state and remove its relative z. If the children are reparented in
// the same transaction, then we have to make sure we reparent the children first so we do not
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index 9a8deae..a93f5f6 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -28,6 +28,7 @@
#include "ContainerLayer.h"
#include "DisplayDevice.h"
#include "EffectLayer.h"
+#include "FrameTracer/FrameTracer.h"
#include "Layer.h"
#include "MonitoredProducer.h"
#include "NativeWindowSurface.h"
@@ -130,6 +131,9 @@
return new EffectLayer(args);
}
+std::unique_ptr<FrameTracer> DefaultFactory::createFrameTracer() {
+ return std::make_unique<FrameTracer>();
+}
} // namespace android::surfaceflinger
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 40774ef..90032d4 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -54,6 +54,7 @@
sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) override;
sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) override;
sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) override;
+ std::unique_ptr<FrameTracer> createFrameTracer() override;
};
} // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 2dd563b..69e9c3c 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -34,6 +34,7 @@
class EffectLayer;
class ContainerLayer;
class DisplayDevice;
+class FrameTracer;
class GraphicBuffer;
class HWComposer;
class IGraphicBufferConsumer;
@@ -100,6 +101,7 @@
virtual sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) = 0;
virtual sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) = 0;
virtual sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) = 0;
+ virtual std::unique_ptr<FrameTracer> createFrameTracer() = 0;
protected:
~Factory() = default;
diff --git a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
index 0208728..cfbb3f5 100644
--- a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
@@ -57,11 +57,12 @@
namespace {
TEST_F(OneShotTimerTest, createAndDestroyTest) {
mIdleTimer = std::make_unique<scheduler::OneShotTimer>(
- 3ms, [] {}, [] {});
+ "TestTimer", 3ms, [] {}, [] {});
}
TEST_F(OneShotTimerTest, startStopTest) {
- mIdleTimer = std::make_unique<scheduler::OneShotTimer>(30ms, mResetTimerCallback.getInvocable(),
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 30ms,
+ mResetTimerCallback.getInvocable(),
mExpiredTimerCallback.getInvocable());
auto startTime = std::chrono::steady_clock::now();
mIdleTimer->start();
@@ -81,7 +82,8 @@
}
TEST_F(OneShotTimerTest, resetTest) {
- mIdleTimer = std::make_unique<scheduler::OneShotTimer>(20ms, mResetTimerCallback.getInvocable(),
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 20ms,
+ mResetTimerCallback.getInvocable(),
mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
@@ -106,7 +108,8 @@
}
TEST_F(OneShotTimerTest, resetBackToBackTest) {
- mIdleTimer = std::make_unique<scheduler::OneShotTimer>(20ms, mResetTimerCallback.getInvocable(),
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 20ms,
+ mResetTimerCallback.getInvocable(),
mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
@@ -137,7 +140,8 @@
}
TEST_F(OneShotTimerTest, startNotCalledTest) {
- mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms,
+ mResetTimerCallback.getInvocable(),
mExpiredTimerCallback.getInvocable());
// The start hasn't happened, so the callback does not happen.
EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
@@ -149,7 +153,8 @@
}
TEST_F(OneShotTimerTest, idleTimerIdlesTest) {
- mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms,
+ mResetTimerCallback.getInvocable(),
mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
@@ -169,7 +174,8 @@
}
TEST_F(OneShotTimerTest, timeoutCallbackExecutionTest) {
- mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms,
+ mResetTimerCallback.getInvocable(),
mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
@@ -178,7 +184,8 @@
}
TEST_F(OneShotTimerTest, noCallbacksAfterStopAndResetTest) {
- mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms,
+ mResetTimerCallback.getInvocable(),
mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
@@ -192,7 +199,8 @@
}
TEST_F(OneShotTimerTest, noCallbacksAfterStopTest) {
- mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 3ms,
+ mResetTimerCallback.getInvocable(),
mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index a9d9dc0..1b6e9ed 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -83,7 +83,7 @@
mTouchTimer.reset();
}
mTouchTimer.emplace(
- std::chrono::milliseconds(millis),
+ "Testable Touch timer", std::chrono::milliseconds(millis),
[this] { touchTimerCallback(TimerState::Reset); },
[this] { touchTimerCallback(TimerState::Expired); });
mTouchTimer->start();
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 6ce738a..eba3f8e 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -30,6 +30,7 @@
#include "DisplayDevice.h"
#include "EffectLayer.h"
#include "FakeVsyncConfiguration.h"
+#include "FrameTracer/FrameTracer.h"
#include "Layer.h"
#include "NativeWindowSurface.h"
#include "Scheduler/MessageQueue.h"
@@ -41,6 +42,7 @@
#include "TestableScheduler.h"
#include "mock/DisplayHardware/MockDisplay.h"
#include "mock/MockDisplayIdGenerator.h"
+#include "mock/MockFrameTracer.h"
namespace android {
@@ -148,6 +150,10 @@
return nullptr;
}
+ std::unique_ptr<FrameTracer> createFrameTracer() override {
+ return std::make_unique<mock::FrameTracer>();
+ }
+
using CreateBufferQueueFunction =
std::function<void(sp<IGraphicBufferProducer>* /* outProducer */,
sp<IGraphicBufferConsumer>* /* outConsumer */,
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index 3d60479..a142022 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -475,6 +475,20 @@
}
}
+TEST_F(VSyncPredictorTest, InconsistentVsyncValueIsFlushedEventually) {
+ EXPECT_TRUE(tracker.addVsyncTimestamp(600));
+ EXPECT_TRUE(tracker.needsMoreSamples());
+
+ EXPECT_FALSE(tracker.addVsyncTimestamp(mNow += mPeriod));
+
+ for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
+ EXPECT_TRUE(tracker.needsMoreSamples());
+ EXPECT_TRUE(tracker.addVsyncTimestamp(mNow += mPeriod));
+ }
+
+ EXPECT_FALSE(tracker.needsMoreSamples());
+}
+
} // namespace android::scheduler
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 4df7b7c..3728731 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -1,6 +1,8 @@
cc_library_shared {
name: "libvr_hwc-hal",
+ system_ext_specific: true,
+
srcs: [
"impl/vr_hwc.cpp",
"impl/vr_composer_client.cpp",
@@ -97,6 +99,7 @@
cc_binary {
name: "vr_hwc",
+ system_ext_specific: true,
vintf_fragments: ["manifest_vr_hwc.xml"],
srcs: [
"vr_hardware_composer_service.cpp",
diff --git a/services/vr/performanced/Android.bp b/services/vr/performanced/Android.bp
index 20301f6..0ef8cc4 100644
--- a/services/vr/performanced/Android.bp
+++ b/services/vr/performanced/Android.bp
@@ -30,6 +30,7 @@
cc_binary {
name: "performanced",
+ system_ext_specific: true,
defaults: ["performanced_defaults"],
srcs: [
"cpu_set.cpp",