Merge "Block untrusted touches in InputDispatcher"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 5db44c7..307e21c 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -53,6 +53,9 @@
},
{
"include-filter": "*RelativeZTest.*"
+ },
+ {
+ "include-filter": "*RefreshRateOverlayTest.*"
}
]
},
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index c8277fe..91d5524 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1350,7 +1350,7 @@
static void DumpHals(int out_fd = STDOUT_FILENO) {
if (!ds.IsZipping()) {
RunCommand("HARDWARE HALS", {"lshal", "--all", "--types=all", "--debug"},
- CommandOptions::WithTimeout(10).AsRootIfAvailable().Build(),
+ CommandOptions::WithTimeout(60).AsRootIfAvailable().Build(),
false, out_fd);
return;
}
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index c8355e2..7aac7da 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -373,7 +373,6 @@
outReturn->clear();
for (const std::string& instance : allInstances) {
- // TODO(b/169275998): allow checking policy only once for the interface
if (mAccess->canFind(ctx, interface + "/" + instance)) {
outReturn->push_back(instance);
}
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
index 3ada05c..6c3b79b 100644
--- a/cmds/surfacereplayer/proto/src/trace.proto
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -25,9 +25,10 @@
repeated SurfaceChange surface_change = 1;
repeated DisplayChange display_change = 2;
- required bool synchronous = 3;
- required bool animation = 4;
- optional Origin origin = 5;
+ required bool synchronous = 3;
+ required bool animation = 4;
+ optional Origin origin = 5;
+ optional uint64 id = 6;
}
message SurfaceChange {
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index 2b5667d..86e4f5d 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -584,9 +584,7 @@
return;
}
- auto handle = mLayers[dtc.layer_id()]->getHandle();
-
- t.deferTransactionUntil_legacy(mLayers[id], handle, dtc.frame_number());
+ t.deferTransactionUntil_legacy(mLayers[id], mLayers[dtc.layer_id()], dtc.frame_number());
}
void Replayer::setDisplaySurface(SurfaceComposerClient::Transaction& t,
@@ -706,11 +704,11 @@
void Replayer::setReparentChange(SurfaceComposerClient::Transaction& t,
layer_id id, const ReparentChange& c) {
- sp<IBinder> newParentHandle = nullptr;
+ sp<SurfaceControl> newSurfaceControl = nullptr;
if (mLayers.count(c.parent_id()) != 0 && mLayers[c.parent_id()] != nullptr) {
- newParentHandle = mLayers[c.parent_id()]->getHandle();
+ newSurfaceControl = mLayers[c.parent_id()];
}
- t.reparent(mLayers[id], newParentHandle);
+ t.reparent(mLayers[id], newSurfaceControl);
}
void Replayer::setRelativeParentChange(SurfaceComposerClient::Transaction& t,
@@ -719,7 +717,7 @@
ALOGE("Layer %d not found in set relative parent transaction", c.relative_parent_id());
return;
}
- t.setRelativeLayer(mLayers[id], mLayers[c.relative_parent_id()]->getHandle(), c.z());
+ t.setRelativeLayer(mLayers[id], mLayers[c.relative_parent_id()], c.z());
}
void Replayer::setDetachChildrenChange(SurfaceComposerClient::Transaction& t,
@@ -733,7 +731,7 @@
ALOGE("Layer %d not found in reparent children transaction", c.parent_id());
return;
}
- t.reparentChildren(mLayers[id], mLayers[c.parent_id()]->getHandle());
+ t.reparentChildren(mLayers[id], mLayers[c.parent_id()]);
}
void Replayer::setShadowRadiusChange(SurfaceComposerClient::Transaction& t,
diff --git a/include/binder/Enum.h b/include/binder/Enum.h
new file mode 100644
index 0000000..4c25654
--- /dev/null
+++ b/include/binder/Enum.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#error Do not rely on global include files. All Android cc_* programs are given access to \
+ include_dirs for frameworks/native/include via global configuration, but this is legacy \
+ configuration. Instead, you should have a direct dependency on libbinder OR one of your \
+ dependencies should re-export libbinder headers with export_shared_lib_headers.
diff --git a/include/input/Flags.h b/include/input/Flags.h
index 4ad9056..072dd18 100644
--- a/include/input/Flags.h
+++ b/include/input/Flags.h
@@ -22,6 +22,7 @@
#include <string>
#include <type_traits>
+#include "NamedEnum.h"
#include "utils/BitSet.h"
#ifndef __UI_INPUT_FLAGS_H
@@ -30,38 +31,6 @@
namespace android {
namespace details {
-template <typename F, F V>
-constexpr std::optional<std::string_view> enum_value_name() {
- // Should look something like (but all on one line):
- // std::optional<std::string_view>
- // android::details::enum_value_name()
- // [F = android::test::TestFlags, V = android::test::TestFlags::ONE]
- std::string_view view = __PRETTY_FUNCTION__;
- size_t templateStart = view.rfind("[");
- size_t templateEnd = view.rfind("]");
- if (templateStart == std::string::npos || templateEnd == std::string::npos) {
- return std::nullopt;
- }
-
- // Extract the template parameters without the enclosing braces.
- // Example (cont'd): F = android::test::TestFlags, V = android::test::TestFlags::ONE
- view = view.substr(templateStart + 1, templateEnd - templateStart - 1);
- size_t valStart = view.rfind("V = ");
- if (valStart == std::string::npos) {
- return std::nullopt;
- }
-
- // Example (cont'd): V = android::test::TestFlags::ONE
- view = view.substr(valStart);
- size_t nameStart = view.rfind("::");
- if (nameStart == std::string::npos) {
- return std::nullopt;
- }
-
- // Chop off the initial "::"
- nameStart += 2;
- return view.substr(nameStart);
-}
template <typename F>
inline constexpr auto flag_count = sizeof(F) * __CHAR_BIT__;
diff --git a/include/input/NamedEnum.h b/include/input/NamedEnum.h
new file mode 100644
index 0000000..42cfb12
--- /dev/null
+++ b/include/input/NamedEnum.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/stringprintf.h>
+
+#include <array>
+#include <cstdint>
+#include <optional>
+#include <string>
+
+#ifndef __UI_INPUT_NAMEDENUM_H
+#define __UI_INPUT_NAMEDENUM_H
+
+namespace android {
+
+namespace details {
+template <typename E, E V>
+constexpr std::optional<std::string_view> enum_value_name() {
+ // Should look something like (but all on one line):
+ // std::optional<std::string_view>
+ // android::details::enum_value_name()
+ // [E = android::test::TestEnums, V = android::test::TestEnums::ONE]
+ std::string_view view = __PRETTY_FUNCTION__;
+ size_t templateStart = view.rfind("[");
+ size_t templateEnd = view.rfind("]");
+ if (templateStart == std::string::npos || templateEnd == std::string::npos) {
+ return std::nullopt;
+ }
+
+ // Extract the template parameters without the enclosing braces.
+ // Example (cont'd): E = android::test::TestEnums, V = android::test::TestEnums::ONE
+ view = view.substr(templateStart + 1, templateEnd - templateStart - 1);
+ size_t valStart = view.rfind("V = ");
+ if (valStart == std::string::npos) {
+ return std::nullopt;
+ }
+
+ // Example (cont'd): V = android::test::TestEnums::ONE
+ view = view.substr(valStart);
+ size_t nameStart = view.rfind("::");
+ if (nameStart == std::string::npos) {
+ return std::nullopt;
+ }
+
+ // Chop off the initial "::"
+ nameStart += 2;
+ return view.substr(nameStart);
+}
+
+template <typename E, typename T, T... I>
+constexpr auto generate_enum_values(std::integer_sequence<T, I...> seq) {
+ constexpr size_t count = seq.size();
+
+ std::array<E, count> values{};
+ for (size_t i = 0, v = 0; v < count; ++i) {
+ values[v++] = static_cast<E>(T{0} + i);
+ }
+
+ return values;
+}
+
+template <typename E, std::size_t N>
+inline constexpr auto enum_values =
+ generate_enum_values<E>(std::make_integer_sequence<std::underlying_type_t<E>, N>{});
+
+template <typename E, std::size_t N, std::size_t... I>
+constexpr auto generate_enum_names(std::index_sequence<I...>) noexcept {
+ return std::array<std::optional<std::string_view>, sizeof...(I)>{
+ {enum_value_name<E, enum_values<E, N>[I]>()...}};
+}
+
+template <typename E, std::size_t N>
+inline constexpr auto enum_names = generate_enum_names<E, N>(std::make_index_sequence<N>{});
+
+} // namespace details
+
+class NamedEnum {
+public:
+ // By default allowed enum value range is 0 ~ 7.
+ template <typename E>
+ static constexpr size_t max = 8;
+
+ template <auto V>
+ static constexpr auto enum_name() {
+ using E = decltype(V);
+ return details::enum_value_name<E, V>();
+ }
+
+ template <typename E>
+ static constexpr std::optional<std::string_view> enum_name(E val) {
+ auto idx = static_cast<size_t>(val);
+ return idx < max<E> ? details::enum_names<E, max<E>>[idx] : std::nullopt;
+ }
+
+ // Helper function for parsing enum value to string.
+ // Example : enum class TestEnums { ZERO = 0x0 };
+ // NamedEnum::string(TestEnums::ZERO) returns string of "ZERO".
+ // Note the default maximum enum is 8, if the enum ID to be parsed if greater than 8 like 16,
+ // it should be declared to specialized the maximum enum by below:
+ // template <> constexpr size_t NamedEnum::max<TestEnums> = 16;
+ // If the enum class definition is sparse and contains enum values starting from a large value,
+ // Do not specialize it to a large number to avoid performance issues.
+ // The recommended maximum enum number to specialize is 64.
+ template <typename E>
+ static const std::string string(E val) {
+ std::string result;
+ std::optional<std::string_view> enumString = enum_name(val);
+ result += enumString ? enumString.value() : base::StringPrintf("0x%08x", val);
+ return result;
+ }
+};
+
+} // namespace android
+
+#endif // __UI_INPUT_NAMEDENUM_H
\ No newline at end of file
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 06f6249..ddd9f9b 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -520,14 +520,19 @@
// Write RPC headers. (previously just the interface token)
status_t Parcel::writeInterfaceToken(const String16& interface)
{
+ return writeInterfaceToken(interface.string(), interface.size());
+}
+
+status_t Parcel::writeInterfaceToken(const char16_t* str, size_t len) {
const IPCThreadState* threadState = IPCThreadState::self();
writeInt32(threadState->getStrictModePolicy() | STRICT_MODE_PENALTY_GATHER);
updateWorkSourceRequestHeaderPosition();
writeInt32(threadState->shouldPropagateWorkSource() ?
threadState->getCallingWorkSourceUid() : IPCThreadState::kUnsetWorkSource);
writeInt32(kHeader);
+
// currently the interface identification token is just its name as a string
- return writeString16(interface);
+ return writeString16(str, len);
}
bool Parcel::replaceCallingWorkSourceUid(uid_t uid)
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index b6cfb8e..fbfd6c5 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -86,6 +86,7 @@
// Writes the RPC header.
status_t writeInterfaceToken(const String16& interface);
+ status_t writeInterfaceToken(const char16_t* str, size_t len);
// Parses the RPC header, returning true if the interface name
// in the header matches the expected interface from the caller.
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 51fd84c..9508de0 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -73,12 +73,11 @@
AIBinder::AIBinder(const AIBinder_Class* clazz) : mClazz(clazz) {}
AIBinder::~AIBinder() {}
-bool AIBinder::associateClass(const AIBinder_Class* clazz) {
- if (clazz == nullptr) return false;
+std::optional<bool> AIBinder::associateClassInternal(const AIBinder_Class* clazz,
+ const String8& newDescriptor, bool set) {
+ std::lock_guard<std::mutex> lock(mClazzMutex);
if (mClazz == clazz) return true;
- String8 newDescriptor(clazz->getInterfaceDescriptor());
-
if (mClazz != nullptr) {
String8 currentDescriptor(mClazz->getInterfaceDescriptor());
if (newDescriptor == currentDescriptor) {
@@ -97,6 +96,23 @@
return false;
}
+ if (set) {
+ // if this is a local object, it's not one known to libbinder_ndk
+ mClazz = clazz;
+ return true;
+ }
+
+ return {};
+}
+
+bool AIBinder::associateClass(const AIBinder_Class* clazz) {
+ if (clazz == nullptr) return false;
+
+ String8 newDescriptor(clazz->getInterfaceDescriptor());
+
+ auto result = associateClassInternal(clazz, newDescriptor, false);
+ if (result.has_value()) return *result;
+
CHECK(asABpBinder() != nullptr); // ABBinder always has a descriptor
String8 descriptor(getBinder()->getInterfaceDescriptor());
@@ -112,10 +128,7 @@
return false;
}
- // if this is a local object, it's not one known to libbinder_ndk
- mClazz = clazz;
-
- return true;
+ return associateClassInternal(clazz, newDescriptor, true).value();
}
ABBinder::ABBinder(const AIBinder_Class* clazz, void* userData)
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index 902fe79..bf27046 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -22,6 +22,7 @@
#include <atomic>
#include <mutex>
+#include <optional>
#include <vector>
#include <binder/Binder.h>
@@ -52,10 +53,14 @@
}
private:
+ std::optional<bool> associateClassInternal(const AIBinder_Class* clazz,
+ const ::android::String8& newDescriptor, bool set);
+
// AIBinder instance is instance of this class for a local object. In order to transact on a
// remote object, this also must be set for simplicity (although right now, only the
// interfaceDescriptor from it is used).
const AIBinder_Class* mClazz;
+ std::mutex mClazzMutex;
};
// This is a local AIBinder object with a known class.
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 81a5f02..6d0a369 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -532,7 +532,17 @@
}
fn on_transact(&self, code: $crate::TransactionCode, data: &$crate::Parcel, reply: &mut $crate::Parcel) -> $crate::Result<()> {
- $on_transact(&*self.0, code, data, reply)
+ match $on_transact(&*self.0, code, data, reply) {
+ // The C++ backend converts UNEXPECTED_NULL into an exception
+ Err($crate::StatusCode::UNEXPECTED_NULL) => {
+ let status = $crate::Status::new_exception(
+ $crate::ExceptionCode::NULL_POINTER,
+ None,
+ );
+ reply.write(&status)
+ },
+ result => result
+ }
}
fn get_class() -> $crate::InterfaceClass {
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 82212d8..5002fc6 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -352,7 +352,10 @@
impl Deserialize for SpIBinder {
fn deserialize(parcel: &Parcel) -> Result<SpIBinder> {
- parcel.read_binder().transpose().unwrap()
+ parcel
+ .read_binder()
+ .transpose()
+ .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
}
}
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 56591bd..87f7972 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "BLASTBufferQueue"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
#include <gui/BLASTBufferQueue.h>
#include <gui/BufferItemConsumer.h>
@@ -29,8 +30,20 @@
using namespace std::chrono_literals;
+namespace {
+inline const char* toString(bool b) {
+ return b ? "true" : "false";
+}
+} // namespace
+
namespace android {
+// Macros to include adapter info in log messages
+#define BQA_LOGV(x, ...) \
+ ALOGV("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__)
+#define BQA_LOGE(x, ...) \
+ ALOGE("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__)
+
void BLASTBufferItemConsumer::onDisconnect() {
Mutex::Autolock lock(mFrameEventHistoryMutex);
mPreviouslyConnected = mCurrentlyConnected;
@@ -93,9 +106,10 @@
if (needsDisconnect != nullptr) *needsDisconnect = disconnect;
}
-BLASTBufferQueue::BLASTBufferQueue(const sp<SurfaceControl>& surface, int width, int height,
- bool enableTripleBuffering)
- : mSurfaceControl(surface),
+BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface,
+ int width, int height, bool enableTripleBuffering)
+ : mName(name),
+ mSurfaceControl(surface),
mWidth(width),
mHeight(height),
mNextTransaction(nullptr) {
@@ -110,9 +124,9 @@
mBufferItemConsumer =
new BLASTBufferItemConsumer(mConsumer, GraphicBuffer::USAGE_HW_COMPOSER, 1, true);
static int32_t id = 0;
- auto name = std::string("BLAST Consumer") + std::to_string(id);
+ auto consumerName = mName + "(BLAST Consumer)" + std::to_string(id);
id++;
- mBufferItemConsumer->setName(String8(name.c_str()));
+ mBufferItemConsumer->setName(String8(consumerName.c_str()));
mBufferItemConsumer->setFrameAvailableListener(this);
mBufferItemConsumer->setBufferFreedListener(this);
mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
@@ -127,7 +141,7 @@
mPendingReleaseItem.releaseFence = nullptr;
}
-void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, int width, int height) {
+void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height) {
std::unique_lock _lock{mMutex};
mSurfaceControl = surface;
@@ -152,6 +166,8 @@
const std::vector<SurfaceControlStats>& stats) {
std::unique_lock _lock{mMutex};
ATRACE_CALL();
+ BQA_LOGV("transactionCallback");
+ mInitialCallbackReceived = true;
if (!stats.empty()) {
mTransformHint = stats[0].transformHint;
@@ -169,7 +185,7 @@
if (!stats.empty()) {
mPendingReleaseItem.releaseFence = stats[0].previousReleaseFence;
} else {
- ALOGE("Warning: no SurfaceControlStats returned in BLASTBufferQueue callback");
+ BQA_LOGE("Warning: no SurfaceControlStats returned in BLASTBufferQueue callback");
mPendingReleaseItem.releaseFence = nullptr;
}
mBufferItemConsumer->releaseBuffer(mPendingReleaseItem.item,
@@ -182,7 +198,7 @@
}
if (mSubmitted.empty()) {
- ALOGE("ERROR: callback with no corresponding submitted buffer item");
+ BQA_LOGE("ERROR: callback with no corresponding submitted buffer item");
}
mPendingReleaseItem.item = std::move(mSubmitted.front());
mSubmitted.pop();
@@ -195,12 +211,20 @@
void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
ATRACE_CALL();
- if (mNumFrameAvailable == 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS + 1) {
+ BQA_LOGV("processNextBufferLocked useNextTransaction=%s", toString(useNextTransaction));
+
+ // Wait to acquire a buffer if there are no frames available or we have acquired the maximum
+ // number of buffers.
+ // As a special case, we wait for the first callback before acquiring the second buffer so we
+ // can ensure the first buffer is presented if multiple buffers are queued in succession.
+ if (mNumFrameAvailable == 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS + 1 ||
+ (!mInitialCallbackReceived && mNumAcquired == 1)) {
+ BQA_LOGV("processNextBufferLocked waiting for frame available or callback");
return;
}
if (mSurfaceControl == nullptr) {
- ALOGE("ERROR : surface control is null");
+ BQA_LOGE("ERROR : surface control is null");
return;
}
@@ -227,6 +251,13 @@
return;
}
+ if (rejectBuffer(bufferItem)) {
+ BQA_LOGE("rejecting buffer:configured size=%dx%d, buffer{size=%dx%d transform=%d}", mWidth,
+ mHeight, buffer->getWidth(), buffer->getHeight(), bufferItem.mTransform);
+ mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE);
+ return;
+ }
+
mNumAcquired++;
mSubmitted.push(bufferItem);
@@ -246,15 +277,22 @@
bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE);
t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this));
- t->setFrame(mSurfaceControl, {0, 0, mWidth, mHeight});
+ t->setFrame(mSurfaceControl,
+ {0, 0, static_cast<int32_t>(mWidth), static_cast<int32_t>(mHeight)});
t->setCrop(mSurfaceControl, computeCrop(bufferItem));
t->setTransform(mSurfaceControl, bufferItem.mTransform);
t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse);
t->setDesiredPresentTime(bufferItem.mTimestamp);
+ t->setFrameNumber(mSurfaceControl, bufferItem.mFrameNumber);
if (applyTransaction) {
t->apply();
}
+
+ BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64
+ " applyTransaction=%s mTimestamp=%" PRId64,
+ mWidth, mHeight, bufferItem.mFrameNumber, toString(applyTransaction),
+ bufferItem.mTimestamp);
}
Rect BLASTBufferQueue::computeCrop(const BufferItem& item) {
@@ -268,7 +306,10 @@
ATRACE_CALL();
std::unique_lock _lock{mMutex};
- if (mNextTransaction != nullptr) {
+ const bool nextTransactionSet = mNextTransaction != nullptr;
+ BQA_LOGV("onFrameAvailable nextTransactionSet=%s", toString(nextTransactionSet));
+
+ if (nextTransactionSet) {
while (mNumFrameAvailable > 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS + 1) {
mCallbackCV.wait(_lock);
}
@@ -283,4 +324,21 @@
mNextTransaction = t;
}
+bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) const {
+ if (item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) {
+ // Only reject buffers if scaling mode is freeze.
+ return false;
+ }
+
+ uint32_t bufWidth = item.mGraphicBuffer->getWidth();
+ uint32_t bufHeight = item.mGraphicBuffer->getHeight();
+
+ // Take the buffer's orientation into account
+ if (item.mTransform & ui::Transform::ROT_90) {
+ std::swap(bufWidth, bufHeight);
+ }
+
+ // reject buffers if the buffer size doesn't match.
+ return bufWidth != mWidth || bufHeight != mHeight;
+}
} // namespace android
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 7a2f656..964195d 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -69,13 +69,15 @@
}
virtual status_t setTransactionState(
- const Vector<ComposerState>& state, const Vector<DisplayState>& displays,
- uint32_t flags, const sp<IBinder>& applyToken, const InputWindowCommands& commands,
- int64_t desiredPresentTime, const client_cache_t& uncacheBuffer,
- bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks) {
+ int64_t frameTimelineVsyncId, const Vector<ComposerState>& state,
+ const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
+ const InputWindowCommands& commands, int64_t desiredPresentTime,
+ const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
+ const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ SAFE_PARCEL(data.writeInt64, frameTimelineVsyncId);
SAFE_PARCEL(data.writeUint32, static_cast<uint32_t>(state.size()));
for (const auto& s : state) {
SAFE_PARCEL(s.write, data);
@@ -100,6 +102,8 @@
SAFE_PARCEL(data.writeInt64Vector, callbackIds);
}
+ SAFE_PARCEL(data.writeUint64, transactionId);
+
return remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply);
}
@@ -1231,6 +1235,8 @@
case SET_TRANSACTION_STATE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ int64_t frameTimelineVsyncId;
+ SAFE_PARCEL(data.readInt64, &frameTimelineVsyncId);
uint32_t count = 0;
SAFE_PARCEL_READ_SIZE(data.readUint32, &count, data.dataSize());
Vector<ComposerState> state;
@@ -1278,9 +1284,14 @@
SAFE_PARCEL(data.readInt64Vector, &callbackIds);
listenerCallbacks.emplace_back(tmpBinder, callbackIds);
}
- return setTransactionState(state, displays, stateFlags, applyToken, inputWindowCommands,
- desiredPresentTime, uncachedBuffer, hasListenerCallbacks,
- listenerCallbacks);
+
+ uint64_t transactionId = -1;
+ SAFE_PARCEL(data.readUint64, &transactionId);
+
+ return setTransactionState(frameTimelineVsyncId, state, displays, stateFlags,
+ applyToken, inputWindowCommands, desiredPresentTime,
+ uncachedBuffer, hasListenerCallbacks, listenerCallbacks,
+ transactionId);
}
case BOOT_FINISHED: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index 621cf59..a814362 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -49,13 +49,13 @@
status_t createSurface(const String8& name, uint32_t width, uint32_t height, PixelFormat format,
uint32_t flags, const sp<IBinder>& parent, LayerMetadata metadata,
- sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp,
+ sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, int32_t* outId,
uint32_t* outTransformHint) override {
return callRemote<decltype(&ISurfaceComposerClient::createSurface)>(Tag::CREATE_SURFACE,
name, width, height,
format, flags, parent,
std::move(metadata),
- handle, gbp,
+ handle, gbp, outId,
outTransformHint);
}
@@ -63,14 +63,14 @@
PixelFormat format, uint32_t flags,
const sp<IGraphicBufferProducer>& parent,
LayerMetadata metadata, sp<IBinder>* handle,
- sp<IGraphicBufferProducer>* gbp,
+ sp<IGraphicBufferProducer>* gbp, int32_t* outId,
uint32_t* outTransformHint) override {
return callRemote<decltype(
&ISurfaceComposerClient::createWithSurfaceParent)>(Tag::CREATE_WITH_SURFACE_PARENT,
name, width, height, format,
flags, parent,
std::move(metadata), handle, gbp,
- outTransformHint);
+ outId, outTransformHint);
}
status_t clearLayerFrameStats(const sp<IBinder>& handle) const override {
@@ -85,10 +85,11 @@
outStats);
}
- status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle) override {
+ status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle,
+ int32_t* outId) override {
return callRemote<decltype(&ISurfaceComposerClient::mirrorSurface)>(Tag::MIRROR_SURFACE,
mirrorFromHandle,
- outHandle);
+ outHandle, outId);
}
};
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 6ff4a3d..bde73ba 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -18,19 +18,59 @@
#include <inttypes.h>
-#include <utils/Errors.h>
#include <binder/Parcel.h>
-#include <gui/ISurfaceComposerClient.h>
#include <gui/IGraphicBufferProducer.h>
+#include <gui/ISurfaceComposerClient.h>
#include <gui/LayerState.h>
+#include <utils/Errors.h>
#include <cmath>
namespace android {
+layer_state_t::layer_state_t()
+ : what(0),
+ x(0),
+ y(0),
+ z(0),
+ w(0),
+ h(0),
+ layerStack(0),
+ alpha(0),
+ flags(0),
+ mask(0),
+ reserved(0),
+ crop_legacy(Rect::INVALID_RECT),
+ cornerRadius(0.0f),
+ backgroundBlurRadius(0),
+ barrierFrameNumber(0),
+ overrideScalingMode(-1),
+ transform(0),
+ transformToDisplayInverse(false),
+ crop(Rect::INVALID_RECT),
+ orientedDisplaySpaceRect(Rect::INVALID_RECT),
+ dataspace(ui::Dataspace::UNKNOWN),
+ surfaceDamageRegion(),
+ api(-1),
+ colorTransform(mat4()),
+ bgColorAlpha(0),
+ bgColorDataspace(ui::Dataspace::UNKNOWN),
+ colorSpaceAgnostic(false),
+ shadowRadius(0.0f),
+ frameRateSelectionPriority(-1),
+ frameRate(0.0f),
+ frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT),
+ fixedTransformHint(ui::Transform::ROT_INVALID),
+ frameNumber(0) {
+ matrix.dsdx = matrix.dtdy = 1.0f;
+ matrix.dsdy = matrix.dtdx = 0.0f;
+ hdrMetadata.validTypes = 0;
+}
+
status_t layer_state_t::write(Parcel& output) const
{
SAFE_PARCEL(output.writeStrongBinder, surface);
+ SAFE_PARCEL(output.writeInt32, layerId);
SAFE_PARCEL(output.writeUint64, what);
SAFE_PARCEL(output.writeFloat, x);
SAFE_PARCEL(output.writeFloat, y);
@@ -43,13 +83,12 @@
SAFE_PARCEL(output.writeUint32, mask);
SAFE_PARCEL(matrix.write, output);
SAFE_PARCEL(output.write, crop_legacy);
- SAFE_PARCEL(output.writeStrongBinder, barrierHandle_legacy);
- SAFE_PARCEL(output.writeStrongBinder, reparentHandle);
- SAFE_PARCEL(output.writeUint64, frameNumber_legacy);
+ SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, barrierSurfaceControl_legacy);
+ SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, reparentSurfaceControl);
+ SAFE_PARCEL(output.writeUint64, barrierFrameNumber);
SAFE_PARCEL(output.writeInt32, overrideScalingMode);
- SAFE_PARCEL(output.writeStrongBinder, IInterface::asBinder(barrierGbp_legacy));
- SAFE_PARCEL(output.writeStrongBinder, relativeLayerHandle);
- SAFE_PARCEL(output.writeStrongBinder, parentHandleForChild);
+ SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, relativeLayerSurfaceControl);
+ SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, parentSurfaceControlForChild);
SAFE_PARCEL(output.writeFloat, color.r);
SAFE_PARCEL(output.writeFloat, color.g);
SAFE_PARCEL(output.writeFloat, color.b);
@@ -108,12 +147,14 @@
SAFE_PARCEL(output.writeFloat, frameRate);
SAFE_PARCEL(output.writeByte, frameRateCompatibility);
SAFE_PARCEL(output.writeUint32, fixedTransformHint);
+ SAFE_PARCEL(output.writeUint64, frameNumber);
return NO_ERROR;
}
status_t layer_state_t::read(const Parcel& input)
{
SAFE_PARCEL(input.readNullableStrongBinder, &surface);
+ SAFE_PARCEL(input.readInt32, &layerId);
SAFE_PARCEL(input.readUint64, &what);
SAFE_PARCEL(input.readFloat, &x);
SAFE_PARCEL(input.readFloat, &y);
@@ -132,18 +173,15 @@
SAFE_PARCEL(matrix.read, input);
SAFE_PARCEL(input.read, crop_legacy);
- SAFE_PARCEL(input.readNullableStrongBinder, &barrierHandle_legacy);
- SAFE_PARCEL(input.readNullableStrongBinder, &reparentHandle);
- SAFE_PARCEL(input.readUint64, &frameNumber_legacy);
+ SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &barrierSurfaceControl_legacy);
+ SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &reparentSurfaceControl);
+ SAFE_PARCEL(input.readUint64, &barrierFrameNumber);
SAFE_PARCEL(input.readInt32, &overrideScalingMode);
- sp<IBinder> tmpBinder;
- SAFE_PARCEL(input.readNullableStrongBinder, &tmpBinder);
- barrierGbp_legacy = interface_cast<IGraphicBufferProducer>(tmpBinder);
+ SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &relativeLayerSurfaceControl);
+ SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &parentSurfaceControlForChild);
float tmpFloat = 0;
- SAFE_PARCEL(input.readNullableStrongBinder, &relativeLayerHandle);
- SAFE_PARCEL(input.readNullableStrongBinder, &parentHandleForChild);
SAFE_PARCEL(input.readFloat, &tmpFloat);
color.r = tmpFloat;
SAFE_PARCEL(input.readFloat, &tmpFloat);
@@ -187,6 +225,7 @@
SAFE_PARCEL(input.read, &colorTransform, 16 * sizeof(float));
SAFE_PARCEL(input.readFloat, &cornerRadius);
SAFE_PARCEL(input.readUint32, &backgroundBlurRadius);
+ sp<IBinder> tmpBinder;
SAFE_PARCEL(input.readNullableStrongBinder, &tmpBinder);
cachedBuffer.token = tmpBinder;
SAFE_PARCEL(input.readUint64, &cachedBuffer.id);
@@ -213,6 +252,7 @@
SAFE_PARCEL(input.readByte, &frameRateCompatibility);
SAFE_PARCEL(input.readUint32, &tmpUint32);
fixedTransformHint = static_cast<ui::Transform::RotationFlags>(tmpUint32);
+ SAFE_PARCEL(input.readUint64, &frameNumber);
return NO_ERROR;
}
@@ -338,9 +378,8 @@
}
if (other.what & eDeferTransaction_legacy) {
what |= eDeferTransaction_legacy;
- barrierHandle_legacy = other.barrierHandle_legacy;
- barrierGbp_legacy = other.barrierGbp_legacy;
- frameNumber_legacy = other.frameNumber_legacy;
+ barrierSurfaceControl_legacy = other.barrierSurfaceControl_legacy;
+ barrierFrameNumber = other.barrierFrameNumber;
}
if (other.what & eOverrideScalingModeChanged) {
what |= eOverrideScalingModeChanged;
@@ -348,7 +387,7 @@
}
if (other.what & eReparentChildren) {
what |= eReparentChildren;
- reparentHandle = other.reparentHandle;
+ reparentSurfaceControl = other.reparentSurfaceControl;
}
if (other.what & eDetachChildren) {
what |= eDetachChildren;
@@ -357,11 +396,11 @@
what |= eRelativeLayerChanged;
what &= ~eLayerChanged;
z = other.z;
- relativeLayerHandle = other.relativeLayerHandle;
+ relativeLayerSurfaceControl = other.relativeLayerSurfaceControl;
}
if (other.what & eReparent) {
what |= eReparent;
- parentHandleForChild = other.parentHandleForChild;
+ parentSurfaceControlForChild = other.parentSurfaceControlForChild;
}
if (other.what & eDestroySurface) {
what |= eDestroySurface;
@@ -456,6 +495,10 @@
what |= eFixedTransformHintChanged;
fixedTransformHint = other.fixedTransformHint;
}
+ if (other.what & eFrameNumberChanged) {
+ what |= eFrameNumberChanged;
+ frameNumber = other.frameNumber;
+ }
if ((other.what & what) != other.what) {
ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
"other.what=0x%" PRIu64 " what=0x%" PRIu64,
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 8d2a7d9..0068ccf 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -348,15 +348,25 @@
// ---------------------------------------------------------------------------
+// Initialize transaction id counter used to generate transaction ids
+// Transactions will start counting at 1, 0 is used for invalid transactions
+std::atomic<uint32_t> SurfaceComposerClient::Transaction::idCounter = 1;
+
+SurfaceComposerClient::Transaction::Transaction() {
+ mId = generateId();
+}
+
SurfaceComposerClient::Transaction::Transaction(const Transaction& other)
- : mForceSynchronous(other.mForceSynchronous),
+ : mId(other.mId),
+ mForceSynchronous(other.mForceSynchronous),
mTransactionNestCount(other.mTransactionNestCount),
mAnimation(other.mAnimation),
mEarlyWakeup(other.mEarlyWakeup),
mExplicitEarlyWakeupStart(other.mExplicitEarlyWakeupStart),
mExplicitEarlyWakeupEnd(other.mExplicitEarlyWakeupEnd),
mContainsBuffer(other.mContainsBuffer),
- mDesiredPresentTime(other.mDesiredPresentTime) {
+ mDesiredPresentTime(other.mDesiredPresentTime),
+ mFrameTimelineVsyncId(other.mFrameTimelineVsyncId) {
mDisplayStates = other.mDisplayStates;
mComposerStates = other.mComposerStates;
mInputWindowCommands = other.mInputWindowCommands;
@@ -372,6 +382,10 @@
return nullptr;
}
+int64_t SurfaceComposerClient::Transaction::generateId() {
+ return (((int64_t)getpid()) << 32) | idCounter++;
+}
+
status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel) {
const uint32_t forceSynchronous = parcel->readUint32();
const uint32_t transactionNestCount = parcel->readUint32();
@@ -381,6 +395,7 @@
const bool explicitEarlyWakeupEnd = parcel->readBool();
const bool containsBuffer = parcel->readBool();
const int64_t desiredPresentTime = parcel->readInt64();
+ const int64_t frameTimelineVsyncId = parcel->readInt64();
size_t count = static_cast<size_t>(parcel->readUint32());
if (count > parcel->dataSize()) {
@@ -418,7 +433,7 @@
}
for (size_t j = 0; j < numSurfaces; j++) {
sp<SurfaceControl> surface;
- surface = SurfaceControl::readFromParcel(parcel);
+ SAFE_PARCEL(SurfaceControl::readFromParcel, *parcel, &surface);
listenerCallbacks[listener].surfaceControls.insert(surface);
}
}
@@ -430,12 +445,14 @@
std::unordered_map<sp<IBinder>, ComposerState, IBinderHash> composerStates;
composerStates.reserve(count);
for (size_t i = 0; i < count; i++) {
- sp<IBinder> surfaceControlHandle = parcel->readStrongBinder();
+ sp<IBinder> surfaceControlHandle;
+ SAFE_PARCEL(parcel->readStrongBinder, &surfaceControlHandle);
ComposerState composerState;
if (composerState.read(*parcel) == BAD_VALUE) {
return BAD_VALUE;
}
+
composerStates[surfaceControlHandle] = composerState;
}
@@ -451,6 +468,7 @@
mExplicitEarlyWakeupEnd = explicitEarlyWakeupEnd;
mContainsBuffer = containsBuffer;
mDesiredPresentTime = desiredPresentTime;
+ mFrameTimelineVsyncId = frameTimelineVsyncId;
mDisplayStates = displayStates;
mListenerCallbacks = listenerCallbacks;
mComposerStates = composerStates;
@@ -480,6 +498,7 @@
parcel->writeBool(mExplicitEarlyWakeupEnd);
parcel->writeBool(mContainsBuffer);
parcel->writeInt64(mDesiredPresentTime);
+ parcel->writeInt64(mFrameTimelineVsyncId);
parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size()));
for (auto const& displayState : mDisplayStates) {
displayState.write(*parcel);
@@ -494,13 +513,13 @@
}
parcel->writeUint32(static_cast<uint32_t>(callbackInfo.surfaceControls.size()));
for (auto surfaceControl : callbackInfo.surfaceControls) {
- surfaceControl->writeToParcel(parcel);
+ SAFE_PARCEL(surfaceControl->writeToParcel, *parcel);
}
}
parcel->writeUint32(static_cast<uint32_t>(mComposerStates.size()));
- for (auto const& [surfaceHandle, composerState] : mComposerStates) {
- parcel->writeStrongBinder(surfaceHandle);
+ for (auto const& [handle, composerState] : mComposerStates) {
+ SAFE_PARCEL(parcel->writeStrongBinder, handle);
composerState.write(*parcel);
}
@@ -509,11 +528,11 @@
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) {
- for (auto const& [surfaceHandle, composerState] : other.mComposerStates) {
- if (mComposerStates.count(surfaceHandle) == 0) {
- mComposerStates[surfaceHandle] = composerState;
+ for (auto const& [handle, composerState] : other.mComposerStates) {
+ if (mComposerStates.count(handle) == 0) {
+ mComposerStates[handle] = composerState;
} else {
- mComposerStates[surfaceHandle].state.merge(composerState.state);
+ mComposerStates[handle].state.merge(composerState.state);
}
}
@@ -555,6 +574,15 @@
mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup;
mExplicitEarlyWakeupStart = mExplicitEarlyWakeupStart || other.mExplicitEarlyWakeupStart;
mExplicitEarlyWakeupEnd = mExplicitEarlyWakeupEnd || other.mExplicitEarlyWakeupEnd;
+
+ // When merging vsync Ids we take the oldest one
+ if (mFrameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID &&
+ other.mFrameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID) {
+ mFrameTimelineVsyncId = std::max(mFrameTimelineVsyncId, other.mFrameTimelineVsyncId);
+ } else if (mFrameTimelineVsyncId == ISurfaceComposer::INVALID_VSYNC_ID) {
+ mFrameTimelineVsyncId = other.mFrameTimelineVsyncId;
+ }
+
other.clear();
return *this;
}
@@ -572,6 +600,7 @@
mExplicitEarlyWakeupStart = false;
mExplicitEarlyWakeupEnd = false;
mDesiredPresentTime = -1;
+ mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID;
}
void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) {
@@ -582,7 +611,8 @@
uncacheBuffer.id = cacheId;
sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
- sf->setTransactionState({}, {}, 0, applyToken, {}, -1, uncacheBuffer, false, {});
+ sf->setTransactionState(ISurfaceComposer::INVALID_VSYNC_ID, {}, {}, 0, applyToken, {}, -1,
+ uncacheBuffer, false, {}, 0 /* Undefined transactionId */);
}
void SurfaceComposerClient::Transaction::cacheBuffers() {
@@ -592,7 +622,7 @@
size_t count = 0;
for (auto& [handle, cs] : mComposerStates) {
- layer_state_t* s = getLayerState(handle);
+ layer_state_t* s = &(mComposerStates[handle].state);
if (!(s->what & layer_state_t::eBufferChanged)) {
continue;
} else if (s->what & layer_state_t::eCachedBufferChanged) {
@@ -709,11 +739,14 @@
mExplicitEarlyWakeupStart = false;
mExplicitEarlyWakeupEnd = false;
+ uint64_t transactionId = mId;
+ mId = generateId();
+
sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
- sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands,
- mDesiredPresentTime,
+ sf->setTransactionState(mFrameTimelineVsyncId, composerStates, displayStates, flags, applyToken,
+ mInputWindowCommands, mDesiredPresentTime,
{} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,
- hasListenerCallbacks, listenerCallbacks);
+ hasListenerCallbacks, listenerCallbacks, transactionId);
mInputWindowCommands.clear();
mStatus = NO_ERROR;
return NO_ERROR;
@@ -762,11 +795,16 @@
mExplicitEarlyWakeupEnd = true;
}
-layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<IBinder>& handle) {
+layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl>& sc) {
+ auto handle = sc->getHandle();
+
if (mComposerStates.count(handle) == 0) {
// we don't have it, add an initialized layer_state to our list
ComposerState s;
+
s.state.surface = handle;
+ s.state.layerId = sc->getLayerId();
+
mComposerStates[handle] = s;
}
@@ -837,8 +875,8 @@
return *this;
}
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setRelativeLayer(const sp<SurfaceControl>& sc, const sp<IBinder>& relativeTo,
- int32_t z) {
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setRelativeLayer(
+ const sp<SurfaceControl>& sc, const sp<SurfaceControl>& relativeTo, int32_t z) {
layer_state_t* s = getLayerState(sc);
if (!s) {
mStatus = BAD_INDEX;
@@ -846,7 +884,7 @@
}
s->what |= layer_state_t::eRelativeLayerChanged;
s->what &= ~layer_state_t::eLayerChanged;
- s->relativeLayerHandle = relativeTo;
+ s->relativeLayerSurfaceControl = relativeTo;
s->z = z;
registerSurfaceControlForCallback(sc);
@@ -990,64 +1028,45 @@
}
SurfaceComposerClient::Transaction&
-SurfaceComposerClient::Transaction::deferTransactionUntil_legacy(const sp<SurfaceControl>& sc,
- const sp<IBinder>& handle,
- uint64_t frameNumber) {
+SurfaceComposerClient::Transaction::deferTransactionUntil_legacy(
+ const sp<SurfaceControl>& sc, const sp<SurfaceControl>& barrierSurfaceControl,
+ uint64_t frameNumber) {
layer_state_t* s = getLayerState(sc);
if (!s) {
mStatus = BAD_INDEX;
return *this;
}
s->what |= layer_state_t::eDeferTransaction_legacy;
- s->barrierHandle_legacy = handle;
- s->frameNumber_legacy = frameNumber;
-
- registerSurfaceControlForCallback(sc);
- return *this;
-}
-
-SurfaceComposerClient::Transaction&
-SurfaceComposerClient::Transaction::deferTransactionUntil_legacy(const sp<SurfaceControl>& sc,
- const sp<Surface>& barrierSurface,
- uint64_t frameNumber) {
- layer_state_t* s = getLayerState(sc);
- if (!s) {
- mStatus = BAD_INDEX;
- return *this;
- }
- s->what |= layer_state_t::eDeferTransaction_legacy;
- s->barrierGbp_legacy = barrierSurface->getIGraphicBufferProducer();
- s->frameNumber_legacy = frameNumber;
+ s->barrierSurfaceControl_legacy = barrierSurfaceControl;
+ s->barrierFrameNumber = frameNumber;
registerSurfaceControlForCallback(sc);
return *this;
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparentChildren(
- const sp<SurfaceControl>& sc,
- const sp<IBinder>& newParentHandle) {
+ const sp<SurfaceControl>& sc, const sp<SurfaceControl>& newParent) {
layer_state_t* s = getLayerState(sc);
if (!s) {
mStatus = BAD_INDEX;
return *this;
}
s->what |= layer_state_t::eReparentChildren;
- s->reparentHandle = newParentHandle;
+ s->reparentSurfaceControl = newParent;
registerSurfaceControlForCallback(sc);
return *this;
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparent(
- const sp<SurfaceControl>& sc,
- const sp<IBinder>& newParentHandle) {
+ const sp<SurfaceControl>& sc, const sp<SurfaceControl>& newParent) {
layer_state_t* s = getLayerState(sc);
if (!s) {
mStatus = BAD_INDEX;
return *this;
}
s->what |= layer_state_t::eReparent;
- s->parentHandleForChild = newParentHandle;
+ s->parentSurfaceControlForChild = newParent;
registerSurfaceControlForCallback(sc);
return *this;
@@ -1307,6 +1326,20 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameNumber(
+ const sp<SurfaceControl>& sc, uint64_t frameNumber) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+
+ s->what |= layer_state_t::eFrameNumberChanged;
+ s->frameNumber = frameNumber;
+
+ return *this;
+}
+
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::detachChildren(
const sp<SurfaceControl>& sc) {
layer_state_t* s = getLayerState(sc);
@@ -1500,6 +1533,12 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineVsync(
+ int64_t frameTimelineVsyncId) {
+ mFrameTimelineVsyncId = frameTimelineVsyncId;
+ return *this;
+}
+
// ---------------------------------------------------------------------------
DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
@@ -1638,14 +1677,16 @@
sp<IGraphicBufferProducer> gbp;
uint32_t transformHint = 0;
+ int32_t id = -1;
err = mClient->createWithSurfaceParent(name, w, h, format, flags, parentGbp,
- std::move(metadata), &handle, &gbp, &transformHint);
+ std::move(metadata), &handle, &gbp, &id,
+ &transformHint);
if (outTransformHint) {
*outTransformHint = transformHint;
}
ALOGE_IF(err, "SurfaceComposerClient::createWithSurfaceParent error %s", strerror(-err));
if (err == NO_ERROR) {
- return new SurfaceControl(this, handle, gbp, transformHint);
+ return new SurfaceControl(this, handle, gbp, id, transformHint);
}
}
return nullptr;
@@ -1669,14 +1710,16 @@
}
uint32_t transformHint = 0;
+ int32_t id = -1;
err = mClient->createSurface(name, w, h, format, flags, parentHandle, std::move(metadata),
- &handle, &gbp, &transformHint);
+ &handle, &gbp, &id, &transformHint);
+
if (outTransformHint) {
*outTransformHint = transformHint;
}
ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
if (err == NO_ERROR) {
- *outSurface = new SurfaceControl(this, handle, gbp, transformHint);
+ *outSurface = new SurfaceControl(this, handle, gbp, id, transformHint);
}
}
return err;
@@ -1689,9 +1732,10 @@
sp<IBinder> handle;
sp<IBinder> mirrorFromHandle = mirrorFromSurface->getHandle();
- status_t err = mClient->mirrorSurface(mirrorFromHandle, &handle);
+ int32_t layer_id = -1;
+ status_t err = mClient->mirrorSurface(mirrorFromHandle, &handle, &layer_id);
if (err == NO_ERROR) {
- return new SurfaceControl(this, handle, nullptr, true /* owned */);
+ return new SurfaceControl(this, handle, nullptr, layer_id, true /* owned */);
}
return nullptr;
}
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 8dcb71b..e842382 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -24,6 +24,7 @@
#include <android/native_window.h>
#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
#include <utils/Log.h>
#include <utils/threads.h>
@@ -46,11 +47,12 @@
// ============================================================================
SurfaceControl::SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle,
- const sp<IGraphicBufferProducer>& gbp,
+ const sp<IGraphicBufferProducer>& gbp, int32_t layerId,
uint32_t transform)
: mClient(client),
mHandle(handle),
mGraphicBufferProducer(gbp),
+ mLayerId(layerId),
mTransformHint(transform) {}
SurfaceControl::SurfaceControl(const sp<SurfaceControl>& other) {
@@ -58,6 +60,7 @@
mHandle = other->mHandle;
mGraphicBufferProducer = other->mGraphicBufferProducer;
mTransformHint = other->mTransformHint;
+ mLayerId = other->mLayerId;
}
SurfaceControl::~SurfaceControl()
@@ -148,6 +151,10 @@
return mHandle;
}
+int32_t SurfaceControl::getLayerId() const {
+ return mLayerId;
+}
+
sp<IGraphicBufferProducer> SurfaceControl::getIGraphicBufferProducer() const
{
Mutex::Autolock _l(mLock);
@@ -169,42 +176,60 @@
mTransformHint = hint;
}
-void SurfaceControl::writeToParcel(Parcel* parcel)
-{
- parcel->writeStrongBinder(ISurfaceComposerClient::asBinder(mClient->getClient()));
- parcel->writeStrongBinder(mHandle);
- parcel->writeStrongBinder(IGraphicBufferProducer::asBinder(mGraphicBufferProducer));
- parcel->writeUint32(mTransformHint);
+status_t SurfaceControl::writeToParcel(Parcel& parcel) {
+ SAFE_PARCEL(parcel.writeStrongBinder, ISurfaceComposerClient::asBinder(mClient->getClient()));
+ SAFE_PARCEL(parcel.writeStrongBinder, mHandle);
+ SAFE_PARCEL(parcel.writeStrongBinder, IGraphicBufferProducer::asBinder(mGraphicBufferProducer));
+ SAFE_PARCEL(parcel.writeInt32, mLayerId);
+ SAFE_PARCEL(parcel.writeUint32, mTransformHint);
+
+ return NO_ERROR;
}
-sp<SurfaceControl> SurfaceControl::readFromParcel(const Parcel* parcel) {
- bool invalidParcel = false;
- status_t status;
+status_t SurfaceControl::readFromParcel(const Parcel& parcel,
+ sp<SurfaceControl>* outSurfaceControl) {
sp<IBinder> client;
- if ((status = parcel->readStrongBinder(&client)) != OK) {
- ALOGE("Failed to read client: %s", statusToString(status).c_str());
- invalidParcel = true;
- }
sp<IBinder> handle;
- if ((status = parcel->readStrongBinder(&handle)) != OK) {
- ALOGE("Failed to read handle: %s", statusToString(status).c_str());
- invalidParcel = true;
- }
sp<IBinder> gbp;
- if ((status = parcel->readNullableStrongBinder(&gbp)) != OK) {
- ALOGE("Failed to read gbp: %s", statusToString(status).c_str());
- invalidParcel = true;
- }
- uint32_t transformHint = parcel->readUint32();
+ int32_t layerId;
+ uint32_t transformHint;
- if (invalidParcel) {
- return nullptr;
- }
+ SAFE_PARCEL(parcel.readStrongBinder, &client);
+ SAFE_PARCEL(parcel.readStrongBinder, &handle);
+ SAFE_PARCEL(parcel.readNullableStrongBinder, &gbp);
+ SAFE_PARCEL(parcel.readInt32, &layerId);
+ SAFE_PARCEL(parcel.readUint32, &transformHint);
+
// We aren't the original owner of the surface.
- return new SurfaceControl(new SurfaceComposerClient(
- interface_cast<ISurfaceComposerClient>(client)),
- handle.get(), interface_cast<IGraphicBufferProducer>(gbp),
+ *outSurfaceControl =
+ new SurfaceControl(new SurfaceComposerClient(
+ interface_cast<ISurfaceComposerClient>(client)),
+ handle.get(), interface_cast<IGraphicBufferProducer>(gbp), layerId,
transformHint);
+
+ return NO_ERROR;
+}
+
+status_t SurfaceControl::readNullableFromParcel(const Parcel& parcel,
+ sp<SurfaceControl>* outSurfaceControl) {
+ bool isNotNull;
+ SAFE_PARCEL(parcel.readBool, &isNotNull);
+ if (isNotNull) {
+ SAFE_PARCEL(SurfaceControl::readFromParcel, parcel, outSurfaceControl);
+ }
+
+ return NO_ERROR;
+}
+
+status_t SurfaceControl::writeNullableToParcel(Parcel& parcel,
+ const sp<SurfaceControl>& surfaceControl) {
+ auto isNotNull = surfaceControl != nullptr;
+ SAFE_PARCEL(parcel.writeBool, isNotNull);
+ if (isNotNull) {
+ SAFE_PARCEL(surfaceControl->writeToParcel, parcel);
+ }
+
+ return NO_ERROR;
}
// ----------------------------------------------------------------------------
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 2320771..5b1a018 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -66,8 +66,8 @@
: public ConsumerBase::FrameAvailableListener, public BufferItemConsumer::BufferFreedListener
{
public:
- BLASTBufferQueue(const sp<SurfaceControl>& surface, int width, int height,
- bool enableTripleBuffering = true);
+ BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface, int width,
+ int height, bool enableTripleBuffering = true);
sp<IGraphicBufferProducer> getIGraphicBufferProducer() const {
return mProducer;
@@ -81,7 +81,7 @@
const std::vector<SurfaceControlStats>& stats);
void setNextTransaction(SurfaceComposerClient::Transaction *t);
- void update(const sp<SurfaceControl>& surface, int width, int height);
+ void update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height);
virtual ~BLASTBufferQueue() = default;
@@ -94,7 +94,10 @@
void processNextBufferLocked(bool useNextTransaction) REQUIRES(mMutex);
Rect computeCrop(const BufferItem& item);
+ // Return true if we need to reject the buffer based on the scaling mode and the buffer size.
+ bool rejectBuffer(const BufferItem& item) const;
+ std::string mName;
sp<SurfaceControl> mSurfaceControl;
std::mutex mMutex;
@@ -106,17 +109,19 @@
int32_t mNumFrameAvailable GUARDED_BY(mMutex);
int32_t mNumAcquired GUARDED_BY(mMutex);
-
+ bool mInitialCallbackReceived GUARDED_BY(mMutex) = false;
struct PendingReleaseItem {
BufferItem item;
sp<Fence> releaseFence;
};
std::queue<const BufferItem> mSubmitted GUARDED_BY(mMutex);
+ // Keep a reference to the currently presented buffer so we can release it when the next buffer
+ // is ready to be presented.
PendingReleaseItem mPendingReleaseItem GUARDED_BY(mMutex);
- int mWidth GUARDED_BY(mMutex);
- int mHeight GUARDED_BY(mMutex);
+ uint32_t mWidth GUARDED_BY(mMutex);
+ uint32_t mHeight GUARDED_BY(mMutex);
uint32_t mTransformHint GUARDED_BY(mMutex);
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 3627deb..a416147 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -109,6 +109,9 @@
enum ConfigChanged { eConfigChangedSuppress = 0, eConfigChangedDispatch = 1 };
+ // Needs to be in sync with android.graphics.FrameInfo.INVALID_VSYNC_ID in java
+ static constexpr int64_t INVALID_VSYNC_ID = -1;
+
/*
* Create a connection with SurfaceFlinger.
*/
@@ -153,11 +156,11 @@
/* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */
virtual status_t setTransactionState(
- const Vector<ComposerState>& state, const Vector<DisplayState>& displays,
- uint32_t flags, const sp<IBinder>& applyToken,
+ int64_t frameTimelineVsyncId, const Vector<ComposerState>& state,
+ const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,
const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
- const std::vector<ListenerCallbacks>& listenerCallbacks) = 0;
+ const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId) = 0;
/* signal that we're done booting.
* Requires ACCESS_SURFACE_FLINGER permission
diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
index ec0a8d1..f3fcebe 100644
--- a/libs/gui/include/gui/ISurfaceComposerClient.h
+++ b/libs/gui/include/gui/ISurfaceComposerClient.h
@@ -58,7 +58,8 @@
virtual status_t createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format,
uint32_t flags, const sp<IBinder>& parent,
LayerMetadata metadata, sp<IBinder>* handle,
- sp<IGraphicBufferProducer>* gbp, uint32_t* outTransformHint) = 0;
+ sp<IGraphicBufferProducer>* gbp, int32_t* outId,
+ uint32_t* outTransformHint) = 0;
/*
* Requires ACCESS_SURFACE_FLINGER permission
@@ -67,7 +68,7 @@
PixelFormat format, uint32_t flags,
const sp<IGraphicBufferProducer>& parent,
LayerMetadata metadata, sp<IBinder>* handle,
- sp<IGraphicBufferProducer>* gbp,
+ sp<IGraphicBufferProducer>* gbp, int32_t* outId,
uint32_t* outTransformHint) = 0;
/*
@@ -80,7 +81,8 @@
*/
virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const = 0;
- virtual status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle) = 0;
+ virtual status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle,
+ int32_t* outId) = 0;
};
class BnSurfaceComposerClient : public SafeBnInterface<ISurfaceComposerClient> {
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 7a9bb12..fed0ef3 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -49,6 +49,7 @@
#include <gui/ISurfaceComposer.h>
#include <gui/LayerMetadata.h>
+#include <gui/SurfaceControl.h>
#include <math/vec3.h>
#include <ui/GraphicTypes.h>
#include <ui/Rect.h>
@@ -125,45 +126,10 @@
eBackgroundBlurRadiusChanged = 0x80'00000000,
eProducerDisconnect = 0x100'00000000,
eFixedTransformHintChanged = 0x200'00000000,
+ eFrameNumberChanged = 0x400'00000000,
};
- layer_state_t()
- : what(0),
- x(0),
- y(0),
- z(0),
- w(0),
- h(0),
- layerStack(0),
- alpha(0),
- flags(0),
- mask(0),
- reserved(0),
- crop_legacy(Rect::INVALID_RECT),
- cornerRadius(0.0f),
- backgroundBlurRadius(0),
- frameNumber_legacy(0),
- overrideScalingMode(-1),
- transform(0),
- transformToDisplayInverse(false),
- crop(Rect::INVALID_RECT),
- orientedDisplaySpaceRect(Rect::INVALID_RECT),
- dataspace(ui::Dataspace::UNKNOWN),
- surfaceDamageRegion(),
- api(-1),
- colorTransform(mat4()),
- bgColorAlpha(0),
- bgColorDataspace(ui::Dataspace::UNKNOWN),
- colorSpaceAgnostic(false),
- shadowRadius(0.0f),
- frameRateSelectionPriority(-1),
- frameRate(0.0f),
- frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT),
- fixedTransformHint(ui::Transform::ROT_INVALID) {
- matrix.dsdx = matrix.dtdy = 1.0f;
- matrix.dsdy = matrix.dtdx = 0.0f;
- hdrMetadata.validTypes = 0;
- }
+ layer_state_t();
void merge(const layer_state_t& other);
status_t write(Parcel& output) const;
@@ -178,6 +144,7 @@
status_t read(const Parcel& input);
};
sp<IBinder> surface;
+ int32_t layerId;
uint64_t what;
float x;
float y;
@@ -193,16 +160,14 @@
Rect crop_legacy;
float cornerRadius;
uint32_t backgroundBlurRadius;
- sp<IBinder> barrierHandle_legacy;
- sp<IBinder> reparentHandle;
- uint64_t frameNumber_legacy;
+ sp<SurfaceControl> barrierSurfaceControl_legacy;
+ sp<SurfaceControl> reparentSurfaceControl;
+ uint64_t barrierFrameNumber;
int32_t overrideScalingMode;
- sp<IGraphicBufferProducer> barrierGbp_legacy;
+ sp<SurfaceControl> relativeLayerSurfaceControl;
- sp<IBinder> relativeLayerHandle;
-
- sp<IBinder> parentHandleForChild;
+ sp<SurfaceControl> parentSurfaceControlForChild;
half3 color;
@@ -259,6 +224,10 @@
// a buffer of a different size. -1 means the transform hint is not set,
// otherwise the value will be a valid ui::Rotation.
ui::Transform::RotationFlags fixedTransformHint;
+
+ // Used by BlastBufferQueue to forward the framenumber generated by the
+ // graphics producer.
+ uint64_t frameNumber;
};
struct ComposerState {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 6cac287..277060f 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -339,12 +339,18 @@
};
class Transaction : public Parcelable {
+ private:
+ static std::atomic<uint32_t> idCounter;
+ int64_t generateId();
+
protected:
std::unordered_map<sp<IBinder>, ComposerState, IBinderHash> mComposerStates;
- SortedVector<DisplayState > mDisplayStates;
+ SortedVector<DisplayState> mDisplayStates;
std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash>
mListenerCallbacks;
+ uint64_t mId;
+
uint32_t mForceSynchronous = 0;
uint32_t mTransactionNestCount = 0;
bool mAnimation = false;
@@ -367,20 +373,20 @@
// The desired present time does not affect this ordering.
int64_t mDesiredPresentTime = -1;
+ // The vsync Id provided by Choreographer.getVsyncId
+ int64_t mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID;
+
InputWindowCommands mInputWindowCommands;
int mStatus = NO_ERROR;
- layer_state_t* getLayerState(const sp<IBinder>& surfaceHandle);
- layer_state_t* getLayerState(const sp<SurfaceControl>& sc) {
- return getLayerState(sc->getHandle());
- }
+ layer_state_t* getLayerState(const sp<SurfaceControl>& sc);
DisplayState& getDisplayState(const sp<IBinder>& token);
void cacheBuffers();
void registerSurfaceControlForCallback(const sp<SurfaceControl>& sc);
public:
- Transaction() = default;
+ Transaction();
virtual ~Transaction() = default;
Transaction(Transaction const& other);
@@ -418,7 +424,7 @@
// If the relative is removed, the Surface will have no layer and be
// invisible, until the next time set(Relative)Layer is called.
Transaction& setRelativeLayer(const sp<SurfaceControl>& sc,
- const sp<IBinder>& relativeTo, int32_t z);
+ const sp<SurfaceControl>& relativeTo, int32_t z);
Transaction& setFlags(const sp<SurfaceControl>& sc,
uint32_t flags, uint32_t mask);
Transaction& setTransparentRegionHint(const sp<SurfaceControl>& sc,
@@ -438,22 +444,16 @@
// by handle is removed, then we will apply this transaction regardless of
// what frame number has been reached.
Transaction& deferTransactionUntil_legacy(const sp<SurfaceControl>& sc,
- const sp<IBinder>& handle, uint64_t frameNumber);
- // A variant of deferTransactionUntil_legacy which identifies the Layer we wait for by
- // Surface instead of Handle. Useful for clients which may not have the
- // SurfaceControl for some of their Surfaces. Otherwise behaves identically.
- Transaction& deferTransactionUntil_legacy(const sp<SurfaceControl>& sc,
- const sp<Surface>& barrierSurface,
+ const sp<SurfaceControl>& barrierSurfaceControl,
uint64_t frameNumber);
// Reparents all children of this layer to the new parent handle.
Transaction& reparentChildren(const sp<SurfaceControl>& sc,
- const sp<IBinder>& newParentHandle);
+ const sp<SurfaceControl>& newParent);
/// Reparents the current layer to the new parent handle. The new parent must not be null.
// This can be used instead of reparentChildren if the caller wants to
// only re-parent a specific child.
- Transaction& reparent(const sp<SurfaceControl>& sc,
- const sp<IBinder>& newParentHandle);
+ Transaction& reparent(const sp<SurfaceControl>& sc, const sp<SurfaceControl>& newParent);
Transaction& setColor(const sp<SurfaceControl>& sc, const half3& color);
@@ -487,6 +487,8 @@
// ONLY FOR BLAST ADAPTER
Transaction& notifyProducerDisconnect(const sp<SurfaceControl>& sc);
+ // Set the framenumber generated by the graphics producer to mimic BufferQueue behaviour.
+ Transaction& setFrameNumber(const sp<SurfaceControl>& sc, uint64_t frameNumber);
// Detaches all child surfaces (and their children recursively)
// from their SurfaceControl.
@@ -532,6 +534,10 @@
// a buffer of a different size.
Transaction& setFixedTransformHint(const sp<SurfaceControl>& sc, int32_t transformHint);
+ // Sets the frame timeline vsync id received from choreographer that corresponds
+ // to the transaction.
+ Transaction& setFrameTimelineVsync(int64_t frameTimelineVsyncId);
+
status_t setDisplaySurface(const sp<IBinder>& token,
const sp<IGraphicBufferProducer>& bufferProducer);
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index ac2bbcc..35bdfc1 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -20,7 +20,6 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
@@ -44,8 +43,12 @@
class SurfaceControl : public RefBase
{
public:
- static sp<SurfaceControl> readFromParcel(const Parcel* parcel);
- void writeToParcel(Parcel* parcel);
+ static status_t readFromParcel(const Parcel& parcel, sp<SurfaceControl>* outSurfaceControl);
+ status_t writeToParcel(Parcel& parcel);
+
+ static status_t readNullableFromParcel(const Parcel& parcel,
+ sp<SurfaceControl>* outSurfaceControl);
+ static status_t writeNullableToParcel(Parcel& parcel, const sp<SurfaceControl>& surfaceControl);
static bool isValid(const sp<SurfaceControl>& surface) {
return (surface != nullptr) && surface->isValid();
@@ -70,6 +73,7 @@
sp<Surface> getSurface() const;
sp<Surface> createSurface() const;
sp<IBinder> getHandle() const;
+ int32_t getLayerId() const;
sp<IGraphicBufferProducer> getIGraphicBufferProducer() const;
@@ -85,7 +89,8 @@
explicit SurfaceControl(const sp<SurfaceControl>& other);
SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle,
- const sp<IGraphicBufferProducer>& gbp, uint32_t transformHint = 0);
+ const sp<IGraphicBufferProducer>& gbp, int32_t layerId,
+ uint32_t transformHint = 0);
private:
// can't be copied
@@ -105,6 +110,7 @@
sp<IGraphicBufferProducer> mGraphicBufferProducer;
mutable Mutex mLock;
mutable sp<Surface> mSurfaceData;
+ int32_t mLayerId;
uint32_t mTransformHint;
};
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index da0d5f8..9299721 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -44,7 +44,7 @@
class BLASTBufferQueueHelper {
public:
BLASTBufferQueueHelper(const sp<SurfaceControl>& sc, int width, int height) {
- mBlastBufferQueueAdapter = new BLASTBufferQueue(sc, width, height);
+ mBlastBufferQueueAdapter = new BLASTBufferQueue("TestBLASTBufferQueue", sc, width, height);
}
void update(const sp<SurfaceControl>& sc, int width, int height) {
@@ -490,8 +490,8 @@
IGraphicBufferProducer::QueueBufferOutput qbOutput;
IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN,
Rect(bufWidth, bufHeight),
- NATIVE_WINDOW_SCALING_MODE_FREEZE, tr,
- Fence::NO_FENCE);
+ NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW,
+ tr, Fence::NO_FENCE);
igbProducer->queueBuffer(slot, input, &qbOutput);
ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint);
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index ef4d870..483f171 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -381,7 +381,7 @@
childSurface->doTransaction([&](auto &t, auto &sc) {
t.setPosition(sc, -5, -5);
- t.reparent(sc, parentSurface->mSurfaceControl->getHandle());
+ t.reparent(sc, parentSurface->mSurfaceControl);
});
injectTap(106, 106);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index b8b8e4f..5a376da 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -695,12 +695,16 @@
void destroyDisplay(const sp<IBinder>& /*display */) override {}
std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override { return {}; }
sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId) const override { return nullptr; }
- status_t setTransactionState(
- const Vector<ComposerState>& /*state*/, const Vector<DisplayState>& /*displays*/,
- uint32_t /*flags*/, const sp<IBinder>& /*applyToken*/,
- const InputWindowCommands& /*inputWindowCommands*/, int64_t /*desiredPresentTime*/,
- const client_cache_t& /*cachedBuffer*/, bool /*hasListenerCallbacks*/,
- const std::vector<ListenerCallbacks>& /*listenerCallbacks*/) override {
+ status_t setTransactionState(int64_t /*frameTimelineVsyncId*/,
+ const Vector<ComposerState>& /*state*/,
+ const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
+ const sp<IBinder>& /*applyToken*/,
+ const InputWindowCommands& /*inputWindowCommands*/,
+ int64_t /*desiredPresentTime*/,
+ const client_cache_t& /*cachedBuffer*/,
+ bool /*hasListenerCallbacks*/,
+ const std::vector<ListenerCallbacks>& /*listenerCallbacks*/,
+ uint64_t /*transactionId*/) override {
return NO_ERROR;
}
diff --git a/libs/input/InputEventLabels.cpp b/libs/input/InputEventLabels.cpp
index dee240c..c0aa2e2 100644
--- a/libs/input/InputEventLabels.cpp
+++ b/libs/input/InputEventLabels.cpp
@@ -348,6 +348,9 @@
DEFINE_AXIS(SCROLL), \
DEFINE_AXIS(RELATIVE_X), \
DEFINE_AXIS(RELATIVE_Y), \
+ {"RESERVED_29", 29}, \
+ {"RESERVED_30", 30}, \
+ {"RESERVED_31", 31}, \
DEFINE_AXIS(GENERIC_1), \
DEFINE_AXIS(GENERIC_2), \
DEFINE_AXIS(GENERIC_3), \
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 7ff5ab6..44147a5 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -2,6 +2,7 @@
cc_test {
name: "libinput_tests",
srcs: [
+ "NamedEnum_test.cpp",
"Flags_test.cpp",
"IdGenerator_test.cpp",
"InputChannel_test.cpp",
diff --git a/libs/input/tests/NamedEnum_test.cpp b/libs/input/tests/NamedEnum_test.cpp
new file mode 100644
index 0000000..4e93f71
--- /dev/null
+++ b/libs/input/tests/NamedEnum_test.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <input/NamedEnum.h>
+
+namespace android {
+
+// Test enum class maximum enum value smaller than default maximum of 8.
+enum class TestEnums { ZERO = 0x0, ONE = 0x1, TWO = 0x2, THREE = 0x3, SEVEN = 0x7 };
+// Big enum contains enum values greater than default maximum of 8.
+enum class TestBigEnums { ZERO = 0x0, FIFTEEN = 0xF };
+
+// Declared to specialize the maximum enum since the enum size exceeds 8 by default.
+template <>
+constexpr size_t NamedEnum::max<TestBigEnums> = 16;
+
+namespace test {
+using android::TestBigEnums;
+using android::TestEnums;
+
+TEST(NamedEnum, RuntimeNamedEnum) {
+ TestEnums e = TestEnums::ZERO;
+ ASSERT_EQ(NamedEnum::enum_name(e), "ZERO");
+
+ e = TestEnums::ONE;
+ ASSERT_EQ(NamedEnum::enum_name(e), "ONE");
+
+ e = TestEnums::THREE;
+ ASSERT_EQ(NamedEnum::enum_name(e), "THREE");
+
+ e = TestEnums::SEVEN;
+ ASSERT_EQ(NamedEnum::enum_name(e), "SEVEN");
+}
+
+// Test big enum
+TEST(NamedEnum, RuntimeBigNamedEnum) {
+ TestBigEnums e = TestBigEnums::ZERO;
+ ASSERT_EQ(NamedEnum::enum_name(e), "ZERO");
+
+ e = TestBigEnums::FIFTEEN;
+ ASSERT_EQ(NamedEnum::enum_name(e), "FIFTEEN");
+}
+
+TEST(NamedEnum, RuntimeNamedEnumAsString) {
+ TestEnums e = TestEnums::ZERO;
+ ASSERT_EQ(NamedEnum::string(e), "ZERO");
+
+ e = TestEnums::ONE;
+ ASSERT_EQ(NamedEnum::string(e), "ONE");
+
+ e = TestEnums::THREE;
+ ASSERT_EQ(NamedEnum::string(e), "THREE");
+
+ e = TestEnums::SEVEN;
+ ASSERT_EQ(NamedEnum::string(e), "SEVEN");
+}
+
+TEST(NamedEnum, RuntimeBigNamedEnumAsString) {
+ TestBigEnums e = TestBigEnums::ZERO;
+ ASSERT_EQ(NamedEnum::string(e), "ZERO");
+
+ e = TestBigEnums::FIFTEEN;
+ ASSERT_EQ(NamedEnum::string(e), "FIFTEEN");
+}
+
+TEST(NamedEnum, RuntimeUnknownNamedEnum) {
+ TestEnums e = static_cast<TestEnums>(0x5);
+ ASSERT_EQ(NamedEnum::enum_name(e), std::nullopt);
+ e = static_cast<TestEnums>(0x9);
+ ASSERT_EQ(NamedEnum::enum_name(e), std::nullopt);
+}
+
+TEST(NamedEnum, RuntimeUnknownNamedEnumAsString) {
+ TestEnums e = static_cast<TestEnums>(0x5);
+ ASSERT_EQ(NamedEnum::string(e), "0x00000005");
+ e = static_cast<TestEnums>(0x9);
+ ASSERT_EQ(NamedEnum::string(e), "0x00000009");
+}
+
+TEST(NamedEnum, CompileTimeFlagName) {
+ static_assert(NamedEnum::enum_name<TestEnums::TWO>() == "TWO");
+ static_assert(NamedEnum::enum_name<TestEnums::THREE>() == "THREE");
+}
+
+} // namespace test
+
+} // namespace android
diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h
index ca16d2c..a637796 100644
--- a/libs/renderengine/include/renderengine/DisplaySettings.h
+++ b/libs/renderengine/include/renderengine/DisplaySettings.h
@@ -47,8 +47,8 @@
// DataSpace::UNKNOWN otherwise.
ui::Dataspace outputDataspace = ui::Dataspace::UNKNOWN;
- // Additional color transform to apply in linear space after transforming
- // to the output dataspace.
+ // Additional color transform to apply after transforming to the output
+ // dataspace, in non-linear space.
mat4 colorTransform = mat4();
// Region that will be cleared to (0, 0, 0, 1) prior to rendering.
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 0fed08b..69ad189 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -15,30 +15,33 @@
*/
//#define LOG_NDEBUG 0
+#include <cstdint>
#undef LOG_TAG
#define LOG_TAG "RenderEngine"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <cmath>
-
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
-#include <sync/sync.h>
-#include <ui/GraphicBuffer.h>
-#include <utils/Trace.h>
-#include "../gl/GLExtensions.h"
-#include "SkiaGLRenderEngine.h"
-#include "filters/BlurFilter.h"
-
#include <GrContextOptions.h>
-#include <gl/GrGLInterface.h>
-
#include <SkCanvas.h>
+#include <SkColorFilter.h>
+#include <SkColorMatrix.h>
+#include <SkColorSpace.h>
#include <SkImage.h>
#include <SkImageFilters.h>
#include <SkShadowUtils.h>
#include <SkSurface.h>
+#include <gl/GrGLInterface.h>
+#include <sync/sync.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/Trace.h>
+
+#include <cmath>
+
+#include "../gl/GLExtensions.h"
+#include "SkiaGLRenderEngine.h"
+#include "filters/BlurFilter.h"
extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
@@ -130,6 +133,47 @@
return err;
}
+// Converts an android dataspace to a supported SkColorSpace
+// Supported dataspaces are
+// 1. sRGB
+// 2. Display P3
+// 3. BT2020 PQ
+// 4. BT2020 HLG
+// Unknown primaries are mapped to BT709, and unknown transfer functions
+// are mapped to sRGB.
+static sk_sp<SkColorSpace> toColorSpace(ui::Dataspace dataspace) {
+ skcms_Matrix3x3 gamut;
+ switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
+ case HAL_DATASPACE_STANDARD_BT709:
+ gamut = SkNamedGamut::kSRGB;
+ break;
+ case HAL_DATASPACE_STANDARD_BT2020:
+ gamut = SkNamedGamut::kRec2020;
+ break;
+ case HAL_DATASPACE_STANDARD_DCI_P3:
+ gamut = SkNamedGamut::kDisplayP3;
+ break;
+ default:
+ ALOGV("Unsupported Gamut: %d, defaulting to sRGB", dataspace);
+ gamut = SkNamedGamut::kSRGB;
+ break;
+ }
+
+ switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) {
+ case HAL_DATASPACE_TRANSFER_LINEAR:
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, gamut);
+ case HAL_DATASPACE_TRANSFER_SRGB:
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
+ case HAL_DATASPACE_TRANSFER_ST2084:
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, gamut);
+ case HAL_DATASPACE_TRANSFER_HLG:
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kHLG, gamut);
+ default:
+ ALOGV("Unsupported Gamma: %d, defaulting to sRGB transfer", dataspace);
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
+ }
+}
+
std::unique_ptr<SkiaGLRenderEngine> SkiaGLRenderEngine::create(
const RenderEngineCreationArgs& args) {
// initialize EGL for the default display
@@ -257,7 +301,8 @@
mEGLContext(ctxt),
mPlaceholderSurface(placeholder),
mProtectedEGLContext(protectedContext),
- mProtectedPlaceholderSurface(protectedPlaceholder) {
+ mProtectedPlaceholderSurface(protectedPlaceholder),
+ mUseColorManagement(args.useColorManagement) {
// Suppress unused field warnings for things we definitely will need/use
// These EGL fields will all be needed for toggling between protected & unprotected contexts
// Or we need different RE instances for that
@@ -338,6 +383,26 @@
return !!(desc.usage & usage);
}
+static float toDegrees(uint32_t transform) {
+ switch (transform) {
+ case ui::Transform::ROT_90:
+ return 90.0;
+ case ui::Transform::ROT_180:
+ return 180.0;
+ case ui::Transform::ROT_270:
+ return 270.0;
+ default:
+ return 0.0;
+ }
+}
+
+static SkColorMatrix toSkColorMatrix(const mat4& matrix) {
+ return SkColorMatrix(matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0], 0, matrix[0][1],
+ matrix[1][1], matrix[2][1], matrix[3][1], 0, matrix[0][2], matrix[1][2],
+ matrix[2][2], matrix[3][2], 0, matrix[0][3], matrix[1][3], matrix[2][3],
+ matrix[3][3], 0);
+}
+
void SkiaGLRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) {
std::lock_guard<std::mutex> lock(mRenderingMutex);
mImageCache.erase(bufferId);
@@ -385,7 +450,10 @@
if (!surface) {
surface = SkSurface::MakeFromAHardwareBuffer(mGrContext.get(), buffer->toAHardwareBuffer(),
GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
- SkColorSpace::MakeSRGB(), nullptr);
+ mUseColorManagement
+ ? toColorSpace(display.outputDataspace)
+ : SkColorSpace::MakeSRGB(),
+ nullptr);
if (useFramebufferCache && surface) {
ALOGD("Adding to cache");
mSurfaceCache.insert({buffer->getId(), surface});
@@ -395,20 +463,39 @@
ALOGE("Failed to make surface");
return BAD_VALUE;
}
+
auto canvas = surface->getCanvas();
+ // Clear the entire canvas with a transparent black to prevent ghost images.
+ canvas->clear(SK_ColorTRANSPARENT);
canvas->save();
// Before doing any drawing, let's make sure that we'll start at the origin of the display.
// Some displays don't start at 0,0 for example when we're mirroring the screen. Also, virtual
// displays might have different scaling when compared to the physical screen.
+
+ canvas->clipRect(getSkRect(display.physicalDisplay));
canvas->translate(display.physicalDisplay.left, display.physicalDisplay.top);
+
+ const auto clipWidth = display.clip.width();
+ const auto clipHeight = display.clip.height();
+ auto rotatedClipWidth = clipWidth;
+ auto rotatedClipHeight = clipHeight;
+ // Scale is contingent on the rotation result.
+ if (display.orientation & ui::Transform::ROT_90) {
+ std::swap(rotatedClipWidth, rotatedClipHeight);
+ }
const auto scaleX = static_cast<SkScalar>(display.physicalDisplay.width()) /
- static_cast<SkScalar>(display.clip.width());
+ static_cast<SkScalar>(rotatedClipWidth);
const auto scaleY = static_cast<SkScalar>(display.physicalDisplay.height()) /
- static_cast<SkScalar>(display.clip.height());
+ static_cast<SkScalar>(rotatedClipHeight);
canvas->scale(scaleX, scaleY);
- canvas->clipRect(getSkRect(display.clip));
- canvas->drawColor(0, SkBlendMode::kSrc);
+
+ // Canvas rotation is done by centering the clip window at the origin, rotating, translating
+ // back so that the top left corner of the clip is at (0, 0).
+ canvas->translate(rotatedClipWidth / 2, rotatedClipHeight / 2);
+ canvas->rotate(toDegrees(display.orientation));
+ canvas->translate(-clipWidth / 2, -clipHeight / 2);
+ canvas->translate(-display.clip.left, -display.clip.top);
for (const auto& layer : layers) {
SkPaint paint;
const auto& bounds = layer->geometry.boundaries;
@@ -422,6 +509,8 @@
if (layer->source.buffer.buffer) {
ATRACE_NAME("DrawImage");
const auto& item = layer->source.buffer;
+ const auto bufferWidth = item.buffer->getBounds().width();
+ const auto bufferHeight = item.buffer->getBounds().height();
sk_sp<SkImage> image;
auto iter = mImageCache.find(item.buffer->getId());
if (iter != mImageCache.end()) {
@@ -430,7 +519,11 @@
image = SkImage::MakeFromAHardwareBuffer(item.buffer->toAHardwareBuffer(),
item.usePremultipliedAlpha
? kPremul_SkAlphaType
- : kUnpremul_SkAlphaType);
+ : kUnpremul_SkAlphaType,
+ mUseColorManagement
+ ? toColorSpace(
+ layer->sourceDataspace)
+ : SkColorSpace::MakeSRGB());
mImageCache.insert({item.buffer->getId(), image});
}
@@ -442,6 +535,38 @@
} else {
matrix.setIdentity();
}
+
+ auto texMatrix = getSkM44(item.textureTransform).asM33();
+ // textureTansform was intended to be passed directly into a shader, so when
+ // building the total matrix with the textureTransform we need to first
+ // normalize it, then apply the textureTransform, then scale back up.
+ matrix.postScale(1.0f / bufferWidth, 1.0f / bufferHeight);
+
+ auto rotatedBufferWidth = bufferWidth;
+ auto rotatedBufferHeight = bufferHeight;
+
+ // Swap the buffer width and height if we're rotating, so that we
+ // scale back up by the correct factors post-rotation.
+ if (texMatrix.getSkewX() <= -0.5f || texMatrix.getSkewX() >= 0.5f) {
+ std::swap(rotatedBufferWidth, rotatedBufferHeight);
+ // TODO: clean this up.
+ // GLESRenderEngine specifies its texture coordinates in
+ // CW orientation under OpenGL conventions, when they probably should have
+ // been CCW instead. The net result is that orientation
+ // transforms are applied in the reverse
+ // direction to render the correct result, because SurfaceFlinger uses the inverse
+ // of the display transform to correct for that. But this means that
+ // the tex transform passed by SkiaGLRenderEngine will rotate
+ // individual layers in the reverse orientation. Hack around it
+ // by injected a 180 degree rotation, but ultimately this is
+ // a bug in how SurfaceFlinger invokes the RenderEngine
+ // interface, so the proper fix should live there, and GLESRenderEngine
+ // should be fixed accordingly.
+ matrix.postRotate(180, 0.5, 0.5);
+ }
+
+ matrix.postConcat(texMatrix);
+ matrix.postScale(rotatedBufferWidth, rotatedBufferHeight);
paint.setShader(image->makeShader(matrix));
} else {
ATRACE_NAME("DrawColor");
@@ -449,6 +574,8 @@
paint.setColor(SkColor4f{.fR = color.r, .fG = color.g, .fB = color.b, layer->alpha});
}
+ paint.setColorFilter(SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform)));
+
// Layers have a local transform matrix that should be applied to them.
canvas->save();
canvas->concat(getSkM44(layer->geometry.positionTransform));
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 898dc54..ed4ba11 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -17,16 +17,19 @@
#ifndef SF_SKIAGLRENDERENGINE_H_
#define SF_SKIAGLRENDERENGINE_H_
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GrDirectContext.h>
+#include <SkSurface.h>
+#include <android-base/thread_annotations.h>
+#include <renderengine/RenderEngine.h>
#include <sys/types.h>
+
#include <mutex>
#include <unordered_map>
-#include <android-base/thread_annotations.h>
-#include <renderengine/RenderEngine.h>
-
-#include <GrDirectContext.h>
-#include <SkSurface.h>
-
+#include "EGL/egl.h"
#include "SkiaRenderEngine.h"
#include "filters/BlurFilter.h"
@@ -81,6 +84,8 @@
EGLSurface mProtectedPlaceholderSurface;
BlurFilter* mBlurFilter = nullptr;
+ const bool mUseColorManagement;
+
// Cache of GL images that we'll store per GraphicBuffer ID
std::unordered_map<uint64_t, sk_sp<SkImage>> mImageCache GUARDED_BY(mRenderingMutex);
// Mutex guarding rendering operations, so that:
diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING
new file mode 100644
index 0000000..824c01e
--- /dev/null
+++ b/services/inputflinger/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsWindowManagerDeviceTestCases",
+ "options": [
+ {
+ "include-filter": "android.server.wm.WindowInputTests"
+ }
+ ]
+ }
+ ]
+}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index ab0d340..8b4ae03 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -482,6 +482,33 @@
}
/**
+ * Raise ANR if there is no focused window.
+ * Before the ANR is raised, do a final state check:
+ * 1. The currently focused application must be the same one we are waiting for.
+ * 2. Ensure we still don't have a focused window.
+ */
+void InputDispatcher::processNoFocusedWindowAnrLocked() {
+ // Check if the application that we are waiting for is still focused.
+ std::shared_ptr<InputApplicationHandle> focusedApplication =
+ getValueByKey(mFocusedApplicationHandlesByDisplay, mAwaitedApplicationDisplayId);
+ if (focusedApplication == nullptr ||
+ focusedApplication->getApplicationToken() !=
+ mAwaitedFocusedApplication->getApplicationToken()) {
+ // Unexpected because we should have reset the ANR timer when focused application changed
+ ALOGE("Waited for a focused window, but focused application has already changed to %s",
+ focusedApplication->getName().c_str());
+ return; // The focused application has changed.
+ }
+
+ const sp<InputWindowHandle>& focusedWindowHandle =
+ getFocusedWindowHandleLocked(mAwaitedApplicationDisplayId);
+ if (focusedWindowHandle != nullptr) {
+ return; // We now have a focused window. No need for ANR.
+ }
+ onAnrLocked(mAwaitedFocusedApplication);
+}
+
+/**
* Check if any of the connections' wait queues have events that are too old.
* If we waited for events to be ack'ed for more than the window timeout, raise an ANR.
* Return the time at which we should wake up next.
@@ -492,8 +519,9 @@
// Check if we are waiting for a focused window to appear. Raise ANR if waited too long
if (mNoFocusedWindowTimeoutTime.has_value() && mAwaitedFocusedApplication != nullptr) {
if (currentTime >= *mNoFocusedWindowTimeoutTime) {
- onAnrLocked(mAwaitedFocusedApplication);
+ processNoFocusedWindowAnrLocked();
mAwaitedFocusedApplication.reset();
+ mNoFocusedWindowTimeoutTime = std::nullopt;
return LONG_LONG_MIN;
} else {
// Keep waiting
@@ -1495,6 +1523,7 @@
DEFAULT_INPUT_DISPATCHING_TIMEOUT);
mNoFocusedWindowTimeoutTime = currentTime + timeout.count();
mAwaitedFocusedApplication = focusedApplicationHandle;
+ mAwaitedApplicationDisplayId = displayId;
ALOGW("Waiting because no window has focus but %s may eventually add a "
"window when it finishes starting up. Will wait for %" PRId64 "ms",
mAwaitedFocusedApplication->getName().c_str(), millis(timeout));
@@ -2126,9 +2155,9 @@
auto otherInfo = otherHandle->getInfo();
if (!otherInfo->visible) {
return false;
- } else if (info->ownerPid == otherInfo->ownerPid) {
- // If ownerPid is the same we don't generate occlusion events as there
- // is no in-process security boundary.
+ } else if (info->ownerUid == otherInfo->ownerUid) {
+ // If ownerUid is the same we don't generate occlusion events as there
+ // is no security boundary within an uid.
return false;
} else if (otherInfo->trustedOverlay) {
return false;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index d361b17..1772ad8 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -394,6 +394,11 @@
* Used to raise an ANR when we have no focused window.
*/
std::shared_ptr<InputApplicationHandle> mAwaitedFocusedApplication GUARDED_BY(mLock);
+ /**
+ * The displayId that the focused application is associated with.
+ */
+ int32_t mAwaitedApplicationDisplayId GUARDED_BY(mLock);
+ void processNoFocusedWindowAnrLocked() REQUIRES(mLock);
/**
* This map will store the pending focus requests that cannot be currently processed. This can
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index e957826..ea84835 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -18,6 +18,7 @@
#include "../Macros.h"
// clang-format on
+#include <input/NamedEnum.h>
#include "TouchInputMapper.h"
#include "CursorButtonAccumulator.h"
@@ -257,7 +258,8 @@
}
void TouchInputMapper::dump(std::string& dump) {
- dump += StringPrintf(INDENT2 "Touch Input Mapper (mode - %s):\n", modeToString(mDeviceMode));
+ dump += StringPrintf(INDENT2 "Touch Input Mapper (mode - %s):\n",
+ NamedEnum::string(mDeviceMode).c_str());
dumpParameters(dump);
dumpVirtualKeys(dump);
dumpRawPointerAxes(dump);
@@ -345,22 +347,6 @@
}
}
-const char* TouchInputMapper::modeToString(DeviceMode deviceMode) {
- switch (deviceMode) {
- case DeviceMode::DISABLED:
- return "disabled";
- case DeviceMode::DIRECT:
- return "direct";
- case DeviceMode::UNSCALED:
- return "unscaled";
- case DeviceMode::NAVIGATION:
- return "navigation";
- case DeviceMode::POINTER:
- return "pointer";
- }
- return "unknown";
-}
-
void TouchInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config,
uint32_t changes) {
InputMapper::configure(when, config, changes);
@@ -512,33 +498,9 @@
void TouchInputMapper::dumpParameters(std::string& dump) {
dump += INDENT3 "Parameters:\n";
- switch (mParameters.gestureMode) {
- case Parameters::GestureMode::SINGLE_TOUCH:
- dump += INDENT4 "GestureMode: single-touch\n";
- break;
- case Parameters::GestureMode::MULTI_TOUCH:
- dump += INDENT4 "GestureMode: multi-touch\n";
- break;
- default:
- assert(false);
- }
+ dump += INDENT4 "GestureMode: " + NamedEnum::string(mParameters.gestureMode) + "\n";
- switch (mParameters.deviceType) {
- case Parameters::DeviceType::TOUCH_SCREEN:
- dump += INDENT4 "DeviceType: touchScreen\n";
- break;
- case Parameters::DeviceType::TOUCH_PAD:
- dump += INDENT4 "DeviceType: touchPad\n";
- break;
- case Parameters::DeviceType::TOUCH_NAVIGATION:
- dump += INDENT4 "DeviceType: touchNavigation\n";
- break;
- case Parameters::DeviceType::POINTER:
- dump += INDENT4 "DeviceType: pointer\n";
- break;
- default:
- ALOG_ASSERT(false);
- }
+ dump += INDENT4 "DeviceType: " + NamedEnum::string(mParameters.deviceType) + "\n";
dump += StringPrintf(INDENT4 "AssociatedDisplay: hasAssociatedDisplay=%s, isExternal=%s, "
"displayId='%s'\n",
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 70f872a..766dc90 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -3483,6 +3483,68 @@
mFocusedWindow->assertNoEvents();
}
+/**
+ * If we have no focused window, and a key comes in, we start the ANR timer.
+ * The focused application should add a focused window before the timer runs out to prevent ANR.
+ *
+ * If the user touches another application during this time, the key should be dropped.
+ * Next, if a new focused window comes in, without toggling the focused application,
+ * then no ANR should occur.
+ *
+ * Normally, we would expect the new focused window to be accompanied by 'setFocusedApplication',
+ * but in some cases the policy may not update the focused application.
+ */
+TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_NoAnr) {
+ std::shared_ptr<FakeApplicationHandle> focusedApplication =
+ std::make_shared<FakeApplicationHandle>();
+ focusedApplication->setDispatchingTimeout(60ms);
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, focusedApplication);
+ // The application that owns 'mFocusedWindow' and 'mUnfocusedWindow' is not focused.
+ mFocusedWindow->setFocusable(false);
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mFocusedWindow, mUnfocusedWindow}}});
+ mFocusedWindow->consumeFocusEvent(false);
+
+ // Send a key. The ANR timer should start because there is no focused window.
+ // 'focusedApplication' will get blamed if this timer completes.
+ // Key will not be sent anywhere because we have no focused window. It will remain pending.
+ int32_t result =
+ injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /*repeatCount*/, ADISPLAY_ID_DEFAULT,
+ INPUT_EVENT_INJECTION_SYNC_NONE, 10ms /*injectionTimeout*/);
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, result);
+
+ // Wait until dispatcher starts the "no focused window" timer. If we don't wait here,
+ // then the injected touches won't cause the focused event to get dropped.
+ // The dispatcher only checks for whether the queue should be pruned upon queueing.
+ // If we inject the touch right away and the ANR timer hasn't started, the touch event would
+ // simply be added to the queue without 'shouldPruneInboundQueueLocked' returning 'true'.
+ // For this test, it means that the key would get delivered to the window once it becomes
+ // focused.
+ std::this_thread::sleep_for(10ms);
+
+ // Touch unfocused window. This should force the pending key to get dropped.
+ NotifyMotionArgs motionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {UNFOCUSED_WINDOW_LOCATION});
+ mDispatcher->notifyMotion(&motionArgs);
+
+ // We do not consume the motion right away, because that would require dispatcher to first
+ // process (== drop) the key event, and by that time, ANR will be raised.
+ // Set the focused window first.
+ mFocusedWindow->setFocusable(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mFocusedWindow, mUnfocusedWindow}}});
+ setFocusedWindow(mFocusedWindow);
+ mFocusedWindow->consumeFocusEvent(true);
+ // We do not call "setFocusedApplication" here, even though the newly focused window belongs
+ // to another application. This could be a bug / behaviour in the policy.
+
+ mUnfocusedWindow->consumeMotionDown();
+
+ ASSERT_TRUE(mDispatcher->waitForIdle());
+ // Should not ANR because we actually have a focused window. It was just added too slowly.
+ ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyAnrWasNotCalled());
+}
+
// These tests ensure we cannot send touch events to a window that's positioned behind a window
// that has feature NO_INPUT_CHANNEL.
// Layout:
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index d14a301..3cccaf9 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <log/log.h>
#include <sys/socket.h>
#include <utils/threads.h>
@@ -53,20 +54,13 @@
SensorService::SensorEventConnection::~SensorEventConnection() {
ALOGD_IF(DEBUG_CONNECTIONS, "~SensorEventConnection(%p)", this);
destroy();
-}
-
-void SensorService::SensorEventConnection::destroy() {
- Mutex::Autolock _l(mDestroyLock);
-
- // destroy once only
- if (mDestroyed) {
- return;
- }
-
mService->cleanupConnection(this);
if (mEventCache != nullptr) {
delete[] mEventCache;
}
+}
+
+void SensorService::SensorEventConnection::destroy() {
mDestroyed = true;
}
@@ -679,6 +673,11 @@
int handle, bool enabled, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs,
int reservedFlags)
{
+ if (mDestroyed) {
+ android_errorWriteLog(0x534e4554, "168211968");
+ return DEAD_OBJECT;
+ }
+
status_t err;
if (enabled) {
err = mService->enable(this, handle, samplingPeriodNs, maxBatchReportLatencyNs,
@@ -693,10 +692,19 @@
status_t SensorService::SensorEventConnection::setEventRate(
int handle, nsecs_t samplingPeriodNs)
{
+ if (mDestroyed) {
+ android_errorWriteLog(0x534e4554, "168211968");
+ return DEAD_OBJECT;
+ }
+
return mService->setEventRate(this, handle, samplingPeriodNs, mOpPackageName);
}
status_t SensorService::SensorEventConnection::flush() {
+ if (mDestroyed) {
+ return DEAD_OBJECT;
+ }
+
return mService->flushSensor(this, mOpPackageName);
}
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 8f2d5db..9487a39 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_SENSOR_EVENT_CONNECTION_H
#define ANDROID_SENSOR_EVENT_CONNECTION_H
+#include <atomic>
#include <stdint.h>
#include <sys/types.h>
#include <unordered_map>
@@ -182,8 +183,8 @@
int mTotalAcksNeeded, mTotalAcksReceived;
#endif
- mutable Mutex mDestroyLock;
- bool mDestroyed;
+ // Used to track if this object was inappropriately used after destroy().
+ std::atomic_bool mDestroyed;
// Store a mapping of sensor handles to required AppOp for a sensor. This map only contains a
// valid mapping for sensors that require a permission in order to reduce the lookup time.
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 4cbfdff..1cd753b 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -167,7 +167,7 @@
void updateCloneBufferInfo() override;
uint64_t mPreviousFrameNumber = 0;
- virtual uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const;
+ uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const override;
void setTransformHint(ui::Transform::RotationFlags displayTransformHint) override;
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 33126ab..0863a22 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -340,7 +340,7 @@
FrameTracer::FrameEvent::LATCH);
if (mQueueItems[0].surfaceFrame) {
- mQueueItems[0].surfaceFrame->setActualEndTime(
+ mQueueItems[0].surfaceFrame->setAcquireFenceTime(
mQueueItems[0].item.mFenceTime->getSignalTime());
mFlinger->mFrameTimeline->addSurfaceFrame(std::move(mQueueItems[0].surfaceFrame),
PresentState::Presented);
@@ -381,6 +381,10 @@
return NO_ERROR;
}
+void BufferQueueLayer::setFrameTimelineVsyncForBuffer(int64_t frameTimelineVsyncId) {
+ mFrameTimelineVsyncId = frameTimelineVsyncId;
+}
+
// -----------------------------------------------------------------------
// Interface implementation for BufferLayerConsumer::ContentsChangedListener
// -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index fc992f7..fb8a0c2 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -103,6 +103,7 @@
status_t updateActiveBuffer() override;
status_t updateFrameNumber(nsecs_t latchTime) override;
+ void setFrameTimelineVsyncForBuffer(int64_t frameTimelineVsyncId) override;
sp<Layer> createClone() override;
@@ -146,6 +147,11 @@
std::atomic<bool> mSidebandStreamChanged{false};
sp<ContentsChangedListener> mContentsChangedListener;
+
+ // The last vsync id received on this layer. This will be used when we get
+ // a buffer to correlate the buffer with the vsync id. Can only be accessed
+ // with the SF state lock held.
+ std::optional<int64_t> mFrameTimelineVsyncId;
};
} // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index ea1f78c..361c1f3 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -161,6 +161,10 @@
bool BufferStateLayer::applyPendingStates(Layer::State* stateToCommit) {
mCurrentStateModified = mCurrentState.modified;
bool stateUpdateAvailable = Layer::applyPendingStates(stateToCommit);
+ if (stateUpdateAvailable && mCallbackHandleAcquireTime != -1) {
+ // Update the acquire fence time if we have a buffer
+ mSurfaceFrame->setAcquireFenceTime(mCallbackHandleAcquireTime);
+ }
mCurrentStateModified = stateUpdateAvailable && mCurrentStateModified;
mCurrentState.modified = false;
return stateUpdateAvailable;
@@ -258,12 +262,12 @@
bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence,
nsecs_t postTime, nsecs_t desiredPresentTime,
- const client_cache_t& clientCacheId) {
+ const client_cache_t& clientCacheId, uint64_t frameNumber) {
if (mCurrentState.buffer) {
mReleasePreviousBuffer = true;
}
- mCurrentState.frameNumber++;
+ mCurrentState.frameNumber = frameNumber;
mCurrentState.buffer = buffer;
mCurrentState.clientCacheId = clientCacheId;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 81959ae..c13f5e8 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -70,7 +70,8 @@
bool setCrop(const Rect& crop) override;
bool setFrame(const Rect& frame) override;
bool setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence, nsecs_t postTime,
- nsecs_t desiredPresentTime, const client_cache_t& clientCacheId) override;
+ nsecs_t desiredPresentTime, const client_cache_t& clientCacheId,
+ uint64_t frameNumber) override;
bool setAcquireFence(const sp<Fence>& fence) override;
bool setDataspace(ui::Dataspace dataspace) override;
bool setHdrMetadata(const HdrMetadata& hdrMetadata) override;
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 78bbcba..07817b5 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -79,17 +79,18 @@
status_t Client::createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format,
uint32_t flags, const sp<IBinder>& parentHandle,
LayerMetadata metadata, sp<IBinder>* handle,
- sp<IGraphicBufferProducer>* gbp, uint32_t* outTransformHint) {
+ sp<IGraphicBufferProducer>* gbp, int32_t* outId,
+ uint32_t* outTransformHint) {
// We rely on createLayer to check permissions.
return mFlinger->createLayer(name, this, w, h, format, flags, std::move(metadata), handle, gbp,
- parentHandle, nullptr, outTransformHint);
+ parentHandle, nullptr, outId, outTransformHint);
}
status_t Client::createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h,
PixelFormat format, uint32_t flags,
const sp<IGraphicBufferProducer>& parent,
LayerMetadata metadata, sp<IBinder>* handle,
- sp<IGraphicBufferProducer>* gbp,
+ sp<IGraphicBufferProducer>* gbp, int32_t* outId,
uint32_t* outTransformHint) {
if (mFlinger->authenticateSurfaceTexture(parent) == false) {
ALOGE("failed to authenticate surface texture");
@@ -103,11 +104,12 @@
}
return mFlinger->createLayer(name, this, w, h, format, flags, std::move(metadata), handle, gbp,
- nullptr, layer, outTransformHint);
+ nullptr, layer, outId, outTransformHint);
}
-status_t Client::mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle) {
- return mFlinger->mirrorLayer(this, mirrorFromHandle, outHandle);
+status_t Client::mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle,
+ int32_t* outId) {
+ return mFlinger->mirrorLayer(this, mirrorFromHandle, outHandle, outId);
}
status_t Client::clearLayerFrameStats(const sp<IBinder>& handle) const {
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index f64be3a..9462f1a 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -50,17 +50,18 @@
virtual status_t createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format,
uint32_t flags, const sp<IBinder>& parent,
LayerMetadata metadata, sp<IBinder>* handle,
- sp<IGraphicBufferProducer>* gbp,
+ sp<IGraphicBufferProducer>* gbp, int32_t* outId,
uint32_t* outTransformHint = nullptr);
virtual status_t createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h,
PixelFormat format, uint32_t flags,
const sp<IGraphicBufferProducer>& parent,
LayerMetadata metadata, sp<IBinder>* handle,
- sp<IGraphicBufferProducer>* gbp,
+ sp<IGraphicBufferProducer>* gbp, int32_t* outId,
uint32_t* outTransformHint = nullptr);
- status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* handle);
+ status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* handle,
+ int32_t* outId);
virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const;
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 44edb6e..04dceae 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -148,7 +148,7 @@
LOG_FATAL_IF(outputState.framebufferSpace.bounds == Rect::INVALID_RECT,
"The framebuffer bounds are unknown.");
const auto scale =
- getScale(outputState.framebufferSpace.bounds, outputState.displaySpace.bounds);
+ getScale(outputState.displaySpace.bounds, outputState.framebufferSpace.bounds);
outputState.framebufferSpace.content = outputState.displaySpace.content.scale(scale.x, scale.y);
// Compute layerStackSpace
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 57b399a..1e10365 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -235,16 +235,75 @@
* Output::setProjection()
*/
-TEST_F(OutputTest, setProjectionTriviallyWorks) {
+TEST_F(OutputTest, setProjectionWorks) {
+ const Rect displayRect{0, 0, 1000, 2000};
+ mOutput->editState().displaySpace.bounds = displayRect;
+ mOutput->editState().framebufferSpace.bounds = displayRect;
+
const ui::Rotation orientation = ui::ROTATION_90;
- const Rect frame{1, 2, 3, 4};
- const Rect viewport{5, 6, 7, 8};
+ const Rect frame{50, 60, 100, 100};
+ const Rect viewport{10, 20, 30, 40};
mOutput->setProjection(orientation, viewport, frame);
EXPECT_EQ(orientation, mOutput->getState().displaySpace.orientation);
EXPECT_EQ(frame, mOutput->getState().orientedDisplaySpace.content);
EXPECT_EQ(viewport, mOutput->getState().layerStackSpace.content);
+
+ const auto state = mOutput->getState();
+ EXPECT_EQ(ui::ROTATION_0, state.layerStackSpace.orientation);
+ EXPECT_EQ(viewport, state.layerStackSpace.content);
+ EXPECT_EQ(viewport, state.layerStackSpace.bounds);
+
+ EXPECT_EQ(ui::ROTATION_0, state.orientedDisplaySpace.orientation);
+ EXPECT_EQ(frame, state.orientedDisplaySpace.content);
+ EXPECT_EQ(Rect(0, 0, 2000, 1000), state.orientedDisplaySpace.bounds);
+
+ EXPECT_EQ(displayRect, state.displaySpace.bounds);
+ EXPECT_EQ(Rect(900, 50, 940, 100), state.displaySpace.content);
+ EXPECT_EQ(orientation, state.displaySpace.orientation);
+
+ EXPECT_EQ(displayRect, state.framebufferSpace.bounds);
+ EXPECT_EQ(Rect(900, 50, 940, 100), state.framebufferSpace.content);
+ EXPECT_EQ(orientation, state.framebufferSpace.orientation);
+
+ EXPECT_EQ(state.displaySpace.content, state.transform.transform(state.layerStackSpace.content));
+}
+
+TEST_F(OutputTest, setProjectionWithSmallFramebufferWorks) {
+ const Rect displayRect{0, 0, 1000, 2000};
+ const Rect framebufferRect{0, 0, 500, 1000};
+ mOutput->editState().displaySpace.bounds = displayRect;
+ mOutput->editState().framebufferSpace.bounds = framebufferRect;
+
+ const ui::Rotation orientation = ui::ROTATION_90;
+ const Rect frame{50, 60, 100, 100};
+ const Rect viewport{10, 20, 30, 40};
+
+ mOutput->setProjection(orientation, viewport, frame);
+
+ EXPECT_EQ(orientation, mOutput->getState().displaySpace.orientation);
+ EXPECT_EQ(frame, mOutput->getState().orientedDisplaySpace.content);
+ EXPECT_EQ(viewport, mOutput->getState().layerStackSpace.content);
+
+ const auto state = mOutput->getState();
+ EXPECT_EQ(ui::ROTATION_0, state.layerStackSpace.orientation);
+ EXPECT_EQ(viewport, state.layerStackSpace.content);
+ EXPECT_EQ(viewport, state.layerStackSpace.bounds);
+
+ EXPECT_EQ(ui::ROTATION_0, state.orientedDisplaySpace.orientation);
+ EXPECT_EQ(frame, state.orientedDisplaySpace.content);
+ EXPECT_EQ(Rect(0, 0, 2000, 1000), state.orientedDisplaySpace.bounds);
+
+ EXPECT_EQ(displayRect, state.displaySpace.bounds);
+ EXPECT_EQ(Rect(900, 50, 940, 100), state.displaySpace.content);
+ EXPECT_EQ(orientation, state.displaySpace.orientation);
+
+ EXPECT_EQ(framebufferRect, state.framebufferSpace.bounds);
+ EXPECT_EQ(Rect(450, 25, 470, 50), state.framebufferSpace.content);
+ EXPECT_EQ(orientation, state.framebufferSpace.orientation);
+
+ EXPECT_EQ(state.displaySpace.content, state.transform.transform(state.layerStackSpace.content));
}
/*
@@ -275,12 +334,15 @@
EXPECT_EQ(ui::ROTATION_0, state.layerStackSpace.orientation);
EXPECT_EQ(Rect(0, 0, 2000, 1000), state.layerStackSpace.content);
EXPECT_EQ(Rect(0, 0, 2000, 1000), state.layerStackSpace.bounds);
+
EXPECT_EQ(ui::ROTATION_0, state.orientedDisplaySpace.orientation);
EXPECT_EQ(Rect(0, 0, 900, 450), state.orientedDisplaySpace.content);
EXPECT_EQ(Rect(0, 0, 1000, 500), state.orientedDisplaySpace.bounds);
+
EXPECT_EQ(displayRect, state.displaySpace.bounds);
EXPECT_EQ(Rect(0, 0, 450, 900), state.displaySpace.content);
EXPECT_EQ(ui::ROTATION_90, state.displaySpace.orientation);
+
EXPECT_EQ(displayRect, state.framebufferSpace.bounds);
EXPECT_EQ(Rect(0, 0, 450, 900), state.framebufferSpace.content);
EXPECT_EQ(ui::ROTATION_90, state.framebufferSpace.orientation);
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index a1ccaad..3b7cfb9 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -168,22 +168,16 @@
sPrimaryDisplayRotationFlags = ui::Transform::toRotationFlags(orientation);
}
- const Rect& displayBounds = getCompositionDisplay()->getState().displaySpace.bounds;
- const int displayWidth = displayBounds.width();
- const int displayHeight = displayBounds.height();
-
if (!orientedDisplaySpaceRect.isValid()) {
- // the destination frame can be invalid if it has never been set,
- // in that case we assume the whole display frame.
- orientedDisplaySpaceRect = Rect(displayWidth, displayHeight);
+ // The destination frame can be invalid if it has never been set,
+ // in that case we assume the whole display size.
+ orientedDisplaySpaceRect = getCompositionDisplay()->getState().displaySpace.bounds;
}
if (layerStackSpaceRect.isEmpty()) {
- // layerStackSpaceRect can be invalid if it has never been set, in that case
- // we assume the whole display size.
- // It's also invalid to have an empty layerStackSpaceRect, so we handle that
- // case in the same way.
- layerStackSpaceRect = Rect(displayWidth, displayHeight);
+ // The layerStackSpaceRect can be invalid if it has never been set, in that case
+ // we assume the whole framebuffer size.
+ layerStackSpaceRect = getCompositionDisplay()->getState().framebufferSpace.bounds;
if (orientation == ui::ROTATION_90 || orientation == ui::ROTATION_270) {
std::swap(layerStackSpaceRect.right, layerStackSpaceRect.bottom);
}
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index a12f4c7..43176a3 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -20,13 +20,129 @@
#include "FrameTimeline.h"
#include <android-base/stringprintf.h>
+#include <utils/Log.h>
#include <utils/Trace.h>
+#include <chrono>
#include <cinttypes>
+#include <numeric>
namespace android::frametimeline::impl {
using base::StringAppendF;
+void dumpTable(std::string& result, TimelineItem predictions, TimelineItem actuals,
+ const std::string& indent, PredictionState predictionState, nsecs_t baseTime) {
+ StringAppendF(&result, "%s", indent.c_str());
+ StringAppendF(&result, "\t\t");
+ StringAppendF(&result, " Start time\t\t|");
+ StringAppendF(&result, " End time\t\t|");
+ StringAppendF(&result, " Present time\n");
+ if (predictionState == PredictionState::Valid) {
+ // Dump the Predictions only if they are valid
+ StringAppendF(&result, "%s", indent.c_str());
+ StringAppendF(&result, "Expected\t|");
+ std::chrono::nanoseconds startTime(predictions.startTime - baseTime);
+ std::chrono::nanoseconds endTime(predictions.endTime - baseTime);
+ std::chrono::nanoseconds presentTime(predictions.presentTime - baseTime);
+ StringAppendF(&result, "\t%10.2f\t|\t%10.2f\t|\t%10.2f\n",
+ std::chrono::duration<double, std::milli>(startTime).count(),
+ std::chrono::duration<double, std::milli>(endTime).count(),
+ std::chrono::duration<double, std::milli>(presentTime).count());
+ }
+ StringAppendF(&result, "%s", indent.c_str());
+ StringAppendF(&result, "Actual \t|");
+
+ if (actuals.startTime == 0) {
+ StringAppendF(&result, "\t\tN/A\t|");
+ } else {
+ std::chrono::nanoseconds startTime(std::max<nsecs_t>(0, actuals.startTime - baseTime));
+ StringAppendF(&result, "\t%10.2f\t|",
+ std::chrono::duration<double, std::milli>(startTime).count());
+ }
+ if (actuals.endTime == 0) {
+ StringAppendF(&result, "\t\tN/A\t|");
+ } else {
+ std::chrono::nanoseconds endTime(actuals.endTime - baseTime);
+ StringAppendF(&result, "\t%10.2f\t|",
+ std::chrono::duration<double, std::milli>(endTime).count());
+ }
+ if (actuals.presentTime == 0) {
+ StringAppendF(&result, "\t\tN/A\n");
+ } else {
+ std::chrono::nanoseconds presentTime(std::max<nsecs_t>(0, actuals.presentTime - baseTime));
+ StringAppendF(&result, "\t%10.2f\n",
+ std::chrono::duration<double, std::milli>(presentTime).count());
+ }
+
+ StringAppendF(&result, "%s", indent.c_str());
+ StringAppendF(&result, "----------------------");
+ StringAppendF(&result, "----------------------");
+ StringAppendF(&result, "----------------------");
+ StringAppendF(&result, "----------------------\n");
+}
+
+std::string toString(PredictionState predictionState) {
+ switch (predictionState) {
+ case PredictionState::Valid:
+ return "Valid";
+ case PredictionState::Expired:
+ return "Expired";
+ case PredictionState::None:
+ default:
+ return "None";
+ }
+}
+
+std::string toString(JankType jankType) {
+ switch (jankType) {
+ case JankType::None:
+ return "None";
+ case JankType::Display:
+ return "Composer/Display - outside SF and App";
+ case JankType::SurfaceFlingerDeadlineMissed:
+ return "SurfaceFlinger Deadline Missed";
+ case JankType::AppDeadlineMissed:
+ return "App Deadline Missed";
+ case JankType::PredictionExpired:
+ return "Prediction Expired";
+ case JankType::SurfaceFlingerEarlyLatch:
+ return "SurfaceFlinger Early Latch";
+ default:
+ return "Unclassified";
+ }
+}
+
+std::string jankMetadataBitmaskToString(int32_t jankMetadata) {
+ std::vector<std::string> jankInfo;
+
+ if (jankMetadata & EarlyStart) {
+ jankInfo.emplace_back("Early Start");
+ } else if (jankMetadata & LateStart) {
+ jankInfo.emplace_back("Late Start");
+ }
+
+ if (jankMetadata & EarlyFinish) {
+ jankInfo.emplace_back("Early Finish");
+ } else if (jankMetadata & LateFinish) {
+ jankInfo.emplace_back("Late Finish");
+ }
+
+ if (jankMetadata & EarlyPresent) {
+ jankInfo.emplace_back("Early Present");
+ } else if (jankMetadata & LatePresent) {
+ jankInfo.emplace_back("Late Present");
+ }
+ // TODO(b/169876734): add GPU composition metadata here
+
+ if (jankInfo.empty()) {
+ return "None";
+ }
+ return std::accumulate(jankInfo.begin(), jankInfo.end(), std::string(),
+ [](const std::string& l, const std::string& r) {
+ return l.empty() ? r : l + ", " + r;
+ });
+}
+
int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mMutex);
@@ -68,29 +184,26 @@
mPredictionState(predictionState),
mPredictions(predictions),
mActuals({0, 0, 0}),
- mActualQueueTime(0) {}
+ mActualQueueTime(0),
+ mJankType(JankType::None),
+ mJankMetadata(0) {}
void SurfaceFrame::setPresentState(PresentState state) {
std::lock_guard<std::mutex> lock(mMutex);
mPresentState = state;
}
-PredictionState SurfaceFrame::getPredictionState() {
- std::lock_guard<std::mutex> lock(mMutex);
- return mPredictionState;
-}
-
-SurfaceFrame::PresentState SurfaceFrame::getPresentState() {
+SurfaceFrame::PresentState SurfaceFrame::getPresentState() const {
std::lock_guard<std::mutex> lock(mMutex);
return mPresentState;
}
-TimelineItem SurfaceFrame::getActuals() {
+TimelineItem SurfaceFrame::getActuals() const {
std::lock_guard<std::mutex> lock(mMutex);
return mActuals;
}
-nsecs_t SurfaceFrame::getActualQueueTime() {
+nsecs_t SurfaceFrame::getActualQueueTime() const {
std::lock_guard<std::mutex> lock(mMutex);
return mActualQueueTime;
}
@@ -104,9 +217,9 @@
std::lock_guard<std::mutex> lock(mMutex);
mActualQueueTime = actualQueueTime;
}
-void SurfaceFrame::setActualEndTime(nsecs_t actualEndTime) {
+void SurfaceFrame::setAcquireFenceTime(nsecs_t acquireFenceTime) {
std::lock_guard<std::mutex> lock(mMutex);
- mActuals.endTime = actualEndTime;
+ mActuals.endTime = std::max(acquireFenceTime, mActualQueueTime);
}
void SurfaceFrame::setActualPresentTime(nsecs_t presentTime) {
@@ -114,25 +227,74 @@
mActuals.presentTime = presentTime;
}
-void SurfaceFrame::dump(std::string& result) {
+void SurfaceFrame::setJankInfo(JankType jankType, int32_t jankMetadata) {
std::lock_guard<std::mutex> lock(mMutex);
- StringAppendF(&result, "Present State : %d\n", static_cast<int>(mPresentState));
- StringAppendF(&result, "Prediction State : %d\n", static_cast<int>(mPredictionState));
- StringAppendF(&result, "Predicted Start Time : %" PRId64 "\n", mPredictions.startTime);
- StringAppendF(&result, "Actual Start Time : %" PRId64 "\n", mActuals.startTime);
- StringAppendF(&result, "Actual Queue Time : %" PRId64 "\n", mActualQueueTime);
- StringAppendF(&result, "Predicted Render Complete Time : %" PRId64 "\n", mPredictions.endTime);
- StringAppendF(&result, "Actual Render Complete Time : %" PRId64 "\n", mActuals.endTime);
- StringAppendF(&result, "Predicted Present Time : %" PRId64 "\n", mPredictions.presentTime);
- StringAppendF(&result, "Actual Present Time : %" PRId64 "\n", mActuals.presentTime);
+ mJankType = jankType;
+ mJankMetadata = jankMetadata;
}
-FrameTimeline::FrameTimeline() : mCurrentDisplayFrame(std::make_shared<DisplayFrame>()) {}
+JankType SurfaceFrame::getJankType() const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mJankType;
+}
+
+nsecs_t SurfaceFrame::getBaseTime() const {
+ std::lock_guard<std::mutex> lock(mMutex);
+ nsecs_t baseTime = std::numeric_limits<nsecs_t>::max();
+ if (mPredictionState == PredictionState::Valid) {
+ baseTime = std::min(baseTime, mPredictions.startTime);
+ }
+ if (mActuals.startTime != 0) {
+ baseTime = std::min(baseTime, mActuals.startTime);
+ }
+ baseTime = std::min(baseTime, mActuals.endTime);
+ return baseTime;
+}
+
+std::string presentStateToString(SurfaceFrame::PresentState presentState) {
+ using PresentState = SurfaceFrame::PresentState;
+ switch (presentState) {
+ case PresentState::Presented:
+ return "Presented";
+ case PresentState::Dropped:
+ return "Dropped";
+ case PresentState::Unknown:
+ default:
+ return "Unknown";
+ }
+}
+
+void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t baseTime) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ StringAppendF(&result, "%s", indent.c_str());
+ StringAppendF(&result, "Layer - %s", mLayerName.c_str());
+ if (mJankType != JankType::None) {
+ // Easily identify a janky Surface Frame in the dump
+ StringAppendF(&result, " [*] ");
+ }
+ StringAppendF(&result, "\n");
+ StringAppendF(&result, "%s", indent.c_str());
+ StringAppendF(&result, "Present State : %s\n", presentStateToString(mPresentState).c_str());
+ StringAppendF(&result, "%s", indent.c_str());
+ StringAppendF(&result, "Prediction State : %s\n", toString(mPredictionState).c_str());
+ StringAppendF(&result, "%s", indent.c_str());
+ StringAppendF(&result, "Jank Type : %s\n", toString(mJankType).c_str());
+ StringAppendF(&result, "%s", indent.c_str());
+ StringAppendF(&result, "Jank Metadata: %s\n",
+ jankMetadataBitmaskToString(mJankMetadata).c_str());
+ dumpTable(result, mPredictions, mActuals, indent, mPredictionState, baseTime);
+}
+
+FrameTimeline::FrameTimeline()
+ : mCurrentDisplayFrame(std::make_shared<DisplayFrame>()),
+ mMaxDisplayFrames(kDefaultMaxDisplayFrames) {}
FrameTimeline::DisplayFrame::DisplayFrame()
: surfaceFlingerPredictions(TimelineItem()),
surfaceFlingerActuals(TimelineItem()),
- predictionState(PredictionState::None) {
+ predictionState(PredictionState::None),
+ jankType(JankType::None),
+ jankMetadata(0) {
this->surfaceFrames.reserve(kNumSurfaceFramesInitial);
}
@@ -199,10 +361,75 @@
if (signalTime != Fence::SIGNAL_TIME_INVALID) {
auto& displayFrame = pendingPresentFence.second;
displayFrame->surfaceFlingerActuals.presentTime = signalTime;
+
+ // Jank Analysis for DisplayFrame
+ const auto& sfActuals = displayFrame->surfaceFlingerActuals;
+ const auto& sfPredictions = displayFrame->surfaceFlingerPredictions;
+ if (std::abs(sfActuals.presentTime - sfPredictions.presentTime) > kPresentThreshold) {
+ displayFrame->jankMetadata |= sfActuals.presentTime > sfPredictions.presentTime
+ ? LatePresent
+ : EarlyPresent;
+ }
+ if (std::abs(sfActuals.endTime - sfPredictions.endTime) > kDeadlineThreshold) {
+ if (sfActuals.endTime > sfPredictions.endTime) {
+ displayFrame->jankMetadata |= LateFinish;
+ } else {
+ displayFrame->jankMetadata |= EarlyFinish;
+ }
+
+ if (displayFrame->jankMetadata & EarlyFinish & EarlyPresent) {
+ displayFrame->jankType = JankType::SurfaceFlingerEarlyLatch;
+ } else if (displayFrame->jankMetadata & LateFinish & LatePresent) {
+ displayFrame->jankType = JankType::SurfaceFlingerDeadlineMissed;
+ } else if (displayFrame->jankMetadata & EarlyPresent ||
+ displayFrame->jankMetadata & LatePresent) {
+ // Cases where SF finished early but frame was presented late and vice versa
+ displayFrame->jankType = JankType::Display;
+ }
+ }
+ if (std::abs(sfActuals.startTime - sfPredictions.startTime) > kSFStartThreshold) {
+ displayFrame->jankMetadata |=
+ sfActuals.startTime > sfPredictions.startTime ? LateStart : EarlyStart;
+ }
+
for (auto& surfaceFrame : displayFrame->surfaceFrames) {
if (surfaceFrame->getPresentState() == SurfaceFrame::PresentState::Presented) {
// Only presented SurfaceFrames need to be updated
surfaceFrame->setActualPresentTime(signalTime);
+
+ // Jank Analysis for SurfaceFrame
+ const auto& predictionState = surfaceFrame->getPredictionState();
+ if (predictionState == PredictionState::Expired) {
+ // Jank analysis cannot be done on apps that don't use predictions
+ surfaceFrame->setJankInfo(JankType::PredictionExpired, 0);
+ continue;
+ } else if (predictionState == PredictionState::Valid) {
+ const auto& actuals = surfaceFrame->getActuals();
+ const auto& predictions = surfaceFrame->getPredictions();
+ int32_t jankMetadata = 0;
+ JankType jankType = JankType::None;
+ if (std::abs(actuals.endTime - predictions.endTime) > kDeadlineThreshold) {
+ jankMetadata |= actuals.endTime > predictions.endTime ? LateFinish
+ : EarlyFinish;
+ }
+ if (std::abs(actuals.presentTime - predictions.presentTime) >
+ kPresentThreshold) {
+ jankMetadata |= actuals.presentTime > predictions.presentTime
+ ? LatePresent
+ : EarlyPresent;
+ }
+ if (jankMetadata & EarlyPresent) {
+ jankType = JankType::SurfaceFlingerEarlyLatch;
+ } else if (jankMetadata & LatePresent) {
+ if (jankMetadata & EarlyFinish) {
+ // TODO(b/169890654): Classify this properly
+ jankType = JankType::Display;
+ } else {
+ jankType = JankType::AppDeadlineMissed;
+ }
+ }
+ surfaceFrame->setJankInfo(jankType, jankMetadata);
+ }
}
}
}
@@ -213,7 +440,7 @@
}
void FrameTimeline::finalizeCurrentDisplayFrame() {
- while (mDisplayFrames.size() >= kMaxDisplayFrames) {
+ while (mDisplayFrames.size() >= mMaxDisplayFrames) {
// We maintain only a fixed number of frames' data. Pop older frames
mDisplayFrames.pop_front();
}
@@ -222,30 +449,100 @@
mCurrentDisplayFrame = std::make_shared<DisplayFrame>();
}
-void FrameTimeline::dump(std::string& result) {
- std::lock_guard<std::mutex> lock(mMutex);
- StringAppendF(&result, "Number of display frames : %d\n", (int)mDisplayFrames.size());
- for (const auto& displayFrame : mDisplayFrames) {
- StringAppendF(&result, "---Display Frame---\n");
- StringAppendF(&result, "Prediction State : %d\n",
- static_cast<int>(displayFrame->predictionState));
- StringAppendF(&result, "Predicted SF wake time : %" PRId64 "\n",
- displayFrame->surfaceFlingerPredictions.startTime);
- StringAppendF(&result, "Actual SF wake time : %" PRId64 "\n",
- displayFrame->surfaceFlingerActuals.startTime);
- StringAppendF(&result, "Predicted SF Complete time : %" PRId64 "\n",
- displayFrame->surfaceFlingerPredictions.endTime);
- StringAppendF(&result, "Actual SF Complete time : %" PRId64 "\n",
- displayFrame->surfaceFlingerActuals.endTime);
- StringAppendF(&result, "Predicted Present time : %" PRId64 "\n",
- displayFrame->surfaceFlingerPredictions.presentTime);
- StringAppendF(&result, "Actual Present time : %" PRId64 "\n",
- displayFrame->surfaceFlingerActuals.presentTime);
- for (size_t i = 0; i < displayFrame->surfaceFrames.size(); i++) {
- StringAppendF(&result, "Surface frame - %" PRId32 "\n", (int)i);
- displayFrame->surfaceFrames[i]->dump(result);
+nsecs_t FrameTimeline::findBaseTime(const std::shared_ptr<DisplayFrame>& displayFrame) {
+ nsecs_t baseTime = std::numeric_limits<nsecs_t>::max();
+ if (displayFrame->predictionState == PredictionState::Valid) {
+ baseTime = std::min(baseTime, displayFrame->surfaceFlingerPredictions.startTime);
+ }
+ baseTime = std::min(baseTime, displayFrame->surfaceFlingerActuals.startTime);
+ for (const auto& surfaceFrame : displayFrame->surfaceFrames) {
+ nsecs_t surfaceFrameBaseTime = surfaceFrame->getBaseTime();
+ if (surfaceFrameBaseTime != 0) {
+ baseTime = std::min(baseTime, surfaceFrameBaseTime);
}
}
+ return baseTime;
+}
+
+void FrameTimeline::dumpDisplayFrame(std::string& result,
+ const std::shared_ptr<DisplayFrame>& displayFrame,
+ nsecs_t baseTime) {
+ if (displayFrame->jankType != JankType::None) {
+ // Easily identify a janky Display Frame in the dump
+ StringAppendF(&result, " [*] ");
+ }
+ StringAppendF(&result, "\n");
+ StringAppendF(&result, "Prediction State : %s\n",
+ toString(displayFrame->predictionState).c_str());
+ StringAppendF(&result, "Jank Type : %s\n", toString(displayFrame->jankType).c_str());
+ StringAppendF(&result, "Jank Metadata: %s\n",
+ jankMetadataBitmaskToString(displayFrame->jankMetadata).c_str());
+ dumpTable(result, displayFrame->surfaceFlingerPredictions, displayFrame->surfaceFlingerActuals,
+ "", displayFrame->predictionState, baseTime);
+ StringAppendF(&result, "\n");
+ std::string indent = " "; // 4 spaces
+ for (const auto& surfaceFrame : displayFrame->surfaceFrames) {
+ surfaceFrame->dump(result, indent, baseTime);
+ }
+ StringAppendF(&result, "\n");
+}
+void FrameTimeline::dumpAll(std::string& result) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ StringAppendF(&result, "Number of display frames : %d\n", (int)mDisplayFrames.size());
+ nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : findBaseTime(mDisplayFrames[0]);
+ for (size_t i = 0; i < mDisplayFrames.size(); i++) {
+ StringAppendF(&result, "Display Frame %d", static_cast<int>(i));
+ dumpDisplayFrame(result, mDisplayFrames[i], baseTime);
+ }
+}
+
+void FrameTimeline::dumpJank(std::string& result) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : findBaseTime(mDisplayFrames[0]);
+ for (size_t i = 0; i < mDisplayFrames.size(); i++) {
+ const auto& displayFrame = mDisplayFrames[i];
+ if (displayFrame->jankType == JankType::None) {
+ // Check if any Surface Frame has been janky
+ bool isJanky = false;
+ for (const auto& surfaceFrame : displayFrame->surfaceFrames) {
+ if (surfaceFrame->getJankType() != JankType::None) {
+ isJanky = true;
+ break;
+ }
+ }
+ if (!isJanky) {
+ continue;
+ }
+ }
+ StringAppendF(&result, "Display Frame %d", static_cast<int>(i));
+ dumpDisplayFrame(result, displayFrame, baseTime);
+ }
+}
+void FrameTimeline::parseArgs(const Vector<String16>& args, std::string& result) {
+ ATRACE_CALL();
+ std::unordered_map<std::string, bool> argsMap;
+ for (size_t i = 0; i < args.size(); i++) {
+ argsMap[std::string(String8(args[i]).c_str())] = true;
+ }
+ if (argsMap.count("-jank")) {
+ dumpJank(result);
+ }
+ if (argsMap.count("-all")) {
+ dumpAll(result);
+ }
+}
+
+void FrameTimeline::setMaxDisplayFrames(uint32_t size) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ // The size can either increase or decrease, clear everything, to be consistent
+ mDisplayFrames.clear();
+ mPendingPresentFences.clear();
+ mMaxDisplayFrames = size;
+}
+
+void FrameTimeline::reset() {
+ setMaxDisplayFrames(kDefaultMaxDisplayFrames);
}
} // namespace android::frametimeline::impl
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index a42c32c..bd637df 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -19,12 +19,51 @@
#include <deque>
#include <mutex>
+#include <gui/ISurfaceComposer.h>
#include <ui/FenceTime.h>
#include <utils/RefBase.h>
+#include <utils/String16.h>
#include <utils/Timers.h>
+#include <utils/Vector.h>
namespace android::frametimeline {
+/*
+ * The type of jank that is associated with a Display/Surface frame
+ */
+enum class JankType {
+ // No Jank
+ None,
+ // Jank not related to SurfaceFlinger or the App
+ Display,
+ // SF took too long on the CPU
+ SurfaceFlingerDeadlineMissed,
+ // Either App or GPU took too long on the frame
+ AppDeadlineMissed,
+ // Predictions live for 120ms, if prediction is expired for a frame, there is definitely a jank
+ // associated with the App if this is for a SurfaceFrame, and SF for a DisplayFrame.
+ PredictionExpired,
+ // Latching a buffer early might cause an early present of the frame
+ SurfaceFlingerEarlyLatch,
+};
+
+enum JankMetadata {
+ // Frame was presented earlier than expected
+ EarlyPresent = 0x1,
+ // Frame was presented later than expected
+ LatePresent = 0x2,
+ // App/SF started earlier than expected
+ EarlyStart = 0x4,
+ // App/SF started later than expected
+ LateStart = 0x8,
+ // App/SF finished work earlier than the deadline
+ EarlyFinish = 0x10,
+ // App/SF finished work later than the deadline
+ LateFinish = 0x20,
+ // SF was in GPU composition
+ GpuComposition = 0x40,
+};
+
class FrameTimelineTest;
/*
@@ -38,6 +77,13 @@
nsecs_t startTime;
nsecs_t endTime;
nsecs_t presentTime;
+
+ bool operator==(const TimelineItem& other) const {
+ return startTime == other.startTime && endTime == other.endTime &&
+ presentTime == other.presentTime;
+ }
+
+ bool operator!=(const TimelineItem& other) const { return !(*this == other); }
};
/*
@@ -74,20 +120,20 @@
virtual ~SurfaceFrame() = default;
- virtual TimelineItem getPredictions() = 0;
- virtual TimelineItem getActuals() = 0;
- virtual nsecs_t getActualQueueTime() = 0;
- virtual PresentState getPresentState() = 0;
- virtual PredictionState getPredictionState() = 0;
+ virtual TimelineItem getPredictions() const = 0;
+ virtual TimelineItem getActuals() const = 0;
+ virtual nsecs_t getActualQueueTime() const = 0;
+ virtual PresentState getPresentState() const = 0;
+ virtual PredictionState getPredictionState() const = 0;
virtual void setPresentState(PresentState state) = 0;
// Actual timestamps of the app are set individually at different functions.
// Start time (if the app provides) and Queue time are accessible after queueing the frame,
- // whereas End time is available only during latch.
+ // whereas Acquire Fence time is available only during latch.
virtual void setActualStartTime(nsecs_t actualStartTime) = 0;
virtual void setActualQueueTime(nsecs_t actualQueueTime) = 0;
- virtual void setActualEndTime(nsecs_t actualEndTime) = 0;
+ virtual void setAcquireFenceTime(nsecs_t acquireFenceTime) = 0;
};
/*
@@ -119,7 +165,17 @@
virtual void setSfPresent(nsecs_t sfPresentTime,
const std::shared_ptr<FenceTime>& presentFence) = 0;
- virtual void dump(std::string& result) = 0;
+ // Args:
+ // -jank : Dumps only the Display Frames that are either janky themselves
+ // or contain janky Surface Frames.
+ // -all : Dumps the entire list of DisplayFrames and the SurfaceFrames contained within
+ virtual void parseArgs(const Vector<String16>& args, std::string& result) = 0;
+
+ // Sets the max number of display frames that can be stored. Called by SF backdoor.
+ virtual void setMaxDisplayFrames(uint32_t size);
+
+ // Restores the max number of display frames to default. Called by SF backdoor.
+ virtual void reset() = 0;
};
namespace impl {
@@ -128,7 +184,7 @@
class TokenManager : public android::frametimeline::TokenManager {
public:
- TokenManager() : mCurrentToken(0) {}
+ TokenManager() : mCurrentToken(ISurfaceComposer::INVALID_VSYNC_ID + 1) {}
~TokenManager() = default;
int64_t generateTokenForPredictions(TimelineItem&& predictions) override;
@@ -154,27 +210,33 @@
TimelineItem&& predictions);
~SurfaceFrame() = default;
- TimelineItem getPredictions() override { return mPredictions; };
- TimelineItem getActuals() override;
- nsecs_t getActualQueueTime() override;
- PresentState getPresentState() override;
- PredictionState getPredictionState() override;
+ TimelineItem getPredictions() const override { return mPredictions; };
+ TimelineItem getActuals() const override;
+ nsecs_t getActualQueueTime() const override;
+ PresentState getPresentState() const override;
+ PredictionState getPredictionState() const override { return mPredictionState; };
void setActualStartTime(nsecs_t actualStartTime) override;
void setActualQueueTime(nsecs_t actualQueueTime) override;
- void setActualEndTime(nsecs_t actualEndTime) override;
+ void setAcquireFenceTime(nsecs_t acquireFenceTime) override;
void setPresentState(PresentState state) override;
void setActualPresentTime(nsecs_t presentTime);
- void dump(std::string& result);
+ void setJankInfo(JankType jankType, int32_t jankMetadata);
+ JankType getJankType() const;
+ nsecs_t getBaseTime() const;
+ // All the timestamps are dumped relative to the baseTime
+ void dump(std::string& result, const std::string& indent, nsecs_t baseTime);
private:
const std::string mLayerName;
PresentState mPresentState GUARDED_BY(mMutex);
- PredictionState mPredictionState GUARDED_BY(mMutex);
+ const PredictionState mPredictionState;
const TimelineItem mPredictions;
TimelineItem mActuals GUARDED_BY(mMutex);
- nsecs_t mActualQueueTime;
- std::mutex mMutex;
+ nsecs_t mActualQueueTime GUARDED_BY(mMutex);
+ mutable std::mutex mMutex;
+ JankType mJankType GUARDED_BY(mMutex); // Enum for the type of jank
+ int32_t mJankMetadata GUARDED_BY(mMutex); // Additional details about the jank
};
class FrameTimeline : public android::frametimeline::FrameTimeline {
@@ -190,7 +252,9 @@
void setSfWakeUp(int64_t token, nsecs_t wakeupTime) override;
void setSfPresent(nsecs_t sfPresentTime,
const std::shared_ptr<FenceTime>& presentFence) override;
- void dump(std::string& result) override;
+ void parseArgs(const Vector<String16>& args, std::string& result) override;
+ void setMaxDisplayFrames(uint32_t size) override;
+ void reset() override;
private:
// Friend class for testing
@@ -214,10 +278,19 @@
std::vector<std::unique_ptr<SurfaceFrame>> surfaceFrames;
PredictionState predictionState;
+ JankType jankType = JankType::None; // Enum for the type of jank
+ int32_t jankMetadata = 0x0; // Additional details about the jank
};
void flushPendingPresentFences() REQUIRES(mMutex);
void finalizeCurrentDisplayFrame() REQUIRES(mMutex);
+ // BaseTime is the smallest timestamp in a DisplayFrame.
+ // Used for dumping all timestamps relative to the oldest, making it easy to read.
+ nsecs_t findBaseTime(const std::shared_ptr<DisplayFrame>&) REQUIRES(mMutex);
+ void dumpDisplayFrame(std::string& result, const std::shared_ptr<DisplayFrame>&,
+ nsecs_t baseTime) REQUIRES(mMutex);
+ void dumpAll(std::string& result);
+ void dumpJank(std::string& result);
// Sliding window of display frames. TODO(b/168072834): compare perf with fixed size array
std::deque<std::shared_ptr<DisplayFrame>> mDisplayFrames GUARDED_BY(mMutex);
@@ -226,12 +299,21 @@
std::shared_ptr<DisplayFrame> mCurrentDisplayFrame GUARDED_BY(mMutex);
TokenManager mTokenManager;
std::mutex mMutex;
- static constexpr uint32_t kMaxDisplayFrames = 64;
+ uint32_t mMaxDisplayFrames;
+ static constexpr uint32_t kDefaultMaxDisplayFrames = 64;
// The initial container size for the vector<SurfaceFrames> inside display frame. Although this
// number doesn't represent any bounds on the number of surface frames that can go in a display
// frame, this is a good starting size for the vector so that we can avoid the internal vector
// resizing that happens with push_back.
static constexpr uint32_t kNumSurfaceFramesInitial = 10;
+ // The various thresholds for App and SF. If the actual timestamp falls within the threshold
+ // compared to prediction, we don't treat it as a jank.
+ static constexpr nsecs_t kPresentThreshold =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(2ms).count();
+ static constexpr nsecs_t kDeadlineThreshold =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(2ms).count();
+ static constexpr nsecs_t kSFStartThreshold =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count();
};
} // namespace impl
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 0127b31..a79cbe4 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -62,6 +62,7 @@
#include "DisplayDevice.h"
#include "DisplayHardware/HWComposer.h"
#include "EffectLayer.h"
+#include "FrameTimeline.h"
#include "FrameTracer/FrameTracer.h"
#include "LayerProtoHelper.h"
#include "LayerRejecter.h"
@@ -76,6 +77,7 @@
using base::StringAppendF;
using namespace android::flag_operators;
+using PresentState = frametimeline::SurfaceFrame::PresentState;
std::atomic<int32_t> Layer::sSequence{1};
@@ -124,6 +126,8 @@
mCurrentState.shadowRadius = 0.f;
mCurrentState.treeHasFrameRateVote = false;
mCurrentState.fixedTransformHint = ui::Transform::ROT_INVALID;
+ mCurrentState.frameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID;
+ mCurrentState.postTime = -1;
if (args.flags & ISurfaceComposerClient::eNoColorFill) {
// Set an invalid color so there is no color fill.
@@ -800,10 +804,10 @@
// to be applied as per normal (no synchronization).
mCurrentState.barrierLayer_legacy = nullptr;
} else {
- auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.frameNumber_legacy, this);
+ auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.barrierFrameNumber, this);
if (barrierLayer->addSyncPoint(syncPoint)) {
std::stringstream ss;
- ss << "Adding sync point " << mCurrentState.frameNumber_legacy;
+ ss << "Adding sync point " << mCurrentState.barrierFrameNumber;
ATRACE_NAME(ss.str().c_str());
mRemoteSyncPoints.push_back(std::move(syncPoint));
} else {
@@ -823,8 +827,8 @@
void Layer::popPendingState(State* stateToCommit) {
ATRACE_CALL();
- *stateToCommit = mPendingStates[0];
+ *stateToCommit = mPendingStates[0];
mPendingStates.removeAt(0);
ATRACE_INT(mTransactionName.c_str(), mPendingStates.size());
}
@@ -844,7 +848,7 @@
}
if (mRemoteSyncPoints.front()->getFrameNumber() !=
- mPendingStates[0].frameNumber_legacy) {
+ mPendingStates[0].barrierFrameNumber) {
ALOGE("[%s] Unexpected sync point frame number found", getDebugName());
// Signal our end of the sync point and then dispose of it
@@ -881,6 +885,23 @@
mFlinger->setTraversalNeeded();
}
+ if (stateUpdateAvailable) {
+ const auto vsyncId =
+ stateToCommit->frameTimelineVsyncId == ISurfaceComposer::INVALID_VSYNC_ID
+ ? std::nullopt
+ : std::make_optional(stateToCommit->frameTimelineVsyncId);
+
+ auto surfaceFrame =
+ mFlinger->mFrameTimeline->createSurfaceFrameForToken(mTransactionName, vsyncId);
+ surfaceFrame->setActualQueueTime(stateToCommit->postTime);
+ // For transactions we set the acquire fence time to the post time as we
+ // don't have a buffer. For BufferStateLayer it is overridden in
+ // BufferStateLayer::applyPendingStates
+ surfaceFrame->setAcquireFenceTime(stateToCommit->postTime);
+
+ mSurfaceFrame = std::move(surfaceFrame);
+ }
+
mCurrentState.modified = false;
return stateUpdateAvailable;
}
@@ -1018,6 +1039,7 @@
void Layer::commitTransaction(const State& stateToCommit) {
mDrawingState = stateToCommit;
+ mFlinger->mFrameTimeline->addSurfaceFrame(std::move(mSurfaceFrame), PresentState::Presented);
}
uint32_t Layer::getTransactionFlags(uint32_t flags) {
@@ -1434,8 +1456,12 @@
return true;
}
-void Layer::setFrameTimelineVsync(int64_t frameTimelineVsyncId) {
- mFrameTimelineVsyncId = frameTimelineVsyncId;
+void Layer::setFrameTimelineVsyncForTransaction(int64_t frameTimelineVsyncId, nsecs_t postTime) {
+ mCurrentState.sequence++;
+ mCurrentState.frameTimelineVsyncId = frameTimelineVsyncId;
+ mCurrentState.postTime = postTime;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
}
Layer::FrameRate Layer::getFrameRateForLayerTree() const {
@@ -1463,13 +1489,13 @@
}
mCurrentState.barrierLayer_legacy = barrierLayer;
- mCurrentState.frameNumber_legacy = frameNumber;
+ mCurrentState.barrierFrameNumber = frameNumber;
// We don't set eTransactionNeeded, because just receiving a deferral
// request without any other state updates shouldn't actually induce a delay
mCurrentState.modified = true;
pushPendingState();
mCurrentState.barrierLayer_legacy = nullptr;
- mCurrentState.frameNumber_legacy = 0;
+ mCurrentState.barrierFrameNumber = 0;
mCurrentState.modified = false;
}
@@ -2234,7 +2260,7 @@
void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags,
const DisplayDevice* display) {
- ui::Transform transform = getTransform();
+ const ui::Transform transform = getTransform();
if (traceFlags & SurfaceTracing::TRACE_CRITICAL) {
for (const auto& pendingState : mPendingStatesSnapshot) {
@@ -2242,7 +2268,7 @@
if (barrierLayer != nullptr) {
BarrierLayerProto* barrierLayerProto = layerInfo->add_barrier_layer();
barrierLayerProto->set_id(barrierLayer->sequence);
- barrierLayerProto->set_frame_number(pendingState.frameNumber_legacy);
+ barrierLayerProto->set_frame_number(pendingState.barrierFrameNumber);
}
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 88ece50..02593d5 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -71,6 +71,10 @@
class SurfaceInterceptor;
}
+namespace frametimeline {
+class SurfaceFrame;
+} // namespace frametimeline
+
struct LayerCreationArgs {
LayerCreationArgs(SurfaceFlinger*, sp<Client>, std::string name, uint32_t w, uint32_t h,
uint32_t flags, LayerMetadata);
@@ -187,7 +191,7 @@
// If set, defers this state update until the identified Layer
// receives a frame with the given frameNumber
wp<Layer> barrierLayer_legacy;
- uint64_t frameNumber_legacy;
+ uint64_t barrierFrameNumber;
// the transparentRegion hint is a bit special, it's latched only
// when we receive a buffer -- this is because it's "content"
@@ -267,6 +271,12 @@
// a buffer of a different size. ui::Transform::ROT_INVALID means the
// a fixed transform hint is not set.
ui::Transform::RotationFlags fixedTransformHint;
+
+ // The vsync id that was used to start the transaction
+ int64_t frameTimelineVsyncId;
+
+ // When the transaction was posted
+ nsecs_t postTime;
};
/*
@@ -406,7 +416,7 @@
virtual bool setFrame(const Rect& /*frame*/) { return false; };
virtual bool setBuffer(const sp<GraphicBuffer>& /*buffer*/, const sp<Fence>& /*acquireFence*/,
nsecs_t /*postTime*/, nsecs_t /*desiredPresentTime*/,
- const client_cache_t& /*clientCacheId*/) {
+ const client_cache_t& /*clientCacheId*/, uint64_t /* frameNumber */) {
return false;
};
virtual bool setAcquireFence(const sp<Fence>& /*fence*/) { return false; };
@@ -510,6 +520,8 @@
virtual bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const { return false; }
+ virtual uint64_t getHeadFrameNumber(nsecs_t /* expectedPresentTime */) const { return 0; }
+
/*
* called after composition.
* returns true if the layer latched a new buffer this frame.
@@ -821,7 +833,8 @@
bool setFrameRate(FrameRate);
- void setFrameTimelineVsync(int64_t frameTimelineVsyncId);
+ virtual void setFrameTimelineVsyncForBuffer(int64_t /*frameTimelineVsyncId*/) {}
+ void setFrameTimelineVsyncForTransaction(int64_t frameTimelineVsyncId, nsecs_t postTime);
// Creates a new handle each time, so we only expect
// this to be called once.
@@ -1021,12 +1034,12 @@
// Can only be accessed with the SF state lock held.
bool mChildrenChanged{false};
- // Can only be accessed with the SF state lock held.
- std::optional<int64_t> mFrameTimelineVsyncId;
-
// Window types from WindowManager.LayoutParams
const InputWindowInfo::Type mWindowType;
+ // Can only be accessed with the SF state lock held.
+ std::unique_ptr<frametimeline::SurfaceFrame> mSurfaceFrame;
+
private:
virtual void setTransformHint(ui::Transform::RotationFlags) {}
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index d8477e7..99d061d 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -241,7 +241,8 @@
void RefreshRateOverlay::changeRefreshRate(const RefreshRate& refreshRate) {
mCurrentFps = refreshRate.getFps();
auto buffer = mBufferCache[*mCurrentFps][mFrame];
- mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {});
+ mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {},
+ mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */));
mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
}
@@ -252,7 +253,8 @@
const auto& buffers = mBufferCache[*mCurrentFps];
mFrame = (mFrame + 1) % buffers.size();
auto buffer = buffers[mFrame];
- mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {});
+ mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {},
+ mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */));
mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
}
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 641a0a3..1343375 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -14,9 +14,7 @@
* limitations under the License.
*/
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <binder/IPCThreadState.h>
@@ -28,6 +26,7 @@
#include <gui/IDisplayEventConnection.h>
#include "EventThread.h"
+#include "FrameTimeline.h"
#include "MessageQueue.h"
#include "SurfaceFlinger.h"
@@ -68,15 +67,53 @@
mHandler = new Handler(*this);
}
+// TODO(b/169865816): refactor VSyncInjections to use MessageQueue directly
+// and remove the EventThread from MessageQueue
void MessageQueue::setEventConnection(const sp<EventThreadConnection>& connection) {
if (mEventTube.getFd() >= 0) {
mLooper->removeFd(mEventTube.getFd());
}
mEvents = connection;
- mEvents->stealReceiveChannel(&mEventTube);
- mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
- this);
+ if (mEvents) {
+ mEvents->stealReceiveChannel(&mEventTube);
+ mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
+ this);
+ }
+}
+
+void MessageQueue::vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime) {
+ ATRACE_CALL();
+ // Trace VSYNC-sf
+ mVsync.value = (mVsync.value + 1) % 2;
+
+ {
+ std::lock_guard lock(mVsync.mutex);
+ mVsync.lastCallbackTime = std::chrono::nanoseconds(vsyncTime);
+ }
+ mHandler->dispatchInvalidate(mVsync.tokenManager->generateTokenForPredictions(
+ {targetWakeupTime, readyTime, vsyncTime}),
+ vsyncTime);
+}
+
+void MessageQueue::initVsync(scheduler::VSyncDispatch& dispatch,
+ frametimeline::TokenManager& tokenManager,
+ std::chrono::nanoseconds workDuration) {
+ setDuration(workDuration);
+ mVsync.tokenManager = &tokenManager;
+ mVsync.registration = std::make_unique<
+ scheduler::VSyncCallbackRegistration>(dispatch,
+ std::bind(&MessageQueue::vsyncCallback, this,
+ std::placeholders::_1,
+ std::placeholders::_2,
+ std::placeholders::_3),
+ "sf");
+}
+
+void MessageQueue::setDuration(std::chrono::nanoseconds workDuration) {
+ ATRACE_CALL();
+ std::lock_guard lock(mVsync.mutex);
+ mVsync.workDuration = workDuration;
}
void MessageQueue::waitMessage() {
@@ -106,7 +143,18 @@
}
void MessageQueue::invalidate() {
- mEvents->requestNextVsync();
+ ATRACE_CALL();
+ if (mEvents) {
+ mEvents->requestNextVsync();
+ } else {
+ const auto [workDuration, lastVsyncCallback] = [&] {
+ std::lock_guard lock(mVsync.mutex);
+ std::chrono::nanoseconds mWorkDurationNanos = mVsync.workDuration;
+ return std::make_pair(mWorkDurationNanos.count(), mVsync.lastCallbackTime.count());
+ }();
+
+ mVsync.registration->schedule({workDuration, /*readyDuration=*/0, lastVsyncCallback});
+ }
}
void MessageQueue::refresh() {
@@ -135,5 +183,3 @@
} // namespace android::impl
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index e263b2f..139b38e 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -29,6 +29,8 @@
#include <private/gui/BitTube.h>
#include "EventThread.h"
+#include "TracedOrdinal.h"
+#include "VSyncDispatch.h"
namespace android {
@@ -63,6 +65,9 @@
virtual ~MessageQueue() = default;
virtual void init(const sp<SurfaceFlinger>& flinger) = 0;
+ virtual void initVsync(scheduler::VSyncDispatch&, frametimeline::TokenManager&,
+ std::chrono::nanoseconds workDuration) = 0;
+ virtual void setDuration(std::chrono::nanoseconds workDuration) = 0;
virtual void setEventConnection(const sp<EventThreadConnection>& connection) = 0;
virtual void waitMessage() = 0;
virtual void postMessage(sp<MessageHandler>&&) = 0;
@@ -74,7 +79,8 @@
namespace impl {
-class MessageQueue final : public android::MessageQueue {
+class MessageQueue : public android::MessageQueue {
+protected:
class Handler : public MessageHandler {
enum { eventMaskInvalidate = 0x1, eventMaskRefresh = 0x2, eventMaskTransaction = 0x4 };
MessageQueue& mQueue;
@@ -84,9 +90,9 @@
public:
explicit Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) {}
- virtual void handleMessage(const Message& message);
- void dispatchRefresh();
- void dispatchInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTimestamp);
+ void handleMessage(const Message& message) override;
+ virtual void dispatchRefresh();
+ virtual void dispatchInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTimestamp);
};
friend class Handler;
@@ -94,15 +100,33 @@
sp<SurfaceFlinger> mFlinger;
sp<Looper> mLooper;
sp<EventThreadConnection> mEvents;
+
+ struct Vsync {
+ frametimeline::TokenManager* tokenManager = nullptr;
+ std::unique_ptr<scheduler::VSyncCallbackRegistration> registration;
+
+ std::mutex mutex;
+ TracedOrdinal<std::chrono::nanoseconds> workDuration
+ GUARDED_BY(mutex) = {"VsyncWorkDuration-sf", std::chrono::nanoseconds(0)};
+ std::chrono::nanoseconds lastCallbackTime GUARDED_BY(mutex) = std::chrono::nanoseconds{0};
+ TracedOrdinal<int> value = {"VSYNC-sf", 0};
+ };
+
+ Vsync mVsync;
+
gui::BitTube mEventTube;
sp<Handler> mHandler;
static int cb_eventReceiver(int fd, int events, void* data);
int eventReceiver(int fd, int events);
+ void vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime);
public:
~MessageQueue() override = default;
void init(const sp<SurfaceFlinger>& flinger) override;
+ void initVsync(scheduler::VSyncDispatch&, frametimeline::TokenManager&,
+ std::chrono::nanoseconds workDuration) override;
+ void setDuration(std::chrono::nanoseconds workDuration) override;
void setEventConnection(const sp<EventThreadConnection>& connection) override;
void waitMessage() override;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 3ecda58..47ce4a4 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -137,6 +137,8 @@
void setDisplayPowerState(bool normal);
+ scheduler::VSyncDispatch& getVsyncDispatch() { return *mVsyncSchedule.dispatch; }
+
void dump(std::string&) const;
void dump(ConnectionHandle, std::string&) const;
void dumpVsync(std::string&) const;
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatch.h b/services/surfaceflinger/Scheduler/VSyncDispatch.h
index 0407900..9d71103 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatch.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h
@@ -94,6 +94,13 @@
nsecs_t workDuration = 0;
nsecs_t readyDuration = 0;
nsecs_t earliestVsync = 0;
+
+ bool operator==(const ScheduleTiming& other) const {
+ return workDuration == other.workDuration && readyDuration == other.readyDuration &&
+ earliestVsync == other.earliestVsync;
+ }
+
+ bool operator!=(const ScheduleTiming& other) const { return !(*this == other); }
};
/*
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 8ac459b..bf33e5e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -328,7 +328,7 @@
SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag)
: mFactory(factory),
- mInterceptor(mFactory.createSurfaceInterceptor(this)),
+ mInterceptor(mFactory.createSurfaceInterceptor()),
mTimeStats(std::make_shared<impl::TimeStats>()),
mFrameTracer(std::make_unique<FrameTracer>()),
mFrameTimeline(std::make_unique<frametimeline::impl::FrameTimeline>()),
@@ -1414,8 +1414,8 @@
Mutex::Autolock lock(mStateLock);
if (const auto handle = mScheduler->enableVSyncInjection(enable)) {
- mEventQueue->setEventConnection(
- mScheduler->getEventConnection(enable ? handle : mSfConnectionHandle));
+ mEventQueue->setEventConnection(enable ? mScheduler->getEventConnection(handle)
+ : nullptr);
}
}).wait();
@@ -2867,19 +2867,23 @@
// start the EventThread
mScheduler = getFactory().createScheduler(*mRefreshRateConfigs, *this);
const auto configs = mVsyncConfiguration->getCurrentConfigs();
+ const nsecs_t vsyncPeriod =
+ mRefreshRateConfigs->getRefreshRateFromConfigId(currentConfig).getVsyncPeriod();
mAppConnectionHandle =
mScheduler->createConnection("app", mFrameTimeline->getTokenManager(),
/*workDuration=*/configs.late.appWorkDuration,
/*readyDuration=*/configs.late.sfWorkDuration,
impl::EventThread::InterceptVSyncsCallback());
mSfConnectionHandle =
- mScheduler->createConnection("sf", mFrameTimeline->getTokenManager(),
- /*workDuration=*/configs.late.sfWorkDuration,
- /*readyDuration=*/0ns, [this](nsecs_t timestamp) {
+ mScheduler->createConnection("appSf", mFrameTimeline->getTokenManager(),
+ /*workDuration=*/std::chrono::nanoseconds(vsyncPeriod),
+ /*readyDuration=*/configs.late.sfWorkDuration,
+ [this](nsecs_t timestamp) {
mInterceptor->saveVSyncEvent(timestamp);
});
- mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));
+ mEventQueue->initVsync(mScheduler->getVsyncDispatch(), *mFrameTimeline->getTokenManager(),
+ configs.late.sfWorkDuration);
mRegionSamplingThread =
new RegionSamplingThread(*this, *mScheduler,
@@ -2891,8 +2895,6 @@
// This is a bit hacky, but this avoids a back-pointer into the main SF
// classes from EventThread, and there should be no run-time binder cost
// anyway since there are no connected apps at this point.
- const nsecs_t vsyncPeriod =
- mRefreshRateConfigs->getRefreshRateFromConfigId(currentConfig).getVsyncPeriod();
mScheduler->onPrimaryDisplayConfigChanged(mAppConnectionHandle, primaryDisplayId, currentConfig,
vsyncPeriod);
static auto ignorePresentFences =
@@ -2904,16 +2906,19 @@
void SurfaceFlinger::updatePhaseConfiguration(const RefreshRate& refreshRate) {
mVsyncConfiguration->setRefreshRateFps(refreshRate.getFps());
- setVsyncConfig(mVsyncModulator->setVsyncConfigSet(mVsyncConfiguration->getCurrentConfigs()));
+ setVsyncConfig(mVsyncModulator->setVsyncConfigSet(mVsyncConfiguration->getCurrentConfigs()),
+ refreshRate.getVsyncPeriod());
}
-void SurfaceFlinger::setVsyncConfig(const VsyncModulator::VsyncConfig& config) {
+void SurfaceFlinger::setVsyncConfig(const VsyncModulator::VsyncConfig& config,
+ nsecs_t vsyncPeriod) {
mScheduler->setDuration(mAppConnectionHandle,
/*workDuration=*/config.appWorkDuration,
/*readyDuration=*/config.sfWorkDuration);
mScheduler->setDuration(mSfConnectionHandle,
- /*workDuration=*/config.sfWorkDuration,
- /*readyDuration=*/0ns);
+ /*workDuration=*/std::chrono::nanoseconds(vsyncPeriod),
+ /*readyDuration=*/config.sfWorkDuration);
+ mEventQueue->setDuration(config.sfWorkDuration);
}
void SurfaceFlinger::commitTransaction() {
@@ -3195,12 +3200,13 @@
break;
}
transactions.push_back(transaction);
- applyTransactionState(transaction.states, transaction.displays, transaction.flags,
+ applyTransactionState(transaction.frameTimelineVsyncId, transaction.states,
+ transaction.displays, transaction.flags,
mPendingInputWindowCommands, transaction.desiredPresentTime,
transaction.buffer, transaction.postTime,
transaction.privileged, transaction.hasListenerCallbacks,
- transaction.listenerCallbacks, transaction.originPID,
- transaction.originUID, /*isMainThread*/ true);
+ transaction.listenerCallbacks, transaction.originPid,
+ transaction.originUid, transaction.id, /*isMainThread*/ true);
transactionQueue.pop();
flushedATransaction = true;
}
@@ -3245,10 +3251,11 @@
}
status_t SurfaceFlinger::setTransactionState(
- const Vector<ComposerState>& states, const Vector<DisplayState>& displays, uint32_t flags,
- const sp<IBinder>& applyToken, const InputWindowCommands& inputWindowCommands,
- int64_t desiredPresentTime, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
- const std::vector<ListenerCallbacks>& listenerCallbacks) {
+ int64_t frameTimelineVsyncId, const Vector<ComposerState>& states,
+ const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
+ const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,
+ const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
+ const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId) {
ATRACE_CALL();
const int64_t postTime = systemTime();
@@ -3281,30 +3288,32 @@
}
IPCThreadState* ipc = IPCThreadState::self();
- const int originPID = ipc->getCallingPid();
- const int originUID = ipc->getCallingUid();
+ const int originPid = ipc->getCallingPid();
+ const int originUid = ipc->getCallingUid();
if (pendingTransactions || !transactionIsReadyToBeApplied(desiredPresentTime, states)) {
- mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime,
- uncacheBuffer, postTime, privileged,
- hasListenerCallbacks, listenerCallbacks, originPID,
- originUID);
+ mTransactionQueues[applyToken].emplace(frameTimelineVsyncId, states, displays, flags,
+ desiredPresentTime, uncacheBuffer, postTime,
+ privileged, hasListenerCallbacks, listenerCallbacks,
+ originPid, originUid, transactionId);
setTransactionFlags(eTransactionFlushNeeded);
return NO_ERROR;
}
- applyTransactionState(states, displays, flags, inputWindowCommands, desiredPresentTime,
- uncacheBuffer, postTime, privileged, hasListenerCallbacks,
- listenerCallbacks, originPID, originUID, /*isMainThread*/ false);
+ applyTransactionState(frameTimelineVsyncId, states, displays, flags, inputWindowCommands,
+ desiredPresentTime, uncacheBuffer, postTime, privileged,
+ hasListenerCallbacks, listenerCallbacks, originPid, originUid,
+ transactionId, /*isMainThread*/ false);
return NO_ERROR;
}
void SurfaceFlinger::applyTransactionState(
- const Vector<ComposerState>& states, const Vector<DisplayState>& displays, uint32_t flags,
+ int64_t frameTimelineVsyncId, const Vector<ComposerState>& states,
+ const Vector<DisplayState>& displays, uint32_t flags,
const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime,
const client_cache_t& uncacheBuffer, const int64_t postTime, bool privileged,
bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks,
- int originPID, int originUID, bool isMainThread) {
+ int originPid, int originUid, uint64_t transactionId, bool isMainThread) {
uint32_t transactionFlags = 0;
if (flags & eAnimation) {
@@ -3338,8 +3347,9 @@
std::unordered_set<ListenerCallbacks, ListenerCallbacksHash> listenerCallbacksWithSurfaces;
uint32_t clientStateFlags = 0;
for (const ComposerState& state : states) {
- clientStateFlags |= setClientStateLocked(state, desiredPresentTime, postTime, privileged,
- listenerCallbacksWithSurfaces);
+ clientStateFlags |=
+ setClientStateLocked(frameTimelineVsyncId, state, desiredPresentTime, postTime,
+ privileged, listenerCallbacksWithSurfaces);
if ((flags & eAnimation) && state.state.surface) {
if (const auto layer = fromHandleLocked(state.state.surface).promote(); layer) {
mScheduler->recordLayerHistory(layer.get(), desiredPresentTime,
@@ -3395,7 +3405,7 @@
if (transactionFlags) {
if (mInterceptor->isEnabled()) {
mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags,
- originPID, originUID);
+ originPid, originUid, transactionId);
}
// TODO(b/159125966): Remove eEarlyWakeup completly as no client should use this flag
@@ -3516,8 +3526,8 @@
}
uint32_t SurfaceFlinger::setClientStateLocked(
- const ComposerState& composerState, int64_t desiredPresentTime, int64_t postTime,
- bool privileged,
+ int64_t frameTimelineVsyncId, const ComposerState& composerState,
+ int64_t desiredPresentTime, int64_t postTime, bool privileged,
std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks) {
const layer_state_t& s = composerState.state;
@@ -3586,7 +3596,8 @@
const auto& p = layer->getParent();
if (p == nullptr) {
ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
- if (layer->setRelativeLayer(s.relativeLayerHandle, s.z) && idx >= 0) {
+ if (layer->setRelativeLayer(s.relativeLayerSurfaceControl->getHandle(), s.z) &&
+ idx >= 0) {
mCurrentState.layersSortedByZ.removeAt(idx);
mCurrentState.layersSortedByZ.add(layer);
// we need traversal (state changed)
@@ -3594,7 +3605,7 @@
flags |= eTransactionNeeded|eTraversalNeeded;
}
} else {
- if (p->setChildRelativeLayer(layer, s.relativeLayerHandle, s.z)) {
+ if (p->setChildRelativeLayer(layer, s.relativeLayerSurfaceControl->getHandle(), s.z)) {
flags |= eTransactionNeeded|eTraversalNeeded;
}
}
@@ -3680,24 +3691,13 @@
}
}
if (what & layer_state_t::eDeferTransaction_legacy) {
- if (s.barrierHandle_legacy != nullptr) {
- layer->deferTransactionUntil_legacy(s.barrierHandle_legacy, s.frameNumber_legacy);
- } else if (s.barrierGbp_legacy != nullptr) {
- const sp<IGraphicBufferProducer>& gbp = s.barrierGbp_legacy;
- if (authenticateSurfaceTextureLocked(gbp)) {
- const auto& otherLayer =
- (static_cast<MonitoredProducer*>(gbp.get()))->getLayer();
- layer->deferTransactionUntil_legacy(otherLayer, s.frameNumber_legacy);
- } else {
- ALOGE("Attempt to defer transaction to to an"
- " unrecognized GraphicBufferProducer");
- }
- }
+ layer->deferTransactionUntil_legacy(s.barrierSurfaceControl_legacy->getHandle(),
+ s.barrierFrameNumber);
// We don't trigger a traversal here because if no other state is
// changed, we don't want this to cause any more work
}
if (what & layer_state_t::eReparentChildren) {
- if (layer->reparentChildren(s.reparentHandle)) {
+ if (layer->reparentChildren(s.reparentSurfaceControl->getHandle())) {
flags |= eTransactionNeeded|eTraversalNeeded;
}
}
@@ -3784,7 +3784,10 @@
// lose its relative z order.
if (what & layer_state_t::eReparent) {
bool hadParent = layer->hasParent();
- if (layer->reparent(s.parentHandleForChild)) {
+ auto parentHandle = (s.parentSurfaceControlForChild)
+ ? s.parentSurfaceControlForChild->getHandle()
+ : nullptr;
+ if (layer->reparent(parentHandle)) {
if (!hadParent) {
mCurrentState.layersSortedByZ.remove(layer);
}
@@ -3818,11 +3821,19 @@
buffer = s.buffer;
}
if (buffer) {
- if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime,
- s.cachedBuffer)) {
+ const bool frameNumberChanged = what & layer_state_t::eFrameNumberChanged;
+ const uint64_t frameNumber = frameNumberChanged
+ ? s.frameNumber
+ : layer->getHeadFrameNumber(-1 /* expectedPresentTime */) + 1;
+
+ if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime, s.cachedBuffer,
+ frameNumber)) {
flags |= eTraversalNeeded;
}
}
+
+ layer->setFrameTimelineVsyncForTransaction(frameTimelineVsyncId, postTime);
+
if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded;
// Do not put anything that updates layer state or modifies flags after
// setTransactionCompletedListener
@@ -3835,7 +3846,7 @@
}
status_t SurfaceFlinger::mirrorLayer(const sp<Client>& client, const sp<IBinder>& mirrorFromHandle,
- sp<IBinder>* outHandle) {
+ sp<IBinder>* outHandle, int32_t* outId) {
if (!mirrorFromHandle) {
return NAME_NOT_FOUND;
}
@@ -3860,6 +3871,7 @@
mirrorLayer->mClonedChild = mirrorFrom->createClone();
}
+ *outId = mirrorLayer->sequence;
return addClientLayer(client, *outHandle, nullptr, mirrorLayer, nullptr, nullptr, false,
nullptr /* outTransformHint */);
}
@@ -3869,7 +3881,7 @@
LayerMetadata metadata, sp<IBinder>* handle,
sp<IGraphicBufferProducer>* gbp,
const sp<IBinder>& parentHandle, const sp<Layer>& parentLayer,
- uint32_t* outTransformHint) {
+ int32_t* outId, uint32_t* outTransformHint) {
if (int32_t(w|h) < 0) {
ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)",
int(w), int(h));
@@ -3935,6 +3947,9 @@
mInterceptor->saveSurfaceCreation(layer);
setTransactionFlags(eTransactionNeeded);
+ if (outId) {
+ *outId = layer->sequence;
+ }
return result;
}
@@ -4087,8 +4102,9 @@
d.width = 0;
d.height = 0;
displays.add(d);
- setTransactionState(state, displays, 0, nullptr, mPendingInputWindowCommands, -1, {}, false,
- {});
+ setTransactionState(ISurfaceComposer::INVALID_VSYNC_ID, state, displays, 0, nullptr,
+ mPendingInputWindowCommands, -1, {}, false, {},
+ 0 /* Undefined transactionId */);
setPowerModeInternal(display, hal::PowerMode::ON);
const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
@@ -4223,7 +4239,7 @@
{"--timestats"s, protoDumper(&SurfaceFlinger::dumpTimeStats)},
{"--vsync"s, dumper(&SurfaceFlinger::dumpVSync)},
{"--wide-color"s, dumper(&SurfaceFlinger::dumpWideColorInfo)},
- {"--frametimeline"s, dumper([this](std::string& s) { mFrameTimeline->dump(s); })},
+ {"--frametimeline"s, argsDumper(&SurfaceFlinger::dumpFrameTimeline)},
};
const auto flag = args.empty() ? ""s : std::string(String8(args[0]));
@@ -4306,6 +4322,10 @@
mTimeStats->parseArgs(asProto, args, result);
}
+void SurfaceFlinger::dumpFrameTimeline(const DumpArgs& args, std::string& result) const {
+ mFrameTimeline->parseArgs(args, result);
+}
+
// This should only be called from the main thread. Otherwise it would need
// the lock and should use mCurrentState rather than mDrawingState.
void SurfaceFlinger::logFrameStats() {
@@ -4888,9 +4908,9 @@
code == IBinder::SYSPROPS_TRANSACTION) {
return OK;
}
- // Numbers from 1000 to 1037 are currently used for backdoors. The code
+ // Numbers from 1000 to 1038 are currently used for backdoors. The code
// in onTransact verifies that the user is root, and has access to use SF.
- if (code >= 1000 && code <= 1037) {
+ if (code >= 1000 && code <= 1038) {
ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
return OK;
}
@@ -5246,6 +5266,21 @@
return NO_ERROR;
}
+ // Modify the max number of display frames stored within FrameTimeline
+ case 1038: {
+ n = data.readInt32();
+ if (n < 0 || n > MAX_ALLOWED_DISPLAY_FRAMES) {
+ ALOGW("Invalid max size. Maximum allowed is %d", MAX_ALLOWED_DISPLAY_FRAMES);
+ return BAD_VALUE;
+ }
+ if (n == 0) {
+ // restore to default
+ mFrameTimeline->reset();
+ return NO_ERROR;
+ }
+ mFrameTimeline->setMaxDisplayFrames(n);
+ return NO_ERROR;
+ }
}
}
return err;
@@ -6193,7 +6228,7 @@
return BAD_VALUE;
}
- layer->setFrameTimelineVsync(frameTimelineVsyncId);
+ layer->setFrameTimelineVsyncForBuffer(frameTimelineVsyncId);
return NO_ERROR;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 3b4d5d4..e50ecf0 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -339,8 +339,8 @@
virtual ~SurfaceFlinger();
virtual uint32_t setClientStateLocked(
- const ComposerState& composerState, int64_t desiredPresentTime, int64_t postTime,
- bool privileged,
+ int64_t frameTimelineVsyncId, const ComposerState& composerState,
+ int64_t desiredPresentTime, int64_t postTime, bool privileged,
std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks)
REQUIRES(mStateLock);
virtual void commitTransactionLocked();
@@ -431,13 +431,14 @@
};
struct TransactionState {
- TransactionState(const Vector<ComposerState>& composerStates,
+ TransactionState(int64_t frameTimelineVsyncId, const Vector<ComposerState>& composerStates,
const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
int64_t desiredPresentTime, const client_cache_t& uncacheBuffer,
int64_t postTime, bool privileged, bool hasListenerCallbacks,
- std::vector<ListenerCallbacks> listenerCallbacks, int originPID,
- int originUID)
- : states(composerStates),
+ std::vector<ListenerCallbacks> listenerCallbacks, int originPid,
+ int originUid, uint64_t transactionId)
+ : frameTimelineVsyncId(frameTimelineVsyncId),
+ states(composerStates),
displays(displayStates),
flags(transactionFlags),
desiredPresentTime(desiredPresentTime),
@@ -446,9 +447,11 @@
privileged(privileged),
hasListenerCallbacks(hasListenerCallbacks),
listenerCallbacks(listenerCallbacks),
- originPID(originPID),
- originUID(originUID) {}
+ originPid(originPid),
+ originUid(originUid),
+ id(transactionId) {}
+ int64_t frameTimelineVsyncId;
Vector<ComposerState> states;
Vector<DisplayState> displays;
uint32_t flags;
@@ -458,8 +461,9 @@
bool privileged;
bool hasListenerCallbacks;
std::vector<ListenerCallbacks> listenerCallbacks;
- int originPID;
- int originUID;
+ int originPid;
+ int originUid;
+ uint64_t id;
};
template <typename F, std::enable_if_t<!std::is_member_function_pointer_v<F>>* = nullptr>
@@ -490,11 +494,14 @@
typename Handler = VsyncModulator::VsyncConfigOpt (VsyncModulator::*)(Args...)>
void modulateVsync(Handler handler, Args... args) {
if (const auto config = (*mVsyncModulator.*handler)(args...)) {
- setVsyncConfig(*config);
+ const auto vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
+ setVsyncConfig(*config, vsyncPeriod);
}
}
static const int MAX_TRACING_MEMORY = 100 * 1024 * 1024; // 100MB
+ // Maximum allowed number of display frames that can be set through backdoor
+ static const int MAX_ALLOWED_DISPLAY_FRAMES = 2048;
// Implements IBinder.
status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override;
@@ -508,13 +515,14 @@
void destroyDisplay(const sp<IBinder>& displayToken) override;
std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override;
sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override;
- status_t setTransactionState(const Vector<ComposerState>& state,
+ status_t setTransactionState(int64_t frameTimelineVsyncId, const Vector<ComposerState>& state,
const Vector<DisplayState>& displays, uint32_t flags,
const sp<IBinder>& applyToken,
const InputWindowCommands& inputWindowCommands,
int64_t desiredPresentTime, const client_cache_t& uncacheBuffer,
bool hasListenerCallbacks,
- const std::vector<ListenerCallbacks>& listenerCallbacks) override;
+ const std::vector<ListenerCallbacks>& listenerCallbacks,
+ uint64_t transactionId) override;
void bootFinished() override;
bool authenticateSurfaceTexture(
const sp<IGraphicBufferProducer>& bufferProducer) const override;
@@ -696,7 +704,7 @@
void initScheduler(PhysicalDisplayId primaryDisplayId);
void updatePhaseConfiguration(const RefreshRate&);
- void setVsyncConfig(const VsyncModulator::VsyncConfig&);
+ void setVsyncConfig(const VsyncModulator::VsyncConfig&, nsecs_t vsyncPeriod);
/* handlePageFlip - latch a new buffer if available and compute the dirty
* region. Returns whether a new buffer has been latched, i.e., whether it
@@ -707,15 +715,15 @@
/*
* Transactions
*/
- void applyTransactionState(const Vector<ComposerState>& state,
+ void applyTransactionState(int64_t frameTimelineVsyncId, const Vector<ComposerState>& state,
const Vector<DisplayState>& displays, uint32_t flags,
const InputWindowCommands& inputWindowCommands,
const int64_t desiredPresentTime,
const client_cache_t& uncacheBuffer, const int64_t postTime,
bool privileged, bool hasListenerCallbacks,
const std::vector<ListenerCallbacks>& listenerCallbacks,
- int originPID, int originUID, bool isMainThread = false)
- REQUIRES(mStateLock);
+ int originPid, int originUid, uint64_t transactionId,
+ bool isMainThread = false) REQUIRES(mStateLock);
// Returns true if at least one transaction was flushed
bool flushTransactionQueues();
// Returns true if there is at least one transaction that needs to be flushed
@@ -745,7 +753,7 @@
PixelFormat format, uint32_t flags, LayerMetadata metadata,
sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp,
const sp<IBinder>& parentHandle, const sp<Layer>& parentLayer = nullptr,
- uint32_t* outTransformHint = nullptr);
+ int32_t* outId = nullptr, uint32_t* outTransformHint = nullptr);
status_t createBufferQueueLayer(const sp<Client>& client, std::string name, uint32_t w,
uint32_t h, uint32_t flags, LayerMetadata metadata,
@@ -765,7 +773,7 @@
sp<IBinder>* outHandle, sp<Layer>* outLayer);
status_t mirrorLayer(const sp<Client>& client, const sp<IBinder>& mirrorFromHandle,
- sp<IBinder>* outHandle);
+ sp<IBinder>* outHandle, int32_t* outId);
std::string getUniqueLayerName(const char* name);
@@ -973,6 +981,7 @@
void dumpStatsLocked(const DumpArgs& args, std::string& result) const REQUIRES(mStateLock);
void clearStatsLocked(const DumpArgs& args, std::string& result);
void dumpTimeStats(const DumpArgs& args, bool asProto, std::string& result) const;
+ void dumpFrameTimeline(const DumpArgs& args, std::string& result) const;
void logFrameStats();
void dumpVSync(std::string& result) const REQUIRES(mStateLock);
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index 93d36a6..9a8deae 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -68,8 +68,8 @@
return std::make_unique<Scheduler>(configs, callback);
}
-sp<SurfaceInterceptor> DefaultFactory::createSurfaceInterceptor(SurfaceFlinger* flinger) {
- return new android::impl::SurfaceInterceptor(flinger);
+sp<SurfaceInterceptor> DefaultFactory::createSurfaceInterceptor() {
+ return new android::impl::SurfaceInterceptor();
}
sp<StartPropertySetThread> DefaultFactory::createStartPropertySetThread(
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index e06c2f4..40774ef 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -32,7 +32,7 @@
const scheduler::RefreshRateConfigs&) override;
std::unique_ptr<Scheduler> createScheduler(const scheduler::RefreshRateConfigs&,
ISchedulerCallback&) override;
- sp<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) override;
+ sp<SurfaceInterceptor> createSurfaceInterceptor() override;
sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override;
sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&) override;
sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format,
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 41ccc10..2dd563b 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -73,7 +73,7 @@
const scheduler::RefreshRateConfigs&) = 0;
virtual std::unique_ptr<Scheduler> createScheduler(const scheduler::RefreshRateConfigs&,
ISchedulerCallback&) = 0;
- virtual sp<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) = 0;
+ virtual sp<SurfaceInterceptor> createSurfaceInterceptor() = 0;
virtual sp<StartPropertySetThread> createStartPropertySetThread(
bool timestampPropertyValue) = 0;
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 9d705e5..da58d4e 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -40,11 +40,6 @@
namespace impl {
-SurfaceInterceptor::SurfaceInterceptor(SurfaceFlinger* flinger)
- : mFlinger(flinger)
-{
-}
-
void SurfaceInterceptor::addTransactionTraceListener(
const sp<gui::ITransactionTraceListener>& listener) {
sp<IBinder> asBinder = IInterface::asBinder(listener);
@@ -148,7 +143,7 @@
if (layer->mCurrentState.barrierLayer_legacy != nullptr) {
addDeferTransactionLocked(transaction, layerId,
layer->mCurrentState.barrierLayer_legacy.promote(),
- layer->mCurrentState.frameNumber_legacy);
+ layer->mCurrentState.barrierFrameNumber);
}
addOverrideScalingModeLocked(transaction, layerId, layer->getEffectiveScalingMode());
addFlagsLocked(transaction, layerId, layer->mCurrentState.flags,
@@ -472,34 +467,34 @@
}
if (state.what & layer_state_t::eDeferTransaction_legacy) {
sp<Layer> otherLayer = nullptr;
- if (state.barrierHandle_legacy != nullptr) {
- otherLayer =
- static_cast<Layer::Handle*>(state.barrierHandle_legacy.get())->owner.promote();
- } else if (state.barrierGbp_legacy != nullptr) {
- auto const& gbp = state.barrierGbp_legacy;
- if (mFlinger->authenticateSurfaceTextureLocked(gbp)) {
- otherLayer = (static_cast<MonitoredProducer*>(gbp.get()))->getLayer();
- } else {
- ALOGE("Attempt to defer transaction to to an unrecognized GraphicBufferProducer");
- }
+ if (state.barrierSurfaceControl_legacy != nullptr) {
+ otherLayer = static_cast<Layer::Handle*>(
+ state.barrierSurfaceControl_legacy->getHandle().get())
+ ->owner.promote();
}
- addDeferTransactionLocked(transaction, layerId, otherLayer, state.frameNumber_legacy);
+ addDeferTransactionLocked(transaction, layerId, otherLayer, state.barrierFrameNumber);
}
if (state.what & layer_state_t::eOverrideScalingModeChanged) {
addOverrideScalingModeLocked(transaction, layerId, state.overrideScalingMode);
}
if (state.what & layer_state_t::eReparent) {
- addReparentLocked(transaction, layerId, getLayerIdFromHandle(state.parentHandleForChild));
+ auto parentHandle = (state.parentSurfaceControlForChild)
+ ? state.parentSurfaceControlForChild->getHandle()
+ : nullptr;
+ addReparentLocked(transaction, layerId, getLayerIdFromHandle(parentHandle));
}
if (state.what & layer_state_t::eReparentChildren) {
- addReparentChildrenLocked(transaction, layerId, getLayerIdFromHandle(state.reparentHandle));
+ addReparentChildrenLocked(transaction, layerId,
+ getLayerIdFromHandle(state.reparentSurfaceControl->getHandle()));
}
if (state.what & layer_state_t::eDetachChildren) {
addDetachChildrenLocked(transaction, layerId, true);
}
if (state.what & layer_state_t::eRelativeLayerChanged) {
addRelativeParentLocked(transaction, layerId,
- getLayerIdFromHandle(state.relativeLayerHandle), state.z);
+ getLayerIdFromHandle(
+ state.relativeLayerSurfaceControl->getHandle()),
+ state.z);
}
if (state.what & layer_state_t::eShadowRadiusChanged) {
addShadowRadiusLocked(transaction, layerId, state.shadowRadius);
@@ -527,13 +522,13 @@
void SurfaceInterceptor::addTransactionLocked(
Increment* increment, const Vector<ComposerState>& stateUpdates,
const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
- const Vector<DisplayState>& changedDisplays, uint32_t transactionFlags, int originPID,
- int originUID) {
+ const Vector<DisplayState>& changedDisplays, uint32_t transactionFlags, int originPid,
+ int originUid, uint64_t transactionId) {
Transaction* transaction(increment->mutable_transaction());
transaction->set_synchronous(transactionFlags & BnSurfaceComposer::eSynchronous);
transaction->set_animation(transactionFlags & BnSurfaceComposer::eAnimation);
- setTransactionOriginLocked(transaction, originPID, originUID);
-
+ setTransactionOriginLocked(transaction, originPid, originUid);
+ transaction->set_id(transactionId);
for (const auto& compState: stateUpdates) {
addSurfaceChangesLocked(transaction, compState.state);
}
@@ -655,14 +650,15 @@
void SurfaceInterceptor::saveTransaction(
const Vector<ComposerState>& stateUpdates,
const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
- const Vector<DisplayState>& changedDisplays, uint32_t flags, int originPID, int originUID) {
+ const Vector<DisplayState>& changedDisplays, uint32_t flags, int originPid, int originUid,
+ uint64_t transactionId) {
if (!mEnabled || (stateUpdates.size() <= 0 && changedDisplays.size() <= 0)) {
return;
}
ATRACE_CALL();
std::lock_guard<std::mutex> protoGuard(mTraceMutex);
addTransactionLocked(createTraceIncrementLocked(), stateUpdates, displays, changedDisplays,
- flags, originPID, originUID);
+ flags, originPid, originUid, transactionId);
}
void SurfaceInterceptor::saveSurfaceCreation(const sp<const Layer>& layer) {
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index 4908bae..9ac189a 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -68,8 +68,8 @@
virtual void saveTransaction(
const Vector<ComposerState>& stateUpdates,
const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
- const Vector<DisplayState>& changedDisplays, uint32_t flags, int originPID,
- int originUID) = 0;
+ const Vector<DisplayState>& changedDisplays, uint32_t flags, int originPid,
+ int originUid, uint64_t transactionId) = 0;
// Intercept surface data
virtual void saveSurfaceCreation(const sp<const Layer>& layer) = 0;
@@ -92,7 +92,7 @@
*/
class SurfaceInterceptor final : public android::SurfaceInterceptor {
public:
- explicit SurfaceInterceptor(SurfaceFlinger* const flinger);
+ SurfaceInterceptor() = default;
~SurfaceInterceptor() override = default;
// Both vectors are used to capture the current state of SF as the initial snapshot in the trace
@@ -107,8 +107,8 @@
// Intercept display and surface transactions
void saveTransaction(const Vector<ComposerState>& stateUpdates,
const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
- const Vector<DisplayState>& changedDisplays, uint32_t flags, int originPID,
- int originUID) override;
+ const Vector<DisplayState>& changedDisplays, uint32_t flags, int originPid,
+ int originUid, uint64_t transactionId) override;
// Intercept surface data
void saveSurfaceCreation(const sp<const Layer>& layer) override;
@@ -173,7 +173,8 @@
void addTransactionLocked(Increment* increment, const Vector<ComposerState>& stateUpdates,
const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
const Vector<DisplayState>& changedDisplays,
- uint32_t transactionFlags, int originPID, int originUID);
+ uint32_t transactionFlags, int originPid, int originUid,
+ uint64_t transactionId);
void addReparentLocked(Transaction* transaction, int32_t layerId, int32_t parentId);
void addReparentChildrenLocked(Transaction* transaction, int32_t layerId, int32_t parentId);
void addDetachChildrenLocked(Transaction* transaction, int32_t layerId, bool detached);
@@ -201,7 +202,6 @@
std::string mOutputFileName {DEFAULT_FILENAME};
std::mutex mTraceMutex {};
Trace mTrace {};
- SurfaceFlinger* const mFlinger;
std::mutex mListenersMutex;
std::map<wp<IBinder>, sp<gui::ITransactionTraceListener>> mTraceToggledListeners
GUARDED_BY(mListenersMutex);
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 719c46e..b7edb84 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -34,6 +34,7 @@
"LayerUpdate_test.cpp",
"MirrorLayer_test.cpp",
"MultiDisplayLayerBounds_test.cpp",
+ "RefreshRateOverlay_test.cpp",
"RelativeZ_test.cpp",
"ScreenCapture_test.cpp",
"SetFrameRate_test.cpp",
diff --git a/services/surfaceflinger/tests/DetachChildren_test.cpp b/services/surfaceflinger/tests/DetachChildren_test.cpp
index 3261308..9c7b1fc 100644
--- a/services/surfaceflinger/tests/DetachChildren_test.cpp
+++ b/services/surfaceflinger/tests/DetachChildren_test.cpp
@@ -61,7 +61,7 @@
TransactionUtils::fillSurfaceRGBA8(relative, relativeColor);
Transaction{}
- .setRelativeLayer(relative, mMainSurface->getHandle(), 1)
+ .setRelativeLayer(relative, mMainSurface, 1)
.setPosition(relative, relBounds.left, relBounds.top)
.apply();
@@ -204,7 +204,7 @@
.setLayer(newParentSurface, INT32_MAX - 1)
.show(newParentSurface)
.setPosition(newParentSurface, newParentBounds.left, newParentBounds.top)
- .reparent(childNewClient, newParentSurface->getHandle())
+ .reparent(childNewClient, newParentSurface)
.apply();
{
mCapture = screenshot();
@@ -238,7 +238,7 @@
}
Transaction()
- .deferTransactionUntil_legacy(childNewClient, mMainSurface->getHandle(),
+ .deferTransactionUntil_legacy(childNewClient, mMainSurface,
mMainSurface->getSurface()->getNextFrameNumber())
.apply();
Transaction().detachChildren(mMainSurface).apply();
@@ -290,7 +290,7 @@
Transaction().detachChildren(mMainSurface).apply();
Transaction()
.setCrop_legacy(childNewClient, {0, 0, childBounds.width(), childBounds.height()})
- .deferTransactionUntil_legacy(childNewClient, mMainSurface->getHandle(),
+ .deferTransactionUntil_legacy(childNewClient, mMainSurface,
mMainSurface->getSurface()->getNextFrameNumber())
.apply();
@@ -352,7 +352,7 @@
mCapture->expectColor(mMainSurfaceBounds, Color::BLACK);
}
- Transaction().reparent(mMainSurface, mBlackBgSurface->getHandle()).apply();
+ Transaction().reparent(mMainSurface, mBlackBgSurface).apply();
{
mCapture = screenshot();
mCapture->expectBorder(childBounds, mMainSurfaceColor);
diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
index 83e5060..4947289 100644
--- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
@@ -211,16 +211,13 @@
switch (layerType) {
case ISurfaceComposerClient::eFXSurfaceBufferQueue:
- Transaction()
- .setPosition(layerG, 16, 16)
- .setRelativeLayer(layerG, layerR->getHandle(), 1)
- .apply();
+ Transaction().setPosition(layerG, 16, 16).setRelativeLayer(layerG, layerR, 1).apply();
break;
case ISurfaceComposerClient::eFXSurfaceBufferState:
Transaction()
.setFrame(layerR, Rect(0, 0, 32, 32))
.setFrame(layerG, Rect(16, 16, 48, 48))
- .setRelativeLayer(layerG, layerR->getHandle(), 1)
+ .setRelativeLayer(layerG, layerR, 1)
.apply();
break;
default:
@@ -233,7 +230,7 @@
shot->expectColor(Rect(16, 16, 48, 48), Color::GREEN);
}
- Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).apply();
+ Transaction().setRelativeLayer(layerG, layerR, -1).apply();
{
SCOPED_TRACE("layerG below");
auto shot = getScreenCapture();
@@ -266,7 +263,7 @@
case ISurfaceComposerClient::eFXSurfaceBufferQueue:
Transaction()
.setPosition(layerG, 8, 8)
- .setRelativeLayer(layerG, layerR->getHandle(), 3)
+ .setRelativeLayer(layerG, layerR, 3)
.setPosition(layerB, 16, 16)
.setLayer(layerB, mLayerZBase + 2)
.apply();
@@ -275,7 +272,7 @@
Transaction()
.setFrame(layerR, Rect(0, 0, 32, 32))
.setFrame(layerG, Rect(8, 8, 40, 40))
- .setRelativeLayer(layerG, layerR->getHandle(), 3)
+ .setRelativeLayer(layerG, layerR, 3)
.setFrame(layerB, Rect(16, 16, 48, 48))
.setLayer(layerB, mLayerZBase + 2)
.apply();
@@ -303,7 +300,7 @@
}
// layerR = 4, layerG = layerR - 3, layerB = 2
- Transaction().setRelativeLayer(layerG, layerR->getHandle(), -3).apply();
+ Transaction().setRelativeLayer(layerG, layerR, -3).apply();
{
SCOPED_TRACE("layerB < (layerG < layerR)");
auto shot = getScreenCapture();
@@ -810,7 +807,7 @@
// channel) should be less than one
const uint8_t tolerance = 1;
Transaction()
- .reparent(colorLayer, parentLayer->getHandle())
+ .reparent(colorLayer, parentLayer)
.setColor(colorLayer, color)
.setAlpha(parentLayer, alpha)
.setLayer(parentLayer, mLayerZBase + 1)
@@ -1225,7 +1222,7 @@
child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
- Transaction().reparent(child, parent->getHandle()).apply();
+ Transaction().reparent(child, parent).apply();
// A layer will default to the frame of its parent
auto shot = getScreenCapture();
@@ -1242,7 +1239,7 @@
child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
- Transaction().reparent(child, parent->getHandle()).apply();
+ Transaction().reparent(child, parent).apply();
// A layer will default to the frame of its parent
auto shot = getScreenCapture();
@@ -1272,7 +1269,7 @@
parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
ASSERT_NO_FATAL_FAILURE(
child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
- Transaction().reparent(child, parent->getHandle()).apply();
+ Transaction().reparent(child, parent).apply();
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32));
Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply();
diff --git a/services/surfaceflinger/tests/LayerTransaction_test.cpp b/services/surfaceflinger/tests/LayerTransaction_test.cpp
index 8d715e1..ef992d6 100644
--- a/services/surfaceflinger/tests/LayerTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTransaction_test.cpp
@@ -50,7 +50,7 @@
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
- Transaction().reparent(layer, layer->getHandle()).apply();
+ Transaction().reparent(layer, layer).apply();
{
// We expect the transaction to be silently dropped, but for SurfaceFlinger
diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
index 7d4314f..c57ad43 100644
--- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
@@ -87,10 +87,7 @@
ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
- Transaction()
- .setPosition(layerG, 16, 16)
- .setRelativeLayer(layerG, layerR->getHandle(), 1)
- .apply();
+ Transaction().setPosition(layerG, 16, 16).setRelativeLayer(layerG, layerR, 1).apply();
Transaction().reparent(layerG, nullptr).apply();
@@ -154,10 +151,7 @@
ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
- Transaction()
- .reparent(layerR, parent->getHandle())
- .reparent(layerG, parent->getHandle())
- .apply();
+ Transaction().reparent(layerR, parent).reparent(layerG, parent).apply();
Transaction().setLayer(layerR, -1).setLayer(layerG, -2).apply();
{
SCOPED_TRACE("layerR");
@@ -241,7 +235,7 @@
auto transaction = Transaction()
.setCornerRadius(parent, cornerRadius)
.setCrop_legacy(parent, Rect(0, 0, size, size))
- .reparent(child, parent->getHandle())
+ .reparent(child, parent)
.setPosition(child, 0, size)
// Rotate by half PI
.setMatrix(child, 0.0f, -1.0f, 1.0f, 0.0f);
@@ -283,14 +277,14 @@
Transaction()
.setCornerRadius(parent, cornerRadius)
.setCrop_legacy(parent, Rect(0, 0, size, size))
- .reparent(child, parent->getHandle())
+ .reparent(child, parent)
.setPosition(child, 0, size / 2)
.apply();
} else {
Transaction()
.setCornerRadius(parent, cornerRadius)
.setFrame(parent, Rect(0, 0, size, size))
- .reparent(child, parent->getHandle())
+ .reparent(child, parent)
.setFrame(child, Rect(0, size / 2, size, size))
.apply();
}
diff --git a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
index ab74c50..f8a0bc1 100644
--- a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
@@ -54,10 +54,10 @@
ASSERT_NO_FATAL_FAILURE(layerB = createLayer("test B", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerB, Color::BLUE, 32, 32));
- Transaction().reparent(layerB, parent->getHandle()).apply();
+ Transaction().reparent(layerB, parent).apply();
// layerR = mLayerZBase, layerG = layerR - 1, layerB = -2
- Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).setLayer(layerB, -2).apply();
+ Transaction().setRelativeLayer(layerG, layerR, -1).setLayer(layerB, -2).apply();
std::unique_ptr<ScreenCapture> screenshot;
// only layerB is in this range
@@ -88,10 +88,7 @@
.setCrop_legacy(childLayer, Rect(0, 0, 20, 30))
.apply();
- Transaction()
- .setRelativeLayer(childLayer, parent->getHandle(), -1)
- .setLayer(childLayer, 1)
- .apply();
+ Transaction().setRelativeLayer(childLayer, parent, -1).setLayer(childLayer, 1).apply();
{
SCOPED_TRACE("setLayer above");
@@ -101,10 +98,7 @@
screenshot->expectColor(Rect(0, 0, 20, 30), Color::RED);
}
- Transaction()
- .setLayer(childLayer, 1)
- .setRelativeLayer(childLayer, parent->getHandle(), -1)
- .apply();
+ Transaction().setLayer(childLayer, 1).setRelativeLayer(childLayer, parent, -1).apply();
{
SCOPED_TRACE("setRelative below");
@@ -141,7 +135,7 @@
.setLayer(relativeParent, mLayerZBase)
.apply();
- Transaction().setRelativeLayer(childLayer, relativeParent->getHandle(), 1).apply();
+ Transaction().setRelativeLayer(childLayer, relativeParent, 1).apply();
{
SCOPED_TRACE("setLayer above");
diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp
index c56d473..38da0b1 100644
--- a/services/surfaceflinger/tests/LayerUpdate_test.cpp
+++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp
@@ -173,13 +173,13 @@
// set up two deferred transactions on different frames
asTransaction([&](Transaction& t) {
t.setAlpha(mFGSurfaceControl, 0.75);
- t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
+ t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl,
mSyncSurfaceControl->getSurface()->getNextFrameNumber());
});
asTransaction([&](Transaction& t) {
t.setPosition(mFGSurfaceControl, 128, 128);
- t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
+ t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl,
mSyncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
});
@@ -480,9 +480,8 @@
mCapture->expectFGColor(84, 84);
}
- asTransaction([&](Transaction& t) {
- t.reparentChildren(mFGSurfaceControl, mBGSurfaceControl->getHandle());
- });
+ asTransaction(
+ [&](Transaction& t) { t.reparentChildren(mFGSurfaceControl, mBGSurfaceControl); });
{
mCapture = screenshot();
@@ -516,7 +515,7 @@
mCapture->expectFGColor(64, 64);
}
- asTransaction([&](Transaction& t) { t.reparent(mGrandChild, mFGSurfaceControl->getHandle()); });
+ asTransaction([&](Transaction& t) { t.reparent(mGrandChild, mFGSurfaceControl); });
{
SCOPED_TRACE("After reparenting grandchild");
@@ -531,9 +530,7 @@
TransactionUtils::fillSurfaceRGBA8(mGrandChild, 111, 111, 111);
// draw grand child behind the foreground surface
- asTransaction([&](Transaction& t) {
- t.setRelativeLayer(mGrandChild, mFGSurfaceControl->getHandle(), -1);
- });
+ asTransaction([&](Transaction& t) { t.setRelativeLayer(mGrandChild, mFGSurfaceControl, -1); });
{
SCOPED_TRACE("Child visible");
@@ -543,7 +540,7 @@
asTransaction([&](Transaction& t) {
t.reparent(mChild, nullptr);
- t.reparentChildren(mChild, mFGSurfaceControl->getHandle());
+ t.reparentChildren(mChild, mFGSurfaceControl);
});
{
@@ -739,7 +736,7 @@
// Show the child layer in a deferred transaction
asTransaction([&](Transaction& t) {
- t.deferTransactionUntil_legacy(mChild, mFGSurfaceControl->getHandle(),
+ t.deferTransactionUntil_legacy(mChild, mFGSurfaceControl,
mFGSurfaceControl->getSurface()->getNextFrameNumber());
t.show(mChild);
});
@@ -776,7 +773,7 @@
mCapture->expectFGColor(84, 84);
}
- asTransaction([&](Transaction& t) { t.reparent(mChild, mBGSurfaceControl->getHandle()); });
+ asTransaction([&](Transaction& t) { t.reparent(mChild, mBGSurfaceControl); });
{
mCapture = screenshot();
@@ -838,7 +835,7 @@
mCapture->checkPixel(10, 10, 63, 195, 63);
}
- asTransaction([&](Transaction& t) { t.reparent(newSurface, mFGSurfaceControl->getHandle()); });
+ asTransaction([&](Transaction& t) { t.reparent(newSurface, mFGSurfaceControl); });
{
mCapture = screenshot();
@@ -869,7 +866,7 @@
Transaction t;
t.setLayer(relative, INT32_MAX)
- .setRelativeLayer(mChild, relative->getHandle(), 1)
+ .setRelativeLayer(mChild, relative, 1)
.setPosition(mFGSurfaceControl, 0, 0)
.apply(true);
diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp
index b49bd54..16826c1 100644
--- a/services/surfaceflinger/tests/MirrorLayer_test.cpp
+++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp
@@ -68,7 +68,7 @@
// Add mirrorLayer as child of mParentLayer so it's shown on the display
Transaction()
- .reparent(mirrorLayer, mParentLayer->getHandle())
+ .reparent(mirrorLayer, mParentLayer)
.setPosition(mirrorLayer, 500, 500)
.show(mirrorLayer)
.apply();
@@ -127,7 +127,7 @@
}
// Add grandchild layer to offscreen layer
- Transaction().reparent(grandchild, mChildLayer->getHandle()).apply();
+ Transaction().reparent(grandchild, mChildLayer).apply();
{
SCOPED_TRACE("Added Grandchild Layer");
auto shot = screenshot();
@@ -138,7 +138,7 @@
}
// Add child layer
- Transaction().reparent(mChildLayer, mParentLayer->getHandle()).apply();
+ Transaction().reparent(mChildLayer, mParentLayer).apply();
{
SCOPED_TRACE("Added Child Layer");
auto shot = screenshot();
@@ -157,7 +157,7 @@
sp<SurfaceControl> mirrorLayer = mClient->mirrorSurface(mChildLayer.get());
Transaction()
- .reparent(mirrorLayer, mParentLayer->getHandle())
+ .reparent(mirrorLayer, mParentLayer)
.setPosition(mirrorLayer, 500, 500)
.show(mirrorLayer)
.apply();
diff --git a/services/surfaceflinger/tests/RefreshRateOverlay_test.cpp b/services/surfaceflinger/tests/RefreshRateOverlay_test.cpp
new file mode 100644
index 0000000..05858bf
--- /dev/null
+++ b/services/surfaceflinger/tests/RefreshRateOverlay_test.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <thread>
+
+#include <gtest/gtest.h>
+
+#include <gui/SurfaceComposerClient.h>
+#include <private/gui/ComposerService.h>
+
+static constexpr int kRefreshRateOverlayCode = 1034;
+static constexpr int kRefreshRateOverlayEnable = 1;
+static constexpr int kRefreshRateOverlayDisable = 0;
+static constexpr int kRefreshRateOverlayQuery = 2;
+
+// These values must match the ones we used for developer options in
+// com.android.settings.development.ShowRefreshRatePreferenceController
+static_assert(kRefreshRateOverlayCode == 1034);
+static_assert(kRefreshRateOverlayEnable == 1);
+static_assert(kRefreshRateOverlayDisable == 0);
+static_assert(kRefreshRateOverlayQuery == 2);
+
+namespace android {
+
+namespace {
+void sendCommandToSf(int command, Parcel& reply) {
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ Parcel request;
+ request.writeInterfaceToken(String16("android.ui.ISurfaceComposer"));
+ request.writeInt32(command);
+ ASSERT_EQ(NO_ERROR,
+ IInterface::asBinder(sf)->transact(kRefreshRateOverlayCode, request, &reply));
+}
+
+bool isOverlayEnabled() {
+ Parcel reply;
+ sendCommandToSf(kRefreshRateOverlayQuery, reply);
+ return reply.readBool();
+}
+
+void waitForOverlay(bool enabled) {
+ static constexpr auto kTimeout = std::chrono::nanoseconds(1s);
+ static constexpr auto kIterations = 10;
+ for (int i = 0; i < kIterations; i++) {
+ if (enabled == isOverlayEnabled()) {
+ return;
+ }
+ std::this_thread::sleep_for(kTimeout / kIterations);
+ }
+}
+
+void toggleOverlay(bool enabled) {
+ if (enabled == isOverlayEnabled()) {
+ return;
+ }
+
+ Parcel reply;
+ const auto command = enabled ? kRefreshRateOverlayEnable : kRefreshRateOverlayDisable;
+ sendCommandToSf(command, reply);
+ waitForOverlay(enabled);
+ ASSERT_EQ(enabled, isOverlayEnabled());
+}
+
+} // namespace
+
+TEST(RefreshRateOverlayTest, enableOverlay) {
+ toggleOverlay(true);
+}
+
+TEST(RefreshRateOverlayTest, disableOverlay) {
+ toggleOverlay(false);
+}
+
+TEST(RefreshRateOverlayTest, enableAndDisableOverlay) {
+ toggleOverlay(true);
+ toggleOverlay(false);
+
+ toggleOverlay(true);
+ toggleOverlay(false);
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/RelativeZ_test.cpp b/services/surfaceflinger/tests/RelativeZ_test.cpp
index 3e0b3c6..fde6e6e 100644
--- a/services/surfaceflinger/tests/RelativeZ_test.cpp
+++ b/services/surfaceflinger/tests/RelativeZ_test.cpp
@@ -70,10 +70,7 @@
sp<SurfaceControl> childLayer =
createColorLayer("Child layer", Color::BLUE, mBackgroundLayer.get());
- Transaction{}
- .setRelativeLayer(childLayer, mForegroundLayer->getHandle(), 1)
- .show(childLayer)
- .apply();
+ Transaction{}.setRelativeLayer(childLayer, mForegroundLayer, 1).show(childLayer).apply();
{
// The childLayer should be in front of the FG control.
@@ -88,7 +85,7 @@
// Background layer (RED)
// Child layer (WHITE)
// Foregroud layer (GREEN)
- Transaction{}.reparent(childLayer, mBackgroundLayer->getHandle()).apply();
+ Transaction{}.reparent(childLayer, mBackgroundLayer).apply();
{
// The relative z info for child layer should be reset, leaving FG control on top.
@@ -118,7 +115,7 @@
createColorLayer("child level 3", Color::GREEN, childLevel2a.get());
Transaction{}
- .setRelativeLayer(childLevel3, childLevel2b->getHandle(), 1)
+ .setRelativeLayer(childLevel3, childLevel2b, 1)
.show(childLevel2a)
.show(childLevel2b)
.show(childLevel3)
@@ -140,7 +137,7 @@
// child level 2 back (BLUE)
// child level 3 (GREEN) (relative to child level 2b)
// child level 2 front (BLACK)
- Transaction{}.reparent(childLevel1, mForegroundLayer->getHandle()).apply();
+ Transaction{}.reparent(childLevel1, mForegroundLayer).apply();
{
// Nothing should change at this point since relative z info was preserved.
@@ -162,7 +159,7 @@
createColorLayer("Relative layer", Color::WHITE, mForegroundLayer.get());
Transaction{}
- .setRelativeLayer(childLayer, relativeToLayer->getHandle(), 1)
+ .setRelativeLayer(childLayer, relativeToLayer, 1)
.show(childLayer)
.show(relativeToLayer)
.apply();
@@ -199,7 +196,7 @@
// Background layer (RED)
// Foregroud layer (GREEN)
// Child layer (BLUE)
- Transaction{}.reparent(childLayer, mForegroundLayer->getHandle()).apply();
+ Transaction{}.reparent(childLayer, mForegroundLayer).apply();
{
// The relative z info for child layer should be reset, leaving the child layer on top.
@@ -230,7 +227,7 @@
createColorLayer("child level 2b", Color::BLACK, childLevel1b.get());
Transaction{}
- .setRelativeLayer(childLevel1a, childLevel2b->getHandle(), 1)
+ .setRelativeLayer(childLevel1a, childLevel2b, 1)
.show(childLevel1a)
.show(childLevel1b)
.show(childLevel2a)
@@ -250,7 +247,7 @@
// // Background layer (RED)
// // Foregroud layer (GREEN)
- Transaction{}.reparent(childLevel1a, childLevel2a->getHandle()).apply();
+ Transaction{}.reparent(childLevel1a, childLevel2a).apply();
{
// The childLevel1a and childLevel1b are no longer on screen
@@ -264,7 +261,7 @@
// child level 2a (BLUE)
// child level 1a (testLayerColor) (relative to child level 2b)
// child level 2b (BLACK)
- Transaction{}.reparent(childLevel1b, mForegroundLayer->getHandle()).apply();
+ Transaction{}.reparent(childLevel1b, mForegroundLayer).apply();
{
// Nothing should change at this point since relative z info was preserved.
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index 3ab2ad1..e173996 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -239,7 +239,7 @@
SurfaceComposerClient::Transaction()
.show(child)
// Set relative layer above fg layer so should be shown above when computing all layers.
- .setRelativeLayer(relative, mFGSurfaceControl->getHandle(), 1)
+ .setRelativeLayer(relative, mFGSurfaceControl, 1)
.show(relative)
.apply(true);
@@ -264,7 +264,7 @@
// Set relative layer below fg layer but relative to child layer so it should be shown
// above child layer.
.setLayer(relative, -1)
- .setRelativeLayer(relative, child->getHandle(), 1)
+ .setRelativeLayer(relative, child, 1)
.show(relative)
.apply(true);
@@ -707,7 +707,7 @@
.setLayer(layerWithFakeUid, INT32_MAX)
.setPosition(layerWithFakeUid, 128, 128)
// reparent a layer that was created with a different uid to the new layer.
- .reparent(layer, layerWithFakeUid->getHandle())
+ .reparent(layer, layerWithFakeUid)
.apply();
// Screenshot from the fakeUid caller with the uid requested allows the layer
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 8570032..104d919 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -397,16 +397,15 @@
}
void SurfaceInterceptorTest::deferredTransactionUpdate(Transaction& t) {
- t.deferTransactionUntil_legacy(mBGSurfaceControl, mBGSurfaceControl->getHandle(),
- DEFERRED_UPDATE);
+ t.deferTransactionUntil_legacy(mBGSurfaceControl, mBGSurfaceControl, DEFERRED_UPDATE);
}
void SurfaceInterceptorTest::reparentUpdate(Transaction& t) {
- t.reparent(mBGSurfaceControl, mFGSurfaceControl->getHandle());
+ t.reparent(mBGSurfaceControl, mFGSurfaceControl);
}
void SurfaceInterceptorTest::relativeParentUpdate(Transaction& t) {
- t.setRelativeLayer(mBGSurfaceControl, mFGSurfaceControl->getHandle(), RELATIVE_Z);
+ t.setRelativeLayer(mBGSurfaceControl, mFGSurfaceControl, RELATIVE_Z);
}
void SurfaceInterceptorTest::detachChildrenUpdate(Transaction& t) {
@@ -414,7 +413,7 @@
}
void SurfaceInterceptorTest::reparentChildrenUpdate(Transaction& t) {
- t.reparentChildren(mBGSurfaceControl, mFGSurfaceControl->getHandle());
+ t.reparentChildren(mBGSurfaceControl, mFGSurfaceControl);
}
void SurfaceInterceptorTest::shadowRadiusUpdate(Transaction& t) {
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 87fc08a..07c558f 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -1322,7 +1322,7 @@
{
TransactionScope ts(*sFakeComposer);
ts.setAlpha(mFGSurfaceControl, 0.75);
- ts.deferTransactionUntil_legacy(mFGSurfaceControl, syncSurfaceControl->getHandle(),
+ ts.deferTransactionUntil_legacy(mFGSurfaceControl, syncSurfaceControl,
syncSurfaceControl->getSurface()->getNextFrameNumber());
}
EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
@@ -1330,7 +1330,7 @@
{
TransactionScope ts(*sFakeComposer);
ts.setPosition(mFGSurfaceControl, 128, 128);
- ts.deferTransactionUntil_legacy(mFGSurfaceControl, syncSurfaceControl->getHandle(),
+ ts.deferTransactionUntil_legacy(mFGSurfaceControl, syncSurfaceControl,
syncSurfaceControl->getSurface()->getNextFrameNumber() +
1);
}
@@ -1376,7 +1376,7 @@
TransactionScope ts(*sFakeComposer);
ts.setPosition(relativeSurfaceControl, 64, 64);
ts.show(relativeSurfaceControl);
- ts.setRelativeLayer(relativeSurfaceControl, mFGSurfaceControl->getHandle(), 1);
+ ts.setRelativeLayer(relativeSurfaceControl, mFGSurfaceControl, 1);
}
auto referenceFrame = mBaseFrame;
// NOTE: All three layers will be visible as the surfaces are
@@ -1606,7 +1606,7 @@
{
TransactionScope ts(*Base::sFakeComposer);
- ts.reparentChildren(Base::mFGSurfaceControl, Base::mBGSurfaceControl->getHandle());
+ ts.reparentChildren(Base::mFGSurfaceControl, Base::mBGSurfaceControl);
}
auto referenceFrame2 = referenceFrame;
@@ -1761,7 +1761,7 @@
// Show the child layer in a deferred transaction
{
TransactionScope ts(*Base::sFakeComposer);
- ts.deferTransactionUntil_legacy(mChild, Base::mFGSurfaceControl->getHandle(),
+ ts.deferTransactionUntil_legacy(mChild, Base::mFGSurfaceControl,
Base::mFGSurfaceControl->getSurface()
->getNextFrameNumber());
ts.show(mChild);
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 6f1f1f2..cf3a4c2 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -47,6 +47,7 @@
"LayerHistoryTest.cpp",
"LayerHistoryTestV2.cpp",
"LayerMetadataTest.cpp",
+ "MessageQueueTest.cpp",
"PromiseTest.cpp",
"SchedulerTest.cpp",
"SchedulerUtilsTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index b750d6b..5864d02 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -1448,7 +1448,7 @@
});
}
- ui::Size SwapWH(const ui::Size size) const { return ui::Size(size.height, size.width); }
+ ui::Size swapWH(const ui::Size size) const { return ui::Size(size.height, size.width); }
void setProjectionForRotation0() {
// A logical rotation of 0 uses the SurfaceFlinger display size
@@ -1459,8 +1459,8 @@
void setProjectionForRotation90() {
// A logical rotation of 90 uses the SurfaceFlinger display size with
// the width/height swapped.
- mDisplayDevice->setProjection(ui::ROTATION_90, Rect(SwapWH(mFlingerDisplaySize)),
- Rect(SwapWH(mFlingerDisplaySize)));
+ mDisplayDevice->setProjection(ui::ROTATION_90, Rect(swapWH(mFlingerDisplaySize)),
+ Rect(swapWH(mFlingerDisplaySize)));
}
void setProjectionForRotation180() {
@@ -1472,8 +1472,8 @@
void setProjectionForRotation270() {
// A logical rotation of 270 uses the SurfaceFlinger display size with
// the width/height swapped.
- mDisplayDevice->setProjection(ui::ROTATION_270, Rect(SwapWH(mFlingerDisplaySize)),
- Rect(SwapWH(mFlingerDisplaySize)));
+ mDisplayDevice->setProjection(ui::ROTATION_270, Rect(swapWH(mFlingerDisplaySize)),
+ Rect(swapWH(mFlingerDisplaySize)));
}
void expectStateForHardwareTransform0() {
@@ -1497,9 +1497,9 @@
EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
// For 90, the orientedDisplaySpaceRect and layerStackSpaceRect have the hardware display
// size width and height swapped
- EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)),
+ EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)),
compositionState.orientedDisplaySpace.content);
- EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.layerStackSpace.content);
+ EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)), compositionState.layerStackSpace.content);
EXPECT_EQ(false, compositionState.needsFiltering);
}
@@ -1523,9 +1523,9 @@
EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
// For 270, the orientedDisplaySpaceRect and layerStackSpaceRect have the hardware display
// size width and height swapped
- EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)),
+ EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)),
compositionState.orientedDisplaySpace.content);
- EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.layerStackSpace.content);
+ EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)), compositionState.layerStackSpace.content);
EXPECT_EQ(false, compositionState.needsFiltering);
}
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 85d2834..69efd7f 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -43,7 +43,7 @@
void SetUp() override {
mFrameTimeline = std::make_unique<impl::FrameTimeline>();
mTokenManager = &mFrameTimeline->mTokenManager;
- maxDisplayFrames = mFrameTimeline->kMaxDisplayFrames;
+ maxDisplayFrames = &mFrameTimeline->mMaxDisplayFrames;
maxTokenRetentionTime = mTokenManager->kMaxRetentionTime;
}
@@ -71,10 +71,15 @@
return mTokenManager->mPredictions;
}
+ uint32_t getNumberOfDisplayFrames() {
+ std::lock_guard<std::mutex> lock(mFrameTimeline->mMutex);
+ return static_cast<uint32_t>(mFrameTimeline->mDisplayFrames.size());
+ }
+
std::unique_ptr<impl::FrameTimeline> mFrameTimeline;
impl::TokenManager* mTokenManager;
FenceToFenceTimeMap fenceFactory;
- uint64_t maxDisplayFrames;
+ uint32_t* maxDisplayFrames;
nsecs_t maxTokenRetentionTime;
};
@@ -178,7 +183,7 @@
TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) {
// Insert kMaxDisplayFrames' count of DisplayFrames to fill the deque
int frameTimeFactor = 0;
- for (size_t i = 0; i < maxDisplayFrames; i++) {
+ for (size_t i = 0; i < *maxDisplayFrames; i++) {
auto presentFence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t surfaceFrameToken = mTokenManager->generateTokenForPredictions(
{10 + frameTimeFactor, 20 + frameTimeFactor, 30 + frameTimeFactor});
@@ -217,4 +222,63 @@
true);
}
+TEST_F(FrameTimelineTest, surfaceFrameEndTimeAcquireFenceAfterQueue) {
+ auto surfaceFrame =
+ mFrameTimeline->createSurfaceFrameForToken("acquireFenceAfterQueue", std::nullopt);
+ surfaceFrame->setActualQueueTime(123);
+ surfaceFrame->setAcquireFenceTime(456);
+ EXPECT_EQ(surfaceFrame->getActuals().endTime, 456);
+}
+
+TEST_F(FrameTimelineTest, surfaceFrameEndTimeAcquireFenceBeforeQueue) {
+ auto surfaceFrame =
+ mFrameTimeline->createSurfaceFrameForToken("acquireFenceAfterQueue", std::nullopt);
+ surfaceFrame->setActualQueueTime(456);
+ surfaceFrame->setAcquireFenceTime(123);
+ EXPECT_EQ(surfaceFrame->getActuals().endTime, 456);
+}
+
+TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) {
+ auto presentFence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ presentFence->signalForTest(2);
+
+ // Size shouldn't exceed maxDisplayFrames - 64
+ for (size_t i = 0; i < *maxDisplayFrames + 10; i++) {
+ auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken("layer1", std::nullopt);
+ int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
+ mFrameTimeline->setSfWakeUp(sfToken, 22);
+ mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
+ SurfaceFrame::PresentState::Presented);
+ mFrameTimeline->setSfPresent(27, presentFence);
+ }
+ EXPECT_EQ(getNumberOfDisplayFrames(), *maxDisplayFrames);
+
+ // Increase the size to 256
+ mFrameTimeline->setMaxDisplayFrames(256);
+ EXPECT_EQ(*maxDisplayFrames, 256);
+
+ for (size_t i = 0; i < *maxDisplayFrames + 10; i++) {
+ auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken("layer1", std::nullopt);
+ int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
+ mFrameTimeline->setSfWakeUp(sfToken, 22);
+ mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
+ SurfaceFrame::PresentState::Presented);
+ mFrameTimeline->setSfPresent(27, presentFence);
+ }
+ EXPECT_EQ(getNumberOfDisplayFrames(), *maxDisplayFrames);
+
+ // Shrink the size to 128
+ mFrameTimeline->setMaxDisplayFrames(128);
+ EXPECT_EQ(*maxDisplayFrames, 128);
+
+ for (size_t i = 0; i < *maxDisplayFrames + 10; i++) {
+ auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken("layer1", std::nullopt);
+ int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
+ mFrameTimeline->setSfWakeUp(sfToken, 22);
+ mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
+ SurfaceFrame::PresentState::Presented);
+ mFrameTimeline->setSfPresent(27, presentFence);
+ }
+ EXPECT_EQ(getNumberOfDisplayFrames(), *maxDisplayFrames);
+}
} // namespace android::frametimeline
diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
new file mode 100644
index 0000000..53dfe3f
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "FrameTimeline.h"
+#include "Scheduler/MessageQueue.h"
+#include "SurfaceFlinger.h"
+
+namespace android {
+
+using namespace std::chrono_literals;
+using namespace testing;
+
+using CallbackToken = scheduler::VSyncDispatch::CallbackToken;
+
+class TestableMessageQueue : public impl::MessageQueue {
+public:
+ class MockHandler : public MessageQueue::Handler {
+ public:
+ explicit MockHandler(MessageQueue& queue) : MessageQueue::Handler(queue) {}
+ ~MockHandler() override = default;
+ MOCK_METHOD2(dispatchInvalidate, void(int64_t vsyncId, nsecs_t expectedVSyncTimestamp));
+ };
+
+ TestableMessageQueue() = default;
+ ~TestableMessageQueue() override = default;
+
+ void initHandler(const sp<MockHandler>& handler) { mHandler = handler; }
+
+ void triggerVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime) {
+ vsyncCallback(vsyncTime, targetWakeupTime, readyTime);
+ }
+};
+
+class MockVSyncDispatch : public scheduler::VSyncDispatch {
+public:
+ MockVSyncDispatch() = default;
+ ~MockVSyncDispatch() override = default;
+
+ MOCK_METHOD2(registerCallback,
+ CallbackToken(std::function<void(nsecs_t, nsecs_t, nsecs_t)> const&, std::string));
+ MOCK_METHOD1(unregisterCallback, void(CallbackToken));
+ MOCK_METHOD2(schedule, scheduler::ScheduleResult(CallbackToken, ScheduleTiming));
+ MOCK_METHOD1(cancel, scheduler::CancelResult(CallbackToken token));
+ MOCK_CONST_METHOD1(dump, void(std::string&));
+};
+
+class MockTokenManager : public frametimeline::TokenManager {
+public:
+ MockTokenManager() = default;
+ ~MockTokenManager() override = default;
+
+ MOCK_METHOD1(generateTokenForPredictions, int64_t(frametimeline::TimelineItem&& prediction));
+};
+
+class MessageQueueTest : public testing::Test {
+public:
+ MessageQueueTest() = default;
+ ~MessageQueueTest() override = default;
+
+ void SetUp() override {
+ EXPECT_NO_FATAL_FAILURE(mEventQueue.initHandler(mHandler));
+
+ EXPECT_CALL(mVSyncDispatch, registerCallback(_, "sf")).WillOnce(Return(mCallbackToken));
+ EXPECT_NO_FATAL_FAILURE(mEventQueue.initVsync(mVSyncDispatch, mTokenManager, mDuration));
+ EXPECT_CALL(mVSyncDispatch, unregisterCallback(mCallbackToken)).Times(1);
+ }
+
+ sp<TestableMessageQueue::MockHandler> mHandler =
+ new TestableMessageQueue::MockHandler(mEventQueue);
+ MockVSyncDispatch mVSyncDispatch;
+ MockTokenManager mTokenManager;
+ TestableMessageQueue mEventQueue;
+
+ const CallbackToken mCallbackToken{5};
+ constexpr static auto mDuration = std::chrono::nanoseconds(100ms);
+ constexpr static auto mDifferentDuration = std::chrono::nanoseconds(250ms);
+};
+
+namespace {
+/* ------------------------------------------------------------------------
+ * Test cases
+ */
+TEST_F(MessageQueueTest, invalidate) {
+ const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(),
+ .readyDuration = 0,
+ .earliestVsync = 0};
+ EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).Times(1);
+ EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate());
+}
+
+TEST_F(MessageQueueTest, invalidateTwice) {
+ InSequence s;
+ const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(),
+ .readyDuration = 0,
+ .earliestVsync = 0};
+
+ EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).Times(1);
+ EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate());
+
+ EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).Times(1);
+ EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate());
+}
+
+TEST_F(MessageQueueTest, invalidateTwiceWithCallback) {
+ InSequence s;
+ const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(),
+ .readyDuration = 0,
+ .earliestVsync = 0};
+
+ EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).Times(1);
+ EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate());
+
+ const auto startTime = 100;
+ const auto endTime = startTime + mDuration.count();
+ const auto presentTime = 500;
+ const auto vsyncId = 42;
+ EXPECT_CALL(mTokenManager,
+ generateTokenForPredictions(
+ frametimeline::TimelineItem(startTime, endTime, presentTime)))
+ .WillOnce(Return(vsyncId));
+ EXPECT_CALL(*mHandler, dispatchInvalidate(vsyncId, presentTime)).Times(1);
+ EXPECT_NO_FATAL_FAILURE(mEventQueue.triggerVsyncCallback(presentTime, startTime, endTime));
+
+ const auto timingAfterCallback =
+ scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(),
+ .readyDuration = 0,
+ .earliestVsync = presentTime};
+
+ EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timingAfterCallback)).Times(1);
+ EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate());
+}
+
+TEST_F(MessageQueueTest, invalidateWithDurationChange) {
+ EXPECT_NO_FATAL_FAILURE(mEventQueue.setDuration(mDifferentDuration));
+
+ const auto timing =
+ scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDifferentDuration.count(),
+ .readyDuration = 0,
+ .earliestVsync = 0};
+
+ EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).Times(1);
+ EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate());
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
index 409f90d..2c8178e 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
@@ -118,7 +118,11 @@
}
void RefreshRateSelectionTest::commitTransaction(Layer* layer) {
- layer->commitTransaction(layer->getCurrentState());
+ layer->pushPendingState();
+ auto c = layer->getCurrentState();
+ if (layer->applyPendingStates(&c)) {
+ layer->commitTransaction(c);
+ }
}
void RefreshRateSelectionTest::setupScheduler() {
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index d4591fc..efee826 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -157,7 +157,11 @@
void SetFrameRateTest::commitTransaction() {
for (auto layer : mLayers) {
- layer.get()->commitTransaction(layer.get()->getCurrentState());
+ layer->pushPendingState();
+ auto c = layer->getCurrentState();
+ if (layer->applyPendingStates(&c)) {
+ layer->commitTransaction(c);
+ }
}
}
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 98b20e8..96e4f5b 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -83,8 +83,8 @@
return nullptr;
}
- sp<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger* flinger) override {
- return new android::impl::SurfaceInterceptor(flinger);
+ sp<SurfaceInterceptor> createSurfaceInterceptor() override {
+ return new android::impl::SurfaceInterceptor();
}
sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override {
@@ -348,16 +348,18 @@
auto& getTransactionQueue() { return mFlinger->mTransactionQueues; }
- auto setTransactionState(const Vector<ComposerState>& states,
+ auto setTransactionState(int64_t frameTimelineVsyncId, const Vector<ComposerState>& states,
const Vector<DisplayState>& displays, uint32_t flags,
const sp<IBinder>& applyToken,
const InputWindowCommands& inputWindowCommands,
int64_t desiredPresentTime, const client_cache_t& uncacheBuffer,
bool hasListenerCallbacks,
- std::vector<ListenerCallbacks>& listenerCallbacks) {
- return mFlinger->setTransactionState(states, displays, flags, applyToken,
- inputWindowCommands, desiredPresentTime, uncacheBuffer,
- hasListenerCallbacks, listenerCallbacks);
+ std::vector<ListenerCallbacks>& listenerCallbacks,
+ uint64_t transactionId) {
+ return mFlinger->setTransactionState(frameTimelineVsyncId, states, displays, flags,
+ applyToken, inputWindowCommands, desiredPresentTime,
+ uncacheBuffer, hasListenerCallbacks, listenerCallbacks,
+ transactionId);
}
auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(); };
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 28415bc..760bf65 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -100,7 +100,9 @@
sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
InputWindowCommands inputWindowCommands;
int64_t desiredPresentTime = -1;
+ int64_t frameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID;
client_cache_t uncacheBuffer;
+ int64_t id = -1;
};
void checkEqual(TransactionInfo info, SurfaceFlinger::TransactionState state) {
@@ -114,11 +116,12 @@
}
void setupSingle(TransactionInfo& transaction, uint32_t flags, bool syncInputWindows,
- int64_t desiredPresentTime) {
+ int64_t desiredPresentTime, int64_t frameTimelineVsyncId) {
mTransactionNumber++;
transaction.flags |= flags; // ISurfaceComposer::eSynchronous;
transaction.inputWindowCommands.syncInputWindows = syncInputWindows;
transaction.desiredPresentTime = desiredPresentTime;
+ transaction.frameTimelineVsyncId = frameTimelineVsyncId;
}
void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
@@ -128,12 +131,13 @@
EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillOnce(Return(systemTime()));
TransactionInfo transaction;
setupSingle(transaction, flags, syncInputWindows,
- /*desiredPresentTime*/ -1);
+ /*desiredPresentTime*/ -1, ISurfaceComposer::INVALID_VSYNC_ID);
nsecs_t applicationTime = systemTime();
- mFlinger.setTransactionState(transaction.states, transaction.displays, transaction.flags,
+ mFlinger.setTransactionState(transaction.frameTimelineVsyncId, transaction.states,
+ transaction.displays, transaction.flags,
transaction.applyToken, transaction.inputWindowCommands,
transaction.desiredPresentTime, transaction.uncacheBuffer,
- mHasListenerCallbacks, mCallbacks);
+ mHasListenerCallbacks, mCallbacks, transaction.id);
// This transaction should not have been placed on the transaction queue.
// If transaction is synchronous or syncs input windows, SF
@@ -162,12 +166,13 @@
.WillOnce(Return(time + nsecs_t(5 * 1e8)));
TransactionInfo transaction;
setupSingle(transaction, flags, syncInputWindows,
- /*desiredPresentTime*/ time + s2ns(1));
+ /*desiredPresentTime*/ time + s2ns(1), ISurfaceComposer::INVALID_VSYNC_ID);
nsecs_t applicationSentTime = systemTime();
- mFlinger.setTransactionState(transaction.states, transaction.displays, transaction.flags,
+ mFlinger.setTransactionState(transaction.frameTimelineVsyncId, transaction.states,
+ transaction.displays, transaction.flags,
transaction.applyToken, transaction.inputWindowCommands,
transaction.desiredPresentTime, transaction.uncacheBuffer,
- mHasListenerCallbacks, mCallbacks);
+ mHasListenerCallbacks, mCallbacks, transaction.id);
nsecs_t returnedTime = systemTime();
EXPECT_LE(returnedTime, applicationSentTime + s2ns(5));
@@ -186,19 +191,20 @@
// transaction that should go on the pending thread
TransactionInfo transactionA;
setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false,
- /*desiredPresentTime*/ time + s2ns(1));
+ /*desiredPresentTime*/ time + s2ns(1), ISurfaceComposer::INVALID_VSYNC_ID);
// transaction that would not have gone on the pending thread if not
// blocked
TransactionInfo transactionB;
setupSingle(transactionB, flags, syncInputWindows,
- /*desiredPresentTime*/ -1);
+ /*desiredPresentTime*/ -1, ISurfaceComposer::INVALID_VSYNC_ID);
nsecs_t applicationSentTime = systemTime();
- mFlinger.setTransactionState(transactionA.states, transactionA.displays, transactionA.flags,
+ mFlinger.setTransactionState(transactionA.frameTimelineVsyncId, transactionA.states,
+ transactionA.displays, transactionA.flags,
transactionA.applyToken, transactionA.inputWindowCommands,
transactionA.desiredPresentTime, transactionA.uncacheBuffer,
- mHasListenerCallbacks, mCallbacks);
+ mHasListenerCallbacks, mCallbacks, transactionA.id);
// This thread should not have been blocked by the above transaction
// (5s is the timeout period that applyTransactionState waits for SF to
@@ -206,10 +212,11 @@
EXPECT_LE(systemTime(), applicationSentTime + s2ns(5));
applicationSentTime = systemTime();
- mFlinger.setTransactionState(transactionB.states, transactionB.displays, transactionB.flags,
+ mFlinger.setTransactionState(transactionB.frameTimelineVsyncId, transactionB.states,
+ transactionB.displays, transactionB.flags,
transactionB.applyToken, transactionB.inputWindowCommands,
transactionB.desiredPresentTime, transactionB.uncacheBuffer,
- mHasListenerCallbacks, mCallbacks);
+ mHasListenerCallbacks, mCallbacks, transactionB.id);
// this thread should have been blocked by the above transaction
// if this is an animation, this thread should be blocked for 5s
@@ -251,11 +258,12 @@
.WillOnce(Return(s2ns(2)));
TransactionInfo transactionA; // transaction to go on pending queue
setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false,
- /*desiredPresentTime*/ s2ns(1));
- mFlinger.setTransactionState(transactionA.states, transactionA.displays, transactionA.flags,
- transactionA.applyToken, transactionA.inputWindowCommands,
- transactionA.desiredPresentTime, transactionA.uncacheBuffer,
- mHasListenerCallbacks, mCallbacks);
+ /*desiredPresentTime*/ s2ns(1), ISurfaceComposer::INVALID_VSYNC_ID);
+ mFlinger.setTransactionState(transactionA.frameTimelineVsyncId, transactionA.states,
+ transactionA.displays, transactionA.flags, transactionA.applyToken,
+ transactionA.inputWindowCommands, transactionA.desiredPresentTime,
+ transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks,
+ transactionA.id);
auto& transactionQueue = mFlinger.getTransactionQueue();
ASSERT_EQ(1, transactionQueue.size());
@@ -271,9 +279,10 @@
// different process) to re-query and reset the cached expected present time
TransactionInfo empty;
empty.applyToken = sp<IBinder>();
- mFlinger.setTransactionState(empty.states, empty.displays, empty.flags, empty.applyToken,
- empty.inputWindowCommands, empty.desiredPresentTime,
- empty.uncacheBuffer, mHasListenerCallbacks, mCallbacks);
+ mFlinger.setTransactionState(empty.frameTimelineVsyncId, empty.states, empty.displays,
+ empty.flags, empty.applyToken, empty.inputWindowCommands,
+ empty.desiredPresentTime, empty.uncacheBuffer,
+ mHasListenerCallbacks, mCallbacks, empty.id);
// flush transaction queue should flush as desiredPresentTime has
// passed
diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
index a82b583..efaa9fa 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
@@ -18,6 +18,7 @@
#include <gmock/gmock.h>
+#include "FrameTimeline.h"
#include "Scheduler/EventThread.h"
#include "Scheduler/MessageQueue.h"
@@ -34,6 +35,10 @@
MOCK_METHOD1(postMessage, void(sp<MessageHandler>&&));
MOCK_METHOD0(invalidate, void());
MOCK_METHOD0(refresh, void());
+ MOCK_METHOD3(initVsync,
+ void(scheduler::VSyncDispatch&, frametimeline::TokenManager&,
+ std::chrono::nanoseconds));
+ MOCK_METHOD1(setDuration, void(std::chrono::nanoseconds workDuration));
};
} // namespace android::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
index e2c8a65..03a04a9 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
@@ -35,10 +35,10 @@
MOCK_METHOD0(isEnabled, bool());
MOCK_METHOD1(addTransactionTraceListener, void(const sp<gui::ITransactionTraceListener>&));
MOCK_METHOD1(binderDied, void(const wp<IBinder>&));
- MOCK_METHOD6(saveTransaction,
+ MOCK_METHOD7(saveTransaction,
void(const Vector<ComposerState>&,
const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>&,
- const Vector<DisplayState>&, uint32_t, int, int));
+ const Vector<DisplayState>&, uint32_t, int, int, uint64_t));
MOCK_METHOD1(saveSurfaceCreation, void(const sp<const Layer>&));
MOCK_METHOD1(saveSurfaceDeletion, void(const sp<const Layer>&));
MOCK_METHOD4(saveBufferUpdate, void(int32_t, uint32_t, uint32_t, uint64_t));