Merge "Move flag feature_overrides to namespace "gpu"" into main
diff --git a/cmds/dumpstate/res/default_screenshot.png b/cmds/dumpstate/res/default_screenshot.png
index 10f36aa..1e14306 100644
--- a/cmds/dumpstate/res/default_screenshot.png
+++ b/cmds/dumpstate/res/default_screenshot.png
Binary files differ
diff --git a/cmds/installd/TEST_MAPPING b/cmds/installd/TEST_MAPPING
index fc4cfc9..d53c94b 100644
--- a/cmds/installd/TEST_MAPPING
+++ b/cmds/installd/TEST_MAPPING
@@ -18,10 +18,6 @@
{
"name": "run_dex2oat_test"
},
- // AdoptableHostTest moves packages, part of which is handled by installd
- {
- "name": "AdoptableHostTest"
- },
{
"name": "CtsUsesLibraryHostTestCases"
},
diff --git a/include/android/system_health.h b/include/android/system_health.h
index bdb1413..4494e32 100644
--- a/include/android/system_health.h
+++ b/include/android/system_health.h
@@ -316,8 +316,6 @@
/**
* Gets the range of the calculation window size for CPU headroom.
*
- * In API version 36, the range will be a superset of [50, 10000].
- *
* Available since API level 36.
*
* @param outMinMillis Non-null output pointer to be set to the minimum window size in milliseconds.
@@ -332,8 +330,6 @@
/**
* Gets the range of the calculation window size for GPU headroom.
*
- * In API version 36, the range will be a superset of [50, 10000].
- *
* Available since API level 36.
*
* @param outMinMillis Non-null output pointer to be set to the minimum window size in milliseconds.
diff --git a/include/input/DisplayTopologyGraph.h b/include/input/DisplayTopologyGraph.h
index 3ae865a..9fc080d 100644
--- a/include/input/DisplayTopologyGraph.h
+++ b/include/input/DisplayTopologyGraph.h
@@ -46,6 +46,8 @@
DisplayTopologyPosition position;
// The offset in DP of the adjacent display, relative to the source display.
float offsetDp;
+
+ std::string dump() const;
};
/**
@@ -55,6 +57,9 @@
ui::LogicalDisplayId primaryDisplayId = ui::LogicalDisplayId::INVALID;
std::unordered_map<ui::LogicalDisplayId, std::vector<DisplayTopologyAdjacentDisplay>> graph;
std::unordered_map<ui::LogicalDisplayId, int> displaysDensity;
+
+ bool isValid() const;
+ std::string dump() const;
};
} // namespace android
diff --git a/include/input/InputFlags.h b/include/input/InputFlags.h
index 4b42f77..16e754e 100644
--- a/include/input/InputFlags.h
+++ b/include/input/InputFlags.h
@@ -22,7 +22,21 @@
public:
/**
* Check if connected displays feature is enabled, either via the feature flag or settings
- * override.
+ * override. Developer setting override allows enabling all the "desktop experiences" features
+ * including input related connected_displays_cursor flag.
+ *
+ * The developer settings override is prioritised over aconfig flags. Any tests that require
+ * applicable aconfig flags to be disabled with SCOPED_FLAG_OVERRIDE also need this developer
+ * option to be reset locally.
+ *
+ * Also note the developer setting override is only applicable to the desktop experiences
+ * related features.
+ *
+ * To enable only the input flag run:
+ * adb shell aflags enable com.android.input.flags.connected_displays_cursor
+ * To override this flag and enable all "desktop experiences" features run:
+ * adb shell aflags enable com.android.window.flags.enable_desktop_mode_through_dev_option
+ * adb shell setprop persist.wm.debug.desktop_experience_devopts 1
*/
static bool connectedDisplaysCursorEnabled();
diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp
index 7c0319a..b1c8994 100644
--- a/libs/binder/BackendUnifiedServiceManager.cpp
+++ b/libs/binder/BackendUnifiedServiceManager.cpp
@@ -130,7 +130,13 @@
bool BinderCacheWithInvalidation::isClientSideCachingEnabled(const std::string& serviceName) {
sp<ProcessState> self = ProcessState::selfOrNull();
- if (!self || self->getThreadPoolMaxTotalThreadCount() <= 0) {
+ // Should not cache if process state could not be found, or if thread pool
+ // max could is not greater than zero.
+ if (!self) {
+ ALOGW("Service retrieved before binder threads started. If they are to be started, "
+ "consider starting binder threads earlier.");
+ return false;
+ } else if (self->getThreadPoolMaxTotalThreadCount() <= 0) {
ALOGW("Thread Pool max thread count is 0. Cannot cache binder as linkToDeath cannot be "
"implemented. serviceName: %s",
serviceName.c_str());
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 16023ff..1f3a45a 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -188,7 +188,9 @@
}
status_t RpcSession::setupPreconnectedClient(unique_fd fd, std::function<unique_fd()>&& request) {
- return setupClient([&](const std::vector<uint8_t>& sessionId, bool incoming) -> status_t {
+ return setupClient([&, fd = std::move(fd),
+ request = std::move(request)](const std::vector<uint8_t>& sessionId,
+ bool incoming) mutable -> status_t {
if (!fd.ok()) {
fd = request();
if (!fd.ok()) return BAD_VALUE;
@@ -476,8 +478,10 @@
return server;
}
-status_t RpcSession::setupClient(const std::function<status_t(const std::vector<uint8_t>& sessionId,
- bool incoming)>& connectAndInit) {
+template <typename Fn,
+ typename /* = std::enable_if_t<std::is_invocable_r_v<
+ status_t, Fn, const std::vector<uint8_t>&, bool>> */>
+status_t RpcSession::setupClient(Fn&& connectAndInit) {
{
RpcMutexLockGuard _l(mMutex);
LOG_ALWAYS_FATAL_IF(mStartedSetup, "Must only setup session once");
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index af37bf2..c9f92da 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -25,6 +25,7 @@
#include <map>
#include <optional>
+#include <type_traits>
#include <vector>
namespace android {
@@ -291,9 +292,14 @@
// join on thread passed to preJoinThreadOwnership
static void join(sp<RpcSession>&& session, PreJoinSetupResult&& result);
- [[nodiscard]] status_t setupClient(
- const std::function<status_t(const std::vector<uint8_t>& sessionId, bool incoming)>&
- connectAndInit);
+ // This is a workaround to support move-only functors.
+ // TODO: use std::move_only_function when it becomes available.
+ template <typename Fn,
+ // Fn must be a callable type taking (const std::vector<uint8_t>&, bool) and returning
+ // status_t
+ typename = std::enable_if_t<
+ std::is_invocable_r_v<status_t, Fn, const std::vector<uint8_t>&, bool>>>
+ [[nodiscard]] status_t setupClient(Fn&& connectAndInit);
[[nodiscard]] status_t setupSocketClient(const RpcSocketAddress& address);
[[nodiscard]] status_t setupOneSocketConnection(const RpcSocketAddress& address,
const std::vector<uint8_t>& sessionId,
diff --git a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
index 48c0ea6..1949cbb 100644
--- a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
+++ b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
@@ -134,9 +134,14 @@
//
// param will be passed to requestFd. Callers can use param to pass contexts to
// the requestFd function.
+//
+// paramDeleteFd will be called when requestFd and param are no longer in use.
+// Callers can pass a function deleting param if necessary. Callers can set
+// paramDeleteFd to null if callers doesn't need to clean up param.
AIBinder* ARpcSession_setupPreconnectedClient(ARpcSession* session,
int (*requestFd)(void* param),
- void* param);
+ void* param,
+ void (*paramDeleteFd)(void* param));
// Sets the file descriptor transport mode for this session.
void ARpcSession_setFileDescriptorTransportMode(ARpcSession* session,
diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp
index 64b1be2..8177fb0 100644
--- a/libs/binder/libbinder_rpc_unstable.cpp
+++ b/libs/binder/libbinder_rpc_unstable.cpp
@@ -248,9 +248,18 @@
#endif // __TRUSTY__
AIBinder* ARpcSession_setupPreconnectedClient(ARpcSession* handle, int (*requestFd)(void* param),
- void* param) {
+ void* param, void (*paramDeleteFd)(void* param)) {
auto session = handleToStrongPointer<RpcSession>(handle);
- auto request = [=] { return unique_fd{requestFd(param)}; };
+ auto deleter = [=](void* param) {
+ if (paramDeleteFd) {
+ paramDeleteFd(param);
+ }
+ };
+ // TODO: use unique_ptr once setupPreconnectedClient uses std::move_only_function.
+ std::shared_ptr<void> sharedParam(param, deleter);
+ auto request = [=, sharedParam = std::move(sharedParam)] {
+ return unique_fd{requestFd(sharedParam.get())};
+ };
if (status_t status = session->setupPreconnectedClient(unique_fd{}, request); status != OK) {
ALOGE("Failed to set up preconnected client. error: %s", statusToString(status).c_str());
return nullptr;
diff --git a/libs/binder/rust/rpcbinder/src/session.rs b/libs/binder/rust/rpcbinder/src/session.rs
index 09688a2..411b9de 100644
--- a/libs/binder/rust/rpcbinder/src/session.rs
+++ b/libs/binder/rust/rpcbinder/src/session.rs
@@ -195,11 +195,13 @@
/// take ownership of) file descriptors already connected to it.
pub fn setup_preconnected_client<T: FromIBinder + ?Sized>(
&self,
- mut request_fd: impl FnMut() -> Option<RawFd>,
+ request_fd: impl FnMut() -> Option<RawFd>,
) -> Result<Strong<T>, StatusCode> {
- // Double reference the factory because trait objects aren't FFI safe.
- let mut request_fd_ref: RequestFd = &mut request_fd;
- let param = &mut request_fd_ref as *mut RequestFd as *mut c_void;
+ // Trait objects aren't FFI safe, so *mut c_void can't be converted back to
+ // *mut dyn FnMut() -> Option<RawFd>>. Double box the factory to make it possible to get
+ // the factory from *mut c_void (to *mut Box<dyn<...>>) in the callbacks.
+ let request_fd_box: Box<dyn FnMut() -> Option<RawFd>> = Box::new(request_fd);
+ let param = Box::into_raw(Box::new(request_fd_box)) as *mut c_void;
// SAFETY: AIBinder returned by RpcPreconnectedClient has correct reference count, and the
// ownership can be safely taken by new_spibinder. RpcPreconnectedClient does not take ownership
@@ -209,6 +211,7 @@
self.as_ptr(),
Some(request_fd_wrapper),
param,
+ Some(param_delete_fd_wrapper),
))
};
Self::get_interface(service)
@@ -225,13 +228,18 @@
}
}
-type RequestFd<'a> = &'a mut dyn FnMut() -> Option<RawFd>;
-
unsafe extern "C" fn request_fd_wrapper(param: *mut c_void) -> c_int {
- let request_fd_ptr = param as *mut RequestFd;
+ let request_fd_ptr = param as *mut Box<dyn FnMut() -> Option<RawFd>>;
// SAFETY: This is only ever called by RpcPreconnectedClient, within the lifetime of the
// BinderFdFactory reference, with param being a properly aligned non-null pointer to an
// initialized instance.
let request_fd = unsafe { request_fd_ptr.as_mut().unwrap() };
request_fd().unwrap_or(-1)
}
+
+unsafe extern "C" fn param_delete_fd_wrapper(param: *mut c_void) {
+ // SAFETY: This is only ever called by RpcPreconnectedClient, with param being the
+ // pointer returned from Box::into_raw.
+ let request_fd_box = unsafe { Box::from_raw(param as *mut Box<dyn FnMut() -> Option<RawFd>>) };
+ drop(request_fd_box);
+}
diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h
index 583ad01..127676b 100644
--- a/libs/binder/trusty/include/binder/RpcServerTrusty.h
+++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h
@@ -94,9 +94,8 @@
static sp<RpcServer> makeRpcServer(std::unique_ptr<RpcTransportCtx> ctx) {
auto rpcServer = sp<RpcServer>::make(std::move(ctx));
- // TODO(b/266741352): follow-up to prevent needing this in the future
- // Trusty needs to be set to the latest stable version that is in prebuilts there.
- LOG_ALWAYS_FATAL_IF(!rpcServer->setProtocolVersion(0));
+ // By default we use the latest stable version.
+ LOG_ALWAYS_FATAL_IF(!rpcServer->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION));
return rpcServer;
}
diff --git a/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp b/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp
index 451383a..12e347e 100644
--- a/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp
+++ b/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp
@@ -27,6 +27,13 @@
using android::sp;
using android::wp;
+// The default behavior in trusty is to allow handles to be passed with tipc IPC.
+// We add mode NONE so that servers do not reject connections from clients who do
+// not change their default transport mode.
+static const std::vector<RpcSession::FileDescriptorTransportMode> TRUSTY_SERVER_SUPPORTED_FD_MODES =
+ {RpcSession::FileDescriptorTransportMode::TRUSTY,
+ RpcSession::FileDescriptorTransportMode::NONE};
+
struct ARpcServerTrusty {
sp<RpcServer> mRpcServer;
@@ -53,6 +60,8 @@
return nullptr;
}
+ rpcServer->setSupportedFileDescriptorTransportModes(TRUSTY_SERVER_SUPPORTED_FD_MODES);
+
rpcServer->setPerSessionRootObject(
[cb, cbArgSp](wp<RpcSession> /*session*/, const void* addrPtr, size_t len) {
auto* aib = (*cb)(addrPtr, len, cbArgSp.get());
diff --git a/libs/binder/trusty/rust/binder_rpc_unstable_bindgen/rules.mk b/libs/binder/trusty/rust/binder_rpc_unstable_bindgen/rules.mk
index ef1b7c3..40fc218 100644
--- a/libs/binder/trusty/rust/binder_rpc_unstable_bindgen/rules.mk
+++ b/libs/binder/trusty/rust/binder_rpc_unstable_bindgen/rules.mk
@@ -30,6 +30,8 @@
trusty/user/base/lib/libstdc++-trusty \
trusty/user/base/lib/trusty-sys \
+MODULE_SRCDEPS := $(LIBBINDER_DIR)/include_rpc_unstable/binder_rpc_unstable.hpp
+
MODULE_BINDGEN_SRC_HEADER := $(LOCAL_DIR)/BinderBindings.hpp
MODULE_BINDGEN_FLAGS += \
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 5ab31db..b5fa321 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -281,6 +281,7 @@
"SurfaceControl.cpp",
"SurfaceComposerClient.cpp",
"SyncFeatures.cpp",
+ "TransactionState.cpp",
"VsyncEventData.cpp",
"view/Surface.cpp",
"WindowInfosListenerReporter.cpp",
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index fa97142..1aae13c 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -937,15 +937,22 @@
: Surface(igbp, controlledByApp, scHandle), mBbq(bbq) {}
void allocateBuffers() override {
+ ATRACE_CALL();
uint32_t reqWidth = mReqWidth ? mReqWidth : mUserWidth;
uint32_t reqHeight = mReqHeight ? mReqHeight : mUserHeight;
auto gbp = getIGraphicBufferProducer();
- std::thread ([reqWidth, reqHeight, gbp=getIGraphicBufferProducer(),
- reqFormat=mReqFormat, reqUsage=mReqUsage] () {
+ std::thread allocateThread([reqWidth, reqHeight, gbp = getIGraphicBufferProducer(),
+ reqFormat = mReqFormat, reqUsage = mReqUsage]() {
+ if (com_android_graphics_libgui_flags_allocate_buffer_priority()) {
+ androidSetThreadName("allocateBuffers");
+ pid_t tid = gettid();
+ androidSetThreadPriority(tid, ANDROID_PRIORITY_DISPLAY);
+ }
+
gbp->allocateBuffers(reqWidth, reqHeight,
reqFormat, reqUsage);
-
- }).detach();
+ });
+ allocateThread.detach();
}
status_t setFrameRate(float frameRate, int8_t compatibility,
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index 1585aae..4926ceb 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -17,6 +17,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "BufferItemConsumer"
//#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <utils/Errors.h>
#include <utils/Log.h>
#include <inttypes.h>
@@ -132,13 +133,36 @@
return OK;
}
+status_t BufferItemConsumer::attachBuffer(const sp<GraphicBuffer>& buffer) {
+ if (!buffer) {
+ BI_LOGE("BufferItemConsumer::attachBuffer no input buffer specified.");
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock _l(mMutex);
+
+ int slot = INVALID_BUFFER_SLOT;
+ status_t status = mConsumer->attachBuffer(&slot, buffer);
+ if (status != OK) {
+ BI_LOGE("BufferItemConsumer::attachBuffer unable to attach buffer %d", status);
+ return status;
+ }
+
+ mSlots[slot] = {
+ .mGraphicBuffer = buffer,
+ .mFence = nullptr,
+ .mFrameNumber = 0,
+ };
+
+ return OK;
+}
+
status_t BufferItemConsumer::releaseBuffer(const BufferItem &item,
const sp<Fence>& releaseFence) {
Mutex::Autolock _l(mMutex);
return releaseBufferSlotLocked(item.mSlot, item.mGraphicBuffer, releaseFence);
}
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
status_t BufferItemConsumer::releaseBuffer(const sp<GraphicBuffer>& buffer,
const sp<Fence>& releaseFence) {
Mutex::Autolock _l(mMutex);
@@ -154,7 +178,6 @@
return releaseBufferSlotLocked(slotIndex, buffer, releaseFence);
}
-#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
status_t BufferItemConsumer::releaseBufferSlotLocked(int slotIndex, const sp<GraphicBuffer>& buffer,
const sp<Fence>& releaseFence) {
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 270bfbd..4681c9e 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -14,10 +14,6 @@
* limitations under the License.
*/
-#include <inttypes.h>
-#include <pwd.h>
-#include <sys/types.h>
-
#define LOG_TAG "BufferQueueConsumer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
//#define LOG_NDEBUG 0
@@ -48,6 +44,11 @@
#include <com_android_graphics_libgui_flags.h>
+#include <inttypes.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <optional>
+
namespace android {
// Macros for include BufferQueueCore information in log messages
@@ -767,11 +768,15 @@
return NO_ERROR;
}
+status_t BufferQueueConsumer::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
+ return setMaxAcquiredBufferCount(maxAcquiredBuffers, std::nullopt);
+}
+
status_t BufferQueueConsumer::setMaxAcquiredBufferCount(
- int maxAcquiredBuffers) {
+ int maxAcquiredBuffers, std::optional<OnBufferReleasedCallback> onBuffersReleasedCallback) {
ATRACE_FORMAT("%s(%d)", __func__, maxAcquiredBuffers);
- sp<IConsumerListener> listener;
+ std::optional<OnBufferReleasedCallback> callback;
{ // Autolock scope
std::unique_lock<std::mutex> lock(mCore->mMutex);
@@ -833,13 +838,20 @@
BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers);
mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers;
VALIDATE_CONSISTENCY();
- if (delta < 0 && mCore->mBufferReleasedCbEnabled) {
- listener = mCore->mConsumerListener;
+ if (delta < 0) {
+ if (onBuffersReleasedCallback) {
+ callback = std::move(onBuffersReleasedCallback);
+ } else if (mCore->mBufferReleasedCbEnabled) {
+ callback = [listener = mCore->mConsumerListener]() {
+ listener->onBuffersReleased();
+ };
+ }
}
}
+
// Call back without lock held
- if (listener != nullptr) {
- listener->onBuffersReleased();
+ if (callback) {
+ (*callback)();
}
return NO_ERROR;
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 117a362..5b89c6e 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -264,7 +264,10 @@
void ConsumerBase::onBuffersReleased() {
Mutex::Autolock lock(mMutex);
+ onBuffersReleasedLocked();
+}
+void ConsumerBase::onBuffersReleasedLocked() {
CB_LOGV("onBuffersReleased");
if (mAbandoned) {
@@ -481,7 +484,8 @@
CB_LOGE("setMaxAcquiredBufferCount: ConsumerBase is abandoned!");
return NO_INIT;
}
- return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers);
+ return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers,
+ {[this]() { onBuffersReleasedLocked(); }});
}
status_t ConsumerBase::setConsumerIsProtected(bool isProtected) {
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 43855da..ad95d1a 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -55,6 +55,28 @@
using gui::FocusRequest;
using gui::WindowInfoHandle;
+namespace {
+bool isSameWindowHandle(const sp<WindowInfoHandle>& lhs, const sp<WindowInfoHandle>& rhs) {
+ if (lhs == rhs) {
+ return true;
+ }
+
+ if (!lhs || !rhs) {
+ return false;
+ }
+
+ return *lhs->getInfo() == *rhs->getInfo();
+};
+
+bool isSameSurfaceControl(const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs) {
+ if (lhs == rhs) {
+ return true;
+ }
+
+ return SurfaceControl::isSameSurface(lhs, rhs);
+};
+} // namespace
+
layer_state_t::layer_state_t()
: surface(nullptr),
layerId(-1),
@@ -73,7 +95,6 @@
transformToDisplayInverse(false),
crop({0, 0, -1, -1}),
dataspace(ui::Dataspace::UNKNOWN),
- surfaceDamageRegion(),
api(-1),
colorTransform(mat4()),
bgColor(0),
@@ -117,19 +138,21 @@
SAFE_PARCEL(output.writeFloat, crop.left);
SAFE_PARCEL(output.writeFloat, crop.bottom);
SAFE_PARCEL(output.writeFloat, crop.right);
- SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, relativeLayerSurfaceControl);
- SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, parentSurfaceControlForChild);
+ SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output,
+ mNotDefCmpState.relativeLayerSurfaceControl);
+ SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output,
+ mNotDefCmpState.parentSurfaceControlForChild);
SAFE_PARCEL(output.writeFloat, color.r);
SAFE_PARCEL(output.writeFloat, color.g);
SAFE_PARCEL(output.writeFloat, color.b);
SAFE_PARCEL(output.writeFloat, color.a);
- SAFE_PARCEL(windowInfoHandle->writeToParcel, &output);
- SAFE_PARCEL(output.write, transparentRegion);
+ SAFE_PARCEL(mNotDefCmpState.windowInfoHandle->writeToParcel, &output);
+ SAFE_PARCEL(output.write, mNotDefCmpState.transparentRegion);
SAFE_PARCEL(output.writeUint32, bufferTransform);
SAFE_PARCEL(output.writeBool, transformToDisplayInverse);
SAFE_PARCEL(output.writeUint32, static_cast<uint32_t>(dataspace));
SAFE_PARCEL(output.write, hdrMetadata);
- SAFE_PARCEL(output.write, surfaceDamageRegion);
+ SAFE_PARCEL(output.write, mNotDefCmpState.surfaceDamageRegion);
SAFE_PARCEL(output.writeInt32, api);
if (sidebandStream) {
@@ -241,8 +264,10 @@
SAFE_PARCEL(input.readFloat, &crop.bottom);
SAFE_PARCEL(input.readFloat, &crop.right);
- SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &relativeLayerSurfaceControl);
- SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &parentSurfaceControlForChild);
+ SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input,
+ &mNotDefCmpState.relativeLayerSurfaceControl);
+ SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input,
+ &mNotDefCmpState.parentSurfaceControlForChild);
float tmpFloat = 0;
SAFE_PARCEL(input.readFloat, &tmpFloat);
@@ -254,9 +279,9 @@
SAFE_PARCEL(input.readFloat, &tmpFloat);
color.a = tmpFloat;
- SAFE_PARCEL(windowInfoHandle->readFromParcel, &input);
+ SAFE_PARCEL(mNotDefCmpState.windowInfoHandle->readFromParcel, &input);
- SAFE_PARCEL(input.read, transparentRegion);
+ SAFE_PARCEL(input.read, mNotDefCmpState.transparentRegion);
SAFE_PARCEL(input.readUint32, &bufferTransform);
SAFE_PARCEL(input.readBool, &transformToDisplayInverse);
@@ -265,7 +290,7 @@
dataspace = static_cast<ui::Dataspace>(tmpUint32);
SAFE_PARCEL(input.read, hdrMetadata);
- SAFE_PARCEL(input.read, surfaceDamageRegion);
+ SAFE_PARCEL(input.read, mNotDefCmpState.surfaceDamageRegion);
SAFE_PARCEL(input.readInt32, &api);
bool tmpBool = false;
@@ -583,7 +608,7 @@
}
if (other.what & eTransparentRegionChanged) {
what |= eTransparentRegionChanged;
- transparentRegion = other.transparentRegion;
+ mNotDefCmpState.transparentRegion = other.mNotDefCmpState.transparentRegion;
}
if (other.what & eFlagsChanged) {
what |= eFlagsChanged;
@@ -615,11 +640,13 @@
what |= eRelativeLayerChanged;
what &= ~eLayerChanged;
z = other.z;
- relativeLayerSurfaceControl = other.relativeLayerSurfaceControl;
+ mNotDefCmpState.relativeLayerSurfaceControl =
+ other.mNotDefCmpState.relativeLayerSurfaceControl;
}
if (other.what & eReparent) {
what |= eReparent;
- parentSurfaceControlForChild = other.parentSurfaceControlForChild;
+ mNotDefCmpState.parentSurfaceControlForChild =
+ other.mNotDefCmpState.parentSurfaceControlForChild;
}
if (other.what & eBufferTransformChanged) {
what |= eBufferTransformChanged;
@@ -665,7 +692,7 @@
}
if (other.what & eSurfaceDamageRegionChanged) {
what |= eSurfaceDamageRegionChanged;
- surfaceDamageRegion = other.surfaceDamageRegion;
+ mNotDefCmpState.surfaceDamageRegion = other.mNotDefCmpState.surfaceDamageRegion;
}
if (other.what & eApiChanged) {
what |= eApiChanged;
@@ -684,7 +711,8 @@
}
if (other.what & eInputInfoChanged) {
what |= eInputInfoChanged;
- windowInfoHandle = sp<WindowInfoHandle>::make(*other.windowInfoHandle);
+ mNotDefCmpState.windowInfoHandle =
+ sp<WindowInfoHandle>::make(*other.mNotDefCmpState.windowInfoHandle);
}
if (other.what & eBackgroundColorChanged) {
what |= eBackgroundColorChanged;
@@ -807,7 +835,8 @@
CHECK_DIFF(diff, eAlphaChanged, other, color.a);
CHECK_DIFF(diff, eMatrixChanged, other, matrix);
if (other.what & eTransparentRegionChanged &&
- (!transparentRegion.hasSameRects(other.transparentRegion))) {
+ (!mNotDefCmpState.transparentRegion.hasSameRects(
+ other.mNotDefCmpState.transparentRegion))) {
diff |= eTransparentRegionChanged;
}
if (other.what & eFlagsChanged) {
@@ -824,8 +853,8 @@
diff &= ~eLayerChanged;
}
if (other.what & eReparent &&
- !SurfaceControl::isSameSurface(parentSurfaceControlForChild,
- other.parentSurfaceControlForChild)) {
+ !SurfaceControl::isSameSurface(mNotDefCmpState.parentSurfaceControlForChild,
+ other.mNotDefCmpState.parentSurfaceControlForChild)) {
diff |= eReparent;
}
CHECK_DIFF(diff, eBufferTransformChanged, other, bufferTransform);
@@ -839,7 +868,8 @@
CHECK_DIFF(diff, eCachingHintChanged, other, cachingHint);
CHECK_DIFF(diff, eHdrMetadataChanged, other, hdrMetadata);
if (other.what & eSurfaceDamageRegionChanged &&
- (!surfaceDamageRegion.hasSameRects(other.surfaceDamageRegion))) {
+ (!mNotDefCmpState.surfaceDamageRegion.hasSameRects(
+ other.mNotDefCmpState.surfaceDamageRegion))) {
diff |= eSurfaceDamageRegionChanged;
}
CHECK_DIFF(diff, eApiChanged, other, api);
@@ -901,6 +931,38 @@
SAFE_PARCEL(input.readFloat, &dsdy);
return NO_ERROR;
}
+void layer_state_t::updateTransparentRegion(const Region& transparentRegion) {
+ what |= eTransparentRegionChanged;
+ mNotDefCmpState.transparentRegion = transparentRegion;
+}
+void layer_state_t::updateSurfaceDamageRegion(const Region& surfaceDamageRegion) {
+ what |= eSurfaceDamageRegionChanged;
+ mNotDefCmpState.surfaceDamageRegion = surfaceDamageRegion;
+}
+void layer_state_t::updateRelativeLayer(const sp<SurfaceControl>& relativeTo, int32_t z) {
+ what |= layer_state_t::eRelativeLayerChanged;
+ what &= ~layer_state_t::eLayerChanged;
+ mNotDefCmpState.relativeLayerSurfaceControl = relativeTo;
+ this->z = z;
+}
+void layer_state_t::updateParentLayer(const sp<SurfaceControl>& newParent) {
+ what |= layer_state_t::eReparent;
+ mNotDefCmpState.parentSurfaceControlForChild =
+ newParent ? newParent->getParentingLayer() : nullptr;
+}
+void layer_state_t::updateInputWindowInfo(sp<gui::WindowInfoHandle>&& info) {
+ what |= eInputInfoChanged;
+ mNotDefCmpState.windowInfoHandle = std::move(info);
+}
+
+bool layer_state_t::NotDefaultComparableState::operator==(
+ const NotDefaultComparableState& rhs) const {
+ return transparentRegion.hasSameRects(rhs.transparentRegion) &&
+ surfaceDamageRegion.hasSameRects(rhs.surfaceDamageRegion) &&
+ isSameWindowHandle(windowInfoHandle, rhs.windowInfoHandle) &&
+ isSameSurfaceControl(relativeLayerSurfaceControl, rhs.relativeLayerSurfaceControl) &&
+ isSameSurfaceControl(parentSurfaceControlForChild, rhs.parentSurfaceControlForChild);
+}
// ------------------------------- InputWindowCommands ----------------------------------------
@@ -1034,8 +1096,8 @@
}
status_t TrustedPresentationListener::writeToParcel(Parcel* parcel) const {
- SAFE_PARCEL(parcel->writeStrongBinder, callbackInterface);
- SAFE_PARCEL(parcel->writeInt32, callbackId);
+ SAFE_PARCEL(parcel->writeStrongBinder, mState.callbackInterface);
+ SAFE_PARCEL(parcel->writeInt32, mState.callbackId);
return NO_ERROR;
}
@@ -1043,9 +1105,9 @@
sp<IBinder> tmpBinder = nullptr;
SAFE_PARCEL(parcel->readNullableStrongBinder, &tmpBinder);
if (tmpBinder) {
- callbackInterface = checked_interface_cast<ITransactionCompletedListener>(tmpBinder);
+ mState.callbackInterface = checked_interface_cast<ITransactionCompletedListener>(tmpBinder);
}
- SAFE_PARCEL(parcel->readInt32, &callbackId);
+ SAFE_PARCEL(parcel->readInt32, &mState.callbackId);
return NO_ERROR;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index bb7184f..e407a63 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1391,11 +1391,16 @@
// ---------------------------------------------------------------------------
sp<IBinder> SurfaceComposerClient::createVirtualDisplay(const std::string& displayName,
- bool isSecure, const std::string& uniqueId,
+ bool isSecure, bool optimizeForPower,
+ const std::string& uniqueId,
float requestedRefreshRate) {
+ const gui::ISurfaceComposer::OptimizationPolicy optimizationPolicy = optimizeForPower
+ ? gui::ISurfaceComposer::OptimizationPolicy::optimizeForPower
+ : gui::ISurfaceComposer::OptimizationPolicy::optimizeForPerformance;
sp<IBinder> display = nullptr;
binder::Status status =
ComposerServiceAIDL::getComposerService()->createVirtualDisplay(displayName, isSecure,
+ optimizationPolicy,
uniqueId,
requestedRefreshRate,
&display);
@@ -1523,11 +1528,7 @@
mStatus = BAD_INDEX;
return *this;
}
- s->what |= layer_state_t::eRelativeLayerChanged;
- s->what &= ~layer_state_t::eLayerChanged;
- s->relativeLayerSurfaceControl = relativeTo;
- s->z = z;
-
+ s->updateRelativeLayer(relativeTo, z);
registerSurfaceControlForCallback(sc);
return *this;
}
@@ -1557,9 +1558,7 @@
mStatus = BAD_INDEX;
return *this;
}
- s->what |= layer_state_t::eTransparentRegionChanged;
- s->transparentRegion = transparentRegion;
-
+ s->updateTransparentRegion(transparentRegion);
registerSurfaceControlForCallback(sc);
return *this;
}
@@ -1721,9 +1720,7 @@
if (SurfaceControl::isSameSurface(sc, newParent)) {
return *this;
}
- s->what |= layer_state_t::eReparent;
- s->parentSurfaceControlForChild = newParent ? newParent->getParentingLayer() : nullptr;
-
+ s->updateParentLayer(newParent);
registerSurfaceControlForCallback(sc);
return *this;
}
@@ -2009,9 +2006,7 @@
mStatus = BAD_INDEX;
return *this;
}
- s->what |= layer_state_t::eSurfaceDamageRegionChanged;
- s->surfaceDamageRegion = surfaceDamageRegion;
-
+ s->updateSurfaceDamageRegion(surfaceDamageRegion);
registerSurfaceControlForCallback(sc);
return *this;
}
@@ -2130,21 +2125,20 @@
mStatus = BAD_INDEX;
return *this;
}
- s->windowInfoHandle = std::move(info);
- s->what |= layer_state_t::eInputInfoChanged;
+ s->updateInputWindowInfo(std::move(info));
return *this;
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFocusedWindow(
const FocusRequest& request) {
- mInputWindowCommands.focusRequests.push_back(request);
+ mInputWindowCommands.addFocusRequest(request);
return *this;
}
SurfaceComposerClient::Transaction&
SurfaceComposerClient::Transaction::addWindowInfosReportedListener(
sp<gui::IWindowInfosReportedListener> windowInfosReportedListener) {
- mInputWindowCommands.windowInfosReportedListeners.insert(windowInfosReportedListener);
+ mInputWindowCommands.addWindowInfosReportedListener(windowInfosReportedListener);
return *this;
}
@@ -2364,10 +2358,6 @@
return *this;
}
-bool SurfaceComposerClient::flagEdgeExtensionEffectUseShader() {
- return com::android::graphics::libgui::flags::edge_extension_shader();
-}
-
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setEdgeExtensionEffect(
const sp<SurfaceControl>& sc, const gui::EdgeExtensionParameters& effect) {
layer_state_t* s = getLayerState(sc);
@@ -2572,8 +2562,9 @@
}
s->what |= layer_state_t::eTrustedPresentationInfoChanged;
s->trustedPresentationThresholds = thresholds;
- s->trustedPresentationListener.callbackInterface = TransactionCompletedListener::getIInstance();
- s->trustedPresentationListener.callbackId = sc->getLayerId();
+ s->trustedPresentationListener.configure(
+ {.callbackInterface = TransactionCompletedListener::getIInstance(),
+ .callbackId = sc->getLayerId()});
return *this;
}
@@ -2589,8 +2580,7 @@
}
s->what |= layer_state_t::eTrustedPresentationInfoChanged;
s->trustedPresentationThresholds = TrustedPresentationThresholds();
- s->trustedPresentationListener.callbackInterface = nullptr;
- s->trustedPresentationListener.callbackId = -1;
+ s->trustedPresentationListener.clear();
return *this;
}
diff --git a/libs/gui/TransactionState.cpp b/libs/gui/TransactionState.cpp
new file mode 100644
index 0000000..9e09bc2
--- /dev/null
+++ b/libs/gui/TransactionState.cpp
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "TransactionState"
+#include <gui/LayerState.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/TransactionState.h>
+#include <private/gui/ParcelUtils.h>
+#include <algorithm>
+
+namespace android {
+
+status_t TransactionState::writeToParcel(Parcel* parcel) const {
+ SAFE_PARCEL(parcel->writeUint64, mId);
+ SAFE_PARCEL(parcel->writeUint32, mFlags);
+ SAFE_PARCEL(parcel->writeInt64, mDesiredPresentTime);
+ SAFE_PARCEL(parcel->writeBool, mIsAutoTimestamp);
+ SAFE_PARCEL(parcel->writeParcelable, mFrameTimelineInfo);
+ SAFE_PARCEL(parcel->writeStrongBinder, mApplyToken);
+ SAFE_PARCEL(parcel->writeBool, mMayContainBuffer);
+ SAFE_PARCEL(parcel->writeBool, mLogCallPoints);
+
+ SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(mDisplayStates.size()));
+ for (auto const& displayState : mDisplayStates) {
+ displayState.write(*parcel);
+ }
+ SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(mComposerStates.size()));
+ for (auto const& composerState : mComposerStates) {
+ composerState.write(*parcel);
+ }
+
+ mInputWindowCommands.write(*parcel);
+ SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(mUncacheBuffers.size()));
+ for (const client_cache_t& uncacheBuffer : mUncacheBuffers) {
+ SAFE_PARCEL(parcel->writeStrongBinder, uncacheBuffer.token.promote());
+ SAFE_PARCEL(parcel->writeUint64, uncacheBuffer.id);
+ }
+
+ SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(mMergedTransactionIds.size()));
+ for (auto mergedTransactionId : mMergedTransactionIds) {
+ SAFE_PARCEL(parcel->writeUint64, mergedTransactionId);
+ }
+
+ SAFE_PARCEL(parcel->writeBool, mHasListenerCallbacks);
+ SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(mListenerCallbacks.size()));
+ for (const auto& [listener, callbackIds] : mListenerCallbacks) {
+ SAFE_PARCEL(parcel->writeStrongBinder, listener);
+ SAFE_PARCEL(parcel->writeParcelableVector, callbackIds);
+ }
+
+ return NO_ERROR;
+}
+
+status_t TransactionState::readFromParcel(const Parcel* parcel) {
+ SAFE_PARCEL(parcel->readUint64, &mId);
+ SAFE_PARCEL(parcel->readUint32, &mFlags);
+ SAFE_PARCEL(parcel->readInt64, &mDesiredPresentTime);
+ SAFE_PARCEL(parcel->readBool, &mIsAutoTimestamp);
+ SAFE_PARCEL(parcel->readParcelable, &mFrameTimelineInfo);
+ SAFE_PARCEL(parcel->readNullableStrongBinder, &mApplyToken);
+ SAFE_PARCEL(parcel->readBool, &mMayContainBuffer);
+ SAFE_PARCEL(parcel->readBool, &mLogCallPoints);
+
+ uint32_t count;
+ SAFE_PARCEL_READ_SIZE(parcel->readUint32, &count, parcel->dataSize())
+ mDisplayStates.clear();
+ mDisplayStates.reserve(count);
+ for (size_t i = 0; i < count; i++) {
+ DisplayState displayState;
+ if (displayState.read(*parcel) == BAD_VALUE) {
+ return BAD_VALUE;
+ }
+ mDisplayStates.emplace_back(std::move(displayState));
+ }
+
+ SAFE_PARCEL_READ_SIZE(parcel->readUint32, &count, parcel->dataSize())
+ mComposerStates.clear();
+ mComposerStates.reserve(count);
+ for (size_t i = 0; i < count; i++) {
+ ComposerState composerState;
+ if (composerState.read(*parcel) == BAD_VALUE) {
+ return BAD_VALUE;
+ }
+ mComposerStates.emplace_back(std::move(composerState));
+ }
+
+ if (status_t status = mInputWindowCommands.read(*parcel) != NO_ERROR) {
+ return status;
+ }
+
+ SAFE_PARCEL_READ_SIZE(parcel->readUint32, &count, parcel->dataSize())
+ mUncacheBuffers.clear();
+ mUncacheBuffers.reserve(count);
+ for (size_t i = 0; i < count; i++) {
+ client_cache_t client_cache;
+ sp<IBinder> tmpBinder;
+ SAFE_PARCEL(parcel->readStrongBinder, &tmpBinder);
+ client_cache.token = tmpBinder;
+ SAFE_PARCEL(parcel->readUint64, &client_cache.id);
+ mUncacheBuffers.emplace_back(std::move(client_cache));
+ }
+
+ SAFE_PARCEL_READ_SIZE(parcel->readUint32, &count, parcel->dataSize())
+ mMergedTransactionIds.clear();
+ mMergedTransactionIds.resize(count);
+ for (size_t i = 0; i < count; i++) {
+ SAFE_PARCEL(parcel->readUint64, &mMergedTransactionIds[i]);
+ }
+
+ SAFE_PARCEL(parcel->readBool, &mHasListenerCallbacks);
+ SAFE_PARCEL_READ_SIZE(parcel->readUint32, &count, parcel->dataSize());
+ mListenerCallbacks.clear();
+ mListenerCallbacks.reserve(count);
+ for (uint32_t i = 0; i < count; i++) {
+ sp<IBinder> tmpBinder;
+ SAFE_PARCEL(parcel->readStrongBinder, &tmpBinder);
+ std::vector<CallbackId> callbackIds;
+ SAFE_PARCEL(parcel->readParcelableVector, &callbackIds);
+ mListenerCallbacks.emplace_back(tmpBinder, callbackIds);
+ }
+
+ return NO_ERROR;
+}
+
+void TransactionState::merge(TransactionState&& other,
+ const std::function<void(layer_state_t&)>& onBufferOverwrite) {
+ while (mMergedTransactionIds.size() + other.mMergedTransactionIds.size() >
+ MAX_MERGE_HISTORY_LENGTH - 1 &&
+ mMergedTransactionIds.size() > 0) {
+ mMergedTransactionIds.pop_back();
+ }
+ if (other.mMergedTransactionIds.size() == MAX_MERGE_HISTORY_LENGTH) {
+ mMergedTransactionIds.insert(mMergedTransactionIds.begin(),
+ other.mMergedTransactionIds.begin(),
+ other.mMergedTransactionIds.end() - 1);
+ } else if (other.mMergedTransactionIds.size() > 0u) {
+ mMergedTransactionIds.insert(mMergedTransactionIds.begin(),
+ other.mMergedTransactionIds.begin(),
+ other.mMergedTransactionIds.end());
+ }
+ mMergedTransactionIds.insert(mMergedTransactionIds.begin(), other.mId);
+
+ for (auto const& otherState : other.mComposerStates) {
+ if (auto it = std::find_if(mComposerStates.begin(), mComposerStates.end(),
+ [&otherState](const auto& composerState) {
+ return composerState.state.surface ==
+ otherState.state.surface;
+ });
+ it != mComposerStates.end()) {
+ if (otherState.state.what & layer_state_t::eBufferChanged) {
+ onBufferOverwrite(it->state);
+ }
+ it->state.merge(otherState.state);
+ } else {
+ mComposerStates.push_back(otherState);
+ }
+ }
+
+ for (auto const& state : other.mDisplayStates) {
+ if (auto it = std::find_if(mDisplayStates.begin(), mDisplayStates.end(),
+ [&state](const auto& displayState) {
+ return displayState.token == state.token;
+ });
+ it != mDisplayStates.end()) {
+ it->merge(state);
+ } else {
+ mDisplayStates.push_back(state);
+ }
+ }
+
+ for (const auto& cacheId : other.mUncacheBuffers) {
+ mUncacheBuffers.push_back(cacheId);
+ }
+
+ mInputWindowCommands.merge(other.mInputWindowCommands);
+ // TODO(b/385156191) Consider merging desired present time.
+ mFlags |= other.mFlags;
+ mMayContainBuffer |= other.mMayContainBuffer;
+ mLogCallPoints |= other.mLogCallPoints;
+
+ // mApplyToken is explicitly not merged. Token should be set before applying the transactions to
+ // make synchronization decisions a bit simpler.
+ mergeFrameTimelineInfo(other.mFrameTimelineInfo);
+ other.clear();
+}
+
+// copied from FrameTimelineInfo::merge()
+void TransactionState::mergeFrameTimelineInfo(const FrameTimelineInfo& other) {
+ // When merging vsync Ids we take the oldest valid one
+ if (mFrameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID &&
+ other.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) {
+ if (other.vsyncId > mFrameTimelineInfo.vsyncId) {
+ mFrameTimelineInfo = other;
+ }
+ } else if (mFrameTimelineInfo.vsyncId == FrameTimelineInfo::INVALID_VSYNC_ID) {
+ mFrameTimelineInfo = other;
+ }
+}
+
+void TransactionState::clear() {
+ mComposerStates.clear();
+ mDisplayStates.clear();
+ mListenerCallbacks.clear();
+ mHasListenerCallbacks = false;
+ mInputWindowCommands.clear();
+ mUncacheBuffers.clear();
+ mDesiredPresentTime = 0;
+ mIsAutoTimestamp = true;
+ mApplyToken = nullptr;
+ mFrameTimelineInfo = {};
+ mMergedTransactionIds.clear();
+ mFlags = 0;
+ mMayContainBuffer = false;
+ mLogCallPoints = false;
+}
+
+layer_state_t* TransactionState::getLayerState(const sp<SurfaceControl>& sc) {
+ auto handle = sc->getLayerStateHandle();
+ if (auto it = std::find_if(mComposerStates.begin(), mComposerStates.end(),
+ [&handle](const auto& composerState) {
+ return composerState.state.surface == handle;
+ });
+ it != mComposerStates.end()) {
+ return &it->state;
+ }
+
+ // 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.push_back(s);
+
+ return &mComposerStates.back().state;
+}
+
+DisplayState& TransactionState::getDisplayState(const sp<IBinder>& token) {
+ if (auto it = std::find_if(mDisplayStates.begin(), mDisplayStates.end(),
+ [token](const auto& display) { return display.token == token; });
+ it != mDisplayStates.end()) {
+ return *it;
+ }
+
+ // If display state doesn't exist, add a new one.
+ DisplayState s;
+ s.token = token;
+ mDisplayStates.push_back(s);
+ return mDisplayStates.back();
+}
+
+}; // namespace android
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
index da47ee2..9b2f089 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -67,6 +67,11 @@
frameRateOverride = 1 << 1,
}
+ enum OptimizationPolicy {
+ optimizeForPower = 0,
+ optimizeForPerformance = 1,
+ }
+
/**
* Signal that we're done booting.
* Requires ACCESS_SURFACE_FLINGER permission
@@ -97,6 +102,10 @@
* The name of the virtual display.
* isSecure
* Whether this virtual display is secure.
+ * optimizationPolicy
+ * Whether to optimize for power or performance. Displays that are optimizing for power may
+ * be dependent on a different display that optimizes for performance when they are on,
+ * which will guarantee performance for all of the other displays.
* uniqueId
* The unique ID for the display.
* requestedRefreshRate
@@ -108,7 +117,7 @@
* requires ACCESS_SURFACE_FLINGER permission.
*/
@nullable IBinder createVirtualDisplay(@utf8InCpp String displayName, boolean isSecure,
- @utf8InCpp String uniqueId, float requestedRefreshRate);
+ OptimizationPolicy optimizationPolicy, @utf8InCpp String uniqueId, float requestedRefreshRate);
/**
* Destroy a virtual display.
diff --git a/libs/gui/include/gui/BufferItemConsumer.h b/libs/gui/include/gui/BufferItemConsumer.h
index 0bfa7b2..fc31f46 100644
--- a/libs/gui/include/gui/BufferItemConsumer.h
+++ b/libs/gui/include/gui/BufferItemConsumer.h
@@ -96,6 +96,14 @@
status_t acquireBuffer(BufferItem* item, nsecs_t presentWhen,
bool waitForFence = true);
+ // Transfer ownership of a buffer to the BufferQueue. On NO_ERROR, the buffer
+ // is considered as if it were acquired. Buffer must not be null.
+ //
+ // Returns
+ // - BAD_VALUE if buffer is null
+ // - INVALID_OPERATION if too many buffers have already been acquired
+ status_t attachBuffer(const sp<GraphicBuffer>& buffer);
+
// Returns an acquired buffer to the queue, allowing it to be reused. Since
// only a fixed number of buffers may be acquired at a time, old buffers
// must be released by calling releaseBuffer to ensure new buffers can be
@@ -105,10 +113,8 @@
status_t releaseBuffer(const BufferItem &item,
const sp<Fence>& releaseFence = Fence::NO_FENCE);
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
status_t releaseBuffer(const sp<GraphicBuffer>& buffer,
const sp<Fence>& releaseFence = Fence::NO_FENCE);
-#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
protected:
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
diff --git a/libs/gui/include/gui/BufferQueueConsumer.h b/libs/gui/include/gui/BufferQueueConsumer.h
index ab1231a..ba6a6a7 100644
--- a/libs/gui/include/gui/BufferQueueConsumer.h
+++ b/libs/gui/include/gui/BufferQueueConsumer.h
@@ -122,7 +122,10 @@
// setMaxAcquiredBufferCount sets the maximum number of buffers that can
// be acquired by the consumer at one time (default 1). This call will
// fail if a producer is connected to the BufferQueue.
- virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
+ virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) override;
+ virtual status_t setMaxAcquiredBufferCount(
+ int maxAcquiredBuffers,
+ std::optional<OnBufferReleasedCallback> onBuffersReleasedCallback) override;
// setConsumerName sets the name used in logging
status_t setConsumerName(const String8& name) override;
diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h
index fd67f09..d2215ef 100644
--- a/libs/gui/include/gui/ConsumerBase.h
+++ b/libs/gui/include/gui/ConsumerBase.h
@@ -191,6 +191,8 @@
#endif
virtual int getSlotForBufferLocked(const sp<GraphicBuffer>& buffer);
+ virtual void onBuffersReleasedLocked();
+
virtual status_t detachBufferLocked(int slotIndex);
// freeBufferLocked frees up the given buffer slot. If the slot has been
diff --git a/libs/gui/include/gui/IGraphicBufferConsumer.h b/libs/gui/include/gui/IGraphicBufferConsumer.h
index 8272a59..8066b07 100644
--- a/libs/gui/include/gui/IGraphicBufferConsumer.h
+++ b/libs/gui/include/gui/IGraphicBufferConsumer.h
@@ -243,6 +243,9 @@
// maxAcquiredBuffers must be (inclusive) between 1 and MAX_MAX_ACQUIRED_BUFFERS. It also cannot
// cause the maxBufferCount value to be exceeded.
//
+ // If called with onBuffersReleasedCallback, that call back will be called in lieu of
+ // IConsumerListener::onBuffersReleased.
+ //
// Return of a value other than NO_ERROR means an error has occurred:
// * NO_INIT - the BufferQueue has been abandoned
// * BAD_VALUE - one of the below conditions occurred:
@@ -253,6 +256,11 @@
// * INVALID_OPERATION - attempting to call this after a producer connected.
virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) = 0;
+ using OnBufferReleasedCallback = std::function<void(void)>;
+ virtual status_t setMaxAcquiredBufferCount(
+ int maxAcquiredBuffers,
+ std::optional<OnBufferReleasedCallback> onBuffersReleasedCallback) = 0;
+
// setConsumerName sets the name used in logging
virtual status_t setConsumerName(const String8& name) = 0;
diff --git a/libs/gui/include/gui/LayerMetadata.h b/libs/gui/include/gui/LayerMetadata.h
index 7ee291d..6381db2 100644
--- a/libs/gui/include/gui/LayerMetadata.h
+++ b/libs/gui/include/gui/LayerMetadata.h
@@ -44,6 +44,10 @@
LayerMetadata& operator=(const LayerMetadata& other);
LayerMetadata& operator=(LayerMetadata&& other);
+ // Note: `default` is not feasible because Parcelable does not provide ==.
+ bool operator==(const LayerMetadata& rhs) const { return mMap == rhs.mMap; }
+ bool operator!=(const LayerMetadata&) const = default;
+
// Merges other into this LayerMetadata. If eraseEmpty is true, any entries in
// in this whose keys are paired with empty values in other will be erased.
bool merge(const LayerMetadata& other, bool eraseEmpty = false);
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index c2680a4..369d3d1 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -17,9 +17,9 @@
#ifndef ANDROID_SF_LAYER_STATE_H
#define ANDROID_SF_LAYER_STATE_H
-
#include <stdint.h>
#include <sys/types.h>
+#include <span>
#include <android/gui/DisplayCaptureArgs.h>
#include <android/gui/IWindowInfosReportedListener.h>
@@ -69,21 +69,39 @@
uint64_t id;
bool operator==(const client_cache_t& other) const { return id == other.id; }
+ bool operator!=(const client_cache_t&) const = default;
bool isValid() const { return token != nullptr; }
};
class TrustedPresentationListener : public Parcelable {
public:
- sp<ITransactionCompletedListener> callbackInterface;
- int callbackId = -1;
+ struct State {
+ sp<ITransactionCompletedListener> callbackInterface;
+ int callbackId = -1;
+ bool operator==(const State&) const = default;
+ bool operator!=(const State&) const = default;
+ };
void invoke(bool presentedWithinThresholds) {
- callbackInterface->onTrustedPresentationChanged(callbackId, presentedWithinThresholds);
+ mState.callbackInterface->onTrustedPresentationChanged(mState.callbackId,
+ presentedWithinThresholds);
+ }
+ void configure(State&& state) { mState = std::move(state); }
+ const sp<ITransactionCompletedListener>& getCallback() { return mState.callbackInterface; }
+ void clear() {
+ mState.callbackInterface = nullptr;
+ mState.callbackId = -1;
}
status_t writeToParcel(Parcel* parcel) const;
status_t readFromParcel(const Parcel* parcel);
+
+ bool operator==(const TrustedPresentationListener& rhs) const { return mState == rhs.mState; }
+ bool operator!=(const TrustedPresentationListener&) const = default;
+
+private:
+ State mState;
};
class BufferData : public Parcelable {
@@ -309,6 +327,32 @@
bool hasValidBuffer() const;
void sanitize(int32_t permissions);
+ void updateTransparentRegion(const Region& transparentRegion);
+ const Region& getTransparentRegion() const { return mNotDefCmpState.transparentRegion; }
+ void updateSurfaceDamageRegion(const Region& surfaceDamageRegion);
+ const Region& getSurfaceDamageRegion() const { return mNotDefCmpState.surfaceDamageRegion; }
+ // Do not update state flags. Used to set up test state.
+ void setSurfaceDamageRegion(Region&& surfaceDamageRegion) {
+ mNotDefCmpState.surfaceDamageRegion = std::move(surfaceDamageRegion);
+ }
+ void updateRelativeLayer(const sp<SurfaceControl>& relativeTo, int32_t z);
+ void updateParentLayer(const sp<SurfaceControl>& newParent);
+ void updateInputWindowInfo(sp<gui::WindowInfoHandle>&& info);
+ const gui::WindowInfo& getWindowInfo() const {
+ return *mNotDefCmpState.windowInfoHandle->getInfo();
+ }
+ gui::WindowInfo* editWindowInfo() { return mNotDefCmpState.windowInfoHandle->editInfo(); }
+
+ const sp<SurfaceControl>& getParentSurfaceControlForChild() const {
+ return mNotDefCmpState.parentSurfaceControlForChild;
+ }
+ const sp<SurfaceControl>& getRelativeLayerSurfaceControl() const {
+ return mNotDefCmpState.relativeLayerSurfaceControl;
+ }
+
+ bool operator==(const layer_state_t&) const = default;
+ bool operator!=(const layer_state_t&) const = default;
+
struct matrix22_t {
float dsdx{0};
float dtdx{0};
@@ -337,28 +381,20 @@
float clientDrawnCornerRadius;
uint32_t backgroundBlurRadius;
- sp<SurfaceControl> relativeLayerSurfaceControl;
-
- sp<SurfaceControl> parentSurfaceControlForChild;
-
half4 color;
// non POD must be last. see write/read
- Region transparentRegion;
uint32_t bufferTransform;
bool transformToDisplayInverse;
FloatRect crop;
std::shared_ptr<BufferData> bufferData = nullptr;
ui::Dataspace dataspace;
HdrMetadata hdrMetadata;
- Region surfaceDamageRegion;
int32_t api;
sp<NativeHandle> sidebandStream;
mat4 colorTransform;
std::vector<BlurRegion> blurRegions;
- sp<gui::WindowInfoHandle> windowInfoHandle = sp<gui::WindowInfoHandle>::make();
-
LayerMetadata metadata;
// The following refer to the alpha, and dataspace, respectively of
@@ -444,6 +480,18 @@
std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> bufferReleaseChannel;
std::shared_ptr<gui::DisplayLuts> luts;
+
+protected:
+ struct NotDefaultComparableState {
+ Region transparentRegion;
+ Region surfaceDamageRegion;
+ sp<gui::WindowInfoHandle> windowInfoHandle = sp<gui::WindowInfoHandle>::make();
+ sp<SurfaceControl> relativeLayerSurfaceControl;
+ sp<SurfaceControl> parentSurfaceControlForChild;
+
+ bool operator==(const NotDefaultComparableState& rhs) const;
+ bool operator!=(const NotDefaultComparableState& rhs) const = default;
+ } mNotDefCmpState;
};
class ComposerState {
@@ -451,6 +499,9 @@
layer_state_t state;
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
+
+ bool operator==(const ComposerState&) const = default;
+ bool operator!=(const ComposerState&) const = default;
};
struct DisplayState {
@@ -516,20 +567,35 @@
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
+
+ bool operator==(const DisplayState&) const = default;
+ bool operator!=(const DisplayState&) const = default;
};
struct InputWindowCommands {
- std::vector<gui::FocusRequest> focusRequests;
- std::unordered_set<sp<gui::IWindowInfosReportedListener>,
- SpHash<gui::IWindowInfosReportedListener>>
- windowInfosReportedListeners;
-
+ using Listener = gui::IWindowInfosReportedListener;
+ using ListenerSet = std::unordered_set<sp<Listener>, SpHash<Listener>>;
// Merges the passed in commands and returns true if there were any changes.
bool merge(const InputWindowCommands& other);
bool empty() const;
void clear();
+ void addFocusRequest(const gui::FocusRequest& request) { focusRequests.push_back(request); }
+ void addWindowInfosReportedListener(const sp<Listener>& listener) {
+ windowInfosReportedListeners.insert(listener);
+ }
+ ListenerSet&& releaseListeners() { return std::move(windowInfosReportedListeners); }
+
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
+
+ std::span<const gui::FocusRequest> getFocusRequests() const { return focusRequests; }
+ const ListenerSet& getListeners() const { return windowInfosReportedListeners; }
+ bool operator==(const InputWindowCommands&) const = default;
+ bool operator!=(const InputWindowCommands&) const = default;
+
+private:
+ std::vector<gui::FocusRequest> focusRequests;
+ ListenerSet windowInfosReportedListeners;
};
static inline int compare_type(const ComposerState& lhs, const ComposerState& rhs) {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 60f16ae..4fda8de 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -345,8 +345,6 @@
static std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>
getDisplayDecorationSupport(const sp<IBinder>& displayToken);
- static bool flagEdgeExtensionEffectUseShader();
-
/**
* Returns how many picture profiles are supported by the display.
*
@@ -396,6 +394,7 @@
static const std::string kEmpty;
static sp<IBinder> createVirtualDisplay(const std::string& displayName, bool isSecure,
+ bool optimizeForPower = true,
const std::string& uniqueId = kEmpty,
float requestedRefreshRate = 0);
diff --git a/libs/gui/include/gui/TransactionState.h b/libs/gui/include/gui/TransactionState.h
new file mode 100644
index 0000000..4358227
--- /dev/null
+++ b/libs/gui/include/gui/TransactionState.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/gui/FrameTimelineInfo.h>
+#include <binder/Parcelable.h>
+#include <gui/LayerState.h>
+
+namespace android {
+
+// Class to store all the transaction data and the parcelling logic
+class TransactionState {
+public:
+ explicit TransactionState() = default;
+ TransactionState(TransactionState const& other) = default;
+ status_t writeToParcel(Parcel* parcel) const;
+ status_t readFromParcel(const Parcel* parcel);
+ layer_state_t* getLayerState(const sp<SurfaceControl>& sc);
+ DisplayState& getDisplayState(const sp<IBinder>& token);
+
+ // Returns the current id of the transaction.
+ // The id is updated every time the transaction is applied.
+ uint64_t getId() const { return mId; }
+ std::vector<uint64_t> getMergedTransactionIds() const { return mMergedTransactionIds; }
+ void enableDebugLogCallPoints() { mLogCallPoints = true; }
+ void merge(TransactionState&& other,
+ const std::function<void(layer_state_t&)>& onBufferOverwrite);
+
+ // copied from FrameTimelineInfo::merge()
+ void mergeFrameTimelineInfo(const FrameTimelineInfo& other);
+ void clear();
+ bool operator==(const TransactionState& rhs) const = default;
+ bool operator!=(const TransactionState& rhs) const = default;
+
+ uint64_t mId = 0;
+ std::vector<uint64_t> mMergedTransactionIds;
+ uint32_t mFlags = 0;
+ // The vsync id provided by Choreographer.getVsyncId and the input event id
+ gui::FrameTimelineInfo mFrameTimelineInfo;
+ // mDesiredPresentTime is the time in nanoseconds that the client would like the transaction
+ // to be presented. When it is not possible to present at exactly that time, it will be
+ // presented after the time has passed.
+ //
+ // If the client didn't pass a desired presentation time, mDesiredPresentTime will be
+ // populated to the time setBuffer was called, and mIsAutoTimestamp will be set to true.
+ //
+ // Desired present times that are more than 1 second in the future may be ignored.
+ // When a desired present time has already passed, the transaction will be presented as soon
+ // as possible.
+ //
+ // Transactions from the same process are presented in the same order that they are applied.
+ // The desired present time does not affect this ordering.
+ int64_t mDesiredPresentTime = 0;
+ bool mIsAutoTimestamp = true;
+ // If not null, transactions will be queued up using this token otherwise a common token
+ // per process will be used.
+ sp<IBinder> mApplyToken;
+ // Indicates that the Transaction may contain buffers that should be cached. The reason this
+ // is only a guess is that buffers can be removed before cache is called. This is only a
+ // hint that at some point a buffer was added to this transaction before apply was called.
+ bool mMayContainBuffer = false;
+ // Prints debug logs when enabled.
+ bool mLogCallPoints = false;
+
+ std::vector<DisplayState> mDisplayStates;
+ std::vector<ComposerState> mComposerStates;
+ InputWindowCommands mInputWindowCommands;
+ std::vector<client_cache_t> mUncacheBuffers;
+ // Note: mHasListenerCallbacks can be true even if mListenerCallbacks is
+ // empty.
+ bool mHasListenerCallbacks = false;
+ std::vector<ListenerCallbacks> mListenerCallbacks;
+
+private:
+ // We keep track of the last MAX_MERGE_HISTORY_LENGTH merged transaction ids.
+ // Ordered most recently merged to least recently merged.
+ static constexpr size_t MAX_MERGE_HISTORY_LENGTH = 10u;
+};
+
+}; // namespace android
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index 420dc21..9ac49c0 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -268,6 +268,7 @@
bool overlaps(const WindowInfo* other) const;
bool operator==(const WindowInfo& inputChannel) const;
+ bool operator!=(const WindowInfo&) const = default;
status_t writeToParcel(android::Parcel* parcel) const override;
@@ -319,6 +320,9 @@
status_t readFromParcel(const android::Parcel* parcel);
status_t writeToParcel(android::Parcel* parcel) const;
+ bool operator==(const WindowInfoHandle& rhs) const { return mInfo == rhs.mInfo; }
+ bool operator!=(const WindowInfoHandle&) const = default;
+
protected:
virtual ~WindowInfoHandle();
diff --git a/libs/gui/include/gui/mock/GraphicBufferConsumer.h b/libs/gui/include/gui/mock/GraphicBufferConsumer.h
index 24d26b1..18a7e12 100644
--- a/libs/gui/include/gui/mock/GraphicBufferConsumer.h
+++ b/libs/gui/include/gui/mock/GraphicBufferConsumer.h
@@ -47,6 +47,7 @@
MOCK_METHOD2(setDefaultBufferSize, status_t(uint32_t, uint32_t));
MOCK_METHOD1(setMaxBufferCount, status_t(int));
MOCK_METHOD1(setMaxAcquiredBufferCount, status_t(int));
+ MOCK_METHOD2(setMaxAcquiredBufferCount, status_t(int, std::optional<OnBufferReleasedCallback>));
MOCK_METHOD1(setConsumerName, status_t(const String8&));
MOCK_METHOD1(setDefaultBufferFormat, status_t(PixelFormat));
MOCK_METHOD1(setDefaultBufferDataSpace, status_t(android_dataspace));
diff --git a/libs/gui/libgui_flags.aconfig b/libs/gui/libgui_flags.aconfig
index 90d91ac..2c3222d 100644
--- a/libs/gui/libgui_flags.aconfig
+++ b/libs/gui/libgui_flags.aconfig
@@ -77,14 +77,6 @@
} # wb_stream_splitter
flag {
- name: "edge_extension_shader"
- namespace: "windowing_frontend"
- description: "Enable edge extension via shader"
- bug: "322036393"
- is_fixed_read_only: true
-} # edge_extension_shader
-
-flag {
name: "buffer_release_channel"
namespace: "window_surfaces"
description: "Enable BufferReleaseChannel to optimize buffer releases"
@@ -150,3 +142,14 @@
bug: "340934031"
is_fixed_read_only: true
} # wb_media_migration
+
+flag {
+ name: "allocate_buffer_priority"
+ namespace: "wear_system_health"
+ description: "Boost priority for buffer allocation"
+ bug: "399701430"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+ is_fixed_read_only: true
+} # allocate_buffer_priority
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 87051a7..e20345d 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -90,6 +90,7 @@
"testserver/TestServerClient.cpp",
"testserver/TestServerHost.cpp",
"TextureRenderer.cpp",
+ "TransactionState_test.cpp",
"VsyncEventData_test.cpp",
"WindowInfo_test.cpp",
],
diff --git a/libs/gui/tests/BufferItemConsumer_test.cpp b/libs/gui/tests/BufferItemConsumer_test.cpp
index b980f88..80eea26 100644
--- a/libs/gui/tests/BufferItemConsumer_test.cpp
+++ b/libs/gui/tests/BufferItemConsumer_test.cpp
@@ -24,6 +24,7 @@
#include <gui/Surface.h>
#include <ui/BufferQueueDefs.h>
#include <ui/GraphicBuffer.h>
+#include <utils/Errors.h>
#include <unordered_set>
@@ -235,6 +236,38 @@
ASSERT_EQ(1, GetFreedBufferCount());
}
+TEST_F(BufferItemConsumerTest, ResizeAcquireCount) {
+ EXPECT_EQ(OK, mBIC->setMaxAcquiredBufferCount(kMaxLockedBuffers + 1));
+ EXPECT_EQ(OK, mBIC->setMaxAcquiredBufferCount(kMaxLockedBuffers + 2));
+ EXPECT_EQ(OK, mBIC->setMaxAcquiredBufferCount(kMaxLockedBuffers - 1));
+ EXPECT_EQ(OK, mBIC->setMaxAcquiredBufferCount(kMaxLockedBuffers - 2));
+ EXPECT_EQ(OK, mBIC->setMaxAcquiredBufferCount(kMaxLockedBuffers + 1));
+ EXPECT_EQ(OK, mBIC->setMaxAcquiredBufferCount(kMaxLockedBuffers - 1));
+}
+
+TEST_F(BufferItemConsumerTest, AttachBuffer) {
+ ASSERT_EQ(OK, mBIC->setMaxAcquiredBufferCount(1));
+
+ int slot;
+ DequeueBuffer(&slot);
+ QueueBuffer(slot);
+ AcquireBuffer(&slot);
+
+ sp<GraphicBuffer> newBuffer1 = sp<GraphicBuffer>::make(kWidth, kHeight, kFormat, kUsage);
+ sp<GraphicBuffer> newBuffer2 = sp<GraphicBuffer>::make(kWidth, kHeight, kFormat, kUsage);
+
+ // For some reason, you can attach an extra buffer?
+ // b/400973991 to investigate
+ EXPECT_EQ(OK, mBIC->attachBuffer(newBuffer1));
+ EXPECT_EQ(INVALID_OPERATION, mBIC->attachBuffer(newBuffer2));
+
+ ReleaseBuffer(slot);
+
+ EXPECT_EQ(OK, mBIC->attachBuffer(newBuffer2));
+ EXPECT_EQ(OK, mBIC->releaseBuffer(newBuffer1, Fence::NO_FENCE));
+ EXPECT_EQ(OK, mBIC->releaseBuffer(newBuffer2, Fence::NO_FENCE));
+}
+
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
// Test that delete BufferItemConsumer triggers onBufferFreed.
TEST_F(BufferItemConsumerTest, DetachBufferWithBuffer) {
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index eb55e3b..e7690e2 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -687,10 +687,11 @@
return binder::Status::ok();
}
- binder::Status createVirtualDisplay(const std::string& /*displayName*/, bool /*isSecure*/,
- const std::string& /*uniqueId*/,
- float /*requestedRefreshRate*/,
- sp<IBinder>* /*outDisplay*/) override {
+ binder::Status createVirtualDisplay(
+ const std::string& /*displayName*/, bool /*isSecure*/,
+ gui::ISurfaceComposer::OptimizationPolicy /*optimizationPolicy*/,
+ const std::string& /*uniqueId*/, float /*requestedRefreshRate*/,
+ sp<IBinder>* /*outDisplay*/) override {
return binder::Status::ok();
}
diff --git a/libs/gui/tests/TransactionState_test.cpp b/libs/gui/tests/TransactionState_test.cpp
new file mode 100644
index 0000000..179b264
--- /dev/null
+++ b/libs/gui/tests/TransactionState_test.cpp
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2025 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 <gmock/gmock.h>
+
+#include <gtest/gtest.h>
+#include <unordered_map>
+#include "android/gui/FocusRequest.h"
+#include "binder/Binder.h"
+#include "binder/Parcel.h"
+#include "gtest/gtest.h"
+#include "gui/LayerState.h"
+#include "gui/WindowInfo.h"
+
+#include "gui/TransactionState.h"
+
+namespace android {
+
+void sprintf(std::string& out, const char* format, ...) {
+ va_list arg_list;
+ va_start(arg_list, format);
+
+ int len = vsnprintf(nullptr, 0, format, arg_list);
+ if (len < 0) {
+ va_end(arg_list);
+ }
+ std::string line(len, '\0');
+ int written = vsnprintf(line.data(), len + 1, format, arg_list);
+ if (written != len) {
+ va_end(arg_list);
+ }
+ line.pop_back();
+ out += line;
+ va_end(arg_list);
+}
+
+constexpr std::string dump_struct(auto& x) {
+ std::string s;
+#if __has_builtin(__builtin_dump_struct)
+ __builtin_dump_struct(&x, sprintf, s);
+#else
+ (void)x;
+#endif
+ return s;
+}
+
+void PrintTo(const TransactionState& state, ::std::ostream* os) {
+ *os << dump_struct(state);
+ *os << state.mFrameTimelineInfo.toString();
+ for (auto mergedId : state.mMergedTransactionIds) {
+ *os << mergedId << ",";
+ }
+}
+
+void PrintTo(const ComposerState& state, ::std::ostream* os) {
+ *os << dump_struct(state.state);
+ *os << state.state.getWindowInfo();
+}
+
+// In case EXPECT_EQ fails, this function is useful to pinpoint exactly which
+// field did not compare ==.
+void Compare(const TransactionState& s1, const TransactionState& s2) {
+ EXPECT_EQ(s1.mId, s2.mId);
+ EXPECT_EQ(s1.mMergedTransactionIds, s2.mMergedTransactionIds);
+ EXPECT_EQ(s1.mFlags, s2.mFlags);
+ EXPECT_EQ(s1.mFrameTimelineInfo, s2.mFrameTimelineInfo);
+ EXPECT_EQ(s1.mDesiredPresentTime, s2.mDesiredPresentTime);
+ EXPECT_EQ(s1.mIsAutoTimestamp, s2.mIsAutoTimestamp);
+ EXPECT_EQ(s1.mApplyToken, s2.mApplyToken);
+ EXPECT_EQ(s1.mMayContainBuffer, s2.mMayContainBuffer);
+ EXPECT_EQ(s1.mLogCallPoints, s2.mLogCallPoints);
+ EXPECT_EQ(s1.mDisplayStates.size(), s2.mDisplayStates.size());
+ EXPECT_THAT(s1.mDisplayStates, ::testing::ContainerEq(s2.mDisplayStates));
+ EXPECT_EQ(s1.mComposerStates.size(), s2.mComposerStates.size());
+ EXPECT_EQ(s1.mComposerStates, s2.mComposerStates);
+ EXPECT_EQ(s1.mInputWindowCommands, s2.mInputWindowCommands);
+ EXPECT_EQ(s1.mUncacheBuffers, s2.mUncacheBuffers);
+ EXPECT_EQ(s1.mHasListenerCallbacks, s2.mHasListenerCallbacks);
+ EXPECT_EQ(s1.mListenerCallbacks.size(), s2.mListenerCallbacks.size());
+ EXPECT_EQ(s1.mListenerCallbacks, s2.mListenerCallbacks);
+}
+
+std::unique_ptr<std::unordered_map<int, sp<BBinder>>> createTokenMap(size_t maxSize) {
+ auto result = std::make_unique<std::unordered_map<int, sp<BBinder>>>();
+ for (size_t i = 0; i < maxSize; ++i) {
+ result->emplace(i, sp<BBinder>::make());
+ }
+ return result;
+}
+
+constexpr size_t kMaxComposerStates = 2;
+ComposerState createComposerStateForTest(size_t i) {
+ static const auto* const sLayerHandle = createTokenMap(kMaxComposerStates).release();
+
+ ComposerState state;
+ state.state.what = layer_state_t::eFlagsChanged;
+ state.state.surface = sLayerHandle->at(i);
+ state.state.layerId = i;
+ state.state.flags = 20 * i;
+ return state;
+}
+
+constexpr size_t kMaxDisplayStates = 5;
+DisplayState createDisplayStateForTest(size_t i) {
+ static const auto* const sDisplayTokens = createTokenMap(kMaxDisplayStates).release();
+
+ DisplayState displayState;
+ displayState.what = DisplayState::eFlagsChanged;
+ displayState.token = sDisplayTokens->at(i);
+ displayState.flags = 20 * i;
+ return displayState;
+}
+
+TransactionState createTransactionStateForTest() {
+ static sp<BBinder> sApplyToken = sp<BBinder>::make();
+
+ TransactionState state;
+ state.mId = 123;
+ state.mMergedTransactionIds.push_back(15);
+ state.mMergedTransactionIds.push_back(0);
+ state.mFrameTimelineInfo.vsyncId = 14;
+ state.mDesiredPresentTime = 11;
+ state.mIsAutoTimestamp = true;
+ state.mApplyToken = sApplyToken;
+ for (size_t i = 0; i < kMaxDisplayStates; i++) {
+ state.mDisplayStates.push_back(createDisplayStateForTest(i));
+ }
+ for (size_t i = 0; i < kMaxComposerStates; i++) {
+ state.mComposerStates.push_back(createComposerStateForTest(i));
+ }
+ static const auto* const sFocusRequestTokens = createTokenMap(5).release();
+ for (int i = 0; i < 5; i++) {
+ gui::FocusRequest request;
+ request.token = sFocusRequestTokens->at(i);
+ request.timestamp = i;
+ state.mInputWindowCommands.addFocusRequest(request);
+ }
+ static const auto* const sCacheToken = createTokenMap(5).release();
+ for (int i = 0; i < 5; i++) {
+ client_cache_t cache;
+ cache.token = sCacheToken->at(i);
+ cache.id = i;
+ state.mUncacheBuffers.emplace_back(std::move(cache));
+ }
+ static const auto* const sListenerCallbacks = []() {
+ auto* callbacks = new std::vector<ListenerCallbacks>();
+ for (int i = 0; i < 5; i++) {
+ callbacks->emplace_back(sp<BBinder>::make(),
+ std::unordered_set<CallbackId, CallbackIdHash>{});
+ }
+ return callbacks;
+ }();
+ state.mHasListenerCallbacks = true;
+ state.mListenerCallbacks = *sListenerCallbacks;
+ return state;
+}
+
+TransactionState createEmptyTransaction(uint64_t id) {
+ TransactionState state;
+ state.mId = id;
+ return state;
+}
+
+TEST(TransactionStateTest, parcel) {
+ TransactionState state = createTransactionStateForTest();
+ Parcel p;
+ state.writeToParcel(&p);
+ p.setDataPosition(0);
+ TransactionState parcelledState;
+ parcelledState.readFromParcel(&p);
+ EXPECT_EQ(state, parcelledState);
+};
+
+TEST(TransactionStateTest, parcelDisplayState) {
+ DisplayState state = createDisplayStateForTest(0);
+ Parcel p;
+ state.write(p);
+ p.setDataPosition(0);
+ DisplayState parcelledState;
+ parcelledState.read(p);
+ EXPECT_EQ(state, parcelledState);
+};
+
+TEST(TransactionStateTest, parcelLayerState) {
+ ComposerState state = createComposerStateForTest(0);
+ Parcel p;
+ state.write(p);
+ p.setDataPosition(0);
+ ComposerState parcelledState;
+ parcelledState.read(p);
+ EXPECT_EQ(state, parcelledState);
+};
+
+TEST(TransactionStateTest, parcelEmptyState) {
+ TransactionState state;
+ Parcel p;
+ state.writeToParcel(&p);
+ p.setDataPosition(0);
+ TransactionState parcelledState;
+ state.readFromParcel(&p);
+ EXPECT_EQ(state, parcelledState);
+};
+
+TEST(TransactionStateTest, mergeLayerState) {
+ ComposerState composerState = createComposerStateForTest(0);
+ ComposerState update;
+ update.state.surface = composerState.state.surface;
+ update.state.layerId = 0;
+ update.state.what = layer_state_t::eAlphaChanged;
+ update.state.color.a = .42;
+ composerState.state.merge(update.state);
+
+ ComposerState expectedMergedState = createComposerStateForTest(0);
+ expectedMergedState.state.what |= layer_state_t::eAlphaChanged;
+ expectedMergedState.state.color.a = .42;
+ EXPECT_EQ(composerState, expectedMergedState);
+};
+
+TEST(TransactionStateTest, merge) {
+ // Setup.
+ static constexpr uint64_t kUpdateTransactionId = 200;
+
+ TransactionState state = createTransactionStateForTest();
+
+ TransactionState update;
+ update.mId = kUpdateTransactionId;
+ {
+ ComposerState composerState;
+ composerState.state.surface = state.mComposerStates[0].state.surface;
+ composerState.state.what = layer_state_t::eAlphaChanged;
+ composerState.state.color.a = .42;
+ update.mComposerStates.push_back(composerState);
+ }
+ {
+ ComposerState composerState;
+ composerState.state.surface = state.mComposerStates[1].state.surface;
+ composerState.state.what = layer_state_t::eBufferChanged;
+ update.mComposerStates.push_back(composerState);
+ }
+ int32_t overrwiteLayerId = -1;
+ // Mutation.
+ state.merge(std::move(update),
+ [&overrwiteLayerId](layer_state_t ls) { overrwiteLayerId = ls.layerId; });
+ // Assertions.
+ EXPECT_EQ(1, overrwiteLayerId);
+ EXPECT_EQ(update, createEmptyTransaction(update.getId()));
+
+ TransactionState expectedMergedState = createTransactionStateForTest();
+ expectedMergedState.mMergedTransactionIds
+ .insert(expectedMergedState.mMergedTransactionIds.begin(), kUpdateTransactionId);
+ expectedMergedState.mComposerStates.at(0).state.what |= layer_state_t::eAlphaChanged;
+ expectedMergedState.mComposerStates.at(0).state.color.a = .42;
+ expectedMergedState.mComposerStates.at(1).state.what |= layer_state_t::eBufferChanged;
+ auto inputCommands = expectedMergedState.mInputWindowCommands;
+
+ // desired present time is not merged.
+ expectedMergedState.mDesiredPresentTime = state.mDesiredPresentTime;
+
+ EXPECT_EQ(state.mComposerStates[0], expectedMergedState.mComposerStates[0]);
+ EXPECT_EQ(state.mInputWindowCommands, expectedMergedState.mInputWindowCommands);
+ EXPECT_EQ(state, expectedMergedState);
+};
+
+TEST(TransactionStateTest, clear) {
+ TransactionState state = createTransactionStateForTest();
+ state.clear();
+ TransactionState emptyState = createEmptyTransaction(state.getId());
+ EXPECT_EQ(state, emptyState);
+};
+
+} // namespace android
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index ff26184..52e0276 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -225,6 +225,7 @@
srcs: [
"AccelerationCurve.cpp",
"CoordinateFilter.cpp",
+ "DisplayTopologyGraph.cpp",
"Input.cpp",
"InputConsumer.cpp",
"InputConsumerNoResampling.cpp",
@@ -270,6 +271,7 @@
shared_libs: [
"android.companion.virtualdevice.flags-aconfig-cc",
+ "com.android.window.flags.window-aconfig_flags_c_lib",
"libPlatformProperties",
"libaconfig_storage_read_api_cc",
"libbase",
diff --git a/libs/input/DisplayTopologyGraph.cpp b/libs/input/DisplayTopologyGraph.cpp
new file mode 100644
index 0000000..934f2e8
--- /dev/null
+++ b/libs/input/DisplayTopologyGraph.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "DisplayTopologyValidator"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <ftl/enum.h>
+#include <input/DisplayTopologyGraph.h>
+#include <input/PrintTools.h>
+#include <ui/LogicalDisplayId.h>
+
+#include <algorithm>
+
+#define INDENT " "
+
+namespace android {
+
+namespace {
+
+DisplayTopologyPosition getOppositePosition(DisplayTopologyPosition position) {
+ switch (position) {
+ case DisplayTopologyPosition::LEFT:
+ return DisplayTopologyPosition::RIGHT;
+ case DisplayTopologyPosition::TOP:
+ return DisplayTopologyPosition::BOTTOM;
+ case DisplayTopologyPosition::RIGHT:
+ return DisplayTopologyPosition::LEFT;
+ case DisplayTopologyPosition::BOTTOM:
+ return DisplayTopologyPosition::TOP;
+ }
+}
+
+bool validatePrimaryDisplay(const android::DisplayTopologyGraph& displayTopologyGraph) {
+ return displayTopologyGraph.primaryDisplayId != ui::LogicalDisplayId::INVALID &&
+ displayTopologyGraph.graph.contains(displayTopologyGraph.primaryDisplayId);
+}
+
+bool validateTopologyGraph(const android::DisplayTopologyGraph& displayTopologyGraph) {
+ for (const auto& [sourceDisplay, adjacentDisplays] : displayTopologyGraph.graph) {
+ for (const DisplayTopologyAdjacentDisplay& adjacentDisplay : adjacentDisplays) {
+ const auto adjacentGraphIt = displayTopologyGraph.graph.find(adjacentDisplay.displayId);
+ if (adjacentGraphIt == displayTopologyGraph.graph.end()) {
+ LOG(ERROR) << "Missing adjacent display in topology graph: "
+ << adjacentDisplay.displayId << " for source " << sourceDisplay;
+ return false;
+ }
+ const auto reverseEdgeIt =
+ std::find_if(adjacentGraphIt->second.begin(), adjacentGraphIt->second.end(),
+ [sourceDisplay](const DisplayTopologyAdjacentDisplay&
+ reverseAdjacentDisplay) {
+ return sourceDisplay == reverseAdjacentDisplay.displayId;
+ });
+ if (reverseEdgeIt == adjacentGraphIt->second.end()) {
+ LOG(ERROR) << "Missing reverse edge in topology graph for: " << sourceDisplay
+ << " -> " << adjacentDisplay.displayId;
+ return false;
+ }
+ DisplayTopologyPosition expectedPosition =
+ getOppositePosition(adjacentDisplay.position);
+ if (reverseEdgeIt->position != expectedPosition) {
+ LOG(ERROR) << "Unexpected reverse edge for: " << sourceDisplay << " -> "
+ << adjacentDisplay.displayId
+ << " expected position: " << ftl::enum_string(expectedPosition)
+ << " actual " << ftl::enum_string(reverseEdgeIt->position);
+ return false;
+ }
+ if (reverseEdgeIt->offsetDp != -adjacentDisplay.offsetDp) {
+ LOG(ERROR) << "Unexpected reverse edge offset: " << sourceDisplay << " -> "
+ << adjacentDisplay.displayId
+ << " expected offset: " << -adjacentDisplay.offsetDp << " actual "
+ << reverseEdgeIt->offsetDp;
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool validateDensities(const android::DisplayTopologyGraph& displayTopologyGraph) {
+ for (const auto& [sourceDisplay, adjacentDisplays] : displayTopologyGraph.graph) {
+ if (!displayTopologyGraph.displaysDensity.contains(sourceDisplay)) {
+ LOG(ERROR) << "Missing density value in topology graph for display: " << sourceDisplay;
+ return false;
+ }
+ }
+ return true;
+}
+
+std::string logicalDisplayIdToString(const ui::LogicalDisplayId& displayId) {
+ return base::StringPrintf("displayId(%d)", displayId.val());
+}
+
+std::string adjacentDisplayToString(const DisplayTopologyAdjacentDisplay& adjacentDisplay) {
+ return adjacentDisplay.dump();
+}
+
+std::string adjacentDisplayVectorToString(
+ const std::vector<DisplayTopologyAdjacentDisplay>& adjacentDisplays) {
+ return dumpVector(adjacentDisplays, adjacentDisplayToString);
+}
+
+} // namespace
+
+std::string DisplayTopologyAdjacentDisplay::dump() const {
+ std::string dump;
+ dump += base::StringPrintf("DisplayTopologyAdjacentDisplay: {displayId: %d, position: %s, "
+ "offsetDp: %f}",
+ displayId.val(), ftl::enum_string(position).c_str(), offsetDp);
+ return dump;
+}
+
+bool DisplayTopologyGraph::isValid() const {
+ return validatePrimaryDisplay(*this) && validateTopologyGraph(*this) &&
+ validateDensities(*this);
+}
+
+std::string DisplayTopologyGraph::dump() const {
+ std::string dump;
+ dump += base::StringPrintf("PrimaryDisplayId: %d\n", primaryDisplayId.val());
+ dump += base::StringPrintf("TopologyGraph:\n");
+ dump += addLinePrefix(dumpMap(graph, logicalDisplayIdToString, adjacentDisplayVectorToString),
+ INDENT);
+ dump += "\n";
+ dump += base::StringPrintf("DisplaysDensity:\n");
+ dump += addLinePrefix(dumpMap(displaysDensity, logicalDisplayIdToString), INDENT);
+ dump += "\n";
+ return dump;
+}
+
+} // namespace android
diff --git a/libs/input/InputFlags.cpp b/libs/input/InputFlags.cpp
index f866f9b..6aa9ae6 100644
--- a/libs/input/InputFlags.cpp
+++ b/libs/input/InputFlags.cpp
@@ -18,6 +18,7 @@
#include <android-base/logging.h>
#include <com_android_input_flags.h>
+#include <com_android_window_flags.h>
#include <cutils/properties.h>
#include <string>
@@ -25,6 +26,9 @@
namespace android {
bool InputFlags::connectedDisplaysCursorEnabled() {
+ if (!com::android::window::flags::enable_desktop_mode_through_dev_option()) {
+ return com::android::input::flags::connected_displays_cursor();
+ }
static std::optional<bool> cachedDevOption;
if (!cachedDevOption.has_value()) {
char value[PROPERTY_VALUE_MAX];
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index fc859cb..983bbde 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -26,13 +26,6 @@
}
flag {
- name: "remove_input_channel_from_windowstate"
- namespace: "input"
- description: "Do not store a copy of input channel inside WindowState."
- bug: "323450804"
-}
-
-flag {
name: "enable_input_event_tracing"
namespace: "input"
description: "Set to true to enable input event tracing, including always-on tracing on non-user builds"
@@ -61,13 +54,6 @@
}
flag {
- name: "enable_touchpad_typing_palm_rejection"
- namespace: "input"
- description: "Enabling additional touchpad palm rejection will disable the tap to click while the user is typing on a physical keyboard"
- bug: "301055381"
-}
-
-flag {
name: "enable_v2_touchpad_typing_palm_rejection"
namespace: "input"
description: "In addition to touchpad palm rejection v1, v2 will also cancel ongoing move gestures while typing and add delay in re-enabling the tap to click."
@@ -127,13 +113,6 @@
}
flag {
- name: "hide_pointer_indicators_for_secure_windows"
- namespace: "input"
- description: "Hide touch and pointer indicators if a secure window is present on display"
- bug: "325252005"
-}
-
-flag {
name: "enable_keyboard_classifier"
namespace: "input"
description: "Keyboard classifier that classifies all keyboards into alphabetic or non-alphabetic"
@@ -260,3 +239,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "enable_display_topology_validation"
+ namespace: "input"
+ description: "Set to true to enable display topology validation"
+ bug: "401219231"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index 9f64d2c..f43694e 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -803,8 +803,7 @@
drawClippedLayers(renderengine, display, dstTexture, texture);
}
- if (com::android::graphics::libgui::flags::edge_extension_shader() &&
- config.cacheEdgeExtension) {
+ if (config.cacheEdgeExtension) {
SFTRACE_NAME("cacheEdgeExtension");
drawEdgeExtensionLayers(renderengine, display, dstTexture, texture);
drawEdgeExtensionLayers(renderengine, p3Display, dstTexture, texture);
diff --git a/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.cpp b/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.cpp
index 4164c4b..f007427 100644
--- a/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.cpp
+++ b/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.cpp
@@ -58,9 +58,6 @@
)");
EdgeExtensionShaderFactory::EdgeExtensionShaderFactory() {
- if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
- return;
- }
mResult = std::make_unique<SkRuntimeEffect::Result>(SkRuntimeEffect::MakeForShader(edgeShader));
LOG_ALWAYS_FATAL_IF(!mResult->errorText.isEmpty(),
"EdgeExtensionShaderFactory compilation "
diff --git a/services/surfaceflinger/Utils/RingBuffer.h b/libs/ui/include/ui/RingBuffer.h
similarity index 93%
rename from services/surfaceflinger/Utils/RingBuffer.h
rename to libs/ui/include/ui/RingBuffer.h
index 215472b..31d5a95 100644
--- a/services/surfaceflinger/Utils/RingBuffer.h
+++ b/libs/ui/include/ui/RingBuffer.h
@@ -19,7 +19,7 @@
#include <stddef.h>
#include <array>
-namespace android::utils {
+namespace android::ui {
template <class T, size_t SIZE>
class RingBuffer {
@@ -31,8 +31,8 @@
~RingBuffer() = default;
constexpr size_t capacity() const { return SIZE; }
-
size_t size() const { return mCount; }
+ bool isFull() const { return size() == capacity(); }
T& next() {
mHead = static_cast<size_t>(mHead + 1) % SIZE;
@@ -67,4 +67,4 @@
size_t mCount = 0;
};
-} // namespace android::utils
+} // namespace android::ui
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 2d8a1e3..2b11786 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -144,6 +144,17 @@
}
cc_test {
+ name: "RingBuffer_test",
+ test_suites: ["device-tests"],
+ shared_libs: ["libui"],
+ srcs: ["RingBuffer_test.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
+
+cc_test {
name: "Size_test",
test_suites: ["device-tests"],
shared_libs: ["libui"],
diff --git a/libs/ui/tests/RingBuffer_test.cpp b/libs/ui/tests/RingBuffer_test.cpp
new file mode 100644
index 0000000..9839492
--- /dev/null
+++ b/libs/ui/tests/RingBuffer_test.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2025 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 <ui/RingBuffer.h>
+
+namespace android::ui {
+
+TEST(RingBuffer, basic) {
+ RingBuffer<int, 5> rb;
+
+ rb.next() = 1;
+ ASSERT_EQ(1, rb.size());
+ ASSERT_EQ(1, rb.back());
+ ASSERT_EQ(1, rb.front());
+
+ rb.next() = 2;
+ ASSERT_EQ(2, rb.size());
+ ASSERT_EQ(2, rb.back());
+ ASSERT_EQ(1, rb.front());
+ ASSERT_EQ(1, rb[-1]);
+
+ rb.next() = 3;
+ ASSERT_EQ(3, rb.size());
+ ASSERT_EQ(3, rb.back());
+ ASSERT_EQ(1, rb.front());
+ ASSERT_EQ(2, rb[-1]);
+ ASSERT_EQ(1, rb[-2]);
+
+ rb.next() = 4;
+ ASSERT_EQ(4, rb.size());
+ ASSERT_EQ(4, rb.back());
+ ASSERT_EQ(1, rb.front());
+ ASSERT_EQ(3, rb[-1]);
+ ASSERT_EQ(2, rb[-2]);
+ ASSERT_EQ(1, rb[-3]);
+
+ rb.next() = 5;
+ ASSERT_EQ(5, rb.size());
+ ASSERT_EQ(5, rb.back());
+ ASSERT_EQ(1, rb.front());
+ ASSERT_EQ(4, rb[-1]);
+ ASSERT_EQ(3, rb[-2]);
+ ASSERT_EQ(2, rb[-3]);
+ ASSERT_EQ(1, rb[-4]);
+
+ rb.next() = 6;
+ ASSERT_EQ(5, rb.size());
+ ASSERT_EQ(6, rb.back());
+ ASSERT_EQ(2, rb.front());
+ ASSERT_EQ(5, rb[-1]);
+ ASSERT_EQ(4, rb[-2]);
+ ASSERT_EQ(3, rb[-3]);
+ ASSERT_EQ(2, rb[-4]);
+}
+
+} // namespace android::ui
\ No newline at end of file
diff --git a/services/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp
index 98b514b..98f0f34 100644
--- a/services/inputflinger/PointerChoreographer.cpp
+++ b/services/inputflinger/PointerChoreographer.cpp
@@ -31,6 +31,7 @@
#include "PointerChoreographer.h"
#define INDENT " "
+#define INDENT2 " "
namespace android {
@@ -535,9 +536,6 @@
}
void PointerChoreographer::onControllerAddedOrRemovedLocked() {
- if (!com::android::input::flags::hide_pointer_indicators_for_secure_windows()) {
- return;
- }
bool requireListener = !mTouchPointersByDevice.empty() || !mMousePointersByDisplay.empty() ||
!mDrawingTabletPointersByDevice.empty() || !mStylusPointersByDevice.empty();
@@ -650,6 +648,8 @@
std::string pointerControllerDump = addLinePrefix(drawingTabletController->dump(), INDENT);
dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
}
+ dump += INDENT "DisplayTopologyGraph:\n";
+ dump += addLinePrefix(mTopology.dump(), INDENT2);
dump += "\n";
}
@@ -677,7 +677,13 @@
mTopology.graph.find(associatedDisplayId) == mTopology.graph.end()) {
return associatedDisplayId;
}
- return mCurrentMouseDisplayId.isValid() ? mCurrentMouseDisplayId : mTopology.primaryDisplayId;
+ if (mCurrentMouseDisplayId.isValid()) {
+ return mCurrentMouseDisplayId;
+ }
+ if (mTopology.primaryDisplayId.isValid()) {
+ return mTopology.primaryDisplayId;
+ }
+ return ui::LogicalDisplayId::DEFAULT;
}
std::pair<ui::LogicalDisplayId, PointerControllerInterface&>
@@ -786,7 +792,8 @@
PointerChoreographer::calculatePointerDisplayChangeToNotify() {
ui::LogicalDisplayId displayIdToNotify = ui::LogicalDisplayId::INVALID;
vec2 cursorPosition = {0, 0};
- if (const auto it = mMousePointersByDisplay.find(mCurrentMouseDisplayId);
+ if (const auto it =
+ mMousePointersByDisplay.find(getTargetMouseDisplayLocked(mCurrentMouseDisplayId));
it != mMousePointersByDisplay.end()) {
const auto& pointerController = it->second;
// Use the displayId from the pointerController, because it accurately reflects whether
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index ef50fc0..888fcfb 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -5222,6 +5222,11 @@
} else {
dump += "Displays: <none>\n";
}
+ dump += StringPrintf("mMaximumObscuringOpacityForTouch: %f\n",
+ mMaximumObscuringOpacityForTouch);
+ dump += "DisplayTopologyGraph:\n";
+ dump += addLinePrefix(mTopology.dump(), INDENT);
+ dump += "\n";
return dump;
}
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 845cab0..58df692 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -32,6 +32,7 @@
#include <unistd.h>
#include <utils/Errors.h>
#include <utils/Thread.h>
+#include <string>
#include "InputDevice.h"
#include "include/gestures.h"
@@ -945,7 +946,10 @@
void InputReader::dump(std::string& dump) {
std::scoped_lock _l(mLock);
+ dumpLocked(dump);
+}
+void InputReader::dumpLocked(std::string& dump) {
mEventHub->dump(dump);
dump += "\n";
@@ -1032,6 +1036,12 @@
InputReader::ContextImpl::ContextImpl(InputReader* reader)
: mReader(reader), mIdGenerator(IdGenerator::Source::INPUT_READER) {}
+std::string InputReader::ContextImpl::dump() {
+ std::string dump;
+ mReader->dumpLocked(dump);
+ return dump;
+}
+
void InputReader::ContextImpl::updateGlobalMetaState() {
// lock is already held by the input loop
mReader->updateGlobalMetaStateLocked();
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 0d6e102..6a25937 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -21,6 +21,7 @@
#include <utils/Mutex.h>
#include <memory>
+#include <string>
#include <unordered_map>
#include <vector>
@@ -142,6 +143,7 @@
public:
explicit ContextImpl(InputReader* reader);
+ std::string dump() REQUIRES(mReader->mLock) override;
// lock is already held by the input loop
void updateGlobalMetaState() NO_THREAD_SAFETY_ANALYSIS override;
int32_t getGlobalMetaState() NO_THREAD_SAFETY_ANALYSIS override;
@@ -216,6 +218,8 @@
// The input device that produced a new gesture most recently.
DeviceId mLastUsedDeviceId GUARDED_BY(mLock){ReservedInputDeviceId::INVALID_INPUT_DEVICE_ID};
+ void dumpLocked(std::string& dump) REQUIRES(mLock);
+
// low-level input event decoding and device management
[[nodiscard]] std::list<NotifyArgs> processEventsLocked(const RawEvent* rawEvents, size_t count)
REQUIRES(mLock);
diff --git a/services/inputflinger/reader/include/InputReaderContext.h b/services/inputflinger/reader/include/InputReaderContext.h
index 20ed74f..f38fd7b 100644
--- a/services/inputflinger/reader/include/InputReaderContext.h
+++ b/services/inputflinger/reader/include/InputReaderContext.h
@@ -20,6 +20,7 @@
#include <input/KeyboardClassifier.h>
#include "NotifyArgs.h"
+#include <string>
#include <vector>
namespace android {
@@ -39,6 +40,8 @@
InputReaderContext() {}
virtual ~InputReaderContext() {}
+ virtual std::string dump() = 0;
+
virtual void updateGlobalMetaState() = 0;
virtual int32_t getGlobalMetaState() = 0;
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 8deff6b..4d36db8 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -24,6 +24,8 @@
#include <cinttypes>
#include <cmath>
#include <cstddef>
+#include <sstream>
+#include <string>
#include <tuple>
#include <math.h>
@@ -138,6 +140,40 @@
*outY = y;
}
+std::ostream& operator<<(std::ostream& out, const RawPointerData::Pointer& p) {
+ out << "id=" << p.id << ", x=" << p.x << ", y=" << p.y << ", pressure=" << p.pressure
+ << ", touchMajor=" << p.touchMajor << ", touchMinor=" << p.touchMinor
+ << ", toolMajor=" << p.toolMajor << ", toolMinor=" << p.toolMinor
+ << ", orientation=" << p.orientation << ", tiltX=" << p.tiltX << ", tiltY=" << p.tiltY
+ << ", distance=" << p.distance << ", toolType=" << ftl::enum_string(p.toolType)
+ << ", isHovering=" << p.isHovering;
+ return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const RawPointerData& data) {
+ out << data.pointerCount << " pointers:\n";
+ for (uint32_t i = 0; i < data.pointerCount; i++) {
+ out << INDENT << "[" << i << "]: " << data.pointers[i] << std::endl;
+ }
+ out << "ID bits: hovering = 0x" << std::hex << std::setfill('0') << std::setw(8)
+ << data.hoveringIdBits.value << ", touching = 0x" << std::setfill('0') << std::setw(8)
+ << data.touchingIdBits.value << ", canceled = 0x" << std::setfill('0') << std::setw(8)
+ << data.canceledIdBits.value << std::dec;
+ return out;
+}
+
+// --- TouchInputMapper::RawState ---
+
+std::ostream& operator<<(std::ostream& out, const TouchInputMapper::RawState& state) {
+ out << "When: " << state.when << std::endl;
+ out << "Read time: " << state.readTime << std::endl;
+ out << "Button state: 0x" << std::setfill('0') << std::setw(8) << std::hex << state.buttonState
+ << std::dec << std::endl;
+ out << "Raw pointer data:" << std::endl;
+ out << addLinePrefix(streamableToString(state.rawPointerData), INDENT);
+ return out;
+}
+
// --- TouchInputMapper ---
TouchInputMapper::TouchInputMapper(InputDeviceContext& deviceContext,
@@ -232,20 +268,8 @@
dump += StringPrintf(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale);
dump += StringPrintf(INDENT3 "Last Raw Button State: 0x%08x\n", mLastRawState.buttonState);
- dump += StringPrintf(INDENT3 "Last Raw Touch: pointerCount=%d\n",
- mLastRawState.rawPointerData.pointerCount);
- for (uint32_t i = 0; i < mLastRawState.rawPointerData.pointerCount; i++) {
- const RawPointerData::Pointer& pointer = mLastRawState.rawPointerData.pointers[i];
- dump += StringPrintf(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, "
- "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, "
- "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, "
- "toolType=%s, isHovering=%s\n",
- i, pointer.id, pointer.x, pointer.y, pointer.pressure,
- pointer.touchMajor, pointer.touchMinor, pointer.toolMajor,
- pointer.toolMinor, pointer.orientation, pointer.tiltX, pointer.tiltY,
- pointer.distance, ftl::enum_string(pointer.toolType).c_str(),
- toString(pointer.isHovering));
- }
+ dump += INDENT3 "Last Raw Touch:\n";
+ dump += addLinePrefix(streamableToString(mLastRawState), INDENT4) + "\n";
dump += StringPrintf(INDENT3 "Last Cooked Button State: 0x%08x\n",
mLastCookedState.buttonState);
@@ -1476,6 +1500,22 @@
last.rawPointerData.touchingIdBits.value, next.rawPointerData.touchingIdBits.value,
last.rawPointerData.hoveringIdBits.value, next.rawPointerData.hoveringIdBits.value,
next.rawPointerData.canceledIdBits.value);
+ if (debugRawEvents() && last.rawPointerData.pointerCount == 0 &&
+ next.rawPointerData.pointerCount == 1) {
+ // Dump a bunch of info to try to debug b/396796958.
+ // TODO(b/396796958): remove this debug dump.
+ ALOGD("pointerCount went from 0 to 1. last:\n%s",
+ addLinePrefix(streamableToString(last), INDENT).c_str());
+ ALOGD("next:\n%s", addLinePrefix(streamableToString(next), INDENT).c_str());
+ ALOGD("InputReader dump:");
+ // The dump is too long to simply add as a format parameter in one log message, so we have
+ // to split it by line and log them individually.
+ std::istringstream stream(mDeviceContext.getContext()->dump());
+ std::string line;
+ while (std::getline(stream, line, '\n')) {
+ ALOGD(INDENT "%s", line.c_str());
+ }
+ }
if (!next.rawPointerData.touchingIdBits.isEmpty() &&
!next.rawPointerData.hoveringIdBits.isEmpty() &&
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 4ef0be8..45fc6bf 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -348,6 +348,8 @@
inline void clear() { *this = RawState(); }
};
+ friend std::ostream& operator<<(std::ostream& out, const RawState& state);
+
struct CookedState {
// Cooked pointer sample data.
CookedPointerData cookedPointerData{};
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
index 480e276..3255877 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
@@ -39,9 +39,6 @@
namespace {
-// This will disable the tap to click while the user is typing on a physical keyboard
-const bool ENABLE_TOUCHPAD_PALM_REJECTION = input_flags::enable_touchpad_typing_palm_rejection();
-
// In addition to v1, v2 will also cancel ongoing move gestures while typing and add delay in
// re-enabling the tap to click.
const bool ENABLE_TOUCHPAD_PALM_REJECTION_V2 =
@@ -226,8 +223,7 @@
if (!mIsHoverCancelled) {
// handleFling calls hoverMove with zero delta on FLING_TAP_DOWN. Don't enable tap to click
// for this case as subsequent handleButtonsChange may choose to ignore this tap.
- if ((ENABLE_TOUCHPAD_PALM_REJECTION || ENABLE_TOUCHPAD_PALM_REJECTION_V2) &&
- (std::abs(deltaX) > 0 || std::abs(deltaY) > 0)) {
+ if (std::abs(deltaX) > 0 || std::abs(deltaY) > 0) {
enableTapToClick(when);
}
}
@@ -278,7 +274,7 @@
// return early to prevent this tap
return out;
}
- } else if (ENABLE_TOUCHPAD_PALM_REJECTION && mReaderContext.isPreventingTouchpadTaps()) {
+ } else if (mReaderContext.isPreventingTouchpadTaps()) {
enableTapToClick(when);
if (gesture.details.buttons.is_tap) {
// return early to prevent this tap
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 18d47f6..677cf1e 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -52,6 +52,7 @@
"AnrTracker_test.cpp",
"CapturedTouchpadEventConverter_test.cpp",
"CursorInputMapper_test.cpp",
+ "DisplayTopologyGraph_test.cpp",
"EventHub_test.cpp",
"FakeEventHub.cpp",
"FakeInputReaderPolicy.cpp",
diff --git a/services/inputflinger/tests/DisplayTopologyGraph_test.cpp b/services/inputflinger/tests/DisplayTopologyGraph_test.cpp
new file mode 100644
index 0000000..fd2f21c
--- /dev/null
+++ b/services/inputflinger/tests/DisplayTopologyGraph_test.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2025 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/DisplayTopologyGraph.h>
+
+#include <string>
+#include <string_view>
+#include <tuple>
+
+namespace android {
+
+namespace {
+
+constexpr ui::LogicalDisplayId DISPLAY_ID_1{1};
+constexpr ui::LogicalDisplayId DISPLAY_ID_2{2};
+constexpr int DENSITY_MEDIUM = 160;
+
+} // namespace
+
+using DisplayTopologyGraphTestFixtureParam =
+ std::tuple<std::string_view /*name*/, DisplayTopologyGraph, bool /*isValid*/>;
+
+class DisplayTopologyGraphTestFixture
+ : public testing::Test,
+ public testing::WithParamInterface<DisplayTopologyGraphTestFixtureParam> {};
+
+TEST_P(DisplayTopologyGraphTestFixture, DisplayTopologyGraphTest) {
+ const auto& [_, displayTopology, isValid] = GetParam();
+ EXPECT_EQ(isValid, displayTopology.isValid());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ DisplayTopologyGraphTest, DisplayTopologyGraphTestFixture,
+ testing::Values(
+ std::make_tuple(
+ "InvalidPrimaryDisplay",
+ DisplayTopologyGraph{.primaryDisplayId = ui::LogicalDisplayId::INVALID,
+ .graph = {},
+ .displaysDensity = {}},
+ false),
+ std::make_tuple("PrimaryDisplayNotInGraph",
+ DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1,
+ .graph = {},
+ .displaysDensity = {}},
+ false),
+ std::make_tuple("DisplayDensityMissing",
+ DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1,
+ .graph = {{DISPLAY_ID_1, {}}},
+ .displaysDensity = {}},
+ false),
+ std::make_tuple("ValidSingleDisplayTopology",
+ DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1,
+ .graph = {{DISPLAY_ID_1, {}}},
+ .displaysDensity = {{DISPLAY_ID_1,
+ DENSITY_MEDIUM}}},
+ true),
+ std::make_tuple(
+ "MissingReverseEdge",
+ DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1,
+ .graph = {{DISPLAY_ID_1,
+ {{DISPLAY_ID_2,
+ DisplayTopologyPosition::TOP, 0}}}},
+ .displaysDensity = {{DISPLAY_ID_1, DENSITY_MEDIUM},
+ {DISPLAY_ID_2, DENSITY_MEDIUM}}},
+ false),
+ std::make_tuple(
+ "IncorrectReverseEdgeDirection",
+ DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1,
+ .graph = {{DISPLAY_ID_1,
+ {{DISPLAY_ID_2,
+ DisplayTopologyPosition::TOP, 0}}},
+ {DISPLAY_ID_2,
+ {{DISPLAY_ID_1,
+ DisplayTopologyPosition::TOP, 0}}}},
+ .displaysDensity = {{DISPLAY_ID_1, DENSITY_MEDIUM},
+ {DISPLAY_ID_2, DENSITY_MEDIUM}}},
+ false),
+ std::make_tuple(
+ "IncorrectReverseEdgeOffset",
+ DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1,
+ .graph = {{DISPLAY_ID_1,
+ {{DISPLAY_ID_2,
+ DisplayTopologyPosition::TOP, 10}}},
+ {DISPLAY_ID_2,
+ {{DISPLAY_ID_1,
+ DisplayTopologyPosition::BOTTOM, 20}}}},
+ .displaysDensity = {{DISPLAY_ID_1, DENSITY_MEDIUM},
+ {DISPLAY_ID_2, DENSITY_MEDIUM}}},
+ false),
+ std::make_tuple(
+ "ValidMultiDisplayTopology",
+ DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1,
+ .graph = {{DISPLAY_ID_1,
+ {{DISPLAY_ID_2,
+ DisplayTopologyPosition::TOP, 10}}},
+ {DISPLAY_ID_2,
+ {{DISPLAY_ID_1,
+ DisplayTopologyPosition::BOTTOM, -10}}}},
+ .displaysDensity = {{DISPLAY_ID_1, DENSITY_MEDIUM},
+ {DISPLAY_ID_2, DENSITY_MEDIUM}}},
+ true)),
+ [](const testing::TestParamInfo<DisplayTopologyGraphTestFixtureParam>& p) {
+ return std::string{std::get<0>(p.param)};
+ });
+
+} // namespace android
diff --git a/services/inputflinger/tests/FakeInputDispatcherPolicy.cpp b/services/inputflinger/tests/FakeInputDispatcherPolicy.cpp
index c4257a8..dcb148f 100644
--- a/services/inputflinger/tests/FakeInputDispatcherPolicy.cpp
+++ b/services/inputflinger/tests/FakeInputDispatcherPolicy.cpp
@@ -198,10 +198,6 @@
ASSERT_EQ(token, *receivedToken);
}
-void FakeInputDispatcherPolicy::setInterceptKeyTimeout(std::chrono::milliseconds timeout) {
- mInterceptKeyTimeout = timeout;
-}
-
std::chrono::nanoseconds FakeInputDispatcherPolicy::getKeyWaitingForEventsTimeout() {
return 500ms;
}
@@ -210,8 +206,9 @@
mStaleEventTimeout = timeout;
}
-void FakeInputDispatcherPolicy::setConsumeKeyBeforeDispatching(bool consumeKeyBeforeDispatching) {
- mConsumeKeyBeforeDispatching = consumeKeyBeforeDispatching;
+void FakeInputDispatcherPolicy::setInterceptKeyBeforeDispatchingResult(
+ std::variant<nsecs_t, inputdispatcher::KeyEntry::InterceptKeyResult> result) {
+ mInterceptKeyBeforeDispatchingResult = result;
}
void FakeInputDispatcherPolicy::assertFocusedDisplayNotified(ui::LogicalDisplayId expectedDisplay) {
@@ -404,7 +401,9 @@
void FakeInputDispatcherPolicy::interceptKeyBeforeQueueing(const KeyEvent& inputEvent, uint32_t&) {
if (inputEvent.getAction() == AKEY_EVENT_ACTION_UP) {
// Clear intercept state when we handled the event.
- mInterceptKeyTimeout = 0ms;
+ if (std::holds_alternative<nsecs_t>(mInterceptKeyBeforeDispatchingResult)) {
+ mInterceptKeyBeforeDispatchingResult = nsecs_t(0);
+ }
}
}
@@ -414,17 +413,20 @@
std::variant<nsecs_t, inputdispatcher::KeyEntry::InterceptKeyResult>
FakeInputDispatcherPolicy::interceptKeyBeforeDispatching(const sp<IBinder>&, const KeyEvent&,
uint32_t) {
- if (mConsumeKeyBeforeDispatching) {
- return inputdispatcher::KeyEntry::InterceptKeyResult::SKIP;
+ if (std::holds_alternative<inputdispatcher::KeyEntry::InterceptKeyResult>(
+ mInterceptKeyBeforeDispatchingResult)) {
+ return mInterceptKeyBeforeDispatchingResult;
}
- nsecs_t delay = std::chrono::nanoseconds(mInterceptKeyTimeout).count();
+ nsecs_t delay =
+ std::chrono::nanoseconds(std::get<nsecs_t>(mInterceptKeyBeforeDispatchingResult))
+ .count();
if (delay == 0) {
return inputdispatcher::KeyEntry::InterceptKeyResult::CONTINUE;
}
// Clear intercept state so we could dispatch the event in next wake.
- mInterceptKeyTimeout = 0ms;
+ mInterceptKeyBeforeDispatchingResult = nsecs_t(0);
return delay;
}
diff --git a/services/inputflinger/tests/FakeInputDispatcherPolicy.h b/services/inputflinger/tests/FakeInputDispatcherPolicy.h
index c387eac..b151686 100644
--- a/services/inputflinger/tests/FakeInputDispatcherPolicy.h
+++ b/services/inputflinger/tests/FakeInputDispatcherPolicy.h
@@ -96,10 +96,6 @@
void assertDropTargetEquals(const InputDispatcherInterface& dispatcher,
const sp<IBinder>& targetToken);
void assertNotifyInputChannelBrokenWasCalled(const sp<IBinder>& token);
- /**
- * Set policy timeout. A value of zero means next key will not be intercepted.
- */
- void setInterceptKeyTimeout(std::chrono::milliseconds timeout);
std::chrono::nanoseconds getKeyWaitingForEventsTimeout() override;
void setStaleEventTimeout(std::chrono::nanoseconds timeout);
void assertUserActivityNotPoked();
@@ -116,7 +112,12 @@
void setUnhandledKeyHandler(std::function<std::optional<KeyEvent>(const KeyEvent&)> handler);
void assertUnhandledKeyReported(int32_t keycode);
void assertUnhandledKeyNotReported();
- void setConsumeKeyBeforeDispatching(bool consumeKeyBeforeDispatching);
+ /**
+ * Set policy timeout or the interception result.
+ * A timeout value of zero means next key will not be intercepted.
+ */
+ void setInterceptKeyBeforeDispatchingResult(
+ std::variant<nsecs_t, inputdispatcher::KeyEntry::InterceptKeyResult> result);
void assertFocusedDisplayNotified(ui::LogicalDisplayId expectedDisplay);
private:
@@ -145,11 +146,10 @@
std::condition_variable mNotifyUserActivity;
std::queue<UserActivityPokeEvent> mUserActivityPokeEvents;
- std::chrono::milliseconds mInterceptKeyTimeout = 0ms;
-
std::chrono::nanoseconds mStaleEventTimeout = 1000ms;
- bool mConsumeKeyBeforeDispatching = false;
+ std::variant<nsecs_t, inputdispatcher::KeyEntry::InterceptKeyResult>
+ mInterceptKeyBeforeDispatchingResult;
BlockingQueue<std::pair<int32_t /*deviceId*/, std::set<gui::Uid>>> mNotifiedInteractions;
diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp
index 914f5ab..35310a5 100644
--- a/services/inputflinger/tests/GestureConverter_test.cpp
+++ b/services/inputflinger/tests/GestureConverter_test.cpp
@@ -42,8 +42,6 @@
namespace {
-const auto TOUCHPAD_PALM_REJECTION =
- ACONFIG_FLAG(input_flags, enable_touchpad_typing_palm_rejection);
const auto TOUCHPAD_PALM_REJECTION_V2 =
ACONFIG_FLAG(input_flags, enable_v2_touchpad_typing_palm_rejection);
@@ -1461,7 +1459,6 @@
}
TEST_F_WITH_FLAGS(GestureConverterTest, TapWithTapToClickDisabled,
- REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION),
REQUIRES_FLAGS_DISABLED(TOUCHPAD_PALM_REJECTION_V2)) {
nsecs_t currentTime = ARBITRARY_GESTURE_TIME;
@@ -1574,8 +1571,7 @@
ASSERT_THAT(args, Each(VariantWith<NotifyMotionArgs>(WithRelativeMotion(0.f, 0.f))));
}
-TEST_F_WITH_FLAGS(GestureConverterTest, ClickWithTapToClickDisabled,
- REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION)) {
+TEST_F(GestureConverterTest, ClickWithTapToClickDisabled) {
// Click should still produce button press/release events
mReader->getContext()->setPreventingTouchpadTaps(true);
@@ -1644,8 +1640,7 @@
ASSERT_FALSE(mReader->getContext()->isPreventingTouchpadTaps());
}
-TEST_F_WITH_FLAGS(GestureConverterTest, MoveEnablesTapToClick,
- REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION)) {
+TEST_F(GestureConverterTest, MoveEnablesTapToClick) {
// initially disable tap-to-click
mReader->getContext()->setPreventingTouchpadTaps(true);
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 2b9b470..835b677 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -5491,7 +5491,8 @@
generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ui::LogicalDisplayId::DEFAULT);
const std::chrono::milliseconds interceptKeyTimeout = 50ms;
const nsecs_t injectTime = keyArgs.eventTime;
- mFakePolicy->setInterceptKeyTimeout(interceptKeyTimeout);
+ mFakePolicy->setInterceptKeyBeforeDispatchingResult(
+ std::chrono::nanoseconds(interceptKeyTimeout).count());
mDispatcher->notifyKey(keyArgs);
// The dispatching time should be always greater than or equal to intercept key timeout.
window->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
@@ -5519,7 +5520,7 @@
// Set a value that's significantly larger than the default consumption timeout. If the
// implementation is correct, the actual value doesn't matter; it won't slow down the test.
- mFakePolicy->setInterceptKeyTimeout(600ms);
+ mFakePolicy->setInterceptKeyBeforeDispatchingResult(std::chrono::nanoseconds(600ms).count());
mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ui::LogicalDisplayId::DEFAULT));
// Window should receive key event immediately when same key up.
window->consumeKeyUp(ui::LogicalDisplayId::DEFAULT);
@@ -7438,7 +7439,8 @@
window->consumeFocusEvent(true);
- mFakePolicy->setConsumeKeyBeforeDispatching(true);
+ mFakePolicy->setInterceptKeyBeforeDispatchingResult(
+ inputdispatcher::KeyEntry::InterceptKeyResult::SKIP);
mDispatcher->notifyKey(
KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
@@ -7464,7 +7466,8 @@
window->consumeFocusEvent(true);
- mFakePolicy->setConsumeKeyBeforeDispatching(true);
+ mFakePolicy->setInterceptKeyBeforeDispatchingResult(
+ inputdispatcher::KeyEntry::InterceptKeyResult::SKIP);
mDispatcher->notifyKey(
KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
@@ -9307,6 +9310,24 @@
mWindow->assertNoEvents();
}
+TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterFocusedWindowChanged) {
+ sp<FakeWindowHandle> anotherWindow =
+ sp<FakeWindowHandle>::make(mApp, mDispatcher, "AnotherWindow",
+ ui::LogicalDisplayId::DEFAULT);
+ anotherWindow->setFocusable(true);
+ mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *anotherWindow->getInfo()}, {}, 0, 0});
+
+ sendAndConsumeKeyDown(/*deviceId=*/1);
+ expectKeyRepeatOnce(/*repeatCount=*/1);
+ expectKeyRepeatOnce(/*repeatCount=*/2);
+ setFocusedWindow(anotherWindow);
+ anotherWindow->consumeFocusEvent(true);
+
+ // Window should receive key up event with cancel.
+ mWindow->consumeKeyUp(ui::LogicalDisplayId::DEFAULT, AKEY_EVENT_FLAG_CANCELED);
+ anotherWindow->assertNoEvents();
+}
+
TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatAfterStaleDeviceKeyUp) {
sendAndConsumeKeyDown(/*deviceId=*/1);
expectKeyRepeatOnce(/*repeatCount=*/1);
diff --git a/services/inputflinger/tests/InterfaceMocks.h b/services/inputflinger/tests/InterfaceMocks.h
index 06d60ce..d4e4bb0 100644
--- a/services/inputflinger/tests/InterfaceMocks.h
+++ b/services/inputflinger/tests/InterfaceMocks.h
@@ -50,6 +50,8 @@
class MockInputReaderContext : public InputReaderContext {
public:
+ std::string dump() override { return "(dump from MockInputReaderContext)"; }
+
MOCK_METHOD(void, updateGlobalMetaState, (), (override));
MOCK_METHOD(int32_t, getGlobalMetaState, (), (override));
diff --git a/services/inputflinger/tests/PointerChoreographer_test.cpp b/services/inputflinger/tests/PointerChoreographer_test.cpp
index 38d0679..2b469c5 100644
--- a/services/inputflinger/tests/PointerChoreographer_test.cpp
+++ b/services/inputflinger/tests/PointerChoreographer_test.cpp
@@ -129,9 +129,6 @@
mInjectedInitialWindowInfos};
void SetUp() override {
- // flag overrides
- input_flags::hide_pointer_indicators_for_secure_windows(true);
-
ON_CALL(mMockPolicy, createPointerController).WillByDefault([this](ControllerType type) {
std::shared_ptr<FakePointerController> pc = std::make_shared<FakePointerController>();
EXPECT_FALSE(pc->isPointerShown());
@@ -361,6 +358,17 @@
assertPointerDisplayIdNotified(DISPLAY_ID);
}
+TEST_F(PointerChoreographerTest, NoDefaultMouseSetFallbackToDefaultDisplayId) {
+ mChoreographer.setDisplayViewports(createViewports({ui::LogicalDisplayId::DEFAULT}));
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0,
+ {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
+ ui::LogicalDisplayId::INVALID)}});
+ assertPointerControllerCreated(ControllerType::MOUSE);
+
+ assertPointerDisplayIdNotified(ui::LogicalDisplayId::DEFAULT);
+}
+
TEST_F(PointerChoreographerTest, WhenViewportIsSetLaterCallsNotifyPointerDisplayIdChanged) {
setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
@@ -2098,10 +2106,7 @@
pc->assertSkipScreenshotFlagNotChanged();
}
-TEST_F_WITH_FLAGS(
- PointerChoreographerTest, HidesPointerScreenshotForExistingPrivacySensitiveWindows,
- REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
- hide_pointer_indicators_for_secure_windows))) {
+TEST_F(PointerChoreographerTest, HidesPointerScreenshotForExistingPrivacySensitiveWindows) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
// Add a first mouse device
@@ -3158,11 +3163,8 @@
class PointerChoreographerWindowInfoListenerTest : public testing::Test {};
-TEST_F_WITH_FLAGS(
- PointerChoreographerWindowInfoListenerTest,
- doesNotCrashIfListenerCalledAfterPointerChoreographerDestroyed,
- REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
- hide_pointer_indicators_for_secure_windows))) {
+TEST_F(PointerChoreographerWindowInfoListenerTest,
+ doesNotCrashIfListenerCalledAfterPointerChoreographerDestroyed) {
sp<android::gui::WindowInfosListener> registeredListener;
sp<android::gui::WindowInfosListener> localListenerCopy;
{
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
index bba7389..9a59039 100644
--- a/services/inputflinger/tests/fuzzers/MapperHelpers.h
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -360,6 +360,7 @@
std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp)
: mEventHub(eventHub), mPolicy(sp<FuzzInputReaderPolicy>::make(fdp)), mFdp(fdp) {}
~FuzzInputReaderContext() {}
+ std::string dump() { return "(dump from FuzzInputReaderContext)"; }
void updateGlobalMetaState() override {}
int32_t getGlobalMetaState() { return mFdp->ConsumeIntegral<int32_t>(); }
void disableVirtualKeysUntil(nsecs_t time) override {}
diff --git a/services/sensorservice/sensorservice_flags.aconfig b/services/sensorservice/sensorservice_flags.aconfig
index 452b428..6308973 100644
--- a/services/sensorservice/sensorservice_flags.aconfig
+++ b/services/sensorservice/sensorservice_flags.aconfig
@@ -37,4 +37,14 @@
metadata {
purpose: PURPOSE_BUGFIX
}
+}
+
+flag {
+ name: "disable_vndk_forged_name"
+ namespace: "sensors"
+ description: "When this flag is enabled, sensor manager will not use forged name to determine if an access is from VNDK"
+ bug: "398253250"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
\ No newline at end of file
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index dea3290..efddc85 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -104,7 +104,7 @@
void detectDisallowedCompositionTypeChange(
aidl::android::hardware::graphics::composer3::Composition from,
aidl::android::hardware::graphics::composer3::Composition to) const;
- bool isClientCompositionForced(bool isPeekingThrough, bool isCached) const;
+ bool isClientCompositionForced(bool isPeekingThrough) const;
void updateLuts(const LayerFECompositionState&,
const std::optional<std::vector<std::optional<LutProperties>>>& properties);
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
index f934cb2..e42b9b1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
@@ -253,7 +253,6 @@
std::unordered_map<size_t, size_t> mFinalLayerCounts;
size_t mCachedSetCreationCount = 0;
size_t mCachedSetCreationCost = 0;
- std::unordered_map<size_t, size_t> mInvalidatedCachedSetAges;
};
} // namespace compositionengine::impl::planner
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index de1d13a..b30cf20 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1389,7 +1389,8 @@
// or complex GPU shaders and it's expensive. We boost the GPU frequency so that
// GPU composition can finish in time. We must reset GPU frequency afterwards,
// because high frequency consumes extra battery.
- const bool expensiveRenderingExpected =
+ const bool expensiveBlurs = mLayerRequestingBackgroundBlur != nullptr;
+ const bool expensiveRenderingExpected = expensiveBlurs ||
std::any_of(clientCompositionLayers.begin(), clientCompositionLayers.end(),
[outputDataspace =
clientCompositionDisplay.outputDataspace](const auto& layer) {
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index b1bbcac..ea36011 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -876,8 +876,7 @@
bool isPeekingThrough, bool skipLayer) {
auto& outputDependentState = editState();
- bool isCached = !skipLayer && outputDependentState.overrideInfo.buffer;
- if (isClientCompositionForced(isPeekingThrough, isCached)) {
+ if (isClientCompositionForced(isPeekingThrough)) {
// If we are forcing client composition, we need to tell the HWC
requestedCompositionType = Composition::CLIENT;
}
@@ -967,12 +966,9 @@
}
}
-bool OutputLayer::isClientCompositionForced(bool isPeekingThrough, bool isCached) const {
- // If this layer was flattened into a CachedSet then it is not necessary for
- // the GPU to compose it.
- bool requiresClientDrawnRoundedCorners = !isCached && getLayerFE().hasRoundedCorners();
+bool OutputLayer::isClientCompositionForced(bool isPeekingThrough) const {
return getState().forceClientComposition ||
- (!isPeekingThrough && requiresClientDrawnRoundedCorners);
+ (!isPeekingThrough && getLayerFE().hasRoundedCorners());
}
void OutputLayer::applyDeviceCompositionTypeChange(Composition compositionType) {
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index b290823..2081cd5 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -243,17 +243,9 @@
mCurrentGeometry = hash;
mLastGeometryUpdate = now;
-
- for (const CachedSet& cachedSet : mLayers) {
- if (cachedSet.getLayerCount() > 1) {
- ++mInvalidatedCachedSetAges[cachedSet.getAge()];
- }
- }
-
mLayers.clear();
if (mNewCachedSet) {
- ++mInvalidatedCachedSetAges[mNewCachedSet->getAge()];
mNewCachedSet = std::nullopt;
}
}
@@ -312,7 +304,6 @@
mNewCachedSet->getFirstLayer().getState()->getId() == (*incomingLayerIter)->getId()) {
if (mNewCachedSet->hasBufferUpdate()) {
ALOGV("[%s] Dropping new cached set", __func__);
- ++mInvalidatedCachedSetAges[0];
mNewCachedSet = std::nullopt;
} else if (mNewCachedSet->hasReadyBuffer()) {
ALOGV("[%s] Found ready buffer", __func__);
@@ -339,10 +330,6 @@
};
++incomingLayerIter;
}
-
- if (currentLayerIter->getLayerCount() > 1) {
- ++mInvalidatedCachedSetAges[currentLayerIter->getAge()];
- }
++currentLayerIter;
skipCount -= layerCount;
@@ -382,7 +369,6 @@
priorBlurLayer = currentLayerIter->getBlurLayer();
} else if (currentLayerIter->getLayerCount() > 1) {
// Break the current layer into its constituent layers
- ++mInvalidatedCachedSetAges[currentLayerIter->getAge()];
for (CachedSet& layer : currentLayerIter->decompose()) {
bool disableBlur =
priorBlurLayer && priorBlurLayer == (*incomingLayerIter)->getOutputLayer();
diff --git a/services/surfaceflinger/Display/DisplayModeController.cpp b/services/surfaceflinger/Display/DisplayModeController.cpp
index a086aee..87a677c 100644
--- a/services/surfaceflinger/Display/DisplayModeController.cpp
+++ b/services/surfaceflinger/Display/DisplayModeController.cpp
@@ -97,9 +97,7 @@
const bool force = desiredModeOpt->force;
desiredModeOpt = std::move(desiredMode);
desiredModeOpt->emitEvent |= emitEvent;
- if (FlagManager::getInstance().connected_display()) {
- desiredModeOpt->force |= force;
- }
+ desiredModeOpt->force |= force;
return DesiredModeAction::None;
}
@@ -191,7 +189,7 @@
// cleared until the next `SF::initiateDisplayModeChanges`. However, the desired mode has been
// consumed at this point, so clear the `force` flag to prevent an endless loop of
// `initiateModeChange`.
- if (FlagManager::getInstance().connected_display()) {
+ {
std::scoped_lock lock(displayPtr->desiredModeLock);
if (displayPtr->desiredModeOpt) {
displayPtr->desiredModeOpt->force = false;
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index e8b09b0..b396544 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -51,6 +51,17 @@
namespace hal = hardware::graphics::composer::hal;
+namespace gui {
+inline std::string_view to_string(ISurfaceComposer::OptimizationPolicy optimizationPolicy) {
+ switch (optimizationPolicy) {
+ case ISurfaceComposer::OptimizationPolicy::optimizeForPower:
+ return "optimizeForPower";
+ case ISurfaceComposer::OptimizationPolicy::optimizeForPerformance:
+ return "optimizeForPerformance";
+ }
+}
+} // namespace gui
+
DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(
const sp<SurfaceFlinger>& flinger, HWComposer& hwComposer, const wp<IBinder>& displayToken,
std::shared_ptr<compositionengine::Display> compositionDisplay)
@@ -169,8 +180,7 @@
}
void DisplayDevice::setPowerMode(hal::PowerMode mode) {
- // TODO(b/241285876): Skip this for virtual displays.
- if (mode == hal::PowerMode::OFF || mode == hal::PowerMode::ON) {
+ if (!isVirtual() && (mode == hal::PowerMode::OFF || mode == hal::PowerMode::ON)) {
if (mStagedBrightness && mBrightness != mStagedBrightness) {
getCompositionDisplay()->setNextBrightness(*mStagedBrightness);
mBrightness = *mStagedBrightness;
@@ -283,6 +293,7 @@
dumper.dump("name"sv, '"' + mDisplayName + '"');
dumper.dump("powerMode"sv, mPowerMode);
+ dumper.dump("optimizationPolicy"sv, mOptimizationPolicy);
if (mRefreshRateSelector) {
mRefreshRateSelector->dump(dumper);
@@ -305,6 +316,15 @@
mCompositionDisplay->setSecure(secure);
}
+gui::ISurfaceComposer::OptimizationPolicy DisplayDevice::getOptimizationPolicy() const {
+ return mOptimizationPolicy;
+}
+
+void DisplayDevice::setOptimizationPolicy(
+ gui::ISurfaceComposer::OptimizationPolicy optimizationPolicy) {
+ mOptimizationPolicy = optimizationPolicy;
+}
+
const Rect DisplayDevice::getBounds() const {
return mCompositionDisplay->getState().displaySpace.getBoundsAsRect();
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index b5a543a..02522a3 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -93,6 +93,11 @@
bool isSecure() const;
void setSecure(bool secure);
+ // The optimization policy influences whether this display is optimized for power or
+ // performance.
+ gui::ISurfaceComposer::OptimizationPolicy getOptimizationPolicy() const;
+ void setOptimizationPolicy(gui::ISurfaceComposer::OptimizationPolicy optimizationPolicy);
+
int getWidth() const;
int getHeight() const;
ui::Size getSize() const { return {getWidth(), getHeight()}; }
@@ -236,6 +241,9 @@
// TODO(b/182939859): Remove special cases for primary display.
const bool mIsPrimary;
+ gui::ISurfaceComposer::OptimizationPolicy mOptimizationPolicy =
+ gui::ISurfaceComposer::OptimizationPolicy::optimizeForPerformance;
+
uint32_t mFlags = 0;
// Requested refresh rate in fps, supported only for virtual displays.
@@ -283,11 +291,16 @@
std::string displayName;
std::string uniqueId;
bool isSecure = false;
+
+ gui::ISurfaceComposer::OptimizationPolicy optimizationPolicy =
+ gui::ISurfaceComposer::OptimizationPolicy::optimizeForPerformance;
bool isProtected = false;
// Refer to DisplayDevice::mRequestedRefreshRate, for virtual display only
Fps requestedRefreshRate;
int32_t maxLayerPictureProfiles = 0;
bool hasPictureProcessing = false;
+ hardware::graphics::composer::hal::PowerMode initialPowerMode{
+ hardware::graphics::composer::hal::PowerMode::OFF};
private:
static std::atomic<int32_t> sNextSequenceId;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 01f382f..8d16a6b 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -439,11 +439,8 @@
// FIXME (b/319505580): At least the first config set on an external display must be
// `setActiveConfig`, so skip over the block that calls `setActiveConfigWithConstraints`
// for simplicity.
- const bool connected_display = FlagManager::getInstance().connected_display();
-
if (isVsyncPeriodSwitchSupported() &&
- (!connected_display ||
- getConnectionType().value_opt() != ui::DisplayConnectionType::External)) {
+ getConnectionType().value_opt() != ui::DisplayConnectionType::External) {
Hwc2::IComposerClient::VsyncPeriodChangeConstraints hwc2Constraints;
hwc2Constraints.desiredTimeNanos = constraints.desiredTimeNanos;
hwc2Constraints.seamlessRequired = constraints.seamlessRequired;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 545ed19..14088a6 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -145,7 +145,7 @@
case HotplugEvent::Disconnected:
return onHotplugDisconnect(hwcDisplayId);
case HotplugEvent::LinkUnstable:
- return {};
+ return onHotplugLinkTrainingFailure(hwcDisplayId);
}
}
@@ -1245,6 +1245,16 @@
return DisplayIdentificationInfo{.id = *displayId};
}
+std::optional<DisplayIdentificationInfo> HWComposer::onHotplugLinkTrainingFailure(
+ hal::HWDisplayId hwcDisplayId) {
+ const auto displayId = toPhysicalDisplayId(hwcDisplayId);
+ if (!displayId) {
+ LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Invalid HWC display");
+ return {};
+ }
+ return DisplayIdentificationInfo{.id = *displayId};
+}
+
void HWComposer::loadCapabilities() {
static_assert(sizeof(hal::Capability) == sizeof(int32_t), "Capability size has changed");
auto capabilities = mComposer->getCapabilities();
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 2c0aa3d..472411c 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -544,6 +544,7 @@
std::optional<DisplayIdentificationInfo> onHotplugConnect(hal::HWDisplayId);
std::optional<DisplayIdentificationInfo> onHotplugDisconnect(hal::HWDisplayId);
+ std::optional<DisplayIdentificationInfo> onHotplugLinkTrainingFailure(hal::HWDisplayId);
bool shouldIgnoreHotplugConnect(hal::HWDisplayId, uint8_t port,
bool hasDisplayIdentificationData) const;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index 1f0d5d0..964a970 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -41,7 +41,7 @@
if (forceFullDamage) {
outSurfaceDamageRegion = Region::INVALID_REGION;
} else {
- outSurfaceDamageRegion = requested.surfaceDamageRegion;
+ outSurfaceDamageRegion = requested.getSurfaceDamageRegion();
}
}
@@ -376,7 +376,7 @@
updateSurfaceDamage(requested, requested.hasReadyFrame(), forceFullDamage, surfaceDamage);
if (forceUpdate || requested.what & layer_state_t::eTransparentRegionChanged) {
- transparentRegionHint = requested.transparentRegion;
+ transparentRegionHint = requested.getTransparentRegion();
}
if (forceUpdate || requested.what & layer_state_t::eFlagsChanged) {
layerOpaqueFlagSet =
@@ -448,15 +448,7 @@
}
if (forceUpdate || requested.what & layer_state_t::eInputInfoChanged) {
- if (requested.windowInfoHandle) {
- inputInfo = *requested.windowInfoHandle->getInfo();
- } else {
- inputInfo = {};
- // b/271132344 revisit this and see if we can always use the layers uid/pid
- inputInfo.name = requested.name;
- inputInfo.ownerUid = requested.ownerUid;
- inputInfo.ownerPid = requested.ownerPid;
- }
+ inputInfo = requested.getWindowInfo();
inputInfo.id = static_cast<int32_t>(uniqueSequence);
touchCropId = requested.touchCropId;
}
@@ -548,7 +540,7 @@
case Composition::INVALID:
return 'i';
case Composition::SOLID_COLOR:
- return 'e';
+ return 'c';
case Composition::CURSOR:
return 'u';
case Composition::SIDEBAND:
@@ -556,7 +548,7 @@
case Composition::DISPLAY_DECORATION:
return 'a';
case Composition::REFRESH_RATE_INDICATOR:
- return 'f';
+ return 'r';
case Composition::CLIENT:
case Composition::DEVICE:
break;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index 86ef6ca..28a6031 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -1090,7 +1090,7 @@
snapshot.transformedBounds = snapshot.geomLayerTransform.transform(snapshot.geomLayerBounds);
const Rect geomLayerBoundsWithoutTransparentRegion =
RequestedLayerState::reduce(Rect(snapshot.geomLayerBounds),
- requested.transparentRegion);
+ requested.getTransparentRegion());
snapshot.transformedBoundsWithoutTransparentRegion =
snapshot.geomLayerTransform.transform(geomLayerBoundsWithoutTransparentRegion);
snapshot.parentTransform = parentSnapshot.geomLayerTransform;
@@ -1098,7 +1098,7 @@
if (requested.potentialCursor) {
// Subtract the transparent region and snap to the bounds
const Rect bounds = RequestedLayerState::reduce(Rect(snapshot.croppedBufferSize),
- requested.transparentRegion);
+ requested.getTransparentRegion());
snapshot.cursorFrame = snapshot.geomLayerTransform.transform(bounds);
}
}
@@ -1132,22 +1132,14 @@
const Args& args) {
using InputConfig = gui::WindowInfo::InputConfig;
- if (requested.windowInfoHandle) {
- snapshot.inputInfo = *requested.windowInfoHandle->getInfo();
- } else {
- snapshot.inputInfo = {};
- // b/271132344 revisit this and see if we can always use the layers uid/pid
- snapshot.inputInfo.name = requested.name;
- snapshot.inputInfo.ownerUid = gui::Uid{requested.ownerUid};
- snapshot.inputInfo.ownerPid = gui::Pid{requested.ownerPid};
- }
+ snapshot.inputInfo = requested.getWindowInfo();
snapshot.touchCropId = requested.touchCropId;
snapshot.inputInfo.id = static_cast<int32_t>(snapshot.uniqueSequence);
snapshot.inputInfo.displayId =
ui::LogicalDisplayId{static_cast<int32_t>(snapshot.outputFilter.layerStack.id)};
snapshot.inputInfo.touchOcclusionMode = requested.hasInputInfo()
- ? requested.windowInfoHandle->getInfo()->touchOcclusionMode
+ ? requested.getWindowInfo().touchOcclusionMode
: parentSnapshot.inputInfo.touchOcclusionMode;
snapshot.inputInfo.canOccludePresentation = parentSnapshot.inputInfo.canOccludePresentation ||
(requested.flags & layer_state_t::eCanOccludePresentation);
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index 58c235e..d322a61 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -63,8 +63,11 @@
metadata.merge(args.metadata);
changes |= RequestedLayerState::Changes::Metadata;
handleAlive = true;
- // TODO: b/305254099 remove once we don't pass invisible windows to input
- windowInfoHandle = nullptr;
+ // b/271132344 revisit this and see if we can always use the layers uid/pid
+ auto* windowInfo = editWindowInfo();
+ windowInfo->name = name;
+ windowInfo->ownerPid = ownerPid;
+ windowInfo->ownerUid = ownerUid;
if (parentId != UNASSIGNED_LAYER_ID) {
canBeRoot = false;
}
@@ -105,7 +108,7 @@
currentHdrSdrRatio = 1.f;
dataspaceRequested = false;
hdrMetadata.validTypes = 0;
- surfaceDamageRegion = Region::INVALID_REGION;
+ mNotDefCmpState.surfaceDamageRegion = Region::INVALID_REGION;
cornerRadius = 0.0f;
clientDrawnCornerRadius = 0.0f;
backgroundBlurRadius = 0;
@@ -278,7 +281,7 @@
if (clientState.what & layer_state_t::eReparent) {
changes |= RequestedLayerState::Changes::Parent;
parentId = resolvedComposerState.parentId;
- parentSurfaceControlForChild = nullptr;
+ mNotDefCmpState.parentSurfaceControlForChild = nullptr;
// Once a layer has be reparented, it cannot be placed at the root. It sounds odd
// but thats the existing logic and until we make this behavior more explicit, we need
// to maintain this logic.
@@ -288,7 +291,7 @@
changes |= RequestedLayerState::Changes::RelativeParent;
relativeParentId = resolvedComposerState.relativeParentId;
isRelativeOf = true;
- relativeLayerSurfaceControl = nullptr;
+ mNotDefCmpState.relativeLayerSurfaceControl = nullptr;
}
if ((clientState.what & layer_state_t::eLayerChanged ||
(clientState.what & layer_state_t::eReparent && parentId == UNASSIGNED_LAYER_ID)) &&
@@ -304,7 +307,7 @@
}
if (clientState.what & layer_state_t::eInputInfoChanged) {
touchCropId = resolvedComposerState.touchCropId;
- windowInfoHandle->editInfo()->touchableRegionCropHandle.clear();
+ editWindowInfo()->touchableRegionCropHandle.clear();
}
if (clientState.what & layer_state_t::eStretchChanged) {
stretchEffect.sanitize();
@@ -554,12 +557,9 @@
}
bool RequestedLayerState::hasInputInfo() const {
- if (!windowInfoHandle) {
- return false;
- }
- const auto windowInfo = windowInfoHandle->getInfo();
- return windowInfo->token != nullptr ||
- windowInfo->inputConfig.test(gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL);
+ const auto& windowInfo = getWindowInfo();
+ return windowInfo.token != nullptr ||
+ windowInfo.inputConfig.test(gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL);
}
bool RequestedLayerState::needsInputInfo() const {
@@ -571,13 +571,9 @@
return true;
}
- if (!windowInfoHandle) {
- return false;
- }
-
- const auto windowInfo = windowInfoHandle->getInfo();
- return windowInfo->token != nullptr ||
- windowInfo->inputConfig.test(gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL);
+ const auto& windowInfo = getWindowInfo();
+ return windowInfo.token != nullptr ||
+ windowInfo.inputConfig.test(gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL);
}
bool RequestedLayerState::hasBufferOrSidebandStream() const {
diff --git a/services/surfaceflinger/HdrLayerInfoReporter.h b/services/surfaceflinger/HdrLayerInfoReporter.h
index 614f33f..758b111 100644
--- a/services/surfaceflinger/HdrLayerInfoReporter.h
+++ b/services/surfaceflinger/HdrLayerInfoReporter.h
@@ -19,11 +19,11 @@
#include <android-base/thread_annotations.h>
#include <android/gui/IHdrLayerInfoListener.h>
#include <binder/IBinder.h>
+#include <ui/RingBuffer.h>
#include <utils/Timers.h>
#include <unordered_map>
-#include "Utils/RingBuffer.h"
#include "WpHash.h"
namespace android {
@@ -102,7 +102,7 @@
EventHistoryEntry(const HdrLayerInfo& info) : info(info) { timestamp = systemTime(); }
};
- utils::RingBuffer<EventHistoryEntry, 32> mHdrInfoHistory;
+ ui::RingBuffer<EventHistoryEntry, 32> mHdrInfoHistory;
};
} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 6af0f59..081bb22 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -288,7 +288,7 @@
bool leaveState);
inline bool hasTrustedPresentationListener() {
- return mTrustedPresentationListener.callbackInterface != nullptr;
+ return mTrustedPresentationListener.getCallback() != nullptr;
}
// Sets the masked bits.
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 44cd319..84b1a73 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -447,7 +447,7 @@
}
layerInfo->set_type("Layer");
- LayerProtoHelper::writeToProto(requestedState.transparentRegion,
+ LayerProtoHelper::writeToProto(requestedState.getTransparentRegion(),
[&]() { return layerInfo->mutable_transparent_region(); });
layerInfo->set_layer_stack(snapshot.outputFilter.layerStack.id);
diff --git a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp
index cd7210c..788448d 100644
--- a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp
+++ b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp
@@ -515,7 +515,7 @@
}
void PowerAdvisor::setExpectedPresentTime(TimePoint expectedPresentTime) {
- mExpectedPresentTimes.append(expectedPresentTime);
+ mExpectedPresentTimes.next() = expectedPresentTime;
}
void PowerAdvisor::setSfPresentTiming(TimePoint presentFenceTime, TimePoint presentEndTime) {
@@ -532,7 +532,7 @@
}
void PowerAdvisor::setCommitStart(TimePoint commitStartTime) {
- mCommitStartTimes.append(commitStartTime);
+ mCommitStartTimes.next() = commitStartTime;
}
void PowerAdvisor::setCompositeEnd(TimePoint compositeEndTime) {
@@ -579,7 +579,7 @@
}
// Tracks when we finish presenting to hwc
- TimePoint estimatedHwcEndTime = mCommitStartTimes[0];
+ TimePoint estimatedHwcEndTime = mCommitStartTimes.back();
// How long we spent this frame not doing anything, waiting for fences or vsync
Duration idleDuration = 0ns;
@@ -643,13 +643,13 @@
// Also add the frame delay duration since the target did not move while we were delayed
Duration totalDuration = mFrameDelayDuration +
std::max(estimatedHwcEndTime, estimatedGpuEndTime.value_or(TimePoint{0ns})) -
- mCommitStartTimes[0];
+ mCommitStartTimes.back();
Duration totalDurationWithoutGpu =
- mFrameDelayDuration + estimatedHwcEndTime - mCommitStartTimes[0];
+ mFrameDelayDuration + estimatedHwcEndTime - mCommitStartTimes.back();
// We finish SurfaceFlinger when post-composition finishes, so add that in here
Duration flingerDuration =
- estimatedFlingerEndTime + mLastPostcompDuration - mCommitStartTimes[0];
+ estimatedFlingerEndTime + mLastPostcompDuration - mCommitStartTimes.back();
Duration estimatedGpuDuration = firstGpuTimeline.has_value()
? estimatedGpuEndTime.value_or(TimePoint{0ns}) - firstGpuTimeline->startTime
: Duration::fromNs(0);
@@ -661,7 +661,7 @@
hal::WorkDuration duration{
.timeStampNanos = TimePoint::now().ns(),
.durationNanos = combinedDuration.ns(),
- .workPeriodStartTimestampNanos = mCommitStartTimes[0].ns(),
+ .workPeriodStartTimestampNanos = mCommitStartTimes.back().ns(),
.cpuDurationNanos = supportsGpuReporting() ? cpuDuration.ns() : 0,
.gpuDurationNanos = supportsGpuReporting() ? estimatedGpuDuration.ns() : 0,
};
diff --git a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h
index 540a9df..b97160a 100644
--- a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h
+++ b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h
@@ -23,6 +23,7 @@
#include <ui/DisplayId.h>
#include <ui/FenceTime.h>
+#include <ui/RingBuffer.h>
#include <utils/Mutex.h>
// FMQ library in IPower does questionable conversions
@@ -247,27 +248,6 @@
std::optional<GpuTimeline> estimateGpuTiming(std::optional<TimePoint> previousEndTime);
};
- template <class T, size_t N>
- class RingBuffer {
- std::array<T, N> elements = {};
- size_t mIndex = 0;
- size_t numElements = 0;
-
- public:
- void append(T item) {
- mIndex = (mIndex + 1) % N;
- numElements = std::min(N, numElements + 1);
- elements[mIndex] = item;
- }
- bool isFull() const { return numElements == N; }
- // Allows access like [0] == current, [-1] = previous, etc..
- T& operator[](int offset) {
- size_t positiveOffset =
- static_cast<size_t>((offset % static_cast<int>(N)) + static_cast<int>(N));
- return elements[(mIndex + positiveOffset) % N];
- }
- };
-
// Filter and sort the display ids by a given property
std::vector<DisplayId> getOrderedDisplayIds(
std::optional<TimePoint> DisplayTimingData::*sortBy);
@@ -287,9 +267,9 @@
// Last frame's post-composition duration
Duration mLastPostcompDuration{0ns};
// Buffer of recent commit start times
- RingBuffer<TimePoint, 2> mCommitStartTimes;
+ ui::RingBuffer<TimePoint, 2> mCommitStartTimes;
// Buffer of recent expected present times
- RingBuffer<TimePoint, 2> mExpectedPresentTimes;
+ ui::RingBuffer<TimePoint, 2> mExpectedPresentTimes;
// Most recent present fence time, provided by SF after composition engine finishes presenting
TimePoint mLastPresentFenceTime;
// Most recent composition engine present end time, returned with the present fence from SF
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 4da76f6..e587178 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -986,7 +986,7 @@
if (const auto pacesetterOpt = pacesetterDisplayLocked()) {
const Display& pacesetter = *pacesetterOpt;
- if (!FlagManager::getInstance().connected_display() || params.toggleIdleTimer) {
+ if (params.toggleIdleTimer) {
pacesetter.selectorPtr->setIdleTimerCallbacks(
{.platform = {.onReset = [this] { idleTimerCallback(TimerState::Reset); },
.onExpired = [this] { idleTimerCallback(TimerState::Expired); }},
@@ -1018,7 +1018,7 @@
}
void Scheduler::demotePacesetterDisplay(PromotionParams params) {
- if (!FlagManager::getInstance().connected_display() || params.toggleIdleTimer) {
+ if (params.toggleIdleTimer) {
// No need to lock for reads on kMainThreadContext.
if (const auto pacesetterPtr =
FTL_FAKE_GUARD(mDisplayLock, pacesetterSelectorPtrLocked())) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 3fdddac..81389e7 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -386,7 +386,7 @@
// a deadlock where the main thread joins with the timer thread as the timer thread waits to
// lock a mutex held by the main thread.
struct PromotionParams {
- // Whether to stop and start the idle timer. Ignored unless connected_display flag is set.
+ // Whether to stop and start the idle timer.
bool toggleIdleTimer;
};
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index b9c79df..bb04d12 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -208,7 +208,8 @@
auto it = mRateMap.find(idealPeriod());
// Calculated slope over the period of time can become outdated as the new timestamps are
// stored. Using idealPeriod instead provides a rate which is valid at all the times.
- auto const currentPeriod = FlagManager::getInstance().vsync_predictor_recovery()
+ auto const currentPeriod =
+ mDisplayModePtr->getVrrConfig() && FlagManager::getInstance().vsync_predictor_recovery()
? idealPeriod()
: it->second.slope;
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h
index 813d4de..ff461d2 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h
@@ -24,6 +24,7 @@
#include <ui/DisplayId.h>
#include <ui/Fence.h>
#include <ui/FenceTime.h>
+#include <ui/RingBuffer.h>
#include <scheduler/Features.h>
#include <scheduler/FrameTime.h>
@@ -34,7 +35,6 @@
// TODO(b/185536303): Pull to FTL.
#include "../../../TracedOrdinal.h"
#include "../../../Utils/Dumper.h"
-#include "../../../Utils/RingBuffer.h"
namespace android::scheduler {
@@ -108,7 +108,7 @@
std::pair<bool /* wouldBackpressure */, PresentFence> expectedSignaledPresentFence(
Period vsyncPeriod, Period minFramePeriod) const;
std::array<PresentFence, 2> mPresentFencesLegacy;
- utils::RingBuffer<PresentFence, 5> mPresentFences;
+ ui::RingBuffer<PresentFence, 5> mPresentFences;
FrameTime mLastSignaledFrameTime;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 35cb63e..9cd2314 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -384,6 +384,7 @@
bool SurfaceFlinger::hasSyncFramework;
int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
int64_t SurfaceFlinger::minAcquiredBuffers = 1;
+std::optional<int64_t> SurfaceFlinger::maxAcquiredBuffersOpt;
uint32_t SurfaceFlinger::maxGraphicsWidth;
uint32_t SurfaceFlinger::maxGraphicsHeight;
bool SurfaceFlinger::useContextPriority;
@@ -452,6 +453,7 @@
maxFrameBufferAcquiredBuffers = max_frame_buffer_acquired_buffers(2);
minAcquiredBuffers =
SurfaceFlingerProperties::min_acquired_buffers().value_or(minAcquiredBuffers);
+ maxAcquiredBuffersOpt = SurfaceFlingerProperties::max_acquired_buffers();
maxGraphicsWidth = std::max(max_graphics_width(0), 0);
maxGraphicsHeight = std::max(max_graphics_height(0), 0);
@@ -576,9 +578,10 @@
mScheduler->run();
}
-sp<IBinder> SurfaceFlinger::createVirtualDisplay(const std::string& displayName, bool isSecure,
- const std::string& uniqueId,
- float requestedRefreshRate) {
+sp<IBinder> SurfaceFlinger::createVirtualDisplay(
+ const std::string& displayName, bool isSecure,
+ gui::ISurfaceComposer::OptimizationPolicy optimizationPolicy, const std::string& uniqueId,
+ float requestedRefreshRate) {
// SurfaceComposerAIDL checks for some permissions, but adding an additional check here.
// This is to ensure that only root, system, and graphics can request to create a secure
// display. Secure displays can show secure content so we add an additional restriction on it.
@@ -588,6 +591,8 @@
return nullptr;
}
+ ALOGD("Creating virtual display: %s", displayName.c_str());
+
class DisplayToken : public BBinder {
sp<SurfaceFlinger> flinger;
virtual ~DisplayToken() {
@@ -611,6 +616,9 @@
// Set display as protected when marked as secure to ensure no behavior change
// TODO (b/314820005): separate as a different arg when creating the display.
state.isProtected = isSecure;
+ state.optimizationPolicy = optimizationPolicy;
+ // Virtual displays start in ON mode.
+ state.initialPowerMode = hal::PowerMode::ON;
state.displayName = displayName;
state.uniqueId = uniqueId;
state.requestedRefreshRate = Fps::fromValue(requestedRefreshRate);
@@ -632,6 +640,9 @@
ALOGE("%s: Invalid operation on physical display", __func__);
return INVALID_OPERATION;
}
+
+ ALOGD("Destroying virtual display: %s", state.displayName.c_str());
+
mCurrentState.displays.removeItemsAt(index);
setTransactionFlags(eDisplayTransactionNeeded);
return NO_ERROR;
@@ -1009,9 +1020,8 @@
mPowerAdvisor->init();
if (base::GetBoolProperty("service.sf.prime_shader_cache"s, true)) {
- if (setSchedFifo(false) != NO_ERROR) {
- ALOGW("Can't set SCHED_OTHER for primeCache");
- }
+ constexpr const char* kWhence = "primeCache";
+ setSchedFifo(false, kWhence);
mRenderEnginePrimeCacheFuture.callOnce([this] {
renderengine::PrimeCacheConfig config;
@@ -1047,9 +1057,7 @@
return getRenderEngine().primeCache(config);
});
- if (setSchedFifo(true) != NO_ERROR) {
- ALOGW("Can't set SCHED_FIFO after primeCache");
- }
+ setSchedFifo(true, kWhence);
}
// Avoid blocking the main thread on `init` to set properties.
@@ -2286,8 +2294,7 @@
void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp,
std::optional<hal::VsyncPeriodNanos> vsyncPeriod) {
- if (FlagManager::getInstance().connected_display() && timestamp < 0 &&
- vsyncPeriod.has_value()) {
+ if (timestamp < 0 && vsyncPeriod.has_value()) {
if (mIsHdcpViaNegVsync && vsyncPeriod.value() == ~1) {
const int32_t value = static_cast<int32_t>(-timestamp);
// one byte is good enough to encode android.hardware.drm.HdcpLevel
@@ -2339,9 +2346,19 @@
return;
}
- if (event == DisplayHotplugEvent::ERROR_LINK_UNSTABLE &&
- !FlagManager::getInstance().display_config_error_hal()) {
- return;
+ if (event == DisplayHotplugEvent::ERROR_LINK_UNSTABLE) {
+ if (!FlagManager::getInstance().display_config_error_hal()) {
+ return;
+ }
+ {
+ std::lock_guard<std::mutex> lock(mHotplugMutex);
+ mPendingHotplugEvents.push_back(
+ HotplugEvent{hwcDisplayId, HWComposer::HotplugEvent::LinkUnstable});
+ }
+ if (mScheduler) {
+ mScheduler->scheduleConfigure();
+ }
+ // do not return to also report the error.
}
// TODO(b/311403559): use enum type instead of int
@@ -3554,9 +3571,8 @@
std::vector<HWComposer::HWCDisplayMode> hwcModes;
std::optional<hal::HWConfigId> activeModeHwcIdOpt;
- const bool isExternalDisplay = FlagManager::getInstance().connected_display() &&
- getHwComposer().getDisplayConnectionType(displayId) ==
- ui::DisplayConnectionType::External;
+ const bool isExternalDisplay = getHwComposer().getDisplayConnectionType(displayId) ==
+ ui::DisplayConnectionType::External;
int attempt = 0;
constexpr int kMaxAttempts = 3;
@@ -3719,11 +3735,12 @@
const auto displayId = info->id;
const ftl::Concat displayString("display ", displayId.value, "(HAL ID ", hwcDisplayId,
')');
-
- if (event == HWComposer::HotplugEvent::Connected) {
+ // TODO: b/393126541 - replace if with switch as all cases are handled.
+ if (event == HWComposer::HotplugEvent::Connected ||
+ event == HWComposer::HotplugEvent::LinkUnstable) {
const auto activeModeIdOpt =
processHotplugConnect(displayId, hwcDisplayId, std::move(*info),
- displayString.c_str());
+ displayString.c_str(), event);
if (!activeModeIdOpt) {
mScheduler->dispatchHotplugError(
static_cast<int32_t>(DisplayHotplugEvent::ERROR_UNKNOWN));
@@ -3749,7 +3766,7 @@
LOG_ALWAYS_FATAL_IF(!snapshotOpt);
mDisplayModeController.registerDisplay(*snapshotOpt, *activeModeIdOpt, config);
- } else {
+ } else { // event == HWComposer::HotplugEvent::Disconnected
// Unregister before destroying the DisplaySnapshot below.
mDisplayModeController.unregisterDisplay(displayId);
@@ -3764,7 +3781,8 @@
std::optional<DisplayModeId> SurfaceFlinger::processHotplugConnect(PhysicalDisplayId displayId,
hal::HWDisplayId hwcDisplayId,
DisplayIdentificationInfo&& info,
- const char* displayString) {
+ const char* displayString,
+ HWComposer::HotplugEvent event) {
auto [displayModes, activeMode] = loadDisplayModes(displayId);
if (!activeMode) {
ALOGE("Failed to hotplug %s", displayString);
@@ -3799,6 +3817,9 @@
state.physical->port = port;
ALOGI("Reconnecting %s", displayString);
return activeModeId;
+ } else if (event == HWComposer::HotplugEvent::LinkUnstable) {
+ ALOGE("Failed to reconnect unknown %s", displayString);
+ return std::nullopt;
}
const sp<IBinder> token = sp<BBinder>::make();
@@ -3899,7 +3920,12 @@
getPhysicalDisplayOrientation(compositionDisplay->getId(), creationArgs.isPrimary);
ALOGV("Display Orientation: %s", toCString(creationArgs.physicalOrientation));
- creationArgs.initialPowerMode = state.isVirtual() ? hal::PowerMode::ON : hal::PowerMode::OFF;
+ if (FlagManager::getInstance().correct_virtual_display_power_state()) {
+ creationArgs.initialPowerMode = state.initialPowerMode;
+ } else {
+ creationArgs.initialPowerMode =
+ state.isVirtual() ? hal::PowerMode::ON : hal::PowerMode::OFF;
+ }
creationArgs.requestedRefreshRate = state.requestedRefreshRate;
@@ -3927,6 +3953,7 @@
display->setProjection(state.orientation, state.layerStackSpaceRect,
state.orientedDisplaySpaceRect);
display->setDisplayName(state.displayName);
+ display->setOptimizationPolicy(state.optimizationPolicy);
display->setFlags(state.flags);
return display;
@@ -3972,6 +3999,8 @@
// Virtual displays without a surface are dormant:
// they have external state (layer stack, projection,
// etc.) but no internal state (i.e. a DisplayDevice).
+ ALOGD("Not adding dormant virtual display with token %p: %s", displayToken.unsafe_get(),
+ state.displayName.c_str());
return;
}
@@ -4051,8 +4080,7 @@
// For an external display, loadDisplayModes already attempted to select the same mode
// as DM, but SF still needs to be updated to match.
// TODO (b/318534874): Let DM decide the initial mode.
- if (const auto& physical = state.physical;
- mScheduler && physical && FlagManager::getInstance().connected_display()) {
+ if (const auto& physical = state.physical; mScheduler && physical) {
const bool isInternalDisplay = mPhysicalDisplays.get(physical->id)
.transform(&PhysicalDisplay::isInternal)
.value_or(false);
@@ -4136,7 +4164,7 @@
if (currentState.physical) {
const auto display = getDisplayDeviceLocked(displayToken);
if (!mSkipPowerOnForQuiescent) {
- setPowerModeInternal(display, hal::PowerMode::ON);
+ setPhysicalDisplayPowerMode(display, hal::PowerMode::ON);
}
if (display->getPhysicalId() == mActiveDisplayId) {
@@ -4320,20 +4348,19 @@
std::move(displayInfos),
ftl::to_underlying(vsyncId),
frameTime.ns()},
- std::move(
- inputWindowCommands.windowInfosReportedListeners),
+ std::move(inputWindowCommands.releaseListeners()),
/* forceImmediateCall= */ visibleWindowsChanged ||
- !inputWindowCommands.focusRequests.empty());
+ !inputWindowCommands.getFocusRequests().empty());
} else {
// If there are listeners but no changes to input windows, call the listeners
// immediately.
- for (const auto& listener : inputWindowCommands.windowInfosReportedListeners) {
+ for (const auto& listener : inputWindowCommands.getListeners()) {
if (IInterface::asBinder(listener)->isBinderAlive()) {
listener->onWindowInfosReported();
}
}
}
- for (const auto& focusRequest : inputWindowCommands.focusRequests) {
+ for (const auto& focusRequest : inputWindowCommands.getFocusRequests()) {
inputFlinger->setFocusedWindow(focusRequest);
}
}});
@@ -5060,16 +5087,16 @@
mBufferCountTracker.increment(resolvedState.layerId);
}
if (resolvedState.state.what & layer_state_t::eReparent) {
- resolvedState.parentId =
- getLayerIdFromSurfaceControl(resolvedState.state.parentSurfaceControlForChild);
+ resolvedState.parentId = getLayerIdFromSurfaceControl(
+ resolvedState.state.getParentSurfaceControlForChild());
}
if (resolvedState.state.what & layer_state_t::eRelativeLayerChanged) {
- resolvedState.relativeParentId =
- getLayerIdFromSurfaceControl(resolvedState.state.relativeLayerSurfaceControl);
+ resolvedState.relativeParentId = getLayerIdFromSurfaceControl(
+ resolvedState.state.getRelativeLayerSurfaceControl());
}
if (resolvedState.state.what & layer_state_t::eInputInfoChanged) {
wp<IBinder>& touchableRegionCropHandle =
- resolvedState.state.windowInfoHandle->editInfo()->touchableRegionCropHandle;
+ resolvedState.state.editWindowInfo()->touchableRegionCropHandle;
resolvedState.touchCropId =
LayerHandle::getLayerId(touchableRegionCropHandle.promote());
}
@@ -5628,7 +5655,7 @@
// In case of a restart, ensure all displays are off.
for (const auto& [id, display] : mPhysicalDisplays) {
- setPowerModeInternal(getDisplayDeviceLocked(id), hal::PowerMode::OFF);
+ setPhysicalDisplayPowerMode(getDisplayDeviceLocked(id), hal::PowerMode::OFF);
}
// Power on all displays. The primary display is first, so becomes the active display. Also,
@@ -5637,13 +5664,14 @@
// Additionally, do not turn on displays if the boot should be quiescent.
if (!mSkipPowerOnForQuiescent) {
for (const auto& [id, display] : mPhysicalDisplays) {
- setPowerModeInternal(getDisplayDeviceLocked(id), hal::PowerMode::ON);
+ setPhysicalDisplayPowerMode(getDisplayDeviceLocked(id), hal::PowerMode::ON);
}
}
}
}
-void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) {
+void SurfaceFlinger::setPhysicalDisplayPowerMode(const sp<DisplayDevice>& display,
+ hal::PowerMode mode) {
if (display->isVirtual()) {
// TODO(b/241285876): This code path should not be reachable, so enforce this at compile
// time.
@@ -5695,16 +5723,11 @@
}
if (displayId == mActiveDisplayId) {
- // TODO(b/281692563): Merge the syscalls. For now, keep uclamp in a separate syscall and
- // set it before SCHED_FIFO due to b/190237315.
- if (setSchedAttr(true) != NO_ERROR) {
- ALOGW("Failed to set uclamp.min after powering on active display: %s",
- strerror(errno));
- }
- if (setSchedFifo(true) != NO_ERROR) {
- ALOGW("Failed to set SCHED_FIFO after powering on active display: %s",
- strerror(errno));
- }
+ // TODO: b/281692563 - Merge the syscalls. For now, keep uclamp in a separate syscall
+ // and set it before SCHED_FIFO due to b/190237315.
+ constexpr const char* kWhence = "setPowerMode(ON)";
+ setSchedAttr(true, kWhence);
+ setSchedFifo(true, kWhence);
}
getHwComposer().setPowerMode(displayId, mode);
@@ -5731,14 +5754,9 @@
if (const auto display = getActivatableDisplay()) {
onActiveDisplayChangedLocked(activeDisplay.get(), *display);
} else {
- if (setSchedFifo(false) != NO_ERROR) {
- ALOGW("Failed to set SCHED_OTHER after powering off active display: %s",
- strerror(errno));
- }
- if (setSchedAttr(false) != NO_ERROR) {
- ALOGW("Failed set uclamp.min after powering off active display: %s",
- strerror(errno));
- }
+ constexpr const char* kWhence = "setPowerMode(OFF)";
+ setSchedFifo(false, kWhence);
+ setSchedAttr(false, kWhence);
if (currentModeNotDozeSuspend) {
if (!FlagManager::getInstance().multithreaded_present()) {
@@ -5803,17 +5821,33 @@
}
void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
- auto future = mScheduler->schedule([=, this]() FTL_FAKE_GUARD(mStateLock) FTL_FAKE_GUARD(
- kMainThreadContext) {
+ auto future = mScheduler->schedule([=, this]() FTL_FAKE_GUARD(kMainThreadContext) {
mSkipPowerOnForQuiescent = false;
- const auto display = getDisplayDeviceLocked(displayToken);
+ const auto display = FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(displayToken));
if (!display) {
- ALOGE("Attempt to set power mode %d for invalid display token %p", mode,
- displayToken.get());
+ Mutex::Autolock lock(mStateLock);
+ const ssize_t index = mCurrentState.displays.indexOfKey(displayToken);
+ if (index >= 0) {
+ auto& state = mCurrentState.displays.editValueFor(displayToken);
+ if (state.isVirtual()) {
+ ALOGD("Setting power mode %d for a dormant virtual display with token %p", mode,
+ displayToken.get());
+ state.initialPowerMode = static_cast<hal::PowerMode>(mode);
+ return;
+ }
+ }
+ ALOGE("Failed to set power mode %d for display token %p", mode, displayToken.get());
} else if (display->isVirtual()) {
- ALOGW("Attempt to set power mode %d for virtual display", mode);
+ if (FlagManager::getInstance().correct_virtual_display_power_state()) {
+ ALOGD("Setting power mode %d on virtual display %s", mode,
+ display->getDisplayName().c_str());
+ display->setPowerMode(static_cast<hal::PowerMode>(mode));
+ } else {
+ ALOGW("Attempt to set power mode %d for virtual display", mode);
+ }
} else {
- setPowerModeInternal(display, static_cast<hal::PowerMode>(mode));
+ ftl::FakeGuard guard(mStateLock);
+ setPhysicalDisplayPowerMode(display, static_cast<hal::PowerMode>(mode));
}
});
@@ -7201,7 +7235,7 @@
return PERMISSION_DENIED;
}
-status_t SurfaceFlinger::setSchedFifo(bool enabled) {
+void SurfaceFlinger::setSchedFifo(bool enabled, const char* whence) {
static constexpr int kFifoPriority = 2;
static constexpr int kOtherPriority = 0;
@@ -7216,19 +7250,19 @@
}
if (sched_setscheduler(0, sched_policy, ¶m) != 0) {
- return -errno;
+ const char* kPolicy[] = {"SCHED_OTHER", "SCHED_FIFO"};
+ ALOGW("%s: Failed to set %s: %s", whence, kPolicy[sched_policy == SCHED_FIFO],
+ strerror(errno));
}
-
- return NO_ERROR;
}
-status_t SurfaceFlinger::setSchedAttr(bool enabled) {
+void SurfaceFlinger::setSchedAttr(bool enabled, const char* whence) {
static const unsigned int kUclampMin =
base::GetUintProperty<unsigned int>("ro.surface_flinger.uclamp.min"s, 0U);
if (!kUclampMin) {
// uclamp.min set to 0 (default), skip setting
- return NO_ERROR;
+ return;
}
sched_attr attr = {};
@@ -7239,10 +7273,9 @@
attr.sched_util_max = 1024;
if (syscall(__NR_sched_setattr, 0, &attr, 0)) {
- return -errno;
+ const char* kAction[] = {"disable", "enable"};
+ ALOGW("%s: Failed to %s uclamp.min: %s", whence, kAction[enabled], strerror(errno));
}
-
- return NO_ERROR;
}
namespace {
@@ -8240,11 +8273,13 @@
int SurfaceFlinger::calculateMaxAcquiredBufferCount(Fps refreshRate,
std::chrono::nanoseconds presentLatency) {
- auto pipelineDepth = presentLatency.count() / refreshRate.getPeriodNsecs();
+ int64_t pipelineDepth = presentLatency.count() / refreshRate.getPeriodNsecs();
if (presentLatency.count() % refreshRate.getPeriodNsecs()) {
pipelineDepth++;
}
- return std::max(minAcquiredBuffers, static_cast<int64_t>(pipelineDepth - 1));
+ const int64_t maxAcquiredBuffers =
+ std::min(pipelineDepth - 1, maxAcquiredBuffersOpt.value_or(pipelineDepth - 1));
+ return std::max(minAcquiredBuffers, maxAcquiredBuffers);
}
status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const {
@@ -8362,10 +8397,6 @@
void SurfaceFlinger::updateHdcpLevels(hal::HWDisplayId hwcDisplayId, int32_t connectedLevel,
int32_t maxLevel) {
- if (!FlagManager::getInstance().connected_display()) {
- return;
- }
-
Mutex::Autolock lock(mStateLock);
const auto idOpt = getHwComposer().toPhysicalDisplayId(hwcDisplayId);
@@ -8749,16 +8780,16 @@
}
}
-binder::Status SurfaceComposerAIDL::createVirtualDisplay(const std::string& displayName,
- bool isSecure, const std::string& uniqueId,
- float requestedRefreshRate,
- sp<IBinder>* outDisplay) {
+binder::Status SurfaceComposerAIDL::createVirtualDisplay(
+ const std::string& displayName, bool isSecure,
+ gui::ISurfaceComposer::OptimizationPolicy optimizationPolicy, const std::string& uniqueId,
+ float requestedRefreshRate, sp<IBinder>* outDisplay) {
status_t status = checkAccessPermission();
if (status != OK) {
return binderStatusFromStatusT(status);
}
- *outDisplay =
- mFlinger->createVirtualDisplay(displayName, isSecure, uniqueId, requestedRefreshRate);
+ *outDisplay = mFlinger->createVirtualDisplay(displayName, isSecure, optimizationPolicy,
+ uniqueId, requestedRefreshRate);
return binder::Status::ok();
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 3f454ba..fc596d7 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -211,11 +211,9 @@
SurfaceFlinger(surfaceflinger::Factory&, SkipInitializationTag) ANDROID_API;
explicit SurfaceFlinger(surfaceflinger::Factory&) ANDROID_API;
- // set main thread scheduling policy
- static status_t setSchedFifo(bool enabled) ANDROID_API;
-
- // set main thread scheduling attributes
- static status_t setSchedAttr(bool enabled);
+ // Set scheduling policy and attributes of main thread.
+ static void setSchedFifo(bool enabled, const char* whence);
+ static void setSchedAttr(bool enabled, const char* whence);
static char const* getServiceName() ANDROID_API { return "SurfaceFlinger"; }
@@ -240,6 +238,11 @@
// ISurfaceComposer.getMaxAcquiredBufferCount().
static int64_t minAcquiredBuffers;
+ // Controls the maximum acquired buffers SurfaceFlinger will suggest via
+ // ISurfaceComposer.getMaxAcquiredBufferCount().
+ // Value is set through ro.surface_flinger.max_acquired_buffers.
+ static std::optional<int64_t> maxAcquiredBuffersOpt;
+
// Controls the maximum width and height in pixels that the graphics pipeline can support for
// GPU fallback composition. For example, 8k devices with 4k GPUs, or 4k devices with 2k GPUs.
static uint32_t maxGraphicsWidth;
@@ -531,6 +534,7 @@
// ISurfaceComposer implementation:
sp<IBinder> createVirtualDisplay(const std::string& displayName, bool isSecure,
+ gui::ISurfaceComposer::OptimizationPolicy optimizationPolicy,
const std::string& uniqueId,
float requestedRefreshRate = 0.0f);
status_t destroyVirtualDisplay(const sp<IBinder>& displayToken);
@@ -729,7 +733,7 @@
void applyActiveMode(PhysicalDisplayId) REQUIRES(kMainThreadContext);
// Called on the main thread in response to setPowerMode()
- void setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode)
+ void setPhysicalDisplayPowerMode(const sp<DisplayDevice>& display, hal::PowerMode mode)
REQUIRES(mStateLock, kMainThreadContext);
// Returns the preferred mode for PhysicalDisplayId if the Scheduler has selected one for that
@@ -1067,7 +1071,8 @@
// Returns the active mode ID, or nullopt on hotplug failure.
std::optional<DisplayModeId> processHotplugConnect(PhysicalDisplayId, hal::HWDisplayId,
DisplayIdentificationInfo&&,
- const char* displayString)
+ const char* displayString,
+ HWComposer::HotplugEvent event)
REQUIRES(mStateLock, kMainThreadContext);
void processHotplugDisconnect(PhysicalDisplayId, const char* displayString)
REQUIRES(mStateLock, kMainThreadContext);
@@ -1564,9 +1569,11 @@
const sp<IBinder>& layerHandle,
sp<gui::IDisplayEventConnection>* outConnection) override;
binder::Status createConnection(sp<gui::ISurfaceComposerClient>* outClient) override;
- binder::Status createVirtualDisplay(const std::string& displayName, bool isSecure,
- const std::string& uniqueId, float requestedRefreshRate,
- sp<IBinder>* outDisplay) override;
+ binder::Status createVirtualDisplay(
+ const std::string& displayName, bool isSecure,
+ gui::ISurfaceComposer::OptimizationPolicy optimizationPolicy,
+ const std::string& uniqueId, float requestedRefreshRate,
+ sp<IBinder>* outDisplay) override;
binder::Status destroyVirtualDisplay(const sp<IBinder>& displayToken) override;
binder::Status getPhysicalDisplayIds(std::vector<int64_t>* outDisplayIds) override;
binder::Status getPhysicalDisplayToken(int64_t displayId, sp<IBinder>* outDisplay) override;
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index 2676ca6..3297c16 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -139,7 +139,8 @@
colorProto->set_b(layer.color.b);
}
if (layer.what & layer_state_t::eTransparentRegionChanged) {
- LayerProtoHelper::writeToProto(layer.transparentRegion, proto.mutable_transparent_region());
+ LayerProtoHelper::writeToProto(layer.getTransparentRegion(),
+ proto.mutable_transparent_region());
}
if (layer.what & layer_state_t::eBufferTransformChanged) {
proto.set_transform(layer.bufferTransform);
@@ -191,33 +192,30 @@
}
if (layer.what & layer_state_t::eInputInfoChanged) {
- if (layer.windowInfoHandle) {
- const gui::WindowInfo* inputInfo = layer.windowInfoHandle->getInfo();
- perfetto::protos::LayerState_WindowInfo* windowInfoProto =
- proto.mutable_window_info_handle();
- windowInfoProto->set_layout_params_flags(inputInfo->layoutParamsFlags.get());
- windowInfoProto->set_layout_params_type(
- static_cast<int32_t>(inputInfo->layoutParamsType));
- windowInfoProto->set_input_config(inputInfo->inputConfig.get());
- LayerProtoHelper::writeToProto(inputInfo->touchableRegion,
- windowInfoProto->mutable_touchable_region());
- windowInfoProto->set_surface_inset(inputInfo->surfaceInset);
- windowInfoProto->set_focusable(
- !inputInfo->inputConfig.test(gui::WindowInfo::InputConfig::NOT_FOCUSABLE));
- windowInfoProto->set_has_wallpaper(inputInfo->inputConfig.test(
- gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER));
- windowInfoProto->set_global_scale_factor(inputInfo->globalScaleFactor);
- perfetto::protos::Transform* transformProto = windowInfoProto->mutable_transform();
- transformProto->set_dsdx(inputInfo->transform.dsdx());
- transformProto->set_dtdx(inputInfo->transform.dtdx());
- transformProto->set_dtdy(inputInfo->transform.dtdy());
- transformProto->set_dsdy(inputInfo->transform.dsdy());
- transformProto->set_tx(inputInfo->transform.tx());
- transformProto->set_ty(inputInfo->transform.ty());
- windowInfoProto->set_replace_touchable_region_with_crop(
- inputInfo->replaceTouchableRegionWithCrop);
- windowInfoProto->set_crop_layer_id(resolvedComposerState.touchCropId);
- }
+ const gui::WindowInfo* inputInfo = &layer.getWindowInfo();
+ perfetto::protos::LayerState_WindowInfo* windowInfoProto =
+ proto.mutable_window_info_handle();
+ windowInfoProto->set_layout_params_flags(inputInfo->layoutParamsFlags.get());
+ windowInfoProto->set_layout_params_type(static_cast<int32_t>(inputInfo->layoutParamsType));
+ windowInfoProto->set_input_config(inputInfo->inputConfig.get());
+ LayerProtoHelper::writeToProto(inputInfo->touchableRegion,
+ windowInfoProto->mutable_touchable_region());
+ windowInfoProto->set_surface_inset(inputInfo->surfaceInset);
+ windowInfoProto->set_focusable(
+ !inputInfo->inputConfig.test(gui::WindowInfo::InputConfig::NOT_FOCUSABLE));
+ windowInfoProto->set_has_wallpaper(inputInfo->inputConfig.test(
+ gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER));
+ windowInfoProto->set_global_scale_factor(inputInfo->globalScaleFactor);
+ perfetto::protos::Transform* transformProto = windowInfoProto->mutable_transform();
+ transformProto->set_dsdx(inputInfo->transform.dsdx());
+ transformProto->set_dtdx(inputInfo->transform.dtdx());
+ transformProto->set_dtdy(inputInfo->transform.dtdy());
+ transformProto->set_dsdy(inputInfo->transform.dsdy());
+ transformProto->set_tx(inputInfo->transform.tx());
+ transformProto->set_ty(inputInfo->transform.ty());
+ windowInfoProto->set_replace_touchable_region_with_crop(
+ inputInfo->replaceTouchableRegionWithCrop);
+ windowInfoProto->set_crop_layer_id(resolvedComposerState.touchCropId);
}
if (layer.what & layer_state_t::eBackgroundColorChanged) {
proto.set_bg_color_alpha(layer.bgColor.a);
@@ -410,7 +408,9 @@
layer.color.b = colorProto.b();
}
if (proto.what() & layer_state_t::eTransparentRegionChanged) {
- LayerProtoHelper::readFromProto(proto.transparent_region(), layer.transparentRegion);
+ Region transparentRegion;
+ LayerProtoHelper::readFromProto(proto.transparent_region(), transparentRegion);
+ layer.updateTransparentRegion(transparentRegion);
}
if (proto.what() & layer_state_t::eBufferTransformChanged) {
layer.bufferTransform = proto.transform();
@@ -486,7 +486,7 @@
windowInfoProto.replace_touchable_region_with_crop();
resolvedComposerState.touchCropId = windowInfoProto.crop_layer_id();
- layer.windowInfoHandle = sp<gui::WindowInfoHandle>::make(inputInfo);
+ *layer.editWindowInfo() = inputInfo;
}
if (proto.what() & layer_state_t::eBackgroundColorChanged) {
layer.bgColor.a = proto.bg_color_alpha();
diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
index 5cf4244..84d837c 100644
--- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
@@ -102,11 +102,10 @@
QueuedTransactionState transaction = parser.fromProto(entry.transactions(j));
for (auto& resolvedComposerState : transaction.states) {
if (resolvedComposerState.state.what & layer_state_t::eInputInfoChanged) {
- if (!resolvedComposerState.state.windowInfoHandle->getInfo()->inputConfig.test(
+ if (!resolvedComposerState.state.getWindowInfo().inputConfig.test(
gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL)) {
// create a fake token since the FE expects a valid token
- resolvedComposerState.state.windowInfoHandle->editInfo()->token =
- sp<BBinder>::make();
+ resolvedComposerState.state.editWindowInfo()->token = sp<BBinder>::make();
}
}
}
diff --git a/services/surfaceflinger/common/Android.bp b/services/surfaceflinger/common/Android.bp
index 8786f6e..13f6577 100644
--- a/services/surfaceflinger/common/Android.bp
+++ b/services/surfaceflinger/common/Android.bp
@@ -16,9 +16,9 @@
],
shared_libs: [
"libSurfaceFlingerProp",
- "server_configurable_flags",
"libaconfig_storage_read_api_cc",
"libtracing_perfetto",
+ "server_configurable_flags",
],
static_libs: [
"librenderengine_includes",
@@ -37,11 +37,12 @@
"libsurfaceflinger_common_defaults",
],
static_libs: [
- "libsurfaceflingerflags",
"aconfig_hardware_flags_c_lib",
+ "android.companion.virtualdevice.flags-aconfig-cc",
"android.os.flags-aconfig-cc",
"android.server.display.flags-aconfig-cc",
"libguiflags_no_apex",
+ "libsurfaceflingerflags",
],
}
@@ -51,44 +52,47 @@
"libsurfaceflinger_common_defaults",
],
static_libs: [
- "libsurfaceflingerflags_test",
"aconfig_hardware_flags_c_lib",
+ "android.companion.virtualdevice.flags-aconfig-cc",
"android.os.flags-aconfig-cc-test",
"android.server.display.flags-aconfig-cc",
"libguiflags_no_apex",
+ "libsurfaceflingerflags_test",
],
}
cc_defaults {
name: "libsurfaceflinger_common_deps",
shared_libs: [
- "server_configurable_flags",
"libaconfig_storage_read_api_cc",
"libtracing_perfetto",
+ "server_configurable_flags",
],
static_libs: [
- "libsurfaceflinger_common",
- "libsurfaceflingerflags",
"aconfig_hardware_flags_c_lib",
+ "android.companion.virtualdevice.flags-aconfig-cc",
"android.os.flags-aconfig-cc",
"android.server.display.flags-aconfig-cc",
"libguiflags_no_apex",
+ "libsurfaceflinger_common",
+ "libsurfaceflingerflags",
],
}
cc_defaults {
name: "libsurfaceflinger_common_test_deps",
shared_libs: [
- "server_configurable_flags",
"libaconfig_storage_read_api_cc",
"libtracing_perfetto",
+ "server_configurable_flags",
],
static_libs: [
- "libsurfaceflinger_common_test",
- "libsurfaceflingerflags_test",
"aconfig_hardware_flags_c_lib",
+ "android.companion.virtualdevice.flags-aconfig-cc",
"android.os.flags-aconfig-cc-test",
"android.server.display.flags-aconfig-cc",
"libguiflags_no_apex",
+ "libsurfaceflinger_common_test",
+ "libsurfaceflingerflags_test",
],
}
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index abde524..42fa436 100644
--- a/services/surfaceflinger/common/FlagManager.cpp
+++ b/services/surfaceflinger/common/FlagManager.cpp
@@ -26,8 +26,9 @@
#include <server_configurable_flags/get_flags.h>
#include <cinttypes>
-#include <android_os.h>
+#include <android_companion_virtualdevice_flags.h>
#include <android_hardware_flags.h>
+#include <android_os.h>
#include <com_android_graphics_libgui_flags.h>
#include <com_android_graphics_surfaceflinger_flags.h>
#include <com_android_server_display_feature_flags.h>
@@ -125,6 +126,7 @@
DUMP_ACONFIG_FLAG(adpf_gpu_sf);
DUMP_ACONFIG_FLAG(adpf_native_session_manager);
DUMP_ACONFIG_FLAG(adpf_use_fmq_channel);
+ DUMP_ACONFIG_FLAG(correct_virtual_display_power_state);
DUMP_ACONFIG_FLAG(graphite_renderengine_preview_rollout);
DUMP_ACONFIG_FLAG(increase_missed_frame_jank_threshold);
DUMP_ACONFIG_FLAG(refresh_rate_overlay_on_external_display);
@@ -139,7 +141,6 @@
DUMP_ACONFIG_FLAG(begone_bright_hlg);
DUMP_ACONFIG_FLAG(cache_when_source_crop_layer_only_moved);
DUMP_ACONFIG_FLAG(commit_not_composited);
- DUMP_ACONFIG_FLAG(connected_display);
DUMP_ACONFIG_FLAG(connected_display_hdr);
DUMP_ACONFIG_FLAG(correct_dpi_with_display_size);
DUMP_ACONFIG_FLAG(deprecate_frame_tracker);
@@ -252,7 +253,6 @@
/// Trunk stable readonly flags ///
FLAG_MANAGER_ACONFIG_FLAG(adpf_fmq_sf, "")
FLAG_MANAGER_ACONFIG_FLAG(arr_setframerate_gte_enum, "debug.sf.arr_setframerate_gte_enum")
-FLAG_MANAGER_ACONFIG_FLAG(connected_display, "")
FLAG_MANAGER_ACONFIG_FLAG(enable_small_area_detection, "")
FLAG_MANAGER_ACONFIG_FLAG(stable_edid_ids, "debug.sf.stable_edid_ids")
FLAG_MANAGER_ACONFIG_FLAG(frame_rate_category_mrr, "debug.sf.frame_rate_category_mrr")
@@ -309,6 +309,8 @@
/// Trunk stable server (R/W) flags from outside SurfaceFlinger ///
FLAG_MANAGER_ACONFIG_FLAG_IMPORTED(adpf_use_fmq_channel, "", android::os)
+FLAG_MANAGER_ACONFIG_FLAG_IMPORTED(correct_virtual_display_power_state, "",
+ android::companion::virtualdevice::flags)
/// Trunk stable readonly flags from outside SurfaceFlinger ///
FLAG_MANAGER_ACONFIG_FLAG_IMPORTED(idle_screen_refresh_rate_timeout, "",
diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index 6295c5b..dd7042d 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -60,6 +60,7 @@
bool adpf_native_session_manager() const;
bool adpf_use_fmq_channel() const;
bool adpf_use_fmq_channel_fixed() const;
+ bool correct_virtual_display_power_state() const;
bool graphite_renderengine_preview_rollout() const;
bool increase_missed_frame_jank_threshold() const;
bool refresh_rate_overlay_on_external_display() const;
@@ -74,7 +75,6 @@
bool begone_bright_hlg() const;
bool cache_when_source_crop_layer_only_moved() const;
bool commit_not_composited() const;
- bool connected_display() const;
bool connected_display_hdr() const;
bool correct_dpi_with_display_size() const;
bool deprecate_frame_tracker() const;
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index 73dfa9f..4afcd00 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -77,7 +77,7 @@
}
}
-int main(int, char**) {
+int main() {
signal(SIGPIPE, SIG_IGN);
hardware::configureRpcThreadpool(1 /* maxThreads */,
@@ -91,9 +91,7 @@
// Set uclamp.min setting on all threads, maybe an overkill but we want
// to cover important threads like RenderEngine.
- if (SurfaceFlinger::setSchedAttr(true) != NO_ERROR) {
- ALOGW("Failed to set uclamp.min during boot: %s", strerror(errno));
- }
+ SurfaceFlinger::setSchedAttr(true, __func__);
// The binder threadpool we start will inherit sched policy and priority
// of (this) creating thread. We want the binder thread pool to have
@@ -160,14 +158,8 @@
startDisplayService(); // dependency on SF getting registered above
- if (SurfaceFlinger::setSchedFifo(true) != NO_ERROR) {
- ALOGW("Failed to set SCHED_FIFO during boot: %s", strerror(errno));
- }
-
- // run surface flinger in this thread
+ SurfaceFlinger::setSchedFifo(true, __func__);
flinger->run();
-
- return 0;
}
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index 0ad5ac9..bfafb65 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -483,6 +483,16 @@
prop_name: "ro.surface_flinger.min_acquired_buffers"
}
+# Defines the maximum acquired buffers SurfaceFlinger will suggest via
+# ISurfaceComposer.getMaxAcquiredBufferCount().
+prop {
+ api_name: "max_acquired_buffers"
+ type: Long
+ scope: Public
+ access: Readonly
+ prop_name: "ro.surface_flinger.max_acquired_buffers"
+}
+
# When enabled, SurfaceFlinger will attempt to clear the per-layer HAL buffer cache slots for
# buffers when they are evicted from the app cache by using additional setLayerBuffer commands.
# Ideally, this behavior would always be enabled to reduce graphics memory consumption. However,
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
index 0017300..e2ac233 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
@@ -82,6 +82,11 @@
prop_name: "ro.surface_flinger.ignore_hdr_camera_layers"
}
prop {
+ api_name: "max_acquired_buffers"
+ type: Long
+ prop_name: "ro.surface_flinger.max_acquired_buffers"
+ }
+ prop {
api_name: "max_frame_buffer_acquired_buffers"
type: Long
prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers"
diff --git a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
index 7910e77..82390ac 100644
--- a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
+++ b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
@@ -265,9 +265,8 @@
transactions.back().states.front().state.what = layer_state_t::eInputInfoChanged;
transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.windowInfoHandle =
- sp<gui::WindowInfoHandle>::make();
- auto inputInfo = transactions.back().states.front().state.windowInfoHandle->editInfo();
+ auto inputInfo = transactions.back().states.front().state.editWindowInfo();
+ *inputInfo = {};
inputInfo->touchableRegion = region;
inputInfo->token = sp<BBinder>::make();
mLifecycleManager.applyTransactions(transactions);
@@ -280,9 +279,8 @@
transactions.back().states.front().state.what = layer_state_t::eInputInfoChanged;
transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.windowInfoHandle =
- sp<gui::WindowInfoHandle>::make();
- auto inputInfo = transactions.back().states.front().state.windowInfoHandle->editInfo();
+ auto inputInfo = transactions.back().states.front().state.editWindowInfo();
+ *inputInfo = {};
if (!inputInfo->token) {
inputInfo->token = sp<BBinder>::make();
}
@@ -299,9 +297,8 @@
transactions.back().states.front().state.what = layer_state_t::eInputInfoChanged;
transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.windowInfoHandle =
- sp<gui::WindowInfoHandle>::make();
- auto inputInfo = transactions.back().states.front().state.windowInfoHandle->editInfo();
+ auto inputInfo = transactions.back().states.front().state.editWindowInfo();
+ *inputInfo = {};
inputInfo->touchableRegion = region;
inputInfo->replaceTouchableRegionWithCrop = replaceTouchableRegionWithCrop;
transactions.back().states.front().touchCropId = touchCropId;
@@ -455,9 +452,8 @@
transactions.emplace_back();
transactions.back().states.push_back({});
- transactions.back().states.front().state.what = layer_state_t::eSurfaceDamageRegionChanged;
transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.surfaceDamageRegion = damageRegion;
+ transactions.back().states.front().state.updateSurfaceDamageRegion(damageRegion);
mLifecycleManager.applyTransactions(transactions);
}
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 9ece312..c342e1e 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -468,7 +468,7 @@
layer.externalTexture = buffer;
layer.bufferData->acquireFence = Fence::NO_FENCE;
layer.dataspace = ui::Dataspace::UNKNOWN;
- layer.surfaceDamageRegion = Region(Rect(LayerProperties::HEIGHT, LayerProperties::WIDTH));
+ layer.setSurfaceDamageRegion(Region(Rect(LayerProperties::HEIGHT, LayerProperties::WIDTH)));
Mock::VerifyAndClear(test->mRenderEngine);
}
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 7aad84b..3ed038b 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -1642,8 +1642,8 @@
transactions.back().states.push_back({});
transactions.back().states.front().state.what = layer_state_t::eInputInfoChanged;
transactions.back().states.front().layerId = 3;
- transactions.back().states.front().state.windowInfoHandle = sp<gui::WindowInfoHandle>::make();
- auto inputInfo = transactions.back().states.front().state.windowInfoHandle->editInfo();
+ auto inputInfo = transactions.back().states.front().state.editWindowInfo();
+ *inputInfo = {};
inputInfo->token = sp<BBinder>::make();
mLifecycleManager.applyTransactions(transactions);
@@ -1671,8 +1671,8 @@
transactions.back().states.push_back({});
transactions.back().states.front().state.what = layer_state_t::eInputInfoChanged;
transactions.back().states.front().layerId = 3;
- transactions.back().states.front().state.windowInfoHandle = sp<gui::WindowInfoHandle>::make();
- auto inputInfo = transactions.back().states.front().state.windowInfoHandle->editInfo();
+ auto inputInfo = transactions.back().states.front().state.editWindowInfo();
+ *inputInfo = {};
inputInfo->token = sp<BBinder>::make();
hideLayer(3);
mLifecycleManager.applyTransactions(transactions);
@@ -1879,9 +1879,6 @@
}
TEST_F(LayerSnapshotTest, edgeExtensionPropagatesInHierarchy) {
- if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
- GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
- }
setCrop(1, Rect(0, 0, 20, 20));
setBuffer(1221,
std::make_shared<renderengine::mock::FakeExternalTexture>(20 /* width */,
@@ -1920,9 +1917,6 @@
TEST_F(LayerSnapshotTest, leftEdgeExtensionIncreaseBoundSizeWithinCrop) {
// The left bound is extended when shifting to the right
- if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
- GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
- }
setCrop(1, Rect(0, 0, 20, 20));
const int texSize = 10;
setBuffer(1221,
@@ -1942,9 +1936,6 @@
TEST_F(LayerSnapshotTest, rightEdgeExtensionIncreaseBoundSizeWithinCrop) {
// The right bound is extended when shifting to the left
- if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
- GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
- }
const int crop = 20;
setCrop(1, Rect(0, 0, crop, crop));
const int texSize = 10;
@@ -1965,9 +1956,6 @@
TEST_F(LayerSnapshotTest, topEdgeExtensionIncreaseBoundSizeWithinCrop) {
// The top bound is extended when shifting to the bottom
- if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
- GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
- }
setCrop(1, Rect(0, 0, 20, 20));
const int texSize = 10;
setBuffer(1221,
@@ -1987,9 +1975,6 @@
TEST_F(LayerSnapshotTest, bottomEdgeExtensionIncreaseBoundSizeWithinCrop) {
// The bottom bound is extended when shifting to the top
- if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
- GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
- }
const int crop = 20;
setCrop(1, Rect(0, 0, crop, crop));
const int texSize = 10;
@@ -2010,9 +1995,6 @@
TEST_F(LayerSnapshotTest, multipleEdgeExtensionIncreaseBoundSizeWithinCrop) {
// The left bound is extended when shifting to the right
- if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
- GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
- }
const int crop = 20;
setCrop(1, Rect(0, 0, crop, crop));
const int texSize = 10;
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 1fc874d..49c35e2 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -143,7 +143,7 @@
kDisplay1Mode60->getId()));
// TODO(b/241285191): Restore once VsyncSchedule::getPendingHardwareVsyncState is called by
- // Scheduler::setDisplayPowerMode rather than SF::setPowerModeInternal.
+ // Scheduler::setDisplayPowerMode rather than SF::setPhysicalDisplayPowerMode.
#if 0
// Hardware VSYNC should be disabled for newly registered displays.
EXPECT_CALL(mSchedulerCallback, requestHardwareVsync(kDisplayId2, false)).Times(1);
@@ -254,18 +254,43 @@
}
TEST_F(SchedulerTest, calculateMaxAcquiredBufferCount) {
- EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 30ms));
- EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(90_Hz, 30ms));
- EXPECT_EQ(3, mFlinger.calculateMaxAcquiredBufferCount(120_Hz, 30ms));
+ struct TestCase {
+ Fps refreshRate;
+ std::chrono::nanoseconds presentLatency;
+ int expectedBufferCount;
+ };
- EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 40ms));
+ const auto verifyTestCases = [&](std::vector<TestCase> tests) {
+ for (const auto testCase : tests) {
+ EXPECT_EQ(testCase.expectedBufferCount,
+ mFlinger.calculateMaxAcquiredBufferCount(testCase.refreshRate,
+ testCase.presentLatency));
+ }
+ };
- EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 10ms));
+ std::vector<TestCase> testCases{{60_Hz, 30ms, 1},
+ {90_Hz, 30ms, 2},
+ {120_Hz, 30ms, 3},
+ {60_Hz, 40ms, 2},
+ {60_Hz, 10ms, 1}};
+ verifyTestCases(testCases);
const auto savedMinAcquiredBuffers = mFlinger.mutableMinAcquiredBuffers();
mFlinger.mutableMinAcquiredBuffers() = 2;
- EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 10ms));
+ verifyTestCases({{60_Hz, 10ms, 2}});
mFlinger.mutableMinAcquiredBuffers() = savedMinAcquiredBuffers;
+
+ const auto savedMaxAcquiredBuffers = mFlinger.mutableMaxAcquiredBuffers();
+ mFlinger.mutableMaxAcquiredBuffers() = 2;
+ testCases = {{60_Hz, 30ms, 1},
+ {90_Hz, 30ms, 2},
+ {120_Hz, 30ms, 2}, // max buffers allowed is 2
+ {60_Hz, 40ms, 2},
+ {60_Hz, 10ms, 1}};
+ verifyTestCases(testCases);
+ mFlinger.mutableMaxAcquiredBuffers() = 3; // max buffers allowed is 3
+ verifyTestCases({{120_Hz, 30ms, 3}});
+ mFlinger.mutableMaxAcquiredBuffers() = savedMaxAcquiredBuffers;
}
MATCHER(Is120Hz, "") {
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
index aadff76..aa5b786 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
@@ -141,7 +141,11 @@
// --------------------------------------------------------------------
// Invocation
- sp<IBinder> displayToken = mFlinger.createVirtualDisplay(kDisplayName, false, kUniqueId);
+ sp<IBinder> displayToken =
+ mFlinger.createVirtualDisplay(kDisplayName, false,
+ gui::ISurfaceComposer::OptimizationPolicy::
+ optimizeForPower,
+ kUniqueId);
// --------------------------------------------------------------------
// Postconditions
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
index 62f1a52..3f710fd 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
@@ -407,8 +407,6 @@
}
TEST_F(DisplayModeSwitchingTest, innerXorOuterDisplay) {
- SET_FLAG_FOR_TEST(flags::connected_display, true);
-
const auto [innerDisplay, outerDisplay] = injectOuterDisplay();
EXPECT_TRUE(innerDisplay->isPoweredOn());
@@ -417,8 +415,8 @@
EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60));
EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120));
- mFlinger.setPowerModeInternal(outerDisplay, hal::PowerMode::OFF);
- mFlinger.setPowerModeInternal(innerDisplay, hal::PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(outerDisplay, hal::PowerMode::OFF);
+ mFlinger.setPhysicalDisplayPowerMode(innerDisplay, hal::PowerMode::ON);
EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60));
EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120));
@@ -448,8 +446,8 @@
EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId90));
EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId60));
- mFlinger.setPowerModeInternal(innerDisplay, hal::PowerMode::OFF);
- mFlinger.setPowerModeInternal(outerDisplay, hal::PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(innerDisplay, hal::PowerMode::OFF);
+ mFlinger.setPhysicalDisplayPowerMode(outerDisplay, hal::PowerMode::ON);
EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId90));
EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId60));
@@ -473,8 +471,6 @@
}
TEST_F(DisplayModeSwitchingTest, innerAndOuterDisplay) {
- SET_FLAG_FOR_TEST(flags::connected_display, true);
-
const auto [innerDisplay, outerDisplay] = injectOuterDisplay();
EXPECT_TRUE(innerDisplay->isPoweredOn());
@@ -483,8 +479,8 @@
EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60));
EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120));
- mFlinger.setPowerModeInternal(innerDisplay, hal::PowerMode::ON);
- mFlinger.setPowerModeInternal(outerDisplay, hal::PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(innerDisplay, hal::PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(outerDisplay, hal::PowerMode::ON);
EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60));
EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120));
@@ -526,7 +522,7 @@
EXPECT_THAT(mDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
// Power off the display before the mode has been set.
- mFlinger.setPowerModeInternal(mDisplay, hal::PowerMode::OFF);
+ mFlinger.setPhysicalDisplayPowerMode(mDisplay, hal::PowerMode::OFF);
const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
EXPECT_SET_ACTIVE_CONFIG(kInnerDisplayHwcId, kModeId90);
@@ -543,8 +539,6 @@
}
TEST_F(DisplayModeSwitchingTest, powerOffDuringConcurrentModeSet) {
- SET_FLAG_FOR_TEST(flags::connected_display, true);
-
const auto [innerDisplay, outerDisplay] = injectOuterDisplay();
EXPECT_TRUE(innerDisplay->isPoweredOn());
@@ -553,8 +547,8 @@
EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60));
EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120));
- mFlinger.setPowerModeInternal(innerDisplay, hal::PowerMode::ON);
- mFlinger.setPowerModeInternal(outerDisplay, hal::PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(innerDisplay, hal::PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(outerDisplay, hal::PowerMode::ON);
EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60));
EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120));
@@ -571,7 +565,7 @@
EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
// Power off the outer display before the mode has been set.
- mFlinger.setPowerModeInternal(outerDisplay, hal::PowerMode::OFF);
+ mFlinger.setPhysicalDisplayPowerMode(outerDisplay, hal::PowerMode::OFF);
const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
EXPECT_SET_ACTIVE_CONFIG(kInnerDisplayHwcId, kModeId90);
@@ -588,8 +582,8 @@
EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId90));
EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId60));
- mFlinger.setPowerModeInternal(innerDisplay, hal::PowerMode::OFF);
- mFlinger.setPowerModeInternal(outerDisplay, hal::PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(innerDisplay, hal::PowerMode::OFF);
+ mFlinger.setPhysicalDisplayPowerMode(outerDisplay, hal::PowerMode::ON);
EXPECT_EQ(NO_ERROR,
mFlinger.setDesiredDisplayModeSpecs(outerDisplay->getDisplayToken().promote(),
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp
index 19f8deb..fde2749 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp
@@ -38,30 +38,30 @@
ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
// ...and should still be after powering on.
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
}
TEST_F(FoldableTest, promotesPacesetterOnFoldUnfold) {
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
// The outer display should become the pacesetter after folding.
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::OFF);
- mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::OFF);
+ mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON);
ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId);
// The inner display should become the pacesetter after unfolding.
- mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::OFF);
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::OFF);
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
}
TEST_F(FoldableTest, promotesPacesetterOnConcurrentPowerOn) {
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
// The inner display should stay the pacesetter if both are powered on.
// TODO(b/255635821): The pacesetter should depend on the displays' refresh rates.
- mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON);
ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
// The outer display should become the pacesetter if designated.
@@ -74,20 +74,20 @@
}
TEST_F(FoldableTest, promotesPacesetterOnConcurrentPowerOff) {
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
- mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON);
// The outer display should become the pacesetter if the inner display powers off.
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::OFF);
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::OFF);
ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId);
// The outer display should stay the pacesetter if both are powered on.
// TODO(b/255635821): The pacesetter should depend on the displays' refresh rates.
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId);
// The inner display should become the pacesetter if the outer display powers off.
- mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::OFF);
+ mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::OFF);
ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
}
@@ -114,8 +114,8 @@
.Times(0);
// The injected VsyncSchedule uses TestableScheduler::mockRequestHardwareVsync, so no calls to
- // ISchedulerCallback::requestHardwareVsync are expected during setPowerModeInternal.
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
+ // ISchedulerCallback::requestHardwareVsync are expected during setPhysicalDisplayPowerMode.
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
EXPECT_TRUE(mInnerDisplay->isPoweredOn());
EXPECT_FALSE(mOuterDisplay->isPoweredOn());
@@ -133,10 +133,10 @@
.Times(1);
// The injected VsyncSchedule uses TestableScheduler::mockRequestHardwareVsync, so no calls to
- // ISchedulerCallback::requestHardwareVsync are expected during setPowerModeInternal.
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::OFF);
- mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
+ // ISchedulerCallback::requestHardwareVsync are expected during setPhysicalDisplayPowerMode.
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::OFF);
+ mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON);
EXPECT_FALSE(mInnerDisplay->isPoweredOn());
EXPECT_TRUE(mOuterDisplay->isPoweredOn());
@@ -154,9 +154,9 @@
.Times(1);
// The injected VsyncSchedule uses TestableScheduler::mockRequestHardwareVsync, so no calls to
- // ISchedulerCallback::requestHardwareVsync are expected during setPowerModeInternal.
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
- mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
+ // ISchedulerCallback::requestHardwareVsync are expected during setPhysicalDisplayPowerMode.
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON);
EXPECT_TRUE(mInnerDisplay->isPoweredOn());
EXPECT_TRUE(mOuterDisplay->isPoweredOn());
@@ -173,8 +173,8 @@
EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kOuterDisplayId, true))
.Times(1);
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
- mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON);
}
TEST_F(FoldableTest, disableVsyncOnPowerOffPacesetter) {
@@ -192,10 +192,10 @@
EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kInnerDisplayId, false))
.Times(1);
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
- mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON);
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::OFF);
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::OFF);
// Other display is now the pacesetter.
ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp
index b0cda0f..49972b0 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp
@@ -224,8 +224,6 @@
}
TEST_F(HotplugTest, rejectsHotplugIfFailedToLoadDisplayModes) {
- SET_FLAG_FOR_TEST(flags::connected_display, true);
-
// Inject a primary display.
PrimaryDisplayVariant::injectHwcDisplay(this);
@@ -263,8 +261,6 @@
}
TEST_F(HotplugTest, rejectsHotplugOnActivePortsDuplicate) {
- SET_FLAG_FOR_TEST(flags::connected_display, true);
-
// Inject a primary display.
PrimaryDisplayVariant::injectHwcDisplay(this);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPhysicalDisplayPowerModeTest.cpp
similarity index 88%
rename from services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
rename to services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPhysicalDisplayPowerModeTest.cpp
index fed7b2e..f2fbbdd 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPhysicalDisplayPowerModeTest.cpp
@@ -315,7 +315,7 @@
EventThreadNotSupportedVariant, DispSyncNotSupportedVariant,
TransitionVariant>;
-class SetPowerModeInternalTest : public DisplayTransactionTest {
+class SetPhysicalDisplayPowerModeTest : public DisplayTransactionTest {
public:
template <typename Case>
void transitionDisplayCommon();
@@ -331,7 +331,7 @@
struct PowerModeInitialVSyncEnabled<PowerMode::DOZE> : public std::true_type {};
template <typename Case>
-void SetPowerModeInternalTest::transitionDisplayCommon() {
+void SetPhysicalDisplayPowerModeTest::transitionDisplayCommon() {
// --------------------------------------------------------------------
// Preconditions
@@ -353,7 +353,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.setPowerModeInternal(display, Case::Transition::TARGET_POWER_MODE);
+ mFlinger.setPhysicalDisplayPowerMode(display, Case::Transition::TARGET_POWER_MODE);
// --------------------------------------------------------------------
// Postconditions
@@ -361,7 +361,7 @@
Case::Transition::verifyPostconditions(this);
}
-TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfNoChange) {
+TEST_F(SetPhysicalDisplayPowerModeTest, setPhysicalDisplayPowerModeDoesNothingIfNoChange) {
using Case = SimplePrimaryDisplayCase;
// --------------------------------------------------------------------
@@ -378,7 +378,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(display.mutableDisplayDevice(), PowerMode::ON);
// --------------------------------------------------------------------
// Postconditions
@@ -386,7 +386,7 @@
EXPECT_EQ(PowerMode::ON, display.mutableDisplayDevice()->getPowerMode());
}
-TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfVirtualDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, setPhysicalDisplayPowerModeDoesNothingIfVirtualDisplay) {
using Case = HwcVirtualDisplayCase;
// --------------------------------------------------------------------
@@ -408,7 +408,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), PowerMode::OFF);
+ mFlinger.setPhysicalDisplayPowerMode(display.mutableDisplayDevice(), PowerMode::OFF);
// --------------------------------------------------------------------
// Postconditions
@@ -416,88 +416,88 @@
EXPECT_EQ(PowerMode::ON, display.mutableDisplayDevice()->getPowerMode());
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToOnPrimaryDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOffToOnPrimaryDisplay) {
transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOffToOnVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToDozeSuspendPrimaryDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOffToDozeSuspendPrimaryDisplay) {
transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOffToDozeSuspendVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToOffPrimaryDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOnToOffPrimaryDisplay) {
transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToOffVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOffPrimaryDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromDozeSuspendToOffPrimaryDisplay) {
transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeSuspendToOffVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozePrimaryDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOnToDozePrimaryDisplay) {
transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToDozeVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToDozePrimaryDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromDozeSuspendToDozePrimaryDisplay) {
transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeSuspendToDozeVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeToOnPrimaryDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromDozeToOnPrimaryDisplay) {
transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeToOnVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOnPrimaryDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromDozeSuspendToOnPrimaryDisplay) {
transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeSuspendToOnVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeSuspendPrimaryDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOnToDozeSuspendPrimaryDisplay) {
transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToDozeSuspendVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToUnknownPrimaryDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOnToUnknownPrimaryDisplay) {
transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToUnknownVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToOnExternalDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOffToOnExternalDisplay) {
SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOffToOnVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToDozeSuspendExternalDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOffToDozeSuspendExternalDisplay) {
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOffToDozeSuspendVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToOffExternalDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOnToOffExternalDisplay) {
SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToOffVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOffExternalDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromDozeSuspendToOffExternalDisplay) {
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToOffVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeExternalDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOnToDozeExternalDisplay) {
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToDozeVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToDozeExternalDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromDozeSuspendToDozeExternalDisplay) {
SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToDozeVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeToOnExternalDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromDozeToOnExternalDisplay) {
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeToOnVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOnExternalDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromDozeSuspendToOnExternalDisplay) {
SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToOnVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeSuspendExternalDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOnToDozeSuspendExternalDisplay) {
SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToDozeSuspendVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToUnknownExternalDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOnToUnknownExternalDisplay) {
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToUnknownVariant>>();
}
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 8084450..a3ee08f 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -399,12 +399,16 @@
float requestedRefreshRate = 0.0f) {
static const std::string kTestId =
"virtual:libsurfaceflinger_unittest:TestableSurfaceFlinger";
- return mFlinger->createVirtualDisplay(displayName, isSecure, kTestId, requestedRefreshRate);
+ return mFlinger
+ ->createVirtualDisplay(displayName, isSecure,
+ gui::ISurfaceComposer::OptimizationPolicy::optimizeForPower,
+ kTestId, requestedRefreshRate);
}
auto createVirtualDisplay(const std::string& displayName, bool isSecure,
+ gui::ISurfaceComposer::OptimizationPolicy optimizationPolicy,
const std::string& uniqueId, float requestedRefreshRate = 0.0f) {
- return mFlinger->createVirtualDisplay(displayName, isSecure, uniqueId,
+ return mFlinger->createVirtualDisplay(displayName, isSecure, optimizationPolicy, uniqueId,
requestedRefreshRate);
}
@@ -458,9 +462,9 @@
}
// Allow reading display state without locking, as if called on the SF main thread.
- auto setPowerModeInternal(const sp<DisplayDevice>& display,
- hal::PowerMode mode) NO_THREAD_SAFETY_ANALYSIS {
- return mFlinger->setPowerModeInternal(display, mode);
+ auto setPhysicalDisplayPowerMode(const sp<DisplayDevice>& display,
+ hal::PowerMode mode) NO_THREAD_SAFETY_ANALYSIS {
+ return mFlinger->setPhysicalDisplayPowerMode(display, mode);
}
auto renderScreenImpl(const sp<DisplayDevice> display, const Rect sourceCrop,
@@ -716,6 +720,7 @@
}
auto& mutableMinAcquiredBuffers() { return SurfaceFlinger::minAcquiredBuffers; }
+ auto& mutableMaxAcquiredBuffers() { return SurfaceFlinger::maxAcquiredBuffersOpt; }
auto& mutableLayerSnapshotBuilder() NO_THREAD_SAFETY_ANALYSIS {
return mFlinger->mLayerSnapshotBuilder;
}
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index a221d5e..ccf6a9c 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -444,40 +444,8 @@
}
}
-TEST_F(VSyncPredictorTest, doesNotPredictBeforeTimePointWithHigherIntercept_withPredictorRecovery) {
- SET_FLAG_FOR_TEST(flags::vsync_predictor_recovery, true);
- std::vector<nsecs_t> const simulatedVsyncs{
- 158929578733000,
- 158929306806205, // oldest TS in ringbuffer
- 158929650879052,
- 158929661969209,
- 158929684198847,
- 158929695268171,
- 158929706370359,
- };
- auto const idealPeriod = 11111111;
- auto const expectedPeriod = 11079563;
- auto const expectedIntercept = 1335662;
-
- tracker.setDisplayModePtr(displayMode(idealPeriod));
- for (auto const& timestamp : simulatedVsyncs) {
- tracker.addVsyncTimestamp(timestamp);
- }
-
- auto [slope, intercept] = tracker.getVSyncPredictionModel();
- EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
- EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
-
- // (timePoint - oldestTS) % expectedPeriod works out to be: 894272
- // (timePoint - oldestTS) / expectedPeriod works out to be: 38.08
- auto const timePoint = 158929728723871;
- auto const prediction = tracker.nextAnticipatedVSyncTimeFrom(timePoint);
- EXPECT_THAT(prediction, Ge(timePoint));
-}
-
// See b/145667109, and comment in prod code under test.
TEST_F(VSyncPredictorTest, doesNotPredictBeforeTimePointWithHigherIntercept) {
- SET_FLAG_FOR_TEST(flags::vsync_predictor_recovery, false);
std::vector<nsecs_t> const simulatedVsyncs{
158929578733000,
158929306806205, // oldest TS in ringbuffer