Merge "Remove RefBase from InputListener interface"
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index b743f49..0389e57 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -39,6 +39,12 @@
*/
typedef struct AChoreographer AChoreographer;
+struct AChoreographerFrameCallbackData;
+/**
+ * Opaque type that provides access to an AChoreographerFrameCallbackData object.
+ */
+typedef struct AChoreographerFrameCallbackData AChoreographerFrameCallbackData;
+
/**
* Prototype of the function that is called when a new frame is being rendered.
* It's passed the time that the frame is being rendered as nanoseconds in the
@@ -60,6 +66,14 @@
typedef void (*AChoreographer_frameCallback64)(int64_t frameTimeNanos, void* data);
/**
+ * Prototype of the function that is called when a new frame is being rendered.
+ * It's passed the frame data that should not outlive the callback, as well as the data pointer
+ * provided by the application that registered a callback.
+ */
+typedef void (*AChoreographer_extendedFrameCallback)(
+ const AChoreographerFrameCallbackData* callbackData, void* data);
+
+/**
* Prototype of the function that is called when the display refresh rate
* changes. It's passed the new vsync period in nanoseconds, as well as the data
* pointer provided by the application that registered a callback.
@@ -111,6 +125,14 @@
uint32_t delayMillis) __INTRODUCED_IN(29);
/**
+ * Posts a callback to run on the next frame. The data pointer provided will
+ * be passed to the callback function when it's called.
+ */
+void AChoreographer_postExtendedFrameCallback(AChoreographer* choreographer,
+ AChoreographer_extendedFrameCallback callback, void* data)
+ __INTRODUCED_IN(33);
+
+/**
* Registers a callback to be run when the display refresh rate changes. The
* data pointer provided will be passed to the callback function when it's
* called. The same callback may be registered multiple times, provided that a
@@ -160,6 +182,42 @@
AChoreographer_refreshRateCallback, void* data)
__INTRODUCED_IN(30);
+/**
+ * The time in nanoseconds when the frame started being rendered.
+ */
+int64_t AChoreographerFrameCallbackData_getFrameTimeNanos(
+ const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33);
+
+/**
+ * The number of possible frame timelines.
+ */
+size_t AChoreographerFrameCallbackData_getFrameTimelinesLength(
+ const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33);
+
+/**
+ * Get index of the platform-preferred FrameTimeline.
+ */
+size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex(
+ const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33);
+
+/**
+ * The vsync ID token used to map Choreographer data.
+ */
+int64_t AChoreographerFrameCallbackData_getFrameTimelineVsyncId(
+ const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
+
+/**
+ * The time in nanoseconds which the frame at given index is expected to be presented.
+ */
+int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime(
+ const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
+
+/**
+ * The time in nanoseconds which the frame at given index needs to be ready by.
+ */
+int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadline(
+ const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
+
__END_DECLS
#endif // ANDROID_CHOREOGRAPHER_H
diff --git a/include/ftl/initializer_list.h b/include/ftl/initializer_list.h
index 769c09f..2102c25 100644
--- a/include/ftl/initializer_list.h
+++ b/include/ftl/initializer_list.h
@@ -16,6 +16,7 @@
#pragma once
+#include <functional>
#include <tuple>
#include <utility>
@@ -65,18 +66,18 @@
std::tuple<Types...> tuple;
};
-template <typename K, typename V>
+template <typename K, typename V, typename KeyEqual = std::equal_to<K>>
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, std::size_t... Sizes, typename... Types>
-struct InitializerList<KeyValue<K, V>, std::index_sequence<Sizes...>, Types...> {
+template <typename K, typename V, typename E, std::size_t... Sizes, typename... Types>
+struct InitializerList<KeyValue<K, V, E>, 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,
+ KeyValue<K, V, E>, std::index_sequence<Sizes..., 3>, Types..., std::piecewise_construct_t,
std::tuple<K&&>, std::tuple<Args&&...>> {
return {std::tuple_cat(
std::move(tuple),
@@ -94,9 +95,9 @@
return InitializerList<T>{}(std::forward<Args>(args)...);
}
-template <typename K, typename V, typename... Args>
+template <typename K, typename V, typename E = std::equal_to<K>, typename... Args>
[[nodiscard]] constexpr auto map(Args&&... args) {
- return list<KeyValue<K, V>>(std::forward<Args>(args)...);
+ return list<KeyValue<K, V, E>>(std::forward<Args>(args)...);
}
template <typename K, typename V>
diff --git a/include/ftl/small_map.h b/include/ftl/small_map.h
index bcaba82..2effaa4 100644
--- a/include/ftl/small_map.h
+++ b/include/ftl/small_map.h
@@ -61,7 +61,7 @@
//
// assert(map == SmallMap(ftl::init::map(-1, "xyz")(0, "nil")(42, "???")(123, "abc")));
//
-template <typename K, typename V, std::size_t N>
+template <typename K, typename V, std::size_t N, typename KeyEqual = std::equal_to<K>>
class SmallMap final {
using Map = SmallVector<std::pair<const K, V>, N>;
@@ -153,7 +153,7 @@
auto get(const key_type& key, F f) const
-> std::conditional_t<std::is_void_v<R>, bool, std::optional<R>> {
for (auto& [k, v] : *this) {
- if (k == key) {
+ if (KeyEqual{}(k, key)) {
if constexpr (std::is_void_v<R>) {
f(v);
return true;
@@ -237,9 +237,16 @@
//
bool erase(const key_type& key) { return erase(key, begin()); }
+ // Removes all mappings.
+ //
+ // All iterators are invalidated.
+ //
+ void clear() { map_.clear(); }
+
private:
iterator find(const key_type& key, iterator first) {
- return std::find_if(first, end(), [&key](const auto& pair) { return pair.first == key; });
+ return std::find_if(first, end(),
+ [&key](const auto& pair) { return KeyEqual{}(pair.first, key); });
}
bool erase(const key_type& key, iterator first) {
@@ -261,13 +268,13 @@
};
// Deduction guide for in-place constructor.
-template <typename K, typename V, std::size_t... Sizes, typename... Types>
-SmallMap(InitializerList<KeyValue<K, V>, std::index_sequence<Sizes...>, Types...>&&)
- -> SmallMap<K, V, sizeof...(Sizes)>;
+template <typename K, typename V, typename E, std::size_t... Sizes, typename... Types>
+SmallMap(InitializerList<KeyValue<K, V, E>, std::index_sequence<Sizes...>, Types...>&&)
+ -> SmallMap<K, V, sizeof...(Sizes), E>;
// Returns whether the key-value pairs of two maps are equal.
-template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M>
-bool operator==(const SmallMap<K, V, N>& lhs, const SmallMap<Q, W, M>& rhs) {
+template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M, typename E>
+bool operator==(const SmallMap<K, V, N, E>& lhs, const SmallMap<Q, W, M, E>& rhs) {
if (lhs.size() != rhs.size()) return false;
for (const auto& [k, v] : lhs) {
@@ -281,8 +288,8 @@
}
// TODO: Remove in C++20.
-template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M>
-inline bool operator!=(const SmallMap<K, V, N>& lhs, const SmallMap<Q, W, M>& rhs) {
+template <typename K, typename V, std::size_t N, typename Q, typename W, std::size_t M, typename E>
+inline bool operator!=(const SmallMap<K, V, N, E>& lhs, const SmallMap<Q, W, M, E>& rhs) {
return !(lhs == rhs);
}
diff --git a/include/ftl/small_vector.h b/include/ftl/small_vector.h
index 0341435..65a9536 100644
--- a/include/ftl/small_vector.h
+++ b/include/ftl/small_vector.h
@@ -151,8 +151,6 @@
DISPATCH(reference, back, noexcept)
DISPATCH(const_reference, back, const)
-#undef DISPATCH
-
reference operator[](size_type i) {
return dynamic() ? std::get<Dynamic>(vector_)[i] : std::get<Static>(vector_)[i];
}
@@ -214,13 +212,15 @@
//
// The last() and end() iterators are invalidated.
//
- void pop_back() {
- if (dynamic()) {
- std::get<Dynamic>(vector_).pop_back();
- } else {
- std::get<Static>(vector_).pop_back();
- }
- }
+ DISPATCH(void, pop_back, noexcept)
+
+ // Removes all elements.
+ //
+ // All iterators are invalidated.
+ //
+ DISPATCH(void, clear, noexcept)
+
+#undef DISPATCH
// Erases an element, but does not preserve order. Rather than shifting subsequent elements,
// this moves the last element to the slot of the erased element.
@@ -345,6 +345,7 @@
return true;
}
+ using Impl::clear;
using Impl::pop_back;
void unstable_erase(iterator it) {
diff --git a/include/ftl/static_vector.h b/include/ftl/static_vector.h
index 96a1ae8..cd7b92a 100644
--- a/include/ftl/static_vector.h
+++ b/include/ftl/static_vector.h
@@ -189,8 +189,7 @@
}
StaticVector& operator=(StaticVector&& other) {
- std::destroy(begin(), end());
- size_ = 0;
+ clear();
swap<true>(other);
return *this;
}
@@ -280,6 +279,15 @@
//
void pop_back() { unstable_erase(last()); }
+ // Removes all elements.
+ //
+ // All iterators are invalidated.
+ //
+ void clear() {
+ std::destroy(begin(), end());
+ size_ = 0;
+ }
+
// Erases an element, but does not preserve order. Rather than shifting subsequent elements,
// this moves the last element to the slot of the erased element.
//
diff --git a/libs/battery/MultiStateCounter.h b/libs/battery/MultiStateCounter.h
index e1ee07c..03e1f2a 100644
--- a/libs/battery/MultiStateCounter.h
+++ b/libs/battery/MultiStateCounter.h
@@ -62,7 +62,13 @@
void setValue(state_t state, const T& value);
- void updateValue(const T& value, time_t timestamp);
+ /**
+ * Updates the value for the current state and returns the delta from the previously
+ * set value.
+ */
+ const T& updateValue(const T& value, time_t timestamp);
+
+ void addValue(const T& value);
void reset();
@@ -161,7 +167,9 @@
}
template <class T>
-void MultiStateCounter<T>::updateValue(const T& value, time_t timestamp) {
+const T& MultiStateCounter<T>::updateValue(const T& value, time_t timestamp) {
+ T* returnValue = &emptyValue;
+
// If the counter is disabled, we ignore the update, except when the counter got disabled after
// the previous update, in which case we still need to pick up the residual delta.
if (isEnabled || lastUpdateTimestamp < lastStateChangeTimestamp) {
@@ -172,6 +180,7 @@
if (lastUpdateTimestamp >= 0) {
if (timestamp > lastUpdateTimestamp) {
if (delta(lastValue, value, &deltaValue)) {
+ returnValue = &deltaValue;
time_t timeSinceUpdate = timestamp - lastUpdateTimestamp;
for (int i = 0; i < stateCount; i++) {
time_t timeInState = states[i].timeInStateSinceUpdate;
@@ -195,6 +204,16 @@
}
lastValue = value;
lastUpdateTimestamp = timestamp;
+ return *returnValue;
+}
+
+template <class T>
+void MultiStateCounter<T>::addValue(const T& value) {
+ if (!isEnabled) {
+ return;
+ }
+
+ add(&states[currentState].counter, value, 1 /* numerator */, 1 /* denominator */);
}
template <class T>
@@ -242,7 +261,9 @@
} else {
str << " currentState: none";
}
-
+ if (!isEnabled) {
+ str << " disabled";
+ }
return str.str();
}
diff --git a/libs/battery/MultiStateCounterTest.cpp b/libs/battery/MultiStateCounterTest.cpp
index 319ba76..848fd10 100644
--- a/libs/battery/MultiStateCounterTest.cpp
+++ b/libs/battery/MultiStateCounterTest.cpp
@@ -52,11 +52,12 @@
DoubleMultiStateCounter testCounter(3, 0);
testCounter.updateValue(0, 0);
testCounter.setState(1, 0);
- testCounter.updateValue(3.14, 3000);
+ double delta = testCounter.updateValue(3.14, 3000);
EXPECT_DOUBLE_EQ(0, testCounter.getCount(0));
EXPECT_DOUBLE_EQ(3.14, testCounter.getCount(1));
EXPECT_DOUBLE_EQ(0, testCounter.getCount(2));
+ EXPECT_DOUBLE_EQ(3.14, delta);
}
TEST_F(MultiStateCounterTest, stateChange) {
@@ -177,12 +178,31 @@
// Time moves back. The negative delta from 2000 to 1000 is ignored
testCounter.updateValue(8.0, 1000);
- testCounter.updateValue(11.0, 3000);
+ double delta = testCounter.updateValue(11.0, 3000);
// The total accumulated count is:
// 6.0 // For the period 0-2000
// +(11.0-8.0) // For the period 1000-3000
EXPECT_DOUBLE_EQ(9.0, testCounter.getCount(0));
+
+ // 11.0-8.0
+ EXPECT_DOUBLE_EQ(3.0, delta);
+}
+
+TEST_F(MultiStateCounterTest, addValue) {
+ DoubleMultiStateCounter testCounter(1, 0);
+ testCounter.updateValue(0, 0);
+ testCounter.setState(0, 0);
+ testCounter.updateValue(6.0, 2000);
+
+ testCounter.addValue(8.0);
+
+ EXPECT_DOUBLE_EQ(14.0, testCounter.getCount(0));
+
+ testCounter.setEnabled(false, 3000);
+ testCounter.addValue(888.0);
+
+ EXPECT_DOUBLE_EQ(14.0, testCounter.getCount(0));
}
TEST_F(MultiStateCounterTest, toString) {
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 92df874..06542f0 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -48,10 +48,6 @@
// Another arbitrary value a binder count needs to drop below before another callback will be called
uint32_t BpBinder::sBinderProxyCountLowWatermark = 2000;
-// Once the limit has been exceeded, keep calling the limit callback for every this many new proxies
-// created over the limit.
-constexpr uint32_t REPEAT_LIMIT_CALLBACK_INTERVAL = 1000;
-
enum {
LIMIT_REACHED_MASK = 0x80000000, // A flag denoting that the limit has been reached
COUNTING_VALUE_MASK = 0x7FFFFFFF, // A mask of the remaining bits for the count value
@@ -129,7 +125,7 @@
uint32_t lastLimitCallbackAt = sLastLimitCallbackMap[trackedUid];
if (trackedValue > lastLimitCallbackAt &&
- (trackedValue - lastLimitCallbackAt > REPEAT_LIMIT_CALLBACK_INTERVAL)) {
+ (trackedValue - lastLimitCallbackAt > sBinderProxyCountHighWatermark)) {
ALOGE("Still too many binder proxy objects sent to uid %d from uid %d (%d proxies "
"held)",
getuid(), trackedUid, trackedValue);
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 4ecf4b3..07555f6 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -291,6 +291,9 @@
if (status_t status = mSession->state()->onBinderEntering(mSession, addr, &binder);
status != OK)
return status;
+ if (status_t status = mSession->state()->flushExcessBinderRefs(mSession, addr, binder);
+ status != OK)
+ return status;
}
return finishUnflattenBinder(binder, out);
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 5733993..ba2920e 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -205,8 +205,11 @@
}
mShutdownTrigger->trigger();
+
for (auto& [id, session] : mSessions) {
(void)id;
+ // server lock is a more general lock
+ std::lock_guard<std::mutex> _lSession(session->mMutex);
session->mShutdownTrigger->trigger();
}
@@ -275,7 +278,7 @@
RpcConnectionHeader header;
if (status == OK) {
status = client->interruptableReadFully(server->mShutdownTrigger.get(), &header,
- sizeof(header));
+ sizeof(header), {});
if (status != OK) {
ALOGE("Failed to read ID for client connecting to RPC server: %s",
statusToString(status).c_str());
@@ -288,7 +291,7 @@
if (header.sessionIdSize > 0) {
sessionId.resize(header.sessionIdSize);
status = client->interruptableReadFully(server->mShutdownTrigger.get(),
- sessionId.data(), sessionId.size());
+ sessionId.data(), sessionId.size(), {});
if (status != OK) {
ALOGE("Failed to read session ID for client connecting to RPC server: %s",
statusToString(status).c_str());
@@ -313,7 +316,7 @@
};
status = client->interruptableWriteFully(server->mShutdownTrigger.get(), &response,
- sizeof(response));
+ sizeof(response), {});
if (status != OK) {
ALOGE("Failed to send new session response: %s", statusToString(status).c_str());
// still need to cleanup before we can return
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 38958c9..65f6bc6 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -217,15 +217,17 @@
}
status_t RpcSession::sendDecStrong(const BpBinder* binder) {
- return sendDecStrong(binder->getPrivateAccessor().rpcAddress());
+ // target is 0 because this is used to free BpBinder objects
+ return sendDecStrongToTarget(binder->getPrivateAccessor().rpcAddress(), 0 /*target*/);
}
-status_t RpcSession::sendDecStrong(uint64_t address) {
+status_t RpcSession::sendDecStrongToTarget(uint64_t address, size_t target) {
ExclusiveConnection connection;
status_t status = ExclusiveConnection::find(sp<RpcSession>::fromExisting(this),
ConnectionUse::CLIENT_REFCOUNT, &connection);
if (status != OK) return status;
- return state()->sendDecStrong(connection.get(), sp<RpcSession>::fromExisting(this), address);
+ return state()->sendDecStrongToTarget(connection.get(), sp<RpcSession>::fromExisting(this),
+ address, target);
}
status_t RpcSession::readId() {
@@ -558,7 +560,7 @@
}
auto sendHeaderStatus =
- server->interruptableWriteFully(mShutdownTrigger.get(), &header, sizeof(header));
+ server->interruptableWriteFully(mShutdownTrigger.get(), &header, sizeof(header), {});
if (sendHeaderStatus != OK) {
ALOGE("Could not write connection header to socket: %s",
statusToString(sendHeaderStatus).c_str());
@@ -568,7 +570,7 @@
if (sessionId.size() > 0) {
auto sendSessionIdStatus =
server->interruptableWriteFully(mShutdownTrigger.get(), sessionId.data(),
- sessionId.size());
+ sessionId.size(), {});
if (sendSessionIdStatus != OK) {
ALOGE("Could not write session ID ('%s') to socket: %s",
base::HexString(sessionId.data(), sessionId.size()).c_str(),
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index df935fe..86cc91c 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -152,7 +152,7 @@
return BAD_VALUE;
}
- std::unique_lock<std::mutex> _l(mNodeMutex);
+ std::lock_guard<std::mutex> _l(mNodeMutex);
if (mTerminated) return DEAD_OBJECT;
if (auto it = mNodeForAddress.find(address); it != mNodeForAddress.end()) {
@@ -160,13 +160,7 @@
// implicitly have strong RPC refcount, since we received this binder
it->second.timesRecd++;
-
- _l.unlock();
-
- // We have timesRecd RPC refcounts, but we only need to hold on to one
- // when we keep the object. All additional dec strongs are sent
- // immediately, we wait to send the last one in BpBinder::onLastDecStrong.
- return session->sendDecStrong(address);
+ return OK;
}
// we don't know about this binder, so the other side of the connection
@@ -187,6 +181,36 @@
return OK;
}
+status_t RpcState::flushExcessBinderRefs(const sp<RpcSession>& session, uint64_t address,
+ const sp<IBinder>& binder) {
+ std::unique_lock<std::mutex> _l(mNodeMutex);
+ if (mTerminated) return DEAD_OBJECT;
+
+ auto it = mNodeForAddress.find(address);
+
+ LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(), "Can't be deleted while we hold sp<>");
+ LOG_ALWAYS_FATAL_IF(it->second.binder != binder,
+ "Caller of flushExcessBinderRefs using inconsistent arguments");
+
+ // if this is a local binder, then we want to get rid of all refcounts
+ // (tell the other process it can drop the binder when it wants to - we
+ // have a local sp<>, so we will drop it when we want to as well). if
+ // this is a remote binder, then we need to hold onto one refcount until
+ // it is dropped in BpBinder::onLastStrongRef
+ size_t targetRecd = binder->localBinder() ? 0 : 1;
+
+ // We have timesRecd RPC refcounts, but we only need to hold on to one
+ // when we keep the object. All additional dec strongs are sent
+ // immediately, we wait to send the last one in BpBinder::onLastDecStrong.
+ if (it->second.timesRecd != targetRecd) {
+ _l.unlock();
+
+ return session->sendDecStrongToTarget(address, targetRecd);
+ }
+
+ return OK;
+}
+
size_t RpcState::countBinders() {
std::lock_guard<std::mutex> _l(mNodeMutex);
return mNodeForAddress.size();
@@ -283,7 +307,7 @@
status_t RpcState::rpcSend(const sp<RpcSession::RpcConnection>& connection,
const sp<RpcSession>& session, const char* what, const void* data,
- size_t size) {
+ size_t size, const std::function<status_t()>& altPoll) {
LOG_RPC_DETAIL("Sending %s on RpcTransport %p: %s", what, connection->rpcTransport.get(),
android::base::HexString(data, size).c_str());
@@ -295,7 +319,7 @@
if (status_t status =
connection->rpcTransport->interruptableWriteFully(session->mShutdownTrigger.get(),
- data, size);
+ data, size, altPoll);
status != OK) {
LOG_RPC_DETAIL("Failed to write %s (%zu bytes) on RpcTransport %p, error: %s", what, size,
connection->rpcTransport.get(), statusToString(status).c_str());
@@ -317,7 +341,7 @@
if (status_t status =
connection->rpcTransport->interruptableReadFully(session->mShutdownTrigger.get(),
- data, size);
+ data, size, {});
status != OK) {
LOG_RPC_DETAIL("Failed to read %s (%zu bytes) on RpcTransport %p, error: %s", what, size,
connection->rpcTransport.get(), statusToString(status).c_str());
@@ -427,12 +451,16 @@
const sp<IBinder>& binder, uint32_t code, const Parcel& data,
const sp<RpcSession>& session, Parcel* reply, uint32_t flags) {
if (!data.isForRpc()) {
- ALOGE("Refusing to send RPC with parcel not crafted for RPC");
+ ALOGE("Refusing to send RPC with parcel not crafted for RPC call on binder %p code "
+ "%" PRIu32,
+ binder.get(), code);
return BAD_TYPE;
}
if (data.objectsCount() != 0) {
- ALOGE("Parcel at %p has attached objects but is being used in an RPC call", &data);
+ ALOGE("Parcel at %p has attached objects but is being used in an RPC call on binder %p "
+ "code %" PRIu32,
+ &data, binder.get(), code);
return BAD_TYPE;
}
@@ -495,21 +523,44 @@
memcpy(transactionData.data() + sizeof(RpcWireHeader) + sizeof(RpcWireTransaction), data.data(),
data.dataSize());
+ constexpr size_t kWaitMaxUs = 1000000;
+ constexpr size_t kWaitLogUs = 10000;
+ size_t waitUs = 0;
+
+ // Oneway calls have no sync point, so if many are sent before, whether this
+ // is a twoway or oneway transaction, they may have filled up the socket.
+ // So, make sure we drain them before polling.
+ std::function<status_t()> drainRefs = [&] {
+ if (waitUs > kWaitLogUs) {
+ ALOGE("Cannot send command, trying to process pending refcounts. Waiting %zuus. Too "
+ "many oneway calls?",
+ waitUs);
+ }
+
+ if (waitUs > 0) {
+ usleep(waitUs);
+ waitUs = std::min(kWaitMaxUs, waitUs * 2);
+ } else {
+ waitUs = 1;
+ }
+
+ return drainCommands(connection, session, CommandType::CONTROL_ONLY);
+ };
+
if (status_t status = rpcSend(connection, session, "transaction", transactionData.data(),
- transactionData.size());
- status != OK)
+ transactionData.size(), drainRefs);
+ status != OK) {
// TODO(b/167966510): need to undo onBinderLeaving - we know the
// refcount isn't successfully transferred.
return status;
+ }
if (flags & IBinder::FLAG_ONEWAY) {
LOG_RPC_DETAIL("Oneway command, so no longer waiting on RpcTransport %p",
connection->rpcTransport.get());
// Do not wait on result.
- // However, too many oneway calls may cause refcounts to build up and fill up the socket,
- // so process those.
- return drainCommands(connection, session, CommandType::CONTROL_ONLY);
+ return OK;
}
LOG_ALWAYS_FATAL_IF(reply == nullptr, "Reply parcel must be used for synchronous transaction.");
@@ -567,32 +618,43 @@
return OK;
}
-status_t RpcState::sendDecStrong(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session, uint64_t addr) {
+status_t RpcState::sendDecStrongToTarget(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, uint64_t addr,
+ size_t target) {
+ RpcDecStrong body = {
+ .address = RpcWireAddress::fromRaw(addr),
+ };
+
{
std::lock_guard<std::mutex> _l(mNodeMutex);
if (mTerminated) return DEAD_OBJECT; // avoid fatal only, otherwise races
auto it = mNodeForAddress.find(addr);
LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(),
"Sending dec strong on unknown address %" PRIu64, addr);
- LOG_ALWAYS_FATAL_IF(it->second.timesRecd <= 0, "Bad dec strong %" PRIu64, addr);
- it->second.timesRecd--;
+ LOG_ALWAYS_FATAL_IF(it->second.timesRecd < target, "Can't dec count of %zu to %zu.",
+ it->second.timesRecd, target);
+
+ // typically this happens when multiple threads send dec refs at the
+ // same time - the transactions will get combined automatically
+ if (it->second.timesRecd == target) return OK;
+
+ body.amount = it->second.timesRecd - target;
+ it->second.timesRecd = target;
+
LOG_ALWAYS_FATAL_IF(nullptr != tryEraseNode(it),
"Bad state. RpcState shouldn't own received binder");
}
RpcWireHeader cmd = {
.command = RPC_COMMAND_DEC_STRONG,
- .bodySize = sizeof(RpcWireAddress),
+ .bodySize = sizeof(RpcDecStrong),
};
if (status_t status = rpcSend(connection, session, "dec ref header", &cmd, sizeof(cmd));
status != OK)
return status;
- if (status_t status = rpcSend(connection, session, "dec ref body", &addr, sizeof(addr));
- status != OK)
- return status;
- return OK;
+
+ return rpcSend(connection, session, "dec ref body", &body, sizeof(body));
}
status_t RpcState::getAndExecuteCommand(const sp<RpcSession::RpcConnection>& connection,
@@ -684,7 +746,7 @@
// for 'recursive' calls to this, we have already read and processed the
// binder from the transaction data and taken reference counts into account,
// so it is cached here.
- sp<IBinder> targetRef;
+ sp<IBinder> target;
processTransactInternalTailCall:
if (transactionData.size() < sizeof(RpcWireTransaction)) {
@@ -699,12 +761,9 @@
bool oneway = transaction->flags & IBinder::FLAG_ONEWAY;
status_t replyStatus = OK;
- sp<IBinder> target;
if (addr != 0) {
- if (!targetRef) {
+ if (!target) {
replyStatus = onBinderEntering(session, addr, &target);
- } else {
- target = targetRef;
}
if (replyStatus != OK) {
@@ -823,6 +882,12 @@
}
}
+ // Binder refs are flushed for oneway calls only after all calls which are
+ // built up are executed. Otherwise, they fill up the binder buffer.
+ if (addr != 0 && replyStatus == OK && !oneway) {
+ replyStatus = flushExcessBinderRefs(session, addr, target);
+ }
+
if (oneway) {
if (replyStatus != OK) {
ALOGW("Oneway call failed with error: %d", replyStatus);
@@ -865,12 +930,20 @@
// reset up arguments
transactionData = std::move(todo.data);
- targetRef = std::move(todo.ref);
+ LOG_ALWAYS_FATAL_IF(target != todo.ref,
+ "async list should be associated with a binder");
it->second.asyncTodo.pop();
goto processTransactInternalTailCall;
}
}
+
+ // done processing all the async commands on this binder that we can, so
+ // write decstrongs on the binder
+ if (addr != 0 && replyStatus == OK) {
+ return flushExcessBinderRefs(session, addr, target);
+ }
+
return OK;
}
@@ -912,16 +985,15 @@
status != OK)
return status;
- if (command.bodySize != sizeof(RpcWireAddress)) {
- ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcWireAddress. Terminating!",
- sizeof(RpcWireAddress), command.bodySize);
+ if (command.bodySize != sizeof(RpcDecStrong)) {
+ ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcDecStrong. Terminating!",
+ sizeof(RpcDecStrong), command.bodySize);
(void)session->shutdownAndWait(false);
return BAD_VALUE;
}
- RpcWireAddress* address = reinterpret_cast<RpcWireAddress*>(commandData.data());
+ RpcDecStrong* body = reinterpret_cast<RpcDecStrong*>(commandData.data());
- uint64_t addr = RpcWireAddress::toRaw(*address);
-
+ uint64_t addr = RpcWireAddress::toRaw(body->address);
std::unique_lock<std::mutex> _l(mNodeMutex);
auto it = mNodeForAddress.find(addr);
if (it == mNodeForAddress.end()) {
@@ -939,15 +1011,19 @@
return BAD_VALUE;
}
- if (it->second.timesSent == 0) {
- ALOGE("No record of sending binder, but requested decStrong: %" PRIu64, addr);
+ if (it->second.timesSent < body->amount) {
+ ALOGE("Record of sending binder %zu times, but requested decStrong for %" PRIu64 " of %u",
+ it->second.timesSent, addr, body->amount);
return OK;
}
LOG_ALWAYS_FATAL_IF(it->second.sentRef == nullptr, "Inconsistent state, lost ref for %" PRIu64,
addr);
- it->second.timesSent--;
+ LOG_RPC_DETAIL("Processing dec strong of %" PRIu64 " by %u from %zu", addr, body->amount,
+ it->second.timesSent);
+
+ it->second.timesSent -= body->amount;
sp<IBinder> tempHold = tryEraseNode(it);
_l.unlock();
tempHold = nullptr; // destructor may make binder calls on this session
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index dcfb569..50de22b 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -82,8 +82,29 @@
uint64_t address, uint32_t code, const Parcel& data,
const sp<RpcSession>& session, Parcel* reply,
uint32_t flags);
- [[nodiscard]] status_t sendDecStrong(const sp<RpcSession::RpcConnection>& connection,
- const sp<RpcSession>& session, uint64_t address);
+
+ /**
+ * The ownership model here carries an implicit strong refcount whenever a
+ * binder is sent across processes. Since we have a local strong count in
+ * sp<> over these objects, we only ever need to keep one of these. So,
+ * typically we tell the remote process that we drop all the implicit dec
+ * strongs, and we hold onto the last one. 'target' here is the target
+ * timesRecd (the number of remaining reference counts) we wish to keep.
+ * Typically this should be '0' or '1'. The target is used instead of an
+ * explicit decrement count in order to allow multiple threads to lower the
+ * number of counts simultaneously. Since we only lower the count to 0 when
+ * a binder is deleted, targets of '1' should only be sent when the caller
+ * owns a local strong reference to the binder. Larger targets may be used
+ * for testing, and to make the function generic, but generally this should
+ * be avoided because it would be hard to guarantee another thread doesn't
+ * lower the number of held refcounts to '1'. Note also, these refcounts
+ * must be sent actively. If they are sent when binders are deleted, this
+ * can cause leaks, since even remote binders carry an implicit strong ref
+ * when they are sent to another process.
+ */
+ [[nodiscard]] status_t sendDecStrongToTarget(const sp<RpcSession::RpcConnection>& connection,
+ const sp<RpcSession>& session, uint64_t address,
+ size_t target);
enum class CommandType {
ANY,
@@ -108,6 +129,13 @@
*/
[[nodiscard]] status_t onBinderEntering(const sp<RpcSession>& session, uint64_t address,
sp<IBinder>* out);
+ /**
+ * Called on incoming binders to update refcounting information. This should
+ * only be called when it is done as part of making progress on a
+ * transaction.
+ */
+ [[nodiscard]] status_t flushExcessBinderRefs(const sp<RpcSession>& session, uint64_t address,
+ const sp<IBinder>& binder);
size_t countBinders();
void dump();
@@ -149,7 +177,8 @@
[[nodiscard]] status_t rpcSend(const sp<RpcSession::RpcConnection>& connection,
const sp<RpcSession>& session, const char* what,
- const void* data, size_t size);
+ const void* data, size_t size,
+ const std::function<status_t()>& altPoll = nullptr);
[[nodiscard]] status_t rpcRec(const sp<RpcSession::RpcConnection>& connection,
const sp<RpcSession>& session, const char* what, void* data,
size_t size);
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
index 41f4a9f..7669518 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -43,56 +43,72 @@
return ret;
}
- status_t interruptableWriteFully(FdTrigger* fdTrigger, const void* data, size_t size) override {
- const uint8_t* buffer = reinterpret_cast<const uint8_t*>(data);
- const uint8_t* end = buffer + size;
+ template <typename Buffer, typename SendOrReceive>
+ status_t interruptableReadOrWrite(FdTrigger* fdTrigger, Buffer buffer, size_t size,
+ SendOrReceive sendOrReceiveFun, const char* funName,
+ int16_t event, const std::function<status_t()>& altPoll) {
+ const Buffer end = buffer + size;
MAYBE_WAIT_IN_FLAKE_MODE;
- status_t status;
- while ((status = fdTrigger->triggerablePoll(mSocket.get(), POLLOUT)) == OK) {
- ssize_t writeSize =
- TEMP_FAILURE_RETRY(::send(mSocket.get(), buffer, end - buffer, MSG_NOSIGNAL));
- if (writeSize < 0) {
+ // Since we didn't poll, we need to manually check to see if it was triggered. Otherwise, we
+ // may never know we should be shutting down.
+ if (fdTrigger->isTriggered()) {
+ return DEAD_OBJECT;
+ }
+
+ bool havePolled = false;
+ while (true) {
+ ssize_t processSize = TEMP_FAILURE_RETRY(
+ sendOrReceiveFun(mSocket.get(), buffer, end - buffer, MSG_NOSIGNAL));
+
+ if (processSize < 0) {
int savedErrno = errno;
- LOG_RPC_DETAIL("RpcTransport send(): %s", strerror(savedErrno));
- return -savedErrno;
+
+ // Still return the error on later passes, since it would expose
+ // a problem with polling
+ if (havePolled ||
+ (!havePolled && savedErrno != EAGAIN && savedErrno != EWOULDBLOCK)) {
+ LOG_RPC_DETAIL("RpcTransport %s(): %s", funName, strerror(savedErrno));
+ return -savedErrno;
+ }
+ } else if (processSize == 0) {
+ return DEAD_OBJECT;
+ } else {
+ buffer += processSize;
+ if (buffer == end) {
+ return OK;
+ }
}
- if (writeSize == 0) return DEAD_OBJECT;
-
- buffer += writeSize;
- if (buffer == end) return OK;
+ if (altPoll) {
+ if (status_t status = altPoll(); status != OK) return status;
+ if (fdTrigger->isTriggered()) {
+ return DEAD_OBJECT;
+ }
+ } else {
+ if (status_t status = fdTrigger->triggerablePoll(mSocket.get(), event);
+ status != OK)
+ return status;
+ if (!havePolled) havePolled = true;
+ }
}
- return status;
}
- status_t interruptableReadFully(FdTrigger* fdTrigger, void* data, size_t size) override {
- uint8_t* buffer = reinterpret_cast<uint8_t*>(data);
- uint8_t* end = buffer + size;
+ status_t interruptableWriteFully(FdTrigger* fdTrigger, const void* data, size_t size,
+ const std::function<status_t()>& altPoll) override {
+ return interruptableReadOrWrite(fdTrigger, reinterpret_cast<const uint8_t*>(data), size,
+ send, "send", POLLOUT, altPoll);
+ }
- MAYBE_WAIT_IN_FLAKE_MODE;
-
- status_t status;
- while ((status = fdTrigger->triggerablePoll(mSocket.get(), POLLIN)) == OK) {
- ssize_t readSize =
- TEMP_FAILURE_RETRY(::recv(mSocket.get(), buffer, end - buffer, MSG_NOSIGNAL));
- if (readSize < 0) {
- int savedErrno = errno;
- LOG_RPC_DETAIL("RpcTransport recv(): %s", strerror(savedErrno));
- return -savedErrno;
- }
-
- if (readSize == 0) return DEAD_OBJECT; // EOF
-
- buffer += readSize;
- if (buffer == end) return OK;
- }
- return status;
+ status_t interruptableReadFully(FdTrigger* fdTrigger, void* data, size_t size,
+ const std::function<status_t()>& altPoll) override {
+ return interruptableReadOrWrite(fdTrigger, reinterpret_cast<uint8_t*>(data), size, recv,
+ "recv", POLLIN, altPoll);
}
private:
- android::base::unique_fd mSocket;
+ base::unique_fd mSocket;
};
// RpcTransportCtx with TLS disabled.
diff --git a/libs/binder/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp
index f8cd71d..7f810b1 100644
--- a/libs/binder/RpcTransportTls.cpp
+++ b/libs/binder/RpcTransportTls.cpp
@@ -169,12 +169,13 @@
// If |sslError| is WANT_READ / WANT_WRITE, poll for POLLIN / POLLOUT respectively. Otherwise
// return error. Also return error if |fdTrigger| is triggered before or during poll().
status_t pollForSslError(android::base::borrowed_fd fd, int sslError, FdTrigger* fdTrigger,
- const char* fnString, int additionalEvent = 0) {
+ const char* fnString, int additionalEvent,
+ const std::function<status_t()>& altPoll) {
switch (sslError) {
case SSL_ERROR_WANT_READ:
- return handlePoll(POLLIN | additionalEvent, fd, fdTrigger, fnString);
+ return handlePoll(POLLIN | additionalEvent, fd, fdTrigger, fnString, altPoll);
case SSL_ERROR_WANT_WRITE:
- return handlePoll(POLLOUT | additionalEvent, fd, fdTrigger, fnString);
+ return handlePoll(POLLOUT | additionalEvent, fd, fdTrigger, fnString, altPoll);
case SSL_ERROR_SYSCALL: {
auto queue = toString();
LOG_TLS_DETAIL("%s(): %s. Treating as DEAD_OBJECT. Error queue: %s", fnString,
@@ -194,11 +195,17 @@
bool mHandled = false;
status_t handlePoll(int event, android::base::borrowed_fd fd, FdTrigger* fdTrigger,
- const char* fnString) {
- status_t ret = fdTrigger->triggerablePoll(fd, event);
+ const char* fnString, const std::function<status_t()>& altPoll) {
+ status_t ret;
+ if (altPoll) {
+ ret = altPoll();
+ if (fdTrigger->isTriggered()) ret = DEAD_OBJECT;
+ } else {
+ ret = fdTrigger->triggerablePoll(fd, event);
+ }
+
if (ret != OK && ret != DEAD_OBJECT) {
- ALOGE("triggerablePoll error while poll()-ing after %s(): %s", fnString,
- statusToString(ret).c_str());
+ ALOGE("poll error while after %s(): %s", fnString, statusToString(ret).c_str());
}
clear();
return ret;
@@ -268,8 +275,10 @@
RpcTransportTls(android::base::unique_fd socket, Ssl ssl)
: mSocket(std::move(socket)), mSsl(std::move(ssl)) {}
Result<size_t> peek(void* buf, size_t size) override;
- status_t interruptableWriteFully(FdTrigger* fdTrigger, const void* data, size_t size) override;
- status_t interruptableReadFully(FdTrigger* fdTrigger, void* data, size_t size) override;
+ status_t interruptableWriteFully(FdTrigger* fdTrigger, const void* data, size_t size,
+ const std::function<status_t()>& altPoll) override;
+ status_t interruptableReadFully(FdTrigger* fdTrigger, void* data, size_t size,
+ const std::function<status_t()>& altPoll) override;
private:
android::base::unique_fd mSocket;
@@ -295,7 +304,8 @@
}
status_t RpcTransportTls::interruptableWriteFully(FdTrigger* fdTrigger, const void* data,
- size_t size) {
+ size_t size,
+ const std::function<status_t()>& altPoll) {
auto buffer = reinterpret_cast<const uint8_t*>(data);
const uint8_t* end = buffer + size;
@@ -317,8 +327,8 @@
int sslError = mSsl.getError(writeSize);
// TODO(b/195788248): BIO should contain the FdTrigger, and send(2) / recv(2) should be
// triggerablePoll()-ed. Then additionalEvent is no longer necessary.
- status_t pollStatus =
- errorQueue.pollForSslError(mSocket.get(), sslError, fdTrigger, "SSL_write", POLLIN);
+ status_t pollStatus = errorQueue.pollForSslError(mSocket.get(), sslError, fdTrigger,
+ "SSL_write", POLLIN, altPoll);
if (pollStatus != OK) return pollStatus;
// Do not advance buffer. Try SSL_write() again.
}
@@ -326,7 +336,8 @@
return OK;
}
-status_t RpcTransportTls::interruptableReadFully(FdTrigger* fdTrigger, void* data, size_t size) {
+status_t RpcTransportTls::interruptableReadFully(FdTrigger* fdTrigger, void* data, size_t size,
+ const std::function<status_t()>& altPoll) {
auto buffer = reinterpret_cast<uint8_t*>(data);
uint8_t* end = buffer + size;
@@ -350,8 +361,8 @@
return DEAD_OBJECT;
}
int sslError = mSsl.getError(readSize);
- status_t pollStatus =
- errorQueue.pollForSslError(mSocket.get(), sslError, fdTrigger, "SSL_read");
+ status_t pollStatus = errorQueue.pollForSslError(mSocket.get(), sslError, fdTrigger,
+ "SSL_read", 0, altPoll);
if (pollStatus != OK) return pollStatus;
// Do not advance buffer. Try SSL_read() again.
}
@@ -382,7 +393,7 @@
}
int sslError = ssl->getError(ret);
status_t pollStatus =
- errorQueue.pollForSslError(fd, sslError, fdTrigger, "SSL_do_handshake");
+ errorQueue.pollForSslError(fd, sslError, fdTrigger, "SSL_do_handshake", 0, {});
if (pollStatus != OK) return false;
}
}
diff --git a/libs/binder/RpcWireFormat.h b/libs/binder/RpcWireFormat.h
index a87aa07..171550e 100644
--- a/libs/binder/RpcWireFormat.h
+++ b/libs/binder/RpcWireFormat.h
@@ -85,7 +85,7 @@
*/
RPC_COMMAND_REPLY,
/**
- * follows is RpcWireAddress
+ * follows is RpcDecStrong
*
* note - this in the protocol directly instead of as a 'special
* transaction' in order to keep it as lightweight as possible (we don't
@@ -117,6 +117,13 @@
};
static_assert(sizeof(RpcWireHeader) == 16);
+struct RpcDecStrong {
+ RpcWireAddress address;
+ uint32_t amount;
+ uint32_t reserved;
+};
+static_assert(sizeof(RpcDecStrong) == 16);
+
struct RpcWireTransaction {
RpcWireAddress address;
uint32_t code;
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index 6a29c05..12d448d 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -176,7 +176,8 @@
friend RpcState;
explicit RpcSession(std::unique_ptr<RpcTransportCtx> ctx);
- [[nodiscard]] status_t sendDecStrong(uint64_t address);
+ // for 'target', see RpcState::sendDecStrongToTarget
+ [[nodiscard]] status_t sendDecStrongToTarget(uint64_t address, size_t target);
class EventListener : public virtual RefBase {
public:
diff --git a/libs/binder/include/binder/RpcTransport.h b/libs/binder/include/binder/RpcTransport.h
index 4fe2324..db8b5e9 100644
--- a/libs/binder/include/binder/RpcTransport.h
+++ b/libs/binder/include/binder/RpcTransport.h
@@ -18,6 +18,7 @@
#pragma once
+#include <functional>
#include <memory>
#include <string>
@@ -43,14 +44,20 @@
/**
* Read (or write), but allow to be interrupted by a trigger.
*
+ * altPoll - function to be called instead of polling, when needing to wait
+ * to read/write data. If this returns an error, that error is returned from
+ * this function.
+ *
* Return:
* OK - succeeded in completely processing 'size'
* error - interrupted (failure or trigger)
*/
- [[nodiscard]] virtual status_t interruptableWriteFully(FdTrigger *fdTrigger, const void *buf,
- size_t size) = 0;
- [[nodiscard]] virtual status_t interruptableReadFully(FdTrigger *fdTrigger, void *buf,
- size_t size) = 0;
+ [[nodiscard]] virtual status_t interruptableWriteFully(
+ FdTrigger *fdTrigger, const void *buf, size_t size,
+ const std::function<status_t()> &altPoll) = 0;
+ [[nodiscard]] virtual status_t interruptableReadFully(
+ FdTrigger *fdTrigger, void *buf, size_t size,
+ const std::function<status_t()> &altPoll) = 0;
protected:
RpcTransport() = default;
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index e7c3396..a91092e 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -441,6 +441,8 @@
///
/// Registers the given binder object with the given identifier. If successful,
/// this service can then be retrieved using that identifier.
+///
+/// This function will panic if the identifier contains a 0 byte (NUL).
pub fn add_service(identifier: &str, mut binder: SpIBinder) -> Result<()> {
let instance = CString::new(identifier).unwrap();
let status = unsafe {
@@ -462,6 +464,8 @@
///
/// If any service in the process is registered as lazy, all should be, otherwise
/// the process may be shut down while a service is in use.
+///
+/// This function will panic if the identifier contains a 0 byte (NUL).
pub fn register_lazy_service(identifier: &str, mut binder: SpIBinder) -> Result<()> {
let instance = CString::new(identifier).unwrap();
let status = unsafe {
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 71c0e86..680f0ed 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -134,6 +134,37 @@
},
}
+cc_library_static {
+ name: "libbinder_tls_test_utils",
+ host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+ defaults: [
+ "binder_test_defaults",
+ "libbinder_tls_shared_deps",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libbase",
+ "liblog",
+ ],
+ static_libs: [
+ "libbinder_tls_static",
+ ],
+ srcs: [
+ "RpcTlsTestUtils.cpp",
+ ],
+ export_include_dirs: [
+ "include_tls_test_utils",
+ ],
+ visibility: [
+ ":__subpackages__",
+ ],
+}
+
cc_test {
name: "binderRpcTest",
host_supported: true,
@@ -153,8 +184,6 @@
srcs: [
"binderRpcTest.cpp",
- "RpcAuthTesting.cpp",
- "RpcCertificateVerifierSimple.cpp",
],
shared_libs: [
"libbinder",
@@ -166,6 +195,7 @@
],
static_libs: [
"libbinder_tls_static",
+ "libbinder_tls_test_utils",
"binderRpcTestIface-cpp",
"binderRpcTestIface-ndk",
],
@@ -189,7 +219,6 @@
"libbinder_tls_shared_deps",
],
srcs: [
- "RpcAuthTesting.cpp",
"RpcTlsUtilsTest.cpp",
],
shared_libs: [
@@ -199,6 +228,7 @@
"liblog",
],
static_libs: [
+ "libbinder_tls_test_utils",
"libbinder_tls_static",
],
test_suites: ["general-tests", "device-tests"],
@@ -219,7 +249,6 @@
srcs: [
"binderRpcBenchmark.cpp",
"IBinderRpcBenchmark.aidl",
- "RpcAuthTesting.cpp",
],
shared_libs: [
"libbase",
@@ -228,6 +257,7 @@
"libutils",
],
static_libs: [
+ "libbinder_tls_test_utils",
"libbinder_tls_static",
],
}
diff --git a/libs/binder/tests/RpcAuthTesting.h b/libs/binder/tests/RpcAuthTesting.h
deleted file mode 100644
index c3c2df4..0000000
--- a/libs/binder/tests/RpcAuthTesting.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <binder/RpcAuth.h>
-
-namespace android {
-
-constexpr const uint32_t kCertValidSeconds = 30 * (60 * 60 * 24); // 30 days
-bssl::UniquePtr<EVP_PKEY> makeKeyPairForSelfSignedCert();
-bssl::UniquePtr<X509> makeSelfSignedCert(EVP_PKEY* pKey, uint32_t validSeconds);
-
-// An implementation of RpcAuth that generates a key pair and a self-signed
-// certificate every time configure() is called.
-class RpcAuthSelfSigned : public RpcAuth {
-public:
- RpcAuthSelfSigned(uint32_t validSeconds = kCertValidSeconds) : mValidSeconds(validSeconds) {}
- status_t configure(SSL_CTX* ctx) override;
-
-private:
- const uint32_t mValidSeconds;
-};
-
-class RpcAuthPreSigned : public RpcAuth {
-public:
- RpcAuthPreSigned(bssl::UniquePtr<EVP_PKEY> pkey, bssl::UniquePtr<X509> cert)
- : mPkey(std::move(pkey)), mCert(std::move(cert)) {}
- status_t configure(SSL_CTX* ctx) override;
-
-private:
- bssl::UniquePtr<EVP_PKEY> mPkey;
- bssl::UniquePtr<X509> mCert;
-};
-
-} // namespace android
diff --git a/libs/binder/tests/RpcCertificateVerifierSimple.cpp b/libs/binder/tests/RpcCertificateVerifierSimple.cpp
deleted file mode 100644
index 1f74adc..0000000
--- a/libs/binder/tests/RpcCertificateVerifierSimple.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define LOG_TAG "RpcCertificateVerifierSimple"
-#include <log/log.h>
-
-#include <binder/RpcTlsUtils.h>
-
-#include "RpcCertificateVerifierSimple.h"
-
-namespace android {
-
-status_t RpcCertificateVerifierSimple::verify(const SSL* ssl, uint8_t* outAlert) {
- const char* logPrefix = SSL_is_server(ssl) ? "Server" : "Client";
- bssl::UniquePtr<X509> peerCert(SSL_get_peer_certificate(ssl)); // Does not set error queue
- LOG_ALWAYS_FATAL_IF(peerCert == nullptr,
- "%s: libssl should not ask to verify non-existing cert", logPrefix);
-
- std::lock_guard<std::mutex> lock(mMutex);
- for (const auto& trustedCert : mTrustedPeerCertificates) {
- if (0 == X509_cmp(trustedCert.get(), peerCert.get())) {
- return OK;
- }
- }
- *outAlert = SSL_AD_CERTIFICATE_UNKNOWN;
- return PERMISSION_DENIED;
-}
-
-status_t RpcCertificateVerifierSimple::addTrustedPeerCertificate(RpcCertificateFormat format,
- const std::vector<uint8_t>& cert) {
- bssl::UniquePtr<X509> x509 = deserializeCertificate(cert, format);
- if (x509 == nullptr) {
- ALOGE("Certificate is not in the proper format %s", PrintToString(format).c_str());
- return BAD_VALUE;
- }
- std::lock_guard<std::mutex> lock(mMutex);
- mTrustedPeerCertificates.push_back(std::move(x509));
- return OK;
-}
-
-} // namespace android
diff --git a/libs/binder/tests/RpcAuthTesting.cpp b/libs/binder/tests/RpcTlsTestUtils.cpp
similarity index 72%
rename from libs/binder/tests/RpcAuthTesting.cpp
rename to libs/binder/tests/RpcTlsTestUtils.cpp
index c0587a2..6119313 100644
--- a/libs/binder/tests/RpcAuthTesting.cpp
+++ b/libs/binder/tests/RpcTlsTestUtils.cpp
@@ -13,7 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "RpcAuthTesting.h"
+
+#define LOG_TAG "RpcTlsTestUtils"
+#include <log/log.h>
+
+#include <binder/RpcTlsTestUtils.h>
+
+#include <binder/RpcTlsUtils.h>
+
#include "../Utils.h" // for TEST_AND_RETURN
namespace android {
@@ -80,4 +87,32 @@
return OK;
}
+status_t RpcCertificateVerifierSimple::verify(const SSL* ssl, uint8_t* outAlert) {
+ const char* logPrefix = SSL_is_server(ssl) ? "Server" : "Client";
+ bssl::UniquePtr<X509> peerCert(SSL_get_peer_certificate(ssl)); // Does not set error queue
+ LOG_ALWAYS_FATAL_IF(peerCert == nullptr,
+ "%s: libssl should not ask to verify non-existing cert", logPrefix);
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ for (const auto& trustedCert : mTrustedPeerCertificates) {
+ if (0 == X509_cmp(trustedCert.get(), peerCert.get())) {
+ return OK;
+ }
+ }
+ *outAlert = SSL_AD_CERTIFICATE_UNKNOWN;
+ return PERMISSION_DENIED;
+}
+
+status_t RpcCertificateVerifierSimple::addTrustedPeerCertificate(RpcCertificateFormat format,
+ const std::vector<uint8_t>& cert) {
+ bssl::UniquePtr<X509> x509 = deserializeCertificate(cert, format);
+ if (x509 == nullptr) {
+ ALOGE("Certificate is not in the proper format %s", PrintToString(format).c_str());
+ return BAD_VALUE;
+ }
+ std::lock_guard<std::mutex> lock(mMutex);
+ mTrustedPeerCertificates.push_back(std::move(x509));
+ return OK;
+}
+
} // namespace android
diff --git a/libs/binder/tests/RpcTlsUtilsTest.cpp b/libs/binder/tests/RpcTlsUtilsTest.cpp
index 9b3078d..530606c 100644
--- a/libs/binder/tests/RpcTlsUtilsTest.cpp
+++ b/libs/binder/tests/RpcTlsUtilsTest.cpp
@@ -14,11 +14,10 @@
* limitations under the License.
*/
+#include <binder/RpcTlsTestUtils.h>
#include <binder/RpcTlsUtils.h>
#include <gtest/gtest.h>
-#include "RpcAuthTesting.h"
-
namespace android {
std::string toDebugString(EVP_PKEY* pkey) {
diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp
index 0477d50..6bf6e92 100644
--- a/libs/binder/tests/binderRpcBenchmark.cpp
+++ b/libs/binder/tests/binderRpcBenchmark.cpp
@@ -25,6 +25,7 @@
#include <binder/RpcCertificateVerifier.h>
#include <binder/RpcServer.h>
#include <binder/RpcSession.h>
+#include <binder/RpcTlsTestUtils.h>
#include <binder/RpcTlsUtils.h>
#include <binder/RpcTransportRaw.h>
#include <binder/RpcTransportTls.h>
@@ -37,8 +38,6 @@
#include <sys/types.h>
#include <unistd.h>
-#include "RpcAuthTesting.h"
-
using android::BBinder;
using android::defaultServiceManager;
using android::IBinder;
@@ -50,6 +49,7 @@
using android::RpcAuthPreSigned;
using android::RpcCertificateFormat;
using android::RpcCertificateVerifier;
+using android::RpcCertificateVerifierNoOp;
using android::RpcServer;
using android::RpcSession;
using android::RpcTransportCtxFactory;
@@ -90,13 +90,6 @@
Transport::RPC_TLS,
};
-// Certificate validation happens during handshake and does not affect the result of benchmarks.
-// Skip certificate validation to simplify the setup process.
-class RpcCertificateVerifierNoOp : public RpcCertificateVerifier {
-public:
- status_t verify(const SSL*, uint8_t*) override { return OK; }
-};
-
std::unique_ptr<RpcTransportCtxFactory> makeFactoryTls() {
auto pkey = android::makeKeyPairForSelfSignedCert();
CHECK_NE(pkey.get(), nullptr);
@@ -109,6 +102,8 @@
}
static sp<RpcSession> gSession = RpcSession::make();
+// Certificate validation happens during handshake and does not affect the result of benchmarks.
+// Skip certificate validation to simplify the setup process.
static sp<RpcSession> gSessionTls = RpcSession::make(makeFactoryTls());
#ifdef __BIONIC__
static const String16 kKernelBinderInstance = String16(u"binderRpcBenchmark-control");
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index aad0162..a1058bc 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -31,6 +31,7 @@
#include <binder/ProcessState.h>
#include <binder/RpcServer.h>
#include <binder/RpcSession.h>
+#include <binder/RpcTlsTestUtils.h>
#include <binder/RpcTlsUtils.h>
#include <binder/RpcTransport.h>
#include <binder/RpcTransportRaw.h>
@@ -51,8 +52,6 @@
#include "../RpcSocketAddress.h" // for testing preconnected clients
#include "../RpcState.h" // for debugging
#include "../vm_sockets.h" // for VMADDR_*
-#include "RpcAuthTesting.h"
-#include "RpcCertificateVerifierSimple.h"
using namespace std::chrono_literals;
using namespace std::placeholders;
@@ -1574,7 +1573,7 @@
FdTrigger* fdTrigger) {
std::string message(kMessage);
auto status = serverTransport->interruptableWriteFully(fdTrigger, message.data(),
- message.size());
+ message.size(), {});
if (status != OK) return AssertionFailure() << statusToString(status);
return AssertionSuccess();
}
@@ -1607,7 +1606,7 @@
std::string readMessage(expectedMessage.size(), '\0');
status_t readStatus =
mClientTransport->interruptableReadFully(mFdTrigger.get(), readMessage.data(),
- readMessage.size());
+ readMessage.size(), {});
if (readStatus != OK) {
return AssertionFailure() << statusToString(readStatus);
}
@@ -1801,8 +1800,8 @@
bool shouldContinueWriting = false;
auto serverPostConnect = [&](RpcTransport* serverTransport, FdTrigger* fdTrigger) {
std::string message(RpcTransportTestUtils::kMessage);
- auto status =
- serverTransport->interruptableWriteFully(fdTrigger, message.data(), message.size());
+ auto status = serverTransport->interruptableWriteFully(fdTrigger, message.data(),
+ message.size(), {});
if (status != OK) return AssertionFailure() << statusToString(status);
{
@@ -1812,7 +1811,7 @@
}
}
- status = serverTransport->interruptableWriteFully(fdTrigger, msg2.data(), msg2.size());
+ status = serverTransport->interruptableWriteFully(fdTrigger, msg2.data(), msg2.size(), {});
if (status != DEAD_OBJECT)
return AssertionFailure() << "When FdTrigger is shut down, interruptableWriteFully "
"should return DEAD_OBJECT, but it is "
diff --git a/libs/binder/tests/RpcCertificateVerifierSimple.h b/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h
similarity index 60%
rename from libs/binder/tests/RpcCertificateVerifierSimple.h
rename to libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h
index bdb2426..cbf11bf 100644
--- a/libs/binder/tests/RpcCertificateVerifierSimple.h
+++ b/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h
@@ -16,17 +16,44 @@
#pragma once
+#include <memory>
#include <mutex>
-#include <string_view>
-#include <vector>
-#include <openssl/ssl.h>
-
+#include <binder/RpcAuth.h>
#include <binder/RpcCertificateFormat.h>
#include <binder/RpcCertificateVerifier.h>
+#include <binder/RpcTransport.h>
+#include <openssl/ssl.h>
+#include <utils/Errors.h>
namespace android {
+constexpr const uint32_t kCertValidSeconds = 30 * (60 * 60 * 24); // 30 days
+bssl::UniquePtr<EVP_PKEY> makeKeyPairForSelfSignedCert();
+bssl::UniquePtr<X509> makeSelfSignedCert(EVP_PKEY* pKey, uint32_t validSeconds);
+
+// An implementation of RpcAuth that generates a key pair and a self-signed
+// certificate every time configure() is called.
+class RpcAuthSelfSigned : public RpcAuth {
+public:
+ RpcAuthSelfSigned(uint32_t validSeconds = kCertValidSeconds) : mValidSeconds(validSeconds) {}
+ status_t configure(SSL_CTX* ctx) override;
+
+private:
+ const uint32_t mValidSeconds;
+};
+
+class RpcAuthPreSigned : public RpcAuth {
+public:
+ RpcAuthPreSigned(bssl::UniquePtr<EVP_PKEY> pkey, bssl::UniquePtr<X509> cert)
+ : mPkey(std::move(pkey)), mCert(std::move(cert)) {}
+ status_t configure(SSL_CTX* ctx) override;
+
+private:
+ bssl::UniquePtr<EVP_PKEY> mPkey;
+ bssl::UniquePtr<X509> mCert;
+};
+
// A simple certificate verifier for testing.
// Keep a list of leaf certificates as trusted. No certificate chain support.
//
@@ -50,4 +77,10 @@
std::vector<bssl::UniquePtr<X509>> mTrustedPeerCertificates;
};
+// A RpcCertificateVerifier that does not verify anything.
+class RpcCertificateVerifierNoOp : public RpcCertificateVerifier {
+public:
+ status_t verify(const SSL*, uint8_t*) override { return OK; }
+};
+
} // namespace android
diff --git a/libs/ftl/small_map_test.cpp b/libs/ftl/small_map_test.cpp
index 2e81022..ee650e5 100644
--- a/libs/ftl/small_map_test.cpp
+++ b/libs/ftl/small_map_test.cpp
@@ -345,4 +345,41 @@
}
}
+TEST(SmallMap, Clear) {
+ SmallMap map = ftl::init::map(1, '1')(2, '2')(3, '3');
+
+ map.clear();
+
+ EXPECT_TRUE(map.empty());
+ EXPECT_FALSE(map.dynamic());
+
+ map = ftl::init::map(1, '1')(2, '2')(3, '3');
+ map.try_emplace(4, '4');
+
+ map.clear();
+
+ EXPECT_TRUE(map.empty());
+ EXPECT_TRUE(map.dynamic());
+}
+
+TEST(SmallMap, KeyEqual) {
+ struct KeyEqual {
+ bool operator()(int lhs, int rhs) const { return lhs % 10 == rhs % 10; }
+ };
+
+ SmallMap<int, char, 1, KeyEqual> map;
+
+ EXPECT_TRUE(map.try_emplace(3, '3').second);
+ EXPECT_FALSE(map.try_emplace(13, '3').second);
+
+ EXPECT_TRUE(map.try_emplace(22, '2').second);
+ EXPECT_TRUE(map.contains(42));
+
+ EXPECT_TRUE(map.try_emplace(111, '1').second);
+ EXPECT_EQ(map.get(321), '1');
+
+ map.erase(123);
+ EXPECT_EQ(map, SmallMap(ftl::init::map<int, char, KeyEqual>(1, '1')(2, '2')));
+}
+
} // namespace android::test
diff --git a/libs/ftl/small_vector_test.cpp b/libs/ftl/small_vector_test.cpp
index 3a03e69..4237496 100644
--- a/libs/ftl/small_vector_test.cpp
+++ b/libs/ftl/small_vector_test.cpp
@@ -460,4 +460,34 @@
EXPECT_EQ(0, dead);
}
+TEST(SmallVector, Clear) {
+ int live = 0;
+ int dead = 0;
+
+ SmallVector<DestroyCounts, 2> counts;
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+
+ counts.clear();
+
+ EXPECT_TRUE(counts.empty());
+ EXPECT_FALSE(counts.dynamic());
+
+ EXPECT_EQ(2, live);
+ EXPECT_EQ(0, dead);
+
+ live = 0;
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+
+ counts.clear();
+
+ EXPECT_TRUE(counts.empty());
+ EXPECT_TRUE(counts.dynamic());
+
+ EXPECT_EQ(3, live);
+ EXPECT_EQ(2, dead);
+}
+
} // namespace android::test
diff --git a/libs/ftl/static_vector_test.cpp b/libs/ftl/static_vector_test.cpp
index cbe8dff..2de3ad2 100644
--- a/libs/ftl/static_vector_test.cpp
+++ b/libs/ftl/static_vector_test.cpp
@@ -396,4 +396,19 @@
EXPECT_EQ(0, dead);
}
+TEST(StaticVector, Clear) {
+ int live = 0;
+ int dead = 0;
+
+ StaticVector<DestroyCounts, 5> counts;
+ counts.emplace_back(live, dead);
+ counts.emplace_back(live, dead);
+
+ counts.clear();
+
+ EXPECT_TRUE(counts.empty());
+ EXPECT_EQ(2, live);
+ EXPECT_EQ(0, dead);
+}
+
} // namespace android::test
diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp
index cda9e19..6afd172 100644
--- a/libs/gralloc/types/Android.bp
+++ b/libs/gralloc/types/Android.bp
@@ -33,7 +33,7 @@
target: {
darwin: {
enabled: false,
- }
+ },
},
vendor_available: true,
@@ -48,18 +48,18 @@
min_sdk_version: "29",
srcs: [
- "Gralloc4.cpp"
+ "Gralloc4.cpp",
],
shared_libs: [
- "android.hardware.graphics.common-V2-ndk",
+ "android.hardware.graphics.common-V3-ndk",
"android.hardware.graphics.mapper@4.0",
"libhidlbase",
"liblog",
],
export_shared_lib_headers: [
- "android.hardware.graphics.common-V2-ndk",
+ "android.hardware.graphics.common-V3-ndk",
"android.hardware.graphics.mapper@4.0",
"libhidlbase",
],
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index e1b1efc..6f1a7ae 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -153,6 +153,7 @@
outVsyncEventData->id = ev.vsync.vsyncId;
outVsyncEventData->deadlineTimestamp = ev.vsync.deadlineTimestamp;
outVsyncEventData->frameInterval = ev.vsync.frameInterval;
+ outVsyncEventData->expectedPresentTime = ev.vsync.expectedVSyncTimestamp;
break;
case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected);
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index 4ade240..f3bd139 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -33,6 +33,9 @@
// The current frame interval in ns when this frame was scheduled.
int64_t frameInterval = 0;
+
+ // The anticipated Vsync present time.
+ int64_t expectedPresentTime = 0;
};
class DisplayEventDispatcher : public LooperCallback {
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 78a8b42..16208a7 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -220,7 +220,7 @@
t.apply(true);
}
- void requestFocus() {
+ void requestFocus(int displayId = ADISPLAY_ID_DEFAULT) {
SurfaceComposerClient::Transaction t;
FocusRequest request;
request.token = mInputInfo.token;
@@ -228,7 +228,7 @@
request.focusedToken = nullptr;
request.focusedWindowName = "";
request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
- request.displayId = 0;
+ request.displayId = displayId;
t.setFocusedWindow(request);
t.apply(true);
}
@@ -255,11 +255,6 @@
mInputInfo.touchableRegion.orSelf(Rect(0, 0, width, height));
- // TODO: Fill in from SF?
- mInputInfo.ownerPid = 11111;
- mInputInfo.ownerUid = 11111;
- mInputInfo.displayId = 0;
-
InputApplicationInfo aInfo;
aInfo.token = new BBinder();
aInfo.name = "Test app info";
@@ -373,21 +368,31 @@
int32_t mBufferPostDelay;
};
-void injectTap(int x, int y) {
- char *buf1, *buf2;
+void injectTapOnDisplay(int x, int y, int displayId) {
+ char *buf1, *buf2, *bufDisplayId;
asprintf(&buf1, "%d", x);
asprintf(&buf2, "%d", y);
+ asprintf(&bufDisplayId, "%d", displayId);
if (fork() == 0) {
- execlp("input", "input", "tap", buf1, buf2, NULL);
+ execlp("input", "input", "-d", bufDisplayId, "tap", buf1, buf2, NULL);
+ }
+}
+
+void injectTap(int x, int y) {
+ injectTapOnDisplay(x, y, ADISPLAY_ID_DEFAULT);
+}
+
+void injectKeyOnDisplay(uint32_t keycode, int displayId) {
+ char *buf1, *bufDisplayId;
+ asprintf(&buf1, "%d", keycode);
+ asprintf(&bufDisplayId, "%d", displayId);
+ if (fork() == 0) {
+ execlp("input", "input", "-d", bufDisplayId, "keyevent", buf1, NULL);
}
}
void injectKey(uint32_t keycode) {
- char *buf1;
- asprintf(&buf1, "%d", keycode);
- if (fork() == 0) {
- execlp("input", "input", "keyevent", buf1, NULL);
- }
+ injectKeyOnDisplay(keycode, ADISPLAY_ID_NONE);
}
TEST_F(InputSurfacesTest, can_receive_input) {
@@ -946,4 +951,74 @@
injectKey(AKEYCODE_V);
EXPECT_EQ(surface->consumeEvent(100), nullptr);
}
+
+class MultiDisplayTests : public InputSurfacesTest {
+public:
+ MultiDisplayTests() : InputSurfacesTest() { ProcessState::self()->startThreadPool(); }
+ void TearDown() {
+ if (mVirtualDisplay) {
+ SurfaceComposerClient::destroyDisplay(mVirtualDisplay);
+ }
+ InputSurfacesTest::TearDown();
+ }
+
+ void createDisplay(int32_t width, int32_t height, bool isSecure, ui::LayerStack layerStack) {
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&mProducer, &consumer);
+ consumer->setConsumerName(String8("Virtual disp consumer"));
+ consumer->setDefaultBufferSize(width, height);
+
+ mVirtualDisplay = SurfaceComposerClient::createDisplay(String8("VirtualDisplay"), isSecure);
+ SurfaceComposerClient::Transaction t;
+ t.setDisplaySurface(mVirtualDisplay, mProducer);
+ t.setDisplayFlags(mVirtualDisplay, 0x01 /* DisplayDevice::eReceivesInput */);
+ t.setDisplayLayerStack(mVirtualDisplay, layerStack);
+ t.apply(true);
+ }
+
+ sp<IBinder> mVirtualDisplay;
+ sp<IGraphicBufferProducer> mProducer;
+};
+
+TEST_F(MultiDisplayTests, drop_input_for_secure_layer_on_nonsecure_display) {
+ ui::LayerStack layerStack = ui::LayerStack::fromValue(42);
+ createDisplay(1000, 1000, false /*isSecure*/, layerStack);
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->doTransaction([&](auto &t, auto &sc) {
+ t.setFlags(sc, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure);
+ t.setLayerStack(sc, layerStack);
+ });
+ surface->showAt(100, 100);
+
+ injectTap(101, 101);
+
+ EXPECT_EQ(surface->consumeEvent(100), nullptr);
+
+ surface->requestFocus(layerStack.id);
+ surface->assertFocusChange(true);
+ injectKeyOnDisplay(AKEYCODE_V, layerStack.id);
+ EXPECT_EQ(surface->consumeEvent(100), nullptr);
+}
+
+TEST_F(MultiDisplayTests, dont_drop_input_for_secure_layer_on_secure_display) {
+ ui::LayerStack layerStack = ui::LayerStack::fromValue(42);
+ createDisplay(1000, 1000, true /*isSecure*/, layerStack);
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->doTransaction([&](auto &t, auto &sc) {
+ t.setFlags(sc, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure);
+ t.setLayerStack(sc, layerStack);
+ });
+ surface->showAt(100, 100);
+
+ injectTapOnDisplay(101, 101, layerStack.id);
+ EXPECT_NE(surface->consumeEvent(), nullptr);
+ EXPECT_NE(surface->consumeEvent(), nullptr);
+
+ surface->requestFocus(layerStack.id);
+ surface->assertFocusChange(true);
+ injectKeyOnDisplay(AKEYCODE_V, layerStack.id);
+
+ surface->expectKey(AKEYCODE_V);
+}
+
} // namespace android::test
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index ba71960..4c4a34f 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -77,6 +77,7 @@
struct FrameCallback {
AChoreographer_frameCallback callback;
AChoreographer_frameCallback64 callback64;
+ AChoreographer_extendedFrameCallback extendedCallback;
void* data;
nsecs_t dueTime;
@@ -95,6 +96,27 @@
class Choreographer;
+/**
+ * Implementation of AChoreographerFrameCallbackData.
+ */
+struct ChoreographerFrameCallbackDataImpl {
+ struct FrameTimeline {
+ int64_t vsyncId{0};
+ int64_t expectedPresentTimeNanos{0};
+ int64_t deadlineNanos{0};
+ };
+
+ int64_t frameTimeNanos{0};
+
+ size_t frameTimelinesLength;
+
+ std::vector<FrameTimeline> frameTimelines;
+
+ size_t preferredFrameTimelineIndex;
+
+ const Choreographer* choreographer;
+};
+
struct {
std::mutex lock;
std::vector<Choreographer*> ptrs GUARDED_BY(lock);
@@ -107,7 +129,9 @@
public:
explicit Choreographer(const sp<Looper>& looper) EXCLUDES(gChoreographers.lock);
void postFrameCallbackDelayed(AChoreographer_frameCallback cb,
- AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay);
+ AChoreographer_frameCallback64 cb64,
+ AChoreographer_extendedFrameCallback extendedCallback, void* data,
+ nsecs_t delay);
void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data)
EXCLUDES(gChoreographers.lock);
void unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data);
@@ -130,6 +154,7 @@
int64_t getVsyncId() const;
int64_t getFrameDeadline() const;
int64_t getFrameInterval() const;
+ bool inCallback() const;
private:
Choreographer(const Choreographer&) = delete;
@@ -145,6 +170,8 @@
void scheduleCallbacks();
+ ChoreographerFrameCallbackDataImpl createFrameCallbackData(nsecs_t timestamp) const;
+
std::mutex mLock;
// Protected by mLock
std::priority_queue<FrameCallback> mFrameCallbacks;
@@ -152,6 +179,7 @@
nsecs_t mLatestVsyncPeriod = -1;
VsyncEventData mLastVsyncEventData;
+ bool mInCallback = false;
const sp<Looper> mLooper;
const std::thread::id mThreadId;
@@ -211,10 +239,12 @@
}
}
-void Choreographer::postFrameCallbackDelayed(
- AChoreographer_frameCallback cb, AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay) {
+void Choreographer::postFrameCallbackDelayed(AChoreographer_frameCallback cb,
+ AChoreographer_frameCallback64 cb64,
+ AChoreographer_extendedFrameCallback extendedCallback,
+ void* data, nsecs_t delay) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- FrameCallback callback{cb, cb64, data, now + delay};
+ FrameCallback callback{cb, cb64, extendedCallback, data, now + delay};
{
std::lock_guard<std::mutex> _l{mLock};
mFrameCallbacks.push(callback);
@@ -370,7 +400,15 @@
}
mLastVsyncEventData = vsyncEventData;
for (const auto& cb : callbacks) {
- if (cb.callback64 != nullptr) {
+ if (cb.extendedCallback != nullptr) {
+ const ChoreographerFrameCallbackDataImpl frameCallbackData =
+ createFrameCallbackData(timestamp);
+ mInCallback = true;
+ cb.extendedCallback(reinterpret_cast<const AChoreographerFrameCallbackData*>(
+ &frameCallbackData),
+ cb.data);
+ mInCallback = false;
+ } else if (cb.callback64 != nullptr) {
cb.callback64(timestamp, cb.data);
} else if (cb.callback != nullptr) {
cb.callback(timestamp, cb.data);
@@ -379,8 +417,8 @@
}
void Choreographer::dispatchHotplug(nsecs_t, PhysicalDisplayId displayId, bool connected) {
- ALOGV("choreographer %p ~ received hotplug event (displayId=%s, connected=%s), ignoring.",
- this, to_string(displayId).c_str(), toString(connected));
+ ALOGV("choreographer %p ~ received hotplug event (displayId=%s, connected=%s), ignoring.", this,
+ to_string(displayId).c_str(), toString(connected));
}
void Choreographer::dispatchModeChanged(nsecs_t, PhysicalDisplayId, int32_t, nsecs_t) {
@@ -399,15 +437,15 @@
void Choreographer::handleMessage(const Message& message) {
switch (message.what) {
- case MSG_SCHEDULE_CALLBACKS:
- scheduleCallbacks();
- break;
- case MSG_SCHEDULE_VSYNC:
- scheduleVsync();
- break;
- case MSG_HANDLE_REFRESH_RATE_UPDATES:
- handleRefreshRateUpdates();
- break;
+ case MSG_SCHEDULE_CALLBACKS:
+ scheduleCallbacks();
+ break;
+ case MSG_SCHEDULE_VSYNC:
+ scheduleVsync();
+ break;
+ case MSG_HANDLE_REFRESH_RATE_UPDATES:
+ handleRefreshRateUpdates();
+ break;
}
}
@@ -423,6 +461,22 @@
return mLastVsyncEventData.frameInterval;
}
+bool Choreographer::inCallback() const {
+ return mInCallback;
+}
+
+ChoreographerFrameCallbackDataImpl Choreographer::createFrameCallbackData(nsecs_t timestamp) const {
+ std::vector<ChoreographerFrameCallbackDataImpl::FrameTimeline> frameTimelines;
+ frameTimelines.push_back({.vsyncId = mLastVsyncEventData.id,
+ .expectedPresentTimeNanos = mLastVsyncEventData.expectedPresentTime,
+ .deadlineNanos = mLastVsyncEventData.deadlineTimestamp});
+ return {.frameTimeNanos = timestamp,
+ .frameTimelinesLength = 1,
+ .preferredFrameTimelineIndex = 0,
+ .frameTimelines = frameTimelines,
+ .choreographer = this};
+}
+
} // namespace android
using namespace android;
@@ -435,6 +489,12 @@
return reinterpret_cast<const Choreographer*>(choreographer);
}
+static inline const ChoreographerFrameCallbackDataImpl*
+AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(
+ const AChoreographerFrameCallbackData* data) {
+ return reinterpret_cast<const ChoreographerFrameCallbackDataImpl*>(data);
+}
+
// Glue for private C api
namespace android {
void AChoreographer_signalRefreshRateCallbacks(nsecs_t vsyncPeriod) EXCLUDES(gChoreographers.lock) {
@@ -487,6 +547,11 @@
void* data, uint32_t delayMillis) {
return AChoreographer_postFrameCallbackDelayed64(choreographer, callback, data, delayMillis);
}
+void AChoreographer_routePostExtendedFrameCallback(AChoreographer* choreographer,
+ AChoreographer_extendedFrameCallback callback,
+ void* data) {
+ return AChoreographer_postExtendedFrameCallback(choreographer, callback, data);
+}
void AChoreographer_routeRegisterRefreshRateCallback(AChoreographer* choreographer,
AChoreographer_refreshRateCallback callback,
void* data) {
@@ -497,6 +562,30 @@
void* data) {
return AChoreographer_unregisterRefreshRateCallback(choreographer, callback, data);
}
+int64_t AChoreographerFrameCallbackData_routeGetFrameTimeNanos(
+ const AChoreographerFrameCallbackData* data) {
+ return AChoreographerFrameCallbackData_getFrameTimeNanos(data);
+}
+size_t AChoreographerFrameCallbackData_routeGetFrameTimelinesLength(
+ const AChoreographerFrameCallbackData* data) {
+ return AChoreographerFrameCallbackData_getFrameTimelinesLength(data);
+}
+size_t AChoreographerFrameCallbackData_routeGetPreferredFrameTimelineIndex(
+ const AChoreographerFrameCallbackData* data) {
+ return AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex(data);
+}
+int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineVsyncId(
+ const AChoreographerFrameCallbackData* data, size_t index) {
+ return AChoreographerFrameCallbackData_getFrameTimelineVsyncId(data, index);
+}
+int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTime(
+ const AChoreographerFrameCallbackData* data, size_t index) {
+ return AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime(data, index);
+}
+int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineDeadline(
+ const AChoreographerFrameCallbackData* data, size_t index) {
+ return AChoreographerFrameCallbackData_getFrameTimelineDeadline(data, index);
+}
int64_t AChoreographer_getVsyncId(const AChoreographer* choreographer) {
return AChoreographer_to_Choreographer(choreographer)->getVsyncId();
@@ -523,24 +612,32 @@
}
void AChoreographer_postFrameCallback(AChoreographer* choreographer,
- AChoreographer_frameCallback callback, void* data) {
- AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
- callback, nullptr, data, 0);
+ AChoreographer_frameCallback callback, void* data) {
+ AChoreographer_to_Choreographer(choreographer)
+ ->postFrameCallbackDelayed(callback, nullptr, nullptr, data, 0);
}
void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
- AChoreographer_frameCallback callback, void* data, long delayMillis) {
- AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
- callback, nullptr, data, ms2ns(delayMillis));
+ AChoreographer_frameCallback callback, void* data,
+ long delayMillis) {
+ AChoreographer_to_Choreographer(choreographer)
+ ->postFrameCallbackDelayed(callback, nullptr, nullptr, data, ms2ns(delayMillis));
+}
+void AChoreographer_postExtendedFrameCallback(AChoreographer* choreographer,
+ AChoreographer_extendedFrameCallback callback,
+ void* data) {
+ AChoreographer_to_Choreographer(choreographer)
+ ->postFrameCallbackDelayed(nullptr, nullptr, callback, data, 0);
}
void AChoreographer_postFrameCallback64(AChoreographer* choreographer,
- AChoreographer_frameCallback64 callback, void* data) {
- AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
- nullptr, callback, data, 0);
+ AChoreographer_frameCallback64 callback, void* data) {
+ AChoreographer_to_Choreographer(choreographer)
+ ->postFrameCallbackDelayed(nullptr, callback, nullptr, data, 0);
}
void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer,
- AChoreographer_frameCallback64 callback, void* data, uint32_t delayMillis) {
- AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
- nullptr, callback, data, ms2ns(delayMillis));
+ AChoreographer_frameCallback64 callback, void* data,
+ uint32_t delayMillis) {
+ AChoreographer_to_Choreographer(choreographer)
+ ->postFrameCallbackDelayed(nullptr, callback, nullptr, data, ms2ns(delayMillis));
}
void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer,
AChoreographer_refreshRateCallback callback,
@@ -553,6 +650,58 @@
AChoreographer_to_Choreographer(choreographer)->unregisterRefreshRateCallback(callback, data);
}
+int64_t AChoreographerFrameCallbackData_getFrameTimeNanos(
+ const AChoreographerFrameCallbackData* data) {
+ const ChoreographerFrameCallbackDataImpl* frameCallbackData =
+ AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
+ LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
+ "Data is only valid in callback");
+ return frameCallbackData->frameTimeNanos;
+}
+size_t AChoreographerFrameCallbackData_getFrameTimelinesLength(
+ const AChoreographerFrameCallbackData* data) {
+ const ChoreographerFrameCallbackDataImpl* frameCallbackData =
+ AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
+ LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
+ "Data is only valid in callback");
+ return frameCallbackData->frameTimelinesLength;
+}
+size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex(
+ const AChoreographerFrameCallbackData* data) {
+ const ChoreographerFrameCallbackDataImpl* frameCallbackData =
+ AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
+ LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
+ "Data is only valid in callback");
+ return frameCallbackData->preferredFrameTimelineIndex;
+}
+int64_t AChoreographerFrameCallbackData_getFrameTimelineVsyncId(
+ const AChoreographerFrameCallbackData* data, size_t index) {
+ const ChoreographerFrameCallbackDataImpl* frameCallbackData =
+ AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
+ LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
+ "Data is only valid in callback");
+ LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds");
+ return frameCallbackData->frameTimelines[index].vsyncId;
+}
+int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime(
+ const AChoreographerFrameCallbackData* data, size_t index) {
+ const ChoreographerFrameCallbackDataImpl* frameCallbackData =
+ AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
+ LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
+ "Data is only valid in callback");
+ LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds");
+ return frameCallbackData->frameTimelines[index].expectedPresentTimeNanos;
+}
+int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadline(
+ const AChoreographerFrameCallbackData* data, size_t index) {
+ const ChoreographerFrameCallbackDataImpl* frameCallbackData =
+ AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
+ LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
+ "Data is only valid in callback");
+ LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds");
+ return frameCallbackData->frameTimelines[index].deadlineNanos;
+}
+
AChoreographer* AChoreographer_create() {
Choreographer* choreographer = new Choreographer(nullptr);
status_t result = choreographer->initialize();
diff --git a/libs/nativedisplay/include-private/private/android/choreographer.h b/libs/nativedisplay/include-private/private/android/choreographer.h
index 7d25ce8..6e90853 100644
--- a/libs/nativedisplay/include-private/private/android/choreographer.h
+++ b/libs/nativedisplay/include-private/private/android/choreographer.h
@@ -63,11 +63,26 @@
void AChoreographer_routePostFrameCallbackDelayed64(AChoreographer* choreographer,
AChoreographer_frameCallback64 callback,
void* data, uint32_t delayMillis);
+void AChoreographer_routePostExtendedFrameCallback(AChoreographer* choreographer,
+ AChoreographer_extendedFrameCallback callback,
+ void* data);
void AChoreographer_routeRegisterRefreshRateCallback(AChoreographer* choreographer,
AChoreographer_refreshRateCallback callback,
void* data);
void AChoreographer_routeUnregisterRefreshRateCallback(AChoreographer* choreographer,
AChoreographer_refreshRateCallback callback,
void* data);
+int64_t AChoreographerFrameCallbackData_routeGetFrameTimeNanos(
+ const AChoreographerFrameCallbackData* data);
+size_t AChoreographerFrameCallbackData_routeGetFrameTimelinesLength(
+ const AChoreographerFrameCallbackData* data);
+size_t AChoreographerFrameCallbackData_routeGetPreferredFrameTimelineIndex(
+ const AChoreographerFrameCallbackData* data);
+int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineVsyncId(
+ const AChoreographerFrameCallbackData* data, size_t index);
+int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTime(
+ const AChoreographerFrameCallbackData* data, size_t index);
+int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineDeadline(
+ const AChoreographerFrameCallbackData* data, size_t index);
} // namespace android
diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt
index 9ed4915..b4a70e8 100644
--- a/libs/nativedisplay/libnativedisplay.map.txt
+++ b/libs/nativedisplay/libnativedisplay.map.txt
@@ -7,6 +7,13 @@
AChoreographer_postFrameCallbackDelayed64; # apex # introduced=30
AChoreographer_registerRefreshRateCallback; # apex # introduced=30
AChoreographer_unregisterRefreshRateCallback; # apex # introduced=30
+ AChoreographer_postExtendedFrameCallback; # apex # introduced=33
+ AChoreographerFrameCallbackData_getFrameTimeNanos; # apex # introduced=33
+ AChoreographerFrameCallbackData_getFrameTimelinesLength; # apex # introduced=33
+ AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex; # apex # introduced=33
+ AChoreographerFrameCallbackData_getFrameTimelineVsyncId; # apex # introduced=33
+ AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime; # apex # introduced=33
+ AChoreographerFrameCallbackData_getFrameTimelineDeadline; # apex # introduced=33
AChoreographer_create; # apex # introduced=30
AChoreographer_destroy; # apex # introduced=30
AChoreographer_getFd; # apex # introduced=30
@@ -28,6 +35,13 @@
android::AChoreographer_routePostFrameCallbackDelayed64*;
android::AChoreographer_routeRegisterRefreshRateCallback*;
android::AChoreographer_routeUnregisterRefreshRateCallback*;
+ android::AChoreographer_routePostExtendedFrameCallback*;
+ android::AChoreographerFrameCallbackData_routeGetFrameTimeNanos*;
+ android::AChoreographerFrameCallbackData_routeGetFrameTimelinesLength*;
+ android::AChoreographerFrameCallbackData_routeGetPreferredFrameTimelineIndex*;
+ android::AChoreographerFrameCallbackData_routeGetFrameTimelineVsyncId*;
+ android::AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTime*;
+ android::AChoreographerFrameCallbackData_routeGetFrameTimelineDeadline*;
android::AChoreographer_signalRefreshRateCallbacks*;
android::AChoreographer_getVsyncId*;
android::AChoreographer_getFrameDeadline*;
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 04ba485..36d001f 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -54,7 +54,7 @@
target: {
windows: {
enabled: true,
- }
+ },
},
defaults: [
@@ -159,7 +159,7 @@
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.allocator@4.0",
- "android.hardware.graphics.common-V2-ndk",
+ "android.hardware.graphics.common-V3-ndk",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
@@ -176,7 +176,7 @@
export_shared_lib_headers: [
"android.hardware.graphics.common@1.2",
- "android.hardware.graphics.common-V2-ndk",
+ "android.hardware.graphics.common-V3-ndk",
"android.hardware.graphics.mapper@4.0",
"libgralloctypes",
],
@@ -266,6 +266,6 @@
"Rect.cpp",
"Region.cpp",
"PixelFormat.cpp",
- "Transform.cpp"
+ "Transform.cpp",
],
}
diff --git a/libs/ui/Transform.cpp b/libs/ui/Transform.cpp
index cd68c1c..b34d906 100644
--- a/libs/ui/Transform.cpp
+++ b/libs/ui/Transform.cpp
@@ -396,6 +396,11 @@
result.mMatrix[1][0] = -b*idet;
result.mMatrix[1][1] = a*idet;
result.mType = mType;
+ if (getOrientation() & ROT_90) {
+ // Recalculate the type if there is a 90-degree rotation component, since the inverse
+ // of ROT_90 is ROT_270 and vice versa.
+ result.mType |= UNKNOWN_TYPE;
+ }
vec2 T(-x, -y);
T = result.transform(T);
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index a87740a..0ee15f2 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -27,28 +27,40 @@
name: "Region_test",
shared_libs: ["libui"],
srcs: ["Region_test.cpp"],
- cflags: ["-Wall", "-Werror"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
}
cc_test {
name: "colorspace_test",
shared_libs: ["libui"],
srcs: ["colorspace_test.cpp"],
- cflags: ["-Wall", "-Werror"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
}
cc_test {
name: "DisplayId_test",
shared_libs: ["libui"],
srcs: ["DisplayId_test.cpp"],
- cflags: ["-Wall", "-Werror"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
}
cc_test {
name: "FlattenableHelpers_test",
shared_libs: ["libui"],
srcs: ["FlattenableHelpers_test.cpp"],
- cflags: ["-Wall", "-Werror"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
}
cc_test {
@@ -68,7 +80,10 @@
"GraphicBufferAllocator_test.cpp",
"mock/MockGrallocAllocator.cpp",
],
- cflags: ["-Wall", "-Werror"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
}
cc_test {
@@ -83,14 +98,20 @@
"libutils",
],
srcs: ["GraphicBuffer_test.cpp"],
- cflags: ["-Wall", "-Werror"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
}
// This test has a main method, and requires a separate binary to be built.
cc_test {
name: "GraphicBufferOverBinder_test",
srcs: ["GraphicBufferOverBinder_test.cpp"],
- cflags: ["-Wall", "-Werror"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
shared_libs: [
"libbinder",
"libgui",
@@ -105,7 +126,10 @@
test_suites: ["device-tests"],
shared_libs: ["libui"],
srcs: ["Rect_test.cpp"],
- cflags: ["-Wall", "-Werror"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
}
cc_test {
@@ -113,7 +137,10 @@
test_suites: ["device-tests"],
shared_libs: ["libui"],
srcs: ["Size_test.cpp"],
- cflags: ["-Wall", "-Werror"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
}
cc_test {
@@ -121,6 +148,18 @@
shared_libs: ["libui"],
static_libs: ["libgmock"],
srcs: ["MockFence_test.cpp"],
- cflags: ["-Wall", "-Werror"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
}
+cc_test {
+ name: "Transform_test",
+ shared_libs: ["libui"],
+ srcs: ["Transform_test.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
diff --git a/libs/ui/tests/Transform_test.cpp b/libs/ui/tests/Transform_test.cpp
new file mode 100644
index 0000000..6964284
--- /dev/null
+++ b/libs/ui/tests/Transform_test.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ui/Transform.h>
+
+#include <gtest/gtest.h>
+
+namespace android::ui {
+
+TEST(TransformTest, inverseRotation_hasCorrectType) {
+ const auto testRotationFlagsForInverse = [](Transform::RotationFlags rotation,
+ Transform::RotationFlags expectedInverse,
+ bool isRotation) {
+ const Transform t(rotation, 0, 0);
+ EXPECT_EQ(t.getOrientation(), rotation);
+ const Transform inverse = t.inverse();
+ EXPECT_EQ(inverse.getOrientation(), expectedInverse);
+
+ if (isRotation) {
+ EXPECT_TRUE(t.getType() & Transform::ROTATE);
+ EXPECT_TRUE(inverse.getType() & Transform::ROTATE);
+ } else {
+ EXPECT_FALSE(t.getType() & Transform::ROTATE);
+ EXPECT_FALSE(inverse.getType() & Transform::ROTATE);
+ }
+ };
+
+ testRotationFlagsForInverse(Transform::ROT_0, Transform::ROT_0, false);
+ testRotationFlagsForInverse(Transform::ROT_90, Transform::ROT_270, true);
+ testRotationFlagsForInverse(Transform::ROT_180, Transform::ROT_180, true);
+ testRotationFlagsForInverse(Transform::ROT_270, Transform::ROT_90, true);
+ testRotationFlagsForInverse(Transform::FLIP_H, Transform::FLIP_H, false);
+ testRotationFlagsForInverse(Transform::FLIP_V, Transform::FLIP_V, false);
+}
+
+} // namespace android::ui
diff --git a/services/surfaceflinger/ClientCache.cpp b/services/surfaceflinger/ClientCache.cpp
index 1ef8f78..e7b8995 100644
--- a/services/surfaceflinger/ClientCache.cpp
+++ b/services/surfaceflinger/ClientCache.cpp
@@ -82,10 +82,13 @@
return false;
}
- status_t err = token->linkToDeath(mDeathRecipient);
- if (err != NO_ERROR) {
- ALOGE("failed to cache buffer: could not link to death");
- return false;
+ // Only call linkToDeath if not a local binder
+ if (token->localBinder() == nullptr) {
+ status_t err = token->linkToDeath(mDeathRecipient);
+ if (err != NO_ERROR) {
+ ALOGE("failed to cache buffer: could not link to death");
+ return false;
+ }
}
auto [itr, success] =
mBuffers.emplace(processToken,
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 27146ab..e21b0da 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -283,8 +283,21 @@
return Error::NONE;
}
+bool Display::hasCapability(hal::DisplayCapability capability) const {
+ std::scoped_lock lock(mDisplayCapabilitiesMutex);
+ if (mDisplayCapabilities) {
+ return mDisplayCapabilities->count(capability) > 0;
+ }
+
+ ALOGW("Can't query capability %d."
+ " Display Capabilities were not queried from HWC yet",
+ static_cast<int>(capability));
+
+ return false;
+}
+
Error Display::supportsDoze(bool* outSupport) const {
- *outSupport = mDisplayCapabilities.count(DisplayCapability::DOZE) > 0;
+ *outSupport = hasCapability(DisplayCapability::DOZE);
return Error::NONE;
}
@@ -447,17 +460,21 @@
auto error =
static_cast<Error>(mComposer.getDisplayCapabilities(mId, &tmpCapabilities));
if (error == Error::NONE) {
+ std::scoped_lock lock(mDisplayCapabilitiesMutex);
+ mDisplayCapabilities.emplace();
for (auto capability : tmpCapabilities) {
- mDisplayCapabilities.emplace(static_cast<DisplayCapability>(capability));
+ mDisplayCapabilities->emplace(static_cast<DisplayCapability>(capability));
}
} else if (error == Error::UNSUPPORTED) {
+ std::scoped_lock lock(mDisplayCapabilitiesMutex);
+ mDisplayCapabilities.emplace();
if (mCapabilities.count(Capability::SKIP_CLIENT_COLOR_TRANSFORM)) {
- mDisplayCapabilities.emplace(DisplayCapability::SKIP_CLIENT_COLOR_TRANSFORM);
+ mDisplayCapabilities->emplace(DisplayCapability::SKIP_CLIENT_COLOR_TRANSFORM);
}
bool dozeSupport = false;
error = static_cast<Error>(mComposer.getDozeSupport(mId, &dozeSupport));
if (error == Error::NONE && dozeSupport) {
- mDisplayCapabilities.emplace(DisplayCapability::DOZE);
+ mDisplayCapabilities->emplace(DisplayCapability::DOZE);
}
}
});
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 871465d..a65efb2 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -17,6 +17,7 @@
#pragma once
#include <android-base/expected.h>
+#include <android-base/thread_annotations.h>
#include <gui/HdrMetadata.h>
#include <math/mat4.h>
#include <ui/HdrCapabilities.h>
@@ -79,7 +80,7 @@
virtual hal::HWDisplayId getId() const = 0;
virtual bool isConnected() const = 0;
virtual void setConnected(bool connected) = 0; // For use by Device only
- virtual const std::unordered_set<hal::DisplayCapability>& getCapabilities() const = 0;
+ virtual bool hasCapability(hal::DisplayCapability) const = 0;
virtual bool isVsyncPeriodSwitchSupported() const = 0;
virtual void onLayerDestroyed(hal::HWLayerId layerId) = 0;
@@ -175,7 +176,7 @@
hal::DisplayRequest* outDisplayRequests,
std::unordered_map<HWC2::Layer*, hal::LayerRequest>* outLayerRequests) override;
hal::Error getConnectionType(ui::DisplayConnectionType*) const override;
- hal::Error supportsDoze(bool* outSupport) const override;
+ hal::Error supportsDoze(bool* outSupport) const override EXCLUDES(mDisplayCapabilitiesMutex);
hal::Error getHdrCapabilities(android::HdrCapabilities* outCapabilities) const override;
hal::Error getDisplayedContentSamplingAttributes(hal::PixelFormat* outFormat,
hal::Dataspace* outDataspace,
@@ -214,9 +215,7 @@
hal::HWDisplayId getId() const override { return mId; }
bool isConnected() const override { return mIsConnected; }
void setConnected(bool connected) override; // For use by Device only
- const std::unordered_set<hal::DisplayCapability>& getCapabilities() const override {
- return mDisplayCapabilities;
- };
+ bool hasCapability(hal::DisplayCapability) const override EXCLUDES(mDisplayCapabilitiesMutex);
bool isVsyncPeriodSwitchSupported() const override;
void onLayerDestroyed(hal::HWLayerId layerId) override;
@@ -243,8 +242,10 @@
using Layers = std::unordered_map<hal::HWLayerId, std::weak_ptr<HWC2::impl::Layer>>;
Layers mLayers;
+ mutable std::mutex mDisplayCapabilitiesMutex;
std::once_flag mDisplayCapabilityQueryFlag;
- std::unordered_set<hal::DisplayCapability> mDisplayCapabilities;
+ std::optional<std::unordered_set<hal::DisplayCapability>> mDisplayCapabilities
+ GUARDED_BY(mDisplayCapabilitiesMutex);
};
} // namespace impl
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 256bca9..c63ba0e 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -183,7 +183,7 @@
bool HWComposer::hasDisplayCapability(HalDisplayId displayId,
hal::DisplayCapability capability) const {
RETURN_IF_INVALID_DISPLAY(displayId, false);
- return mDisplayData.at(displayId).hwcDisplay->getCapabilities().count(capability) > 0;
+ return mDisplayData.at(displayId).hwcDisplay->hasCapability(capability);
}
std::optional<DisplayIdentificationInfo> HWComposer::onHotplug(hal::HWDisplayId hwcDisplayId,
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 10391a2b..87afa22 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2154,7 +2154,7 @@
if (traceFlags & SurfaceTracing::TRACE_INPUT) {
WindowInfo info;
if (useDrawing) {
- info = fillInputInfo(ui::Transform());
+ info = fillInputInfo(ui::Transform(), /* displayIsSecure */ true);
} else {
info = state.inputInfo;
}
@@ -2356,7 +2356,7 @@
}
}
-WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform) {
+WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform, bool displayIsSecure) {
if (!hasInputInfo()) {
mDrawingState.inputInfo.name = getName();
mDrawingState.inputInfo.ownerUid = mOwnerUid;
@@ -2385,6 +2385,12 @@
fillTouchOcclusionMode(info);
handleDropInputMode(info);
+ // If the window will be blacked out on a display because the display does not have the secure
+ // flag and the layer has the secure flag set, then drop input.
+ if (!displayIsSecure && isSecure()) {
+ info.inputFeatures |= WindowInfo::Feature::DROP_INPUT;
+ }
+
auto cropLayer = mDrawingState.touchableRegionCrop.promote();
if (info.replaceTouchableRegionWithCrop) {
const Rect bounds(cropLayer ? cropLayer->mScreenBounds : mScreenBounds);
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 7b9303f..8c281d5 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -854,7 +854,7 @@
bool getPremultipledAlpha() const;
void setInputInfo(const gui::WindowInfo& info);
- gui::WindowInfo fillInputInfo(const ui::Transform& displayTransform);
+ gui::WindowInfo fillInputInfo(const ui::Transform& displayTransform, bool displayIsSecure);
/**
* Returns whether this layer has an explicitly set input-info.
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 0789e8d..ec81e63 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -30,6 +30,8 @@
#include <SkRect.h>
#include <SkSurface.h>
#include <gui/IProducerListener.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/SurfaceControl.h>
#undef LOG_TAG
#define LOG_TAG "RefreshRateOverlay"
@@ -190,35 +192,30 @@
}
bool RefreshRateOverlay::createLayer() {
- int32_t layerId;
- const status_t ret =
- mFlinger.createLayer(String8("RefreshRateOverlay"), mClient,
- SevenSegmentDrawer::getWidth(), SevenSegmentDrawer::getHeight(),
- PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceBufferState, LayerMetadata(),
- &mIBinder, &mGbp, nullptr, &layerId);
- if (ret) {
+ mSurfaceControl =
+ SurfaceComposerClient::getDefault()
+ ->createSurface(String8("RefreshRateOverlay"), SevenSegmentDrawer::getWidth(),
+ SevenSegmentDrawer::getHeight(), PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState);
+
+ if (!mSurfaceControl) {
ALOGE("failed to create buffer state layer");
return false;
}
- mLayer = mClient->getLayerUser(mIBinder);
- mLayer->setFrameRate(Layer::FrameRate(Fps(0.0f), Layer::FrameRateCompatibility::NoVote));
- mLayer->setIsAtRoot(true);
-
- // setting Layer's Z requires resorting layersSortedByZ
- ssize_t idx = mFlinger.mDrawingState.layersSortedByZ.indexOf(mLayer);
- if (mLayer->setLayer(INT32_MAX - 2) && idx >= 0) {
- mFlinger.mDrawingState.layersSortedByZ.removeAt(idx);
- mFlinger.mDrawingState.layersSortedByZ.add(mLayer);
- }
+ SurfaceComposerClient::Transaction t;
+ t.setFrameRate(mSurfaceControl, 0.0f,
+ static_cast<int8_t>(Layer::FrameRateCompatibility::NoVote),
+ static_cast<int8_t>(scheduler::Seamlessness::OnlySeamless));
+ t.setLayer(mSurfaceControl, INT32_MAX - 2);
+ t.apply();
return true;
}
-const std::vector<std::shared_ptr<renderengine::ExternalTexture>>&
-RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) {
- ui::Transform::RotationFlags transformHint = mLayer->getTransformHint();
+const std::vector<sp<GraphicBuffer>>& RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) {
+ ui::Transform::RotationFlags transformHint =
+ static_cast<ui::Transform::RotationFlags>(mSurfaceControl->getTransformHint());
// Tell SurfaceFlinger about the pre-rotation on the buffer.
const auto transform = [&] {
switch (transformHint) {
@@ -230,7 +227,10 @@
return ui::Transform::ROT_0;
}
}();
- mLayer->setTransform(transform);
+
+ SurfaceComposerClient::Transaction t;
+ t.setTransform(mSurfaceControl, transform);
+ t.apply();
if (mBufferCache.find(transformHint) == mBufferCache.end() ||
mBufferCache.at(transformHint).find(fps) == mBufferCache.at(transformHint).end()) {
@@ -249,16 +249,7 @@
colorBase.fA = ALPHA;
SkColor color = colorBase.toSkColor();
auto buffers = SevenSegmentDrawer::draw(fps, color, transformHint, mShowSpinner);
- std::vector<std::shared_ptr<renderengine::ExternalTexture>> textures;
- std::transform(buffers.begin(), buffers.end(), std::back_inserter(textures),
- [&](const auto& buffer) -> std::shared_ptr<renderengine::ExternalTexture> {
- return std::make_shared<
- renderengine::ExternalTexture>(buffer,
- mFlinger.getRenderEngine(),
- renderengine::ExternalTexture::
- Usage::READABLE);
- });
- mBufferCache[transformHint].emplace(fps, textures);
+ mBufferCache[transformHint].emplace(fps, buffers);
}
return mBufferCache[transformHint][fps];
@@ -271,30 +262,26 @@
Rect frame((3 * width) >> 4, height >> 5);
frame.offsetBy(width >> 5, height >> 4);
- layer_state_t::matrix22_t matrix;
- matrix.dsdx = frame.getWidth() / static_cast<float>(SevenSegmentDrawer::getWidth());
- matrix.dtdx = 0;
- matrix.dtdy = 0;
- matrix.dsdy = frame.getHeight() / static_cast<float>(SevenSegmentDrawer::getHeight());
- mLayer->setMatrix(matrix, true);
- mLayer->setPosition(frame.left, frame.top);
- mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
+ SurfaceComposerClient::Transaction t;
+ t.setMatrix(mSurfaceControl,
+ frame.getWidth() / static_cast<float>(SevenSegmentDrawer::getWidth()), 0, 0,
+ frame.getHeight() / static_cast<float>(SevenSegmentDrawer::getHeight()));
+ t.setPosition(mSurfaceControl, frame.left, frame.top);
+ t.apply();
}
void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) {
- mLayer->setLayerStack(stack);
- mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
+ SurfaceComposerClient::Transaction t;
+ t.setLayerStack(mSurfaceControl, stack);
+ t.apply();
}
void RefreshRateOverlay::changeRefreshRate(const Fps& fps) {
mCurrentFps = fps.getIntValue();
auto buffer = getOrCreateBuffers(*mCurrentFps)[mFrame];
- mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {},
- mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */),
- std::nullopt /* dequeueTime */, FrameTimelineInfo{},
- nullptr /* releaseBufferListener */, nullptr /* releaseBufferEndpoint */);
-
- mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
+ SurfaceComposerClient::Transaction t;
+ t.setBuffer(mSurfaceControl, buffer);
+ t.apply();
}
void RefreshRateOverlay::onInvalidate() {
@@ -303,12 +290,9 @@
const auto& buffers = getOrCreateBuffers(*mCurrentFps);
mFrame = (mFrame + 1) % buffers.size();
auto buffer = buffers[mFrame];
- mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {},
- mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */),
- std::nullopt /* dequeueTime */, FrameTimelineInfo{},
- nullptr /* releaseBufferListener */, nullptr /* releaseBufferEndpoint */);
-
- mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
+ SurfaceComposerClient::Transaction t;
+ t.setBuffer(mSurfaceControl, buffer);
+ t.apply();
}
} // namespace android
diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h
index 63ae383..354510a 100644
--- a/services/surfaceflinger/RefreshRateOverlay.h
+++ b/services/surfaceflinger/RefreshRateOverlay.h
@@ -37,6 +37,7 @@
class IGraphicBufferProducer;
class Layer;
class SurfaceFlinger;
+class SurfaceControl;
class RefreshRateOverlay {
public:
@@ -70,18 +71,16 @@
};
bool createLayer();
- const std::vector<std::shared_ptr<renderengine::ExternalTexture>>& getOrCreateBuffers(
- uint32_t fps);
+
+ const std::vector<sp<GraphicBuffer>>& getOrCreateBuffers(uint32_t fps);
SurfaceFlinger& mFlinger;
const sp<Client> mClient;
- sp<Layer> mLayer;
sp<IBinder> mIBinder;
sp<IGraphicBufferProducer> mGbp;
- std::unordered_map<
- ui::Transform::RotationFlags,
- std::unordered_map<int, std::vector<std::shared_ptr<renderengine::ExternalTexture>>>>
+ std::unordered_map<ui::Transform::RotationFlags,
+ std::unordered_map<int, std::vector<sp<GraphicBuffer>>>>
mBufferCache;
std::optional<int> mCurrentFps;
int mFrame = 0;
@@ -94,6 +93,8 @@
// Interpolate the colors between these values.
const uint32_t mLowFps;
const uint32_t mHighFps;
+
+ sp<SurfaceControl> mSurfaceControl;
};
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index da2204e..4345b84 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -300,7 +300,6 @@
uint32_t SurfaceFlinger::maxGraphicsHeight;
bool SurfaceFlinger::hasWideColorDisplay;
ui::Rotation SurfaceFlinger::internalDisplayOrientation = ui::ROTATION_0;
-bool SurfaceFlinger::useColorManagement;
bool SurfaceFlinger::useContextPriority;
Dataspace SurfaceFlinger::defaultCompositionDataspace = Dataspace::V0_SRGB;
ui::PixelFormat SurfaceFlinger::defaultCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
@@ -364,11 +363,6 @@
maxGraphicsHeight = std::max(max_graphics_height(0), 0);
hasWideColorDisplay = has_wide_color_display(false);
-
- // Android 12 and beyond, color management in display pipeline is turned on
- // by default.
- useColorManagement = use_color_management(true);
-
mDefaultCompositionDataspace =
static_cast<ui::Dataspace>(default_composition_dataspace(Dataspace::V0_SRGB));
mWideColorGamutCompositionDataspace = static_cast<ui::Dataspace>(wcg_composition_dataspace(
@@ -2730,6 +2724,7 @@
display->setProjection(state.orientation, state.layerStackSpaceRect,
state.orientedDisplaySpaceRect);
display->setDisplayName(state.displayName);
+ display->setFlags(state.flags);
return display;
}
@@ -3088,16 +3083,19 @@
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
if (!layer->needsInputInfo()) return;
- const DisplayDevice* display = nullptr;
- if (enablePerWindowInputRotation()) {
- display = ON_MAIN_THREAD(getDisplayWithInputByLayer(layer)).get();
- }
+ const DisplayDevice* display = ON_MAIN_THREAD(getDisplayWithInputByLayer(layer)).get();
+ ui::Transform displayTransform = ui::Transform();
- // When calculating the screen bounds we ignore the transparent region since it may
- // result in an unwanted offset.
- const auto it = displayTransforms.find(display);
- windowInfos.push_back(
- layer->fillInputInfo(it != displayTransforms.end() ? it->second : ui::Transform()));
+ if (enablePerWindowInputRotation()) {
+ // When calculating the screen bounds we ignore the transparent region since it may
+ // result in an unwanted offset.
+ const auto it = displayTransforms.find(display);
+ if (it != displayTransforms.end()) {
+ displayTransform = it->second;
+ }
+ }
+ const bool displayIsSecure = !display || display->isSecure();
+ windowInfos.push_back(layer->fillInputInfo(displayTransform, displayIsSecure));
});
mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos,
mInputWindowCommands.syncInputWindows);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 141d7ac..6c046fc 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -244,7 +244,7 @@
static ui::Rotation internalDisplayOrientation;
// Indicate if device wants color management on its display.
- static bool useColorManagement;
+ static const constexpr bool useColorManagement = true;
static bool useContextPriority;
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index e15eae8..a8117f7 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -195,17 +195,6 @@
return SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_0;
}
-bool use_color_management(bool defaultValue) {
- auto tmpuseColorManagement = SurfaceFlingerProperties::use_color_management();
- auto tmpHasHDRDisplayVal = has_HDR_display(defaultValue);
- auto tmpHasWideColorDisplayVal = has_wide_color_display(defaultValue);
-
- auto tmpuseColorManagementVal = tmpuseColorManagement.has_value() ? *tmpuseColorManagement :
- defaultValue;
-
- return tmpuseColorManagementVal || tmpHasHDRDisplayVal || tmpHasWideColorDisplayVal;
-}
-
int64_t default_composition_dataspace(Dataspace defaultValue) {
auto temp = SurfaceFlingerProperties::default_composition_dataspace();
if (temp.has_value()) {
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index 039d316..ed18260 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -59,8 +59,6 @@
SurfaceFlingerProperties::primary_display_orientation_values primary_display_orientation(
SurfaceFlingerProperties::primary_display_orientation_values defaultValue);
-bool use_color_management(bool defaultValue);
-
int64_t default_composition_dataspace(
android::hardware::graphics::common::V1_2::Dataspace defaultValue);
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 32ad873..7b86229 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -60,7 +60,7 @@
"android.hardware.graphics.composer@2.1",
],
shared_libs: [
- "android.hardware.graphics.common-V2-ndk",
+ "android.hardware.graphics.common-V3-ndk",
"android.hardware.graphics.common@1.2",
"libandroid",
"libbase",
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 5a21e7b..6cb3052 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -38,7 +38,6 @@
// Default to no wide color display support configured
mFlinger.mutableHasWideColorDisplay() = false;
- mFlinger.mutableUseColorManagement() = false;
mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
mFlinger.setCreateBufferQueueFunction([](auto, auto, auto) {
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 0f1cc67..7746e73 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -233,7 +233,7 @@
// 2) HalVirtualDisplayIdType<...> for hard-coded ID of virtual display backed by HWC.
// 3) GpuVirtualDisplayIdType for virtual display without HWC backing.
template <typename DisplayIdType, int width, int height, Critical critical, Async async,
- Secure secure, Primary primary, int grallocUsage>
+ Secure secure, Primary primary, int grallocUsage, int displayFlags>
struct DisplayVariant {
using DISPLAY_ID = DisplayIdGetter<DisplayIdType>;
using CONNECTION_TYPE = DisplayConnectionTypeGetter<DisplayIdType>;
@@ -261,6 +261,8 @@
// Whether the display is primary
static constexpr Primary PRIMARY = primary;
+ static constexpr int DISPLAY_FLAGS = displayFlags;
+
static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder();
ceDisplayArgs.setId(DISPLAY_ID::get())
@@ -469,16 +471,19 @@
constexpr uint32_t GRALLOC_USAGE_PHYSICAL_DISPLAY =
GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_FB;
+constexpr int PHYSICAL_DISPLAY_FLAGS = 0x1;
+
template <typename PhysicalDisplay, int width, int height, Critical critical>
struct PhysicalDisplayVariant
: DisplayVariant<PhysicalDisplayIdType<PhysicalDisplay>, width, height, critical,
Async::FALSE, Secure::TRUE, PhysicalDisplay::PRIMARY,
- GRALLOC_USAGE_PHYSICAL_DISPLAY>,
- HwcDisplayVariant<PhysicalDisplay::HWC_DISPLAY_ID, DisplayType::PHYSICAL,
- DisplayVariant<PhysicalDisplayIdType<PhysicalDisplay>, width, height,
- critical, Async::FALSE, Secure::TRUE,
- PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY>,
- PhysicalDisplay> {};
+ GRALLOC_USAGE_PHYSICAL_DISPLAY, PHYSICAL_DISPLAY_FLAGS>,
+ HwcDisplayVariant<
+ PhysicalDisplay::HWC_DISPLAY_ID, DisplayType::PHYSICAL,
+ DisplayVariant<PhysicalDisplayIdType<PhysicalDisplay>, width, height, critical,
+ Async::FALSE, Secure::TRUE, PhysicalDisplay::PRIMARY,
+ GRALLOC_USAGE_PHYSICAL_DISPLAY, PHYSICAL_DISPLAY_FLAGS>,
+ PhysicalDisplay> {};
template <bool hasIdentificationData>
struct PrimaryDisplay {
@@ -520,13 +525,16 @@
// A virtual display not supported by the HWC.
constexpr uint32_t GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY = 0;
+constexpr int VIRTUAL_DISPLAY_FLAGS = 0x0;
+
template <int width, int height, Secure secure>
struct NonHwcVirtualDisplayVariant
: DisplayVariant<GpuVirtualDisplayIdType, width, height, Critical::FALSE, Async::TRUE, secure,
- Primary::FALSE, GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY> {
- using Base =
- DisplayVariant<GpuVirtualDisplayIdType, width, height, Critical::FALSE, Async::TRUE,
- secure, Primary::FALSE, GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY>;
+ Primary::FALSE, GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY,
+ VIRTUAL_DISPLAY_FLAGS> {
+ using Base = DisplayVariant<GpuVirtualDisplayIdType, width, height, Critical::FALSE,
+ Async::TRUE, secure, Primary::FALSE,
+ GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY, VIRTUAL_DISPLAY_FLAGS>;
static void injectHwcDisplay(DisplayTransactionTest*) {}
@@ -569,13 +577,16 @@
template <int width, int height, Secure secure>
struct HwcVirtualDisplayVariant
: DisplayVariant<HalVirtualDisplayIdType<42>, width, height, Critical::FALSE, Async::TRUE,
- secure, Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>,
- HwcDisplayVariant<HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID, DisplayType::VIRTUAL,
- DisplayVariant<HalVirtualDisplayIdType<42>, width, height,
- Critical::FALSE, Async::TRUE, secure, Primary::FALSE,
- GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>> {
+ secure, Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY,
+ VIRTUAL_DISPLAY_FLAGS>,
+ HwcDisplayVariant<
+ HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID, DisplayType::VIRTUAL,
+ DisplayVariant<HalVirtualDisplayIdType<42>, width, height, Critical::FALSE,
+ Async::TRUE, secure, Primary::FALSE,
+ GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY, VIRTUAL_DISPLAY_FLAGS>> {
using Base = DisplayVariant<HalVirtualDisplayIdType<42>, width, height, Critical::FALSE,
- Async::TRUE, secure, Primary::FALSE, GRALLOC_USAGE_HW_COMPOSER>;
+ Async::TRUE, secure, Primary::FALSE, GRALLOC_USAGE_HW_COMPOSER,
+ VIRTUAL_DISPLAY_FLAGS>;
using Self = HwcVirtualDisplayVariant<width, height, secure>;
static std::shared_ptr<compositionengine::Display> injectCompositionDisplay(
@@ -665,7 +676,6 @@
static constexpr bool WIDE_COLOR_SUPPORTED = false;
static void injectConfigChange(DisplayTransactionTest* test) {
- test->mFlinger.mutableUseColorManagement() = true;
test->mFlinger.mutableHasWideColorDisplay() = true;
}
@@ -684,7 +694,6 @@
static void injectConfigChange(DisplayTransactionTest* test) {
test->mFlinger.mutableHasWideColorDisplay() = false;
- test->mFlinger.mutableUseColorManagement() = false;
test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
}
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
index 7ead0af..38dceb9 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
@@ -34,7 +34,6 @@
static constexpr bool WIDE_COLOR_SUPPORTED = true;
static void injectConfigChange(DisplayTransactionTest* test) {
- test->mFlinger.mutableUseColorManagement() = true;
test->mFlinger.mutableHasWideColorDisplay() = true;
test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
}
@@ -257,6 +256,7 @@
}
state.isSecure = static_cast<bool>(Case::Display::SECURE);
+ state.flags = Case::Display::DISPLAY_FLAGS;
auto device = mFlinger.setupNewDisplayDeviceInternal(displayToken, compositionDisplay, state,
displaySurface, producer);
@@ -279,6 +279,8 @@
EXPECT_EQ(Case::HdrSupport::HDR_DOLBY_VISION_SUPPORTED, device->hasDolbyVisionSupport());
EXPECT_EQ(Case::PerFrameMetadataSupport::PER_FRAME_METADATA_KEYS,
device->getSupportedPerFrameMetadata());
+ EXPECT_EQ(Case::Display::DISPLAY_FLAGS & DisplayDevice::eReceivesInput,
+ device->receivesInput());
if constexpr (Case::Display::CONNECTION_TYPE::value) {
EXPECT_EQ(1, device->getSupportedModes().size());
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index d8352ed..7072439 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -419,7 +419,6 @@
*/
auto& mutableHasWideColorDisplay() { return SurfaceFlinger::hasWideColorDisplay; }
- auto& mutableUseColorManagement() { return SurfaceFlinger::useColorManagement; }
auto& mutableCurrentState() { return mFlinger->mCurrentState; }
auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; }
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
index c3919d9..fe1544e 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
@@ -30,8 +30,7 @@
MOCK_METHOD(hal::HWDisplayId, getId, (), (const, override));
MOCK_METHOD(bool, isConnected, (), (const, override));
MOCK_METHOD(void, setConnected, (bool), (override));
- MOCK_METHOD(const std::unordered_set<hal::DisplayCapability> &, getCapabilities, (),
- (const, override));
+ MOCK_METHOD(bool, hasCapability, (hal::DisplayCapability), (const, override));
MOCK_METHOD(bool, isVsyncPeriodSwitchSupported, (), (const, override));
MOCK_METHOD(void, onLayerDestroyed, (hal::HWLayerId), (override));