Merge "Rewrite concurrency logic in SurfaceFlinger PowerAdvisor" into main
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index e14af77..c8ab8c0 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -40,6 +40,7 @@
#include <fstream>
#include <functional>
#include <regex>
+#include <thread>
#include <unordered_set>
#include <android-base/file.h>
@@ -555,19 +556,33 @@
// If the initial top-level restorecon above changed the label, then go
// back and restorecon everything recursively
if (inProgress || before != after) {
- ScopedTrace tracer("label-change");
if (existing) {
LOG(DEBUG) << "Detected label change from " << before << " to " << after << " at "
- << path << "; running recursive restorecon";
+ << path << "; running recursive restorecon";
}
- // Temporary mark the folder as "in-progress" to resume in case of reboot/other failure.
- RestoreconInProgress fence(path);
+ auto restorecon = [path, seInfo, uid]() {
+ ScopedTrace tracer("label-change");
- if (selinux_android_restorecon_pkgdir(path.c_str(), seInfo.c_str(), uid,
- SELINUX_ANDROID_RESTORECON_RECURSE) < 0) {
- PLOG(ERROR) << "Failed recursive restorecon for " << path;
- return -1;
+ // Temporary mark the folder as "in-progress" to resume in case of reboot/other failure.
+ RestoreconInProgress fence(path);
+
+ if (selinux_android_restorecon_pkgdir(path.c_str(), seInfo.c_str(), uid,
+ SELINUX_ANDROID_RESTORECON_RECURSE) < 0) {
+ PLOG(ERROR) << "Failed recursive restorecon for " << path;
+ return -1;
+ }
+ return 0;
+ };
+ if (inProgress) {
+ // The previous restorecon was interrupted. It's either crashed (unlikely), or the phone
+ // was rebooted. Possibly because it took too much time. This time let's move it to a
+ // separate thread - so it won't block the rest of the OS.
+ std::thread(restorecon).detach();
+ } else {
+ if (int result = restorecon(); result) {
+ return result;
+ }
}
}
diff --git a/cmds/lshal/Timeout.h b/cmds/lshal/Timeout.h
index e8d22d9..012a5d5 100644
--- a/cmds/lshal/Timeout.h
+++ b/cmds/lshal/Timeout.h
@@ -72,10 +72,14 @@
return false;
}
bool success = state.wait(now + delay);
- if (!success) {
- pthread_kill(thread, SIGINT);
+ if (success) {
+ pthread_join(thread, nullptr);
+ } else {
+ // b/311143089: Abandon this background thread. Resources for a detached
+ // thread are cleaned up when it is terminated. If the background thread
+ // is stalled, it will be terminated when returning from main().
+ pthread_detach(thread);
}
- pthread_join(thread, nullptr);
return success;
}
diff --git a/cmds/lshal/main.cpp b/cmds/lshal/main.cpp
index 366c938..a44f467 100644
--- a/cmds/lshal/main.cpp
+++ b/cmds/lshal/main.cpp
@@ -18,5 +18,6 @@
int main(int argc, char **argv) {
using namespace ::android::lshal;
+ // Background pthreads from timeout() are destroyed upon returning from main().
return Lshal{}.main(Arg{argc, argv});
}
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index d73c3a4..11e8120 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -579,11 +579,6 @@
],
}
-filegroup {
- name: "libbinder_rpc_unstable_header",
- srcs: ["include_rpc_unstable/binder_rpc_unstable.hpp"],
-}
-
// libbinder historically contained additional interfaces that provided specific
// functionality in the platform but have nothing to do with binder itself. These
// are moved out of libbinder in order to avoid the overhead of their vtables.
diff --git a/libs/binder/OS_android.cpp b/libs/binder/OS_android.cpp
index 155588d..1eace85 100644
--- a/libs/binder/OS_android.cpp
+++ b/libs/binder/OS_android.cpp
@@ -20,7 +20,8 @@
#include <cutils/trace.h>
#include <utils/misc.h>
-namespace android::binder::os {
+namespace android::binder {
+namespace os {
uint64_t GetThreadId() {
#ifdef BINDER_RPC_SINGLE_THREADED
@@ -43,4 +44,16 @@
atrace_end(tag);
}
-} // namespace android::binder::os
+} // namespace os
+
+// Legacy trace symbol. To be removed once all of downstream rebuilds.
+void atrace_begin(uint64_t tag, const char* name) {
+ os::trace_begin(tag, name);
+}
+
+// Legacy trace symbol. To be removed once all of downstream rebuilds.
+void atrace_end(uint64_t tag) {
+ os::trace_end(tag);
+}
+
+} // namespace android::binder
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 47b9f58..ccf3ce8 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -139,6 +139,7 @@
"performance*",
"portability*",
],
+ afdo: true,
}
cc_library_headers {
diff --git a/libs/binder/rust/rpcbinder/Android.bp b/libs/binder/rust/rpcbinder/Android.bp
index 788abc4..535ce01 100644
--- a/libs/binder/rust/rpcbinder/Android.bp
+++ b/libs/binder/rust/rpcbinder/Android.bp
@@ -70,7 +70,7 @@
// TODO(b/184872979): remove once the RPC Binder API is stabilised.
rust_bindgen {
name: "libbinder_rpc_unstable_bindgen",
- wrapper_src: ":libbinder_rpc_unstable_header",
+ wrapper_src: "BinderBindings.hpp",
crate_name: "binder_rpc_unstable_bindgen",
visibility: [":__subpackages__"],
source_stem: "bindings",
diff --git a/libs/binder/rust/rpcbinder/BinderBindings.hpp b/libs/binder/rust/rpcbinder/BinderBindings.hpp
new file mode 100644
index 0000000..7feb965
--- /dev/null
+++ b/libs/binder/rust/rpcbinder/BinderBindings.hpp
@@ -0,0 +1 @@
+#include <binder_rpc_unstable.hpp>
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 6d122c5..e34d31e 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -30,8 +30,8 @@
use std::io::Write;
use std::marker::PhantomData;
use std::ops::Deref;
+use std::os::fd::AsRawFd;
use std::os::raw::c_char;
-use std::os::unix::io::AsRawFd;
use std::ptr;
/// Binder action to perform.
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index ed870b6..7f9348d 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -100,6 +100,7 @@
mod native;
mod parcel;
mod proxy;
+#[cfg(not(target_os = "trusty"))]
mod state;
use binder_ndk_sys as sys;
@@ -116,6 +117,7 @@
get_declared_instances, get_interface, get_service, is_declared, wait_for_interface,
wait_for_service, DeathRecipient, SpIBinder, WpIBinder,
};
+#[cfg(not(target_os = "trusty"))]
pub use state::{ProcessState, ThreadState};
/// Binder result containing a [`Status`] on error.
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index b250012..8ae010e 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -24,13 +24,10 @@
use std::convert::TryFrom;
use std::ffi::{c_void, CStr, CString};
-use std::fs::File;
use std::io::Write;
use std::mem::ManuallyDrop;
use std::ops::Deref;
use std::os::raw::c_char;
-use std::os::unix::io::FromRawFd;
-use std::slice;
use std::sync::Mutex;
/// Rust wrapper around Binder remotable objects.
@@ -331,6 +328,7 @@
/// contains a `T` pointer in its user data. fd should be a non-owned file
/// descriptor, and args must be an array of null-terminated string
/// pointers with length num_args.
+ #[cfg(not(target_os = "trusty"))]
unsafe extern "C" fn on_dump(
binder: *mut sys::AIBinder,
fd: i32,
@@ -340,9 +338,10 @@
if fd < 0 {
return StatusCode::UNEXPECTED_NULL as status_t;
}
+ use std::os::fd::FromRawFd;
// Safety: Our caller promised that fd is a file descriptor. We don't
// own this file descriptor, so we need to be careful not to drop it.
- let mut file = unsafe { ManuallyDrop::new(File::from_raw_fd(fd)) };
+ let mut file = unsafe { ManuallyDrop::new(std::fs::File::from_raw_fd(fd)) };
if args.is_null() && num_args != 0 {
return StatusCode::UNEXPECTED_NULL as status_t;
@@ -354,7 +353,7 @@
// Safety: Our caller promised that `args` is an array of
// null-terminated string pointers with length `num_args`.
unsafe {
- slice::from_raw_parts(args, num_args as usize)
+ std::slice::from_raw_parts(args, num_args as usize)
.iter()
.map(|s| CStr::from_ptr(*s))
.collect()
@@ -374,6 +373,19 @@
Err(e) => e as status_t,
}
}
+
+ /// Called to handle the `dump` transaction.
+ #[cfg(target_os = "trusty")]
+ unsafe extern "C" fn on_dump(
+ _binder: *mut sys::AIBinder,
+ _fd: i32,
+ _args: *mut *const c_char,
+ _num_args: u32,
+ ) -> status_t {
+ // This operation is not supported on Trusty right now
+ // because we do not have a uniform way of writing to handles
+ StatusCode::INVALID_OPERATION as status_t
+ }
}
impl<T: Remotable> Drop for Binder<T> {
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index dad3379..7434e9d 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -32,8 +32,8 @@
use std::ffi::{c_void, CStr, CString};
use std::fmt;
use std::mem;
+use std::os::fd::AsRawFd;
use std::os::raw::c_char;
-use std::os::unix::io::AsRawFd;
use std::ptr;
use std::sync::Arc;
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index ba8fb39..e4d4de8 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -134,6 +134,10 @@
"IBinderRpcTest.aidl",
"ParcelableCertificateData.aidl",
],
+ flags: [
+ "-Werror",
+ "-Wno-mixed-oneway",
+ ],
backend: {
java: {
enabled: false,
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index fe79f8e..83db6c9 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -16,6 +16,9 @@
"parcelables/SingleDataParcelable.aidl",
"parcelables/GenericDataParcelable.aidl",
],
+ flags: [
+ "-Werror",
+ ],
backend: {
java: {
enabled: true,
diff --git a/libs/binder/tests/parcel_fuzzer/parcelables/GenericDataParcelable.aidl b/libs/binder/tests/parcel_fuzzer/parcelables/GenericDataParcelable.aidl
index dd08f72..9884dbb 100644
--- a/libs/binder/tests/parcel_fuzzer/parcelables/GenericDataParcelable.aidl
+++ b/libs/binder/tests/parcel_fuzzer/parcelables/GenericDataParcelable.aidl
@@ -17,7 +17,7 @@
parcelable GenericDataParcelable {
enum JustSomeEnum {
- SOME_ENUMERATOR,
+ ONE_ENUMERATOR,
ANOTHER_ENUMERATOR,
MAYBE_ONE_MORE_ENUMERATOR,
}
diff --git a/libs/binder/trusty/rust/rules.mk b/libs/binder/trusty/rust/rules.mk
new file mode 100644
index 0000000..be90df3
--- /dev/null
+++ b/libs/binder/trusty/rust/rules.mk
@@ -0,0 +1,37 @@
+# Copyright (C) 2023 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.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+LIBBINDER_DIR := $(LOCAL_DIR)/../..
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS := $(LIBBINDER_DIR)/rust/src/lib.rs
+
+MODULE_CRATE_NAME := binder
+
+MODULE_LIBRARY_DEPS += \
+ $(LIBBINDER_DIR)/trusty \
+ $(LIBBINDER_DIR)/trusty/ndk \
+ $(LIBBINDER_DIR)/trusty/rust/binder_ndk_sys \
+ external/rust/crates/downcast-rs \
+ trusty/user/base/lib/trusty-sys \
+
+# Trusty does not have `ProcessState`, so there are a few
+# doc links in `IBinder` that are still broken.
+MODULE_RUSTFLAGS += \
+ --allow rustdoc::broken-intra-doc-links \
+
+include make/library.mk
diff --git a/libs/gui/include/gui/view/Surface.h b/libs/gui/include/gui/view/Surface.h
index f7dcbc6..b7aba2b 100644
--- a/libs/gui/include/gui/view/Surface.h
+++ b/libs/gui/include/gui/view/Surface.h
@@ -24,9 +24,9 @@
#include <binder/IBinder.h>
#include <binder/Parcelable.h>
-namespace android {
+#include <gui/IGraphicBufferProducer.h>
-class IGraphicBufferProducer;
+namespace android {
namespace view {
diff --git a/libs/gui/view/Surface.cpp b/libs/gui/view/Surface.cpp
index 198908d..7c15e7c 100644
--- a/libs/gui/view/Surface.cpp
+++ b/libs/gui/view/Surface.cpp
@@ -20,7 +20,6 @@
#include <android/binder_parcel.h>
#include <android/native_window.h>
#include <binder/Parcel.h>
-#include <gui/IGraphicBufferProducer.h>
#include <gui/Surface.h>
#include <gui/view/Surface.h>
#include <system/window.h>
diff --git a/libs/renderengine/skia/AutoBackendTexture.cpp b/libs/renderengine/skia/AutoBackendTexture.cpp
index cd1ac2b..92fe4c0 100644
--- a/libs/renderengine/skia/AutoBackendTexture.cpp
+++ b/libs/renderengine/skia/AutoBackendTexture.cpp
@@ -132,8 +132,8 @@
"\n\tGrBackendTexture: (%i x %i) hasMipmaps: %i isProtected: %i "
"texType: %i\n\t\tGrGLTextureInfo: success: %i fTarget: %u fFormat: %u"
" colorType %i",
- msg, tex.isValid(), dataspace, tex.width(), tex.height(),
- tex.hasMipmaps(), tex.isProtected(),
+ msg, tex.isValid(), static_cast<int32_t>(dataspace), tex.width(),
+ tex.height(), tex.hasMipmaps(), tex.isProtected(),
static_cast<int>(tex.textureType()), retrievedTextureInfo,
textureInfo.fTarget, textureInfo.fFormat, colorType);
break;
diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
index b6274ab..03ff58a 100644
--- a/libs/ui/Gralloc4.cpp
+++ b/libs/ui/Gralloc4.cpp
@@ -468,8 +468,8 @@
uint32_t layerCount, uint64_t usage,
bool* outSupported) const {
IMapper::BufferDescriptorInfo descriptorInfo;
- if (auto error = sBufferDescriptorInfo("isSupported", width, height, format, layerCount, usage,
- &descriptorInfo) != OK) {
+ if (sBufferDescriptorInfo("isSupported", width, height, format, layerCount, usage,
+ &descriptorInfo) != OK) {
// Usage isn't known to the HAL or otherwise failed validation.
*outSupported = false;
return OK;
diff --git a/services/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp
index f1faf69..07a5041 100644
--- a/services/inputflinger/PointerChoreographer.cpp
+++ b/services/inputflinger/PointerChoreographer.cpp
@@ -445,6 +445,59 @@
updatePointerControllersLocked();
}
+bool PointerChoreographer::setPointerIcon(
+ std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon, int32_t displayId,
+ DeviceId deviceId) {
+ std::scoped_lock _l(mLock);
+ if (deviceId < 0) {
+ LOG(WARNING) << "Invalid device id " << deviceId << ". Cannot set pointer icon.";
+ return false;
+ }
+ const InputDeviceInfo* info = findInputDeviceLocked(deviceId);
+ if (!info) {
+ LOG(WARNING) << "No input device info found for id " << deviceId
+ << ". Cannot set pointer icon.";
+ return false;
+ }
+ const uint32_t sources = info->getSources();
+ const auto stylusPointerIt = mStylusPointersByDevice.find(deviceId);
+
+ if (isFromSource(sources, AINPUT_SOURCE_STYLUS) &&
+ stylusPointerIt != mStylusPointersByDevice.end()) {
+ if (std::holds_alternative<std::unique_ptr<SpriteIcon>>(icon)) {
+ if (std::get<std::unique_ptr<SpriteIcon>>(icon) == nullptr) {
+ LOG(FATAL) << "SpriteIcon should not be null";
+ }
+ stylusPointerIt->second->setCustomPointerIcon(
+ *std::get<std::unique_ptr<SpriteIcon>>(icon));
+ } else {
+ stylusPointerIt->second->updatePointerIcon(std::get<PointerIconStyle>(icon));
+ }
+ } else if (isFromSource(sources, AINPUT_SOURCE_MOUSE)) {
+ if (const auto mousePointerIt = mMousePointersByDisplay.find(displayId);
+ mousePointerIt != mMousePointersByDisplay.end()) {
+ if (std::holds_alternative<std::unique_ptr<SpriteIcon>>(icon)) {
+ if (std::get<std::unique_ptr<SpriteIcon>>(icon) == nullptr) {
+ LOG(FATAL) << "SpriteIcon should not be null";
+ }
+ mousePointerIt->second->setCustomPointerIcon(
+ *std::get<std::unique_ptr<SpriteIcon>>(icon));
+ } else {
+ mousePointerIt->second->updatePointerIcon(std::get<PointerIconStyle>(icon));
+ }
+ } else {
+ LOG(WARNING) << "No mouse pointer controller found for display " << displayId
+ << ", device " << deviceId << ".";
+ return false;
+ }
+ } else {
+ LOG(WARNING) << "Cannot set pointer icon for display " << displayId << ", device "
+ << deviceId << ".";
+ return false;
+ }
+ return true;
+}
+
PointerChoreographer::ControllerConstructor PointerChoreographer::getMouseControllerConstructor(
int32_t displayId) {
std::function<std::shared_ptr<PointerControllerInterface>()> ctor =
diff --git a/services/inputflinger/PointerChoreographer.h b/services/inputflinger/PointerChoreographer.h
index 90a0d3f..9b809a1 100644
--- a/services/inputflinger/PointerChoreographer.h
+++ b/services/inputflinger/PointerChoreographer.h
@@ -25,6 +25,8 @@
namespace android {
+struct SpriteIcon;
+
/**
* A helper class that wraps a factory method that acts as a constructor for the type returned
* by the factory method.
@@ -59,6 +61,14 @@
virtual void setShowTouchesEnabled(bool enabled) = 0;
virtual void setStylusPointerIconEnabled(bool enabled) = 0;
/**
+ * Set the icon that is shown for the given pointer. The request may fail in some cases, such
+ * as if the device or display was removed, or if the cursor was moved to a different display.
+ * Returns true if the icon was changed successfully, false otherwise.
+ */
+ virtual bool setPointerIcon(std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon,
+ int32_t displayId, DeviceId deviceId) = 0;
+
+ /**
* This method may be called on any thread (usually by the input manager on a binder thread).
*/
virtual void dump(std::string& dump) = 0;
@@ -77,6 +87,8 @@
FloatPoint getMouseCursorPosition(int32_t displayId) override;
void setShowTouchesEnabled(bool enabled) override;
void setStylusPointerIconEnabled(bool enabled) override;
+ bool setPointerIcon(std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon,
+ int32_t displayId, DeviceId deviceId) override;
void notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) override;
void notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) override;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 6ad3de0..1a94f41 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -649,7 +649,7 @@
if (newWindows.find(oldWindow) == newWindows.end()) {
TouchedWindow touchedWindow;
touchedWindow.windowHandle = oldWindow;
- touchedWindow.targetFlags = InputTarget::Flags::DISPATCH_AS_HOVER_EXIT;
+ touchedWindow.dispatchMode = InputTarget::DispatchMode::HOVER_EXIT;
out.push_back(touchedWindow);
}
}
@@ -660,7 +660,7 @@
if (oldWindows.find(newWindow) == oldWindows.end()) {
// Any windows that have this pointer now, and didn't have it before, should get
// HOVER_ENTER
- touchedWindow.targetFlags = InputTarget::Flags::DISPATCH_AS_HOVER_ENTER;
+ touchedWindow.dispatchMode = InputTarget::DispatchMode::HOVER_ENTER;
} else {
// This pointer was already sent to the window. Use ACTION_HOVER_MOVE.
if (CC_UNLIKELY(maskedAction != AMOTION_EVENT_ACTION_HOVER_MOVE)) {
@@ -674,7 +674,7 @@
}
LOG(severity) << "Expected ACTION_HOVER_MOVE instead of " << entry.getDescription();
}
- touchedWindow.targetFlags = InputTarget::Flags::DISPATCH_AS_IS;
+ touchedWindow.dispatchMode = InputTarget::DispatchMode::AS_IS;
}
touchedWindow.addHoveringPointer(entry.deviceId, pointerId);
if (canReceiveForegroundTouches(*newWindow->getInfo())) {
@@ -1090,7 +1090,16 @@
}
}
if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *motionEntry)) {
- dropReason = DropReason::STALE;
+ // The event is stale. However, only drop stale events if there isn't an ongoing
+ // gesture. That would allow us to complete the processing of the current stroke.
+ const auto touchStateIt = mTouchStatesByDisplay.find(motionEntry->displayId);
+ if (touchStateIt != mTouchStatesByDisplay.end()) {
+ const TouchState& touchState = touchStateIt->second;
+ if (!touchState.hasTouchingPointers(motionEntry->deviceId) &&
+ !touchState.hasHoveringPointers(motionEntry->deviceId)) {
+ dropReason = DropReason::STALE;
+ }
+ }
}
if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DropReason::BLOCKED;
@@ -1316,8 +1325,8 @@
if (info.inputConfig.test(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH)) {
std::bitset<MAX_POINTER_ID + 1> pointerIds;
pointerIds.set(pointerId);
- addPointerWindowTargetLocked(windowHandle, InputTarget::Flags::DISPATCH_AS_OUTSIDE,
- pointerIds,
+ addPointerWindowTargetLocked(windowHandle, InputTarget::DispatchMode::OUTSIDE,
+ ftl::Flags<InputTarget::Flags>(), pointerIds,
/*firstDownTimeInTarget=*/std::nullopt, outsideTargets);
}
}
@@ -1595,7 +1604,6 @@
}
InputTarget target;
target.inputChannel = channel;
- target.flags = InputTarget::Flags::DISPATCH_AS_IS;
entry->dispatchInProgress = true;
std::string message = std::string("Focus ") + (entry->hasFocus ? "entering " : "leaving ") +
channel->getName();
@@ -1669,7 +1677,6 @@
}
InputTarget target;
target.inputChannel = channel;
- target.flags = InputTarget::Flags::DISPATCH_AS_IS;
entry->dispatchInProgress = true;
dispatchEventLocked(currentTime, entry, {target});
@@ -1706,7 +1713,6 @@
}
InputTarget target;
target.inputChannel = channel;
- target.flags = InputTarget::Flags::DISPATCH_AS_IS;
inputTargets.push_back(target);
}
return inputTargets;
@@ -1822,9 +1828,8 @@
LOG_ALWAYS_FATAL_IF(focusedWindow == nullptr);
std::vector<InputTarget> inputTargets;
- addWindowTargetLocked(focusedWindow,
- InputTarget::Flags::FOREGROUND | InputTarget::Flags::DISPATCH_AS_IS,
- getDownTime(*entry), inputTargets);
+ addWindowTargetLocked(focusedWindow, InputTarget::DispatchMode::AS_IS,
+ InputTarget::Flags::FOREGROUND, getDownTime(*entry), inputTargets);
// Add monitor channels from event's or focused display.
addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry));
@@ -1929,10 +1934,9 @@
findFocusedWindowTargetLocked(currentTime, *entry, nextWakeupTime, injectionResult);
if (injectionResult == InputEventInjectionResult::SUCCEEDED) {
LOG_ALWAYS_FATAL_IF(focusedWindow == nullptr);
- addWindowTargetLocked(focusedWindow,
- InputTarget::Flags::FOREGROUND |
- InputTarget::Flags::DISPATCH_AS_IS,
- getDownTime(*entry), inputTargets);
+ addWindowTargetLocked(focusedWindow, InputTarget::DispatchMode::AS_IS,
+ InputTarget::Flags::FOREGROUND, getDownTime(*entry),
+ inputTargets);
}
}
if (injectionResult == InputEventInjectionResult::PENDING) {
@@ -1979,7 +1983,6 @@
}
InputTarget target;
target.inputChannel = channel;
- target.flags = InputTarget::Flags::DISPATCH_AS_IS;
entry->dispatchInProgress = true;
dispatchEventLocked(currentTime, entry, {target});
}
@@ -2391,7 +2394,7 @@
}
// Set target flags.
- ftl::Flags<InputTarget::Flags> targetFlags = InputTarget::Flags::DISPATCH_AS_IS;
+ ftl::Flags<InputTarget::Flags> targetFlags;
if (canReceiveForegroundTouches(*windowHandle->getInfo())) {
// There should only be one touched window that can be "foreground" for the pointer.
@@ -2414,8 +2417,8 @@
pointerIds.set(pointerId);
const bool isDownOrPointerDown = maskedAction == AMOTION_EVENT_ACTION_DOWN ||
maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN;
- tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, entry.deviceId,
- pointerIds,
+ tempTouchState.addOrUpdateWindow(windowHandle, InputTarget::DispatchMode::AS_IS,
+ targetFlags, entry.deviceId, pointerIds,
isDownOrPointerDown
? std::make_optional(entry.eventTime)
: std::nullopt);
@@ -2432,13 +2435,14 @@
if (wallpaper != nullptr) {
ftl::Flags<InputTarget::Flags> wallpaperFlags =
InputTarget::Flags::WINDOW_IS_OBSCURED |
- InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED |
- InputTarget::Flags::DISPATCH_AS_IS;
+ InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED;
if (isSplit) {
wallpaperFlags |= InputTarget::Flags::SPLIT;
}
- tempTouchState.addOrUpdateWindow(wallpaper, wallpaperFlags, entry.deviceId,
- pointerIds, entry.eventTime);
+ tempTouchState.addOrUpdateWindow(wallpaper,
+ InputTarget::DispatchMode::AS_IS,
+ wallpaperFlags, entry.deviceId, pointerIds,
+ entry.eventTime);
}
}
}
@@ -2528,8 +2532,8 @@
const TouchedWindow& touchedWindow =
tempTouchState.getTouchedWindow(oldTouchedWindowHandle);
addPointerWindowTargetLocked(oldTouchedWindowHandle,
- InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT,
- pointerIds,
+ InputTarget::DispatchMode::SLIPPERY_EXIT,
+ ftl::Flags<InputTarget::Flags>(), pointerIds,
touchedWindow.getDownTimeInTarget(entry.deviceId),
targets);
@@ -2538,8 +2542,7 @@
isSplit = !isFromMouse;
}
- ftl::Flags<InputTarget::Flags> targetFlags =
- InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER;
+ ftl::Flags<InputTarget::Flags> targetFlags;
if (canReceiveForegroundTouches(*newTouchedWindowHandle->getInfo())) {
targetFlags |= InputTarget::Flags::FOREGROUND;
}
@@ -2552,8 +2555,10 @@
targetFlags |= InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED;
}
- tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags,
- entry.deviceId, pointerIds, entry.eventTime);
+ tempTouchState.addOrUpdateWindow(newTouchedWindowHandle,
+ InputTarget::DispatchMode::SLIPPERY_ENTER,
+ targetFlags, entry.deviceId, pointerIds,
+ entry.eventTime);
// Check if the wallpaper window should deliver the corresponding event.
slipWallpaperTouch(targetFlags, oldTouchedWindowHandle, newTouchedWindowHandle,
@@ -2586,7 +2591,8 @@
getHoveringWindowsLocked(oldState, tempTouchState, entry);
for (const TouchedWindow& touchedWindow : hoveringWindows) {
std::optional<InputTarget> target =
- createInputTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
+ createInputTargetLocked(touchedWindow.windowHandle, touchedWindow.dispatchMode,
+ touchedWindow.targetFlags,
touchedWindow.getDownTimeInTarget(entry.deviceId));
if (!target) {
continue;
@@ -2623,7 +2629,7 @@
if (foregroundWindowHandle) {
const auto foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid;
for (InputTarget& target : targets) {
- if (target.flags.test(InputTarget::Flags::DISPATCH_AS_OUTSIDE)) {
+ if (target.dispatchMode == InputTarget::DispatchMode::OUTSIDE) {
sp<WindowInfoHandle> targetWindow =
getWindowHandleLocked(target.inputChannel->getConnectionToken());
if (targetWindow->getInfo()->ownerUid != foregroundWindowUid) {
@@ -2649,8 +2655,8 @@
if (touchingPointers.none()) {
continue;
}
- addPointerWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
- touchingPointers,
+ addPointerWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.dispatchMode,
+ touchedWindow.targetFlags, touchingPointers,
touchedWindow.getDownTimeInTarget(entry.deviceId), targets);
}
@@ -2675,7 +2681,7 @@
// If we only have windows getting ACTION_OUTSIDE, then drop the event, because there is no
// window that is actually receiving the entire gesture.
if (std::all_of(targets.begin(), targets.end(), [](const InputTarget& target) {
- return target.flags.test(InputTarget::Flags::DISPATCH_AS_OUTSIDE);
+ return target.dispatchMode == InputTarget::DispatchMode::OUTSIDE;
})) {
LOG(INFO) << "Dropping event because all windows would just receive ACTION_OUTSIDE: "
<< entry.getDescription();
@@ -2685,12 +2691,10 @@
outInjectionResult = InputEventInjectionResult::SUCCEEDED;
+ // Now that we have generated all of the input targets for this event, reset the dispatch
+ // mode for all touched window to AS_IS.
for (TouchedWindow& touchedWindow : tempTouchState.windows) {
- // Targets that we entered in a slippery way will now become AS-IS targets
- if (touchedWindow.targetFlags.test(InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER)) {
- touchedWindow.targetFlags.clear(InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER);
- touchedWindow.targetFlags |= InputTarget::Flags::DISPATCH_AS_IS;
- }
+ touchedWindow.dispatchMode = InputTarget::DispatchMode::AS_IS;
}
// Update final pieces of touch state if the injector had permission.
@@ -2823,7 +2827,7 @@
std::optional<InputTarget> InputDispatcher::createInputTargetLocked(
const sp<android::gui::WindowInfoHandle>& windowHandle,
- ftl::Flags<InputTarget::Flags> targetFlags,
+ InputTarget::DispatchMode dispatchMode, ftl::Flags<InputTarget::Flags> targetFlags,
std::optional<nsecs_t> firstDownTimeInTarget) const {
std::shared_ptr<InputChannel> inputChannel = getInputChannelLocked(windowHandle->getToken());
if (inputChannel == nullptr) {
@@ -2833,6 +2837,7 @@
InputTarget inputTarget;
inputTarget.inputChannel = inputChannel;
inputTarget.windowHandle = windowHandle;
+ inputTarget.dispatchMode = dispatchMode;
inputTarget.flags = targetFlags;
inputTarget.globalScaleFactor = windowHandle->getInfo()->globalScaleFactor;
inputTarget.firstDownTimeInTarget = firstDownTimeInTarget;
@@ -2847,6 +2852,7 @@
}
void InputDispatcher::addWindowTargetLocked(const sp<WindowInfoHandle>& windowHandle,
+ InputTarget::DispatchMode dispatchMode,
ftl::Flags<InputTarget::Flags> targetFlags,
std::optional<nsecs_t> firstDownTimeInTarget,
std::vector<InputTarget>& inputTargets) const {
@@ -2861,7 +2867,8 @@
if (it == inputTargets.end()) {
std::optional<InputTarget> target =
- createInputTargetLocked(windowHandle, targetFlags, firstDownTimeInTarget);
+ createInputTargetLocked(windowHandle, dispatchMode, targetFlags,
+ firstDownTimeInTarget);
if (!target) {
return;
}
@@ -2880,9 +2887,9 @@
void InputDispatcher::addPointerWindowTargetLocked(
const sp<android::gui::WindowInfoHandle>& windowHandle,
- ftl::Flags<InputTarget::Flags> targetFlags, std::bitset<MAX_POINTER_ID + 1> pointerIds,
- std::optional<nsecs_t> firstDownTimeInTarget, std::vector<InputTarget>& inputTargets) const
- REQUIRES(mLock) {
+ InputTarget::DispatchMode dispatchMode, ftl::Flags<InputTarget::Flags> targetFlags,
+ std::bitset<MAX_POINTER_ID + 1> pointerIds, std::optional<nsecs_t> firstDownTimeInTarget,
+ std::vector<InputTarget>& inputTargets) const REQUIRES(mLock) {
if (pointerIds.none()) {
for (const auto& target : inputTargets) {
LOG(INFO) << "Target: " << target;
@@ -2903,7 +2910,7 @@
// input targets for hovering pointers and for touching pointers.
// If we picked an existing input target above, but it's for HOVER_EXIT - let's use a new
// target instead.
- if (it != inputTargets.end() && it->flags.test(InputTarget::Flags::DISPATCH_AS_HOVER_EXIT)) {
+ if (it != inputTargets.end() && it->dispatchMode == InputTarget::DispatchMode::HOVER_EXIT) {
// Force the code below to create a new input target
it = inputTargets.end();
}
@@ -2912,7 +2919,8 @@
if (it == inputTargets.end()) {
std::optional<InputTarget> target =
- createInputTargetLocked(windowHandle, targetFlags, firstDownTimeInTarget);
+ createInputTargetLocked(windowHandle, dispatchMode, targetFlags,
+ firstDownTimeInTarget);
if (!target) {
return;
}
@@ -2920,11 +2928,16 @@
it = inputTargets.end() - 1;
}
+ if (it->dispatchMode != dispatchMode) {
+ LOG(ERROR) << __func__ << ": DispatchMode doesn't match! ignoring new mode="
+ << ftl::enum_string(dispatchMode) << ", it=" << *it;
+ }
if (it->flags != targetFlags) {
- LOG(ERROR) << "Flags don't match! targetFlags=" << targetFlags.string() << ", it=" << *it;
+ LOG(ERROR) << __func__ << ": Flags don't match! new targetFlags=" << targetFlags.string()
+ << ", it=" << *it;
}
if (it->globalScaleFactor != windowInfo->globalScaleFactor) {
- LOG(ERROR) << "Mismatch! it->globalScaleFactor=" << it->globalScaleFactor
+ LOG(ERROR) << __func__ << ": Mismatch! it->globalScaleFactor=" << it->globalScaleFactor
<< ", windowInfo->globalScaleFactor=" << windowInfo->globalScaleFactor;
}
@@ -2939,7 +2952,6 @@
for (const Monitor& monitor : selectResponsiveMonitorsLocked(monitorsIt->second)) {
InputTarget target;
target.inputChannel = monitor.inputChannel;
- target.flags = InputTarget::Flags::DISPATCH_AS_IS;
// target.firstDownTimeInTarget is not set for global monitors. It is only required in split
// touch and global monitoring works as intended even without setting firstDownTimeInTarget
if (const auto& it = mDisplayInfos.find(displayId); it != mDisplayInfos.end()) {
@@ -3266,41 +3278,29 @@
connection->getInputChannelName().c_str());
logOutboundMotionDetails(" ", *splitMotionEntry);
}
- enqueueDispatchEntriesLocked(currentTime, connection, std::move(splitMotionEntry),
- inputTarget);
+ enqueueDispatchEntryAndStartDispatchCycleLocked(currentTime, connection,
+ std::move(splitMotionEntry),
+ inputTarget);
return;
}
}
// Not splitting. Enqueue dispatch entries for the event as is.
- enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
+ enqueueDispatchEntryAndStartDispatchCycleLocked(currentTime, connection, eventEntry,
+ inputTarget);
}
-void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
- const std::shared_ptr<Connection>& connection,
- std::shared_ptr<const EventEntry> eventEntry,
- const InputTarget& inputTarget) {
+void InputDispatcher::enqueueDispatchEntryAndStartDispatchCycleLocked(
+ nsecs_t currentTime, const std::shared_ptr<Connection>& connection,
+ std::shared_ptr<const EventEntry> eventEntry, const InputTarget& inputTarget) {
ATRACE_NAME_IF(ATRACE_ENABLED(),
- StringPrintf("enqueueDispatchEntriesLocked(inputChannel=%s, id=0x%" PRIx32 ")",
+ StringPrintf("enqueueDispatchEntryAndStartDispatchCycleLocked(inputChannel=%s, "
+ "id=0x%" PRIx32 ")",
connection->getInputChannelName().c_str(), eventEntry->id));
- LOG_ALWAYS_FATAL_IF(!inputTarget.flags.any(InputTarget::DISPATCH_MASK),
- "No dispatch flags are set for %s", eventEntry->getDescription().c_str());
const bool wasEmpty = connection->outboundQueue.empty();
- // Enqueue dispatch entries for the requested modes.
- enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- InputTarget::Flags::DISPATCH_AS_HOVER_EXIT);
- enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- InputTarget::Flags::DISPATCH_AS_OUTSIDE);
- enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- InputTarget::Flags::DISPATCH_AS_HOVER_ENTER);
- enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- InputTarget::Flags::DISPATCH_AS_IS);
- enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT);
- enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER);
+ enqueueDispatchEntryLocked(connection, eventEntry, inputTarget);
// If the outbound queue was previously empty, start the dispatch cycle going.
if (wasEmpty && !connection->outboundQueue.empty()) {
@@ -3310,20 +3310,11 @@
void InputDispatcher::enqueueDispatchEntryLocked(const std::shared_ptr<Connection>& connection,
std::shared_ptr<const EventEntry> eventEntry,
- const InputTarget& inputTarget,
- ftl::Flags<InputTarget::Flags> dispatchMode) {
- ftl::Flags<InputTarget::Flags> inputTargetFlags = inputTarget.flags;
- if (!inputTargetFlags.any(dispatchMode)) {
- return;
- }
-
- inputTargetFlags.clear(InputTarget::DISPATCH_MASK);
- inputTargetFlags |= dispatchMode;
-
+ const InputTarget& inputTarget) {
// This is a new event.
// Enqueue a new dispatch entry onto the outbound queue for this connection.
std::unique_ptr<DispatchEntry> dispatchEntry =
- createDispatchEntry(inputTarget, eventEntry, inputTargetFlags);
+ createDispatchEntry(inputTarget, eventEntry, inputTarget.flags);
// Use the eventEntry from dispatchEntry since the entry may have changed and can now be a
// different EventEntry than what was passed in.
@@ -3349,15 +3340,15 @@
int32_t resolvedAction = motionEntry.action;
int32_t resolvedFlags = motionEntry.flags;
- if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_OUTSIDE)) {
+ if (inputTarget.dispatchMode == InputTarget::DispatchMode::OUTSIDE) {
resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE;
- } else if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_HOVER_EXIT)) {
+ } else if (inputTarget.dispatchMode == InputTarget::DispatchMode::HOVER_EXIT) {
resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT;
- } else if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_HOVER_ENTER)) {
+ } else if (inputTarget.dispatchMode == InputTarget::DispatchMode::HOVER_ENTER) {
resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
- } else if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT)) {
+ } else if (inputTarget.dispatchMode == InputTarget::DispatchMode::SLIPPERY_EXIT) {
resolvedAction = AMOTION_EVENT_ACTION_CANCEL;
- } else if (dispatchMode.test(InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER)) {
+ } else if (inputTarget.dispatchMode == InputTarget::DispatchMode::SLIPPERY_ENTER) {
resolvedAction = AMOTION_EVENT_ACTION_DOWN;
}
if (resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE &&
@@ -3429,7 +3420,7 @@
<< cancelEvent->getDescription();
std::unique_ptr<DispatchEntry> cancelDispatchEntry =
createDispatchEntry(inputTarget, std::move(cancelEvent),
- InputTarget::Flags::DISPATCH_AS_IS);
+ ftl::Flags<InputTarget::Flags>());
// Send these cancel events to the queue before sending the event from the new
// device.
@@ -3529,7 +3520,7 @@
std::unordered_set<sp<IBinder>, StrongPointerHash<IBinder>> newConnectionTokens;
std::vector<std::shared_ptr<Connection>> newConnections;
for (const InputTarget& target : targets) {
- if (target.flags.test(InputTarget::Flags::DISPATCH_AS_OUTSIDE)) {
+ if (target.dispatchMode == InputTarget::DispatchMode::OUTSIDE) {
continue; // Skip windows that receive ACTION_OUTSIDE
}
@@ -4006,8 +3997,7 @@
const bool wasEmpty = connection->outboundQueue.empty();
// The target to use if we don't find a window associated with the channel.
- const InputTarget fallbackTarget{.inputChannel = connection->inputChannel,
- .flags = InputTarget::Flags::DISPATCH_AS_IS};
+ const InputTarget fallbackTarget{.inputChannel = connection->inputChannel};
const auto& token = connection->inputChannel->getConnectionToken();
for (size_t i = 0; i < cancelationEvents.size(); i++) {
@@ -4021,8 +4011,8 @@
? std::make_optional(keyEntry.displayId)
: std::nullopt;
if (const auto& window = getWindowHandleLocked(token, targetDisplay); window) {
- addWindowTargetLocked(window, InputTarget::Flags::DISPATCH_AS_IS,
- keyEntry.downTime, targets);
+ addWindowTargetLocked(window, InputTarget::DispatchMode::AS_IS,
+ /*targetFlags=*/{}, keyEntry.downTime, targets);
} else {
targets.emplace_back(fallbackTarget);
}
@@ -4049,8 +4039,9 @@
sendDropWindowCommandLocked(nullptr, /*x=*/0, /*y=*/0);
mDragState.reset();
}
- addPointerWindowTargetLocked(window, InputTarget::Flags::DISPATCH_AS_IS,
- pointerIds, motionEntry.downTime, targets);
+ addPointerWindowTargetLocked(window, InputTarget::DispatchMode::AS_IS,
+ ftl::Flags<InputTarget::Flags>(), pointerIds,
+ motionEntry.downTime, targets);
} else {
targets.emplace_back(fallbackTarget);
const auto it = mDisplayInfos.find(motionEntry.displayId);
@@ -4080,8 +4071,7 @@
}
if (targets.size() != 1) LOG(FATAL) << __func__ << ": InputTarget not created";
- enqueueDispatchEntryLocked(connection, std::move(cancelationEventEntry), targets[0],
- InputTarget::Flags::DISPATCH_AS_IS);
+ enqueueDispatchEntryLocked(connection, std::move(cancelationEventEntry), targets[0]);
}
// If the outbound queue was previously empty, start the dispatch cycle going.
@@ -4124,8 +4114,9 @@
pointerIndex++) {
pointerIds.set(motionEntry.pointerProperties[pointerIndex].id);
}
- addPointerWindowTargetLocked(windowHandle, targetFlags, pointerIds,
- motionEntry.downTime, targets);
+ addPointerWindowTargetLocked(windowHandle, InputTarget::DispatchMode::AS_IS,
+ targetFlags, pointerIds, motionEntry.downTime,
+ targets);
} else {
targets.emplace_back(InputTarget{.inputChannel = connection->inputChannel,
.flags = targetFlags});
@@ -4154,8 +4145,7 @@
}
if (targets.size() != 1) LOG(FATAL) << __func__ << ": InputTarget not created";
- enqueueDispatchEntryLocked(connection, std::move(downEventEntry), targets[0],
- InputTarget::Flags::DISPATCH_AS_IS);
+ enqueueDispatchEntryLocked(connection, std::move(downEventEntry), targets[0]);
}
// If the outbound queue was previously empty, start the dispatch cycle going.
@@ -5502,12 +5492,12 @@
// Add new window.
nsecs_t downTimeInTarget = now();
ftl::Flags<InputTarget::Flags> newTargetFlags =
- oldTargetFlags & (InputTarget::Flags::SPLIT | InputTarget::Flags::DISPATCH_AS_IS);
+ oldTargetFlags & (InputTarget::Flags::SPLIT);
if (canReceiveForegroundTouches(*toWindowHandle->getInfo())) {
newTargetFlags |= InputTarget::Flags::FOREGROUND;
}
- state->addOrUpdateWindow(toWindowHandle, newTargetFlags, deviceId, pointerIds,
- downTimeInTarget);
+ state->addOrUpdateWindow(toWindowHandle, InputTarget::DispatchMode::AS_IS, newTargetFlags,
+ deviceId, pointerIds, downTimeInTarget);
// Store the dragging window.
if (isDragDrop) {
@@ -6210,8 +6200,7 @@
if (fallbackKeyEntry && connection->status == Connection::Status::NORMAL) {
const InputTarget target{.inputChannel = connection->inputChannel,
.flags = dispatchEntry->targetFlags};
- enqueueDispatchEntryLocked(connection, std::move(fallbackKeyEntry), target,
- InputTarget::Flags::DISPATCH_AS_IS);
+ enqueueDispatchEntryLocked(connection, std::move(fallbackKeyEntry), target);
}
releaseDispatchEntry(std::move(dispatchEntry));
}
@@ -6854,18 +6843,15 @@
if (oldWallpaper != nullptr) {
const TouchedWindow& oldTouchedWindow = state.getTouchedWindow(oldWallpaper);
- addPointerWindowTargetLocked(oldWallpaper,
- oldTouchedWindow.targetFlags |
- InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT,
- pointerIds, oldTouchedWindow.getDownTimeInTarget(deviceId),
- targets);
+ addPointerWindowTargetLocked(oldWallpaper, InputTarget::DispatchMode::SLIPPERY_EXIT,
+ oldTouchedWindow.targetFlags, pointerIds,
+ oldTouchedWindow.getDownTimeInTarget(deviceId), targets);
state.removeTouchingPointerFromWindow(deviceId, pointerId, oldWallpaper);
}
if (newWallpaper != nullptr) {
- state.addOrUpdateWindow(newWallpaper,
- InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER |
- InputTarget::Flags::WINDOW_IS_OBSCURED |
+ state.addOrUpdateWindow(newWallpaper, InputTarget::DispatchMode::SLIPPERY_ENTER,
+ InputTarget::Flags::WINDOW_IS_OBSCURED |
InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED,
deviceId, pointerIds);
}
@@ -6901,12 +6887,11 @@
if (newWallpaper != nullptr) {
nsecs_t downTimeInTarget = now();
- ftl::Flags<InputTarget::Flags> wallpaperFlags =
- oldTargetFlags & (InputTarget::Flags::SPLIT | InputTarget::Flags::DISPATCH_AS_IS);
+ ftl::Flags<InputTarget::Flags> wallpaperFlags = oldTargetFlags & InputTarget::Flags::SPLIT;
wallpaperFlags |= InputTarget::Flags::WINDOW_IS_OBSCURED |
InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED;
- state.addOrUpdateWindow(newWallpaper, wallpaperFlags, deviceId, pointerIds,
- downTimeInTarget);
+ state.addOrUpdateWindow(newWallpaper, InputTarget::DispatchMode::AS_IS, wallpaperFlags,
+ deviceId, pointerIds, downTimeInTarget);
std::shared_ptr<Connection> wallpaperConnection =
getConnectionLocked(newWallpaper->getToken());
if (wallpaperConnection != nullptr) {
@@ -6948,4 +6933,21 @@
mConfig.keyRepeatDelay = delay.count();
}
+bool InputDispatcher::isPointerInWindow(const sp<android::IBinder>& token, int32_t displayId,
+ DeviceId deviceId, int32_t pointerId) {
+ std::scoped_lock _l(mLock);
+ auto touchStateIt = mTouchStatesByDisplay.find(displayId);
+ if (touchStateIt == mTouchStatesByDisplay.end()) {
+ return false;
+ }
+ for (const TouchedWindow& window : touchStateIt->second.windows) {
+ if (window.windowHandle->getToken() == token &&
+ (window.hasTouchingPointer(deviceId, pointerId) ||
+ window.hasHoveringPointer(deviceId, pointerId))) {
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 8aa4a87..3f99b2d 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -148,6 +148,9 @@
void setKeyRepeatConfiguration(std::chrono::nanoseconds timeout,
std::chrono::nanoseconds delay) override;
+ bool isPointerInWindow(const sp<IBinder>& token, int32_t displayId, DeviceId deviceId,
+ int32_t pointerId) override;
+
private:
enum class DropReason {
NOT_DROPPED,
@@ -528,13 +531,15 @@
std::optional<InputTarget> createInputTargetLocked(
const sp<android::gui::WindowInfoHandle>& windowHandle,
- ftl::Flags<InputTarget::Flags> targetFlags,
+ InputTarget::DispatchMode dispatchMode, ftl::Flags<InputTarget::Flags> targetFlags,
std::optional<nsecs_t> firstDownTimeInTarget) const REQUIRES(mLock);
void addWindowTargetLocked(const sp<android::gui::WindowInfoHandle>& windowHandle,
+ InputTarget::DispatchMode dispatchMode,
ftl::Flags<InputTarget::Flags> targetFlags,
std::optional<nsecs_t> firstDownTimeInTarget,
std::vector<InputTarget>& inputTargets) const REQUIRES(mLock);
void addPointerWindowTargetLocked(const sp<android::gui::WindowInfoHandle>& windowHandle,
+ InputTarget::DispatchMode dispatchMode,
ftl::Flags<InputTarget::Flags> targetFlags,
std::bitset<MAX_POINTER_ID + 1> pointerIds,
std::optional<nsecs_t> firstDownTimeInTarget,
@@ -580,14 +585,12 @@
const std::shared_ptr<Connection>& connection,
std::shared_ptr<const EventEntry>,
const InputTarget& inputTarget) REQUIRES(mLock);
- void enqueueDispatchEntriesLocked(nsecs_t currentTime,
- const std::shared_ptr<Connection>& connection,
- std::shared_ptr<const EventEntry>,
- const InputTarget& inputTarget) REQUIRES(mLock);
+ void enqueueDispatchEntryAndStartDispatchCycleLocked(
+ nsecs_t currentTime, const std::shared_ptr<Connection>& connection,
+ std::shared_ptr<const EventEntry>, const InputTarget& inputTarget) REQUIRES(mLock);
void enqueueDispatchEntryLocked(const std::shared_ptr<Connection>& connection,
std::shared_ptr<const EventEntry>,
- const InputTarget& inputTarget,
- ftl::Flags<InputTarget::Flags> dispatchMode) REQUIRES(mLock);
+ const InputTarget& inputTarget) REQUIRES(mLock);
status_t publishMotionEvent(Connection& connection, DispatchEntry& dispatchEntry) const;
void startDispatchCycleLocked(nsecs_t currentTime,
const std::shared_ptr<Connection>& connection) REQUIRES(mLock);
diff --git a/services/inputflinger/dispatcher/InputTarget.cpp b/services/inputflinger/dispatcher/InputTarget.cpp
index 343630c..c02c5d6 100644
--- a/services/inputflinger/dispatcher/InputTarget.cpp
+++ b/services/inputflinger/dispatcher/InputTarget.cpp
@@ -95,6 +95,7 @@
} else {
out << "<null>";
}
+ out << ", dispatchMode=" << ftl::enum_string(target.dispatchMode).c_str();
out << ", targetFlags=" << target.flags.string();
out << ", pointers=" << target.getPointerInfoString();
out << "}";
diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h
index 8b8a35a..aef866b 100644
--- a/services/inputflinger/dispatcher/InputTarget.h
+++ b/services/inputflinger/dispatcher/InputTarget.h
@@ -51,46 +51,39 @@
* the same UID from watching all touches. */
ZERO_COORDS = 1 << 3,
- /* This flag indicates that the event should be sent as is.
- * Should always be set unless the event is to be transmuted. */
- DISPATCH_AS_IS = 1 << 8,
-
- /* This flag indicates that a MotionEvent with AMOTION_EVENT_ACTION_DOWN falls outside
- * of the area of this target and so should instead be delivered as an
- * AMOTION_EVENT_ACTION_OUTSIDE to this target. */
- DISPATCH_AS_OUTSIDE = 1 << 9,
-
- /* This flag indicates that a hover sequence is starting in the given window.
- * The event is transmuted into ACTION_HOVER_ENTER. */
- DISPATCH_AS_HOVER_ENTER = 1 << 10,
-
- /* This flag indicates that a hover event happened outside of a window which handled
- * previous hover events, signifying the end of the current hover sequence for that
- * window.
- * The event is transmuted into ACTION_HOVER_ENTER. */
- DISPATCH_AS_HOVER_EXIT = 1 << 11,
-
- /* This flag indicates that the event should be canceled.
- * It is used to transmute ACTION_MOVE into ACTION_CANCEL when a touch slips
- * outside of a window. */
- DISPATCH_AS_SLIPPERY_EXIT = 1 << 12,
-
- /* This flag indicates that the event should be dispatched as an initial down.
- * It is used to transmute ACTION_MOVE into ACTION_DOWN when a touch slips
- * into a new window. */
- DISPATCH_AS_SLIPPERY_ENTER = 1 << 13,
-
/* This flag indicates that the target of a MotionEvent is partly or wholly
* obscured by another visible window above it. The motion event should be
* delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED. */
WINDOW_IS_PARTIALLY_OBSCURED = 1 << 14,
};
- /* Mask for all dispatch modes. */
- static constexpr const ftl::Flags<InputTarget::Flags> DISPATCH_MASK =
- ftl::Flags<InputTarget::Flags>() | Flags::DISPATCH_AS_IS | Flags::DISPATCH_AS_OUTSIDE |
- Flags::DISPATCH_AS_HOVER_ENTER | Flags::DISPATCH_AS_HOVER_EXIT |
- Flags::DISPATCH_AS_SLIPPERY_EXIT | Flags::DISPATCH_AS_SLIPPERY_ENTER;
+ enum class DispatchMode {
+ /* This flag indicates that the event should be sent as is.
+ * Should always be set unless the event is to be transmuted. */
+ AS_IS,
+ /* This flag indicates that a MotionEvent with AMOTION_EVENT_ACTION_DOWN falls outside
+ * of the area of this target and so should instead be delivered as an
+ * AMOTION_EVENT_ACTION_OUTSIDE to this target. */
+ OUTSIDE,
+ /* This flag indicates that a hover sequence is starting in the given window.
+ * The event is transmuted into ACTION_HOVER_ENTER. */
+ HOVER_ENTER,
+ /* This flag indicates that a hover event happened outside of a window which handled
+ * previous hover events, signifying the end of the current hover sequence for that
+ * window.
+ * The event is transmuted into ACTION_HOVER_ENTER. */
+ HOVER_EXIT,
+ /* This flag indicates that the event should be canceled.
+ * It is used to transmute ACTION_MOVE into ACTION_CANCEL when a touch slips
+ * outside of a window. */
+ SLIPPERY_EXIT,
+ /* This flag indicates that the event should be dispatched as an initial down.
+ * It is used to transmute ACTION_MOVE into ACTION_DOWN when a touch slips
+ * into a new window. */
+ SLIPPERY_ENTER,
+
+ ftl_last = SLIPPERY_ENTER,
+ };
// The input channel to be targeted.
std::shared_ptr<InputChannel> inputChannel;
@@ -98,6 +91,9 @@
// Flags for the input target.
ftl::Flags<Flags> flags;
+ // The dispatch mode that should be used for this target.
+ DispatchMode dispatchMode = DispatchMode::AS_IS;
+
// Scaling factor to apply to MotionEvent as it is delivered.
// (ignored for KeyEvents)
float globalScaleFactor = 1.0f;
diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp
index 2ead171..e8d8c18 100644
--- a/services/inputflinger/dispatcher/TouchState.cpp
+++ b/services/inputflinger/dispatcher/TouchState.cpp
@@ -71,6 +71,7 @@
}
void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle,
+ InputTarget::DispatchMode dispatchMode,
ftl::Flags<InputTarget::Flags> targetFlags, DeviceId deviceId,
std::bitset<MAX_POINTER_ID + 1> touchingPointerIds,
std::optional<nsecs_t> firstDownTimeInTarget) {
@@ -85,10 +86,8 @@
// An alternative design choice here would have been to compare here by token, but to
// store per-pointer transform.
if (touchedWindow.windowHandle == windowHandle) {
+ touchedWindow.dispatchMode = dispatchMode;
touchedWindow.targetFlags |= targetFlags;
- if (targetFlags.test(InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT)) {
- touchedWindow.targetFlags.clear(InputTarget::Flags::DISPATCH_AS_IS);
- }
// For cases like hover enter/exit or DISPATCH_AS_OUTSIDE a touch window might not have
// downTime set initially. Need to update existing window when a pointer is down for the
// window.
@@ -101,6 +100,7 @@
}
TouchedWindow touchedWindow;
touchedWindow.windowHandle = windowHandle;
+ touchedWindow.dispatchMode = dispatchMode;
touchedWindow.targetFlags = targetFlags;
touchedWindow.addTouchingPointers(deviceId, touchingPointerIds);
if (firstDownTimeInTarget) {
@@ -133,20 +133,6 @@
}
}
-void TouchState::filterNonAsIsTouchWindows() {
- for (size_t i = 0; i < windows.size();) {
- TouchedWindow& window = windows[i];
- if (window.targetFlags.any(InputTarget::Flags::DISPATCH_AS_IS |
- InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER)) {
- window.targetFlags.clear(InputTarget::DISPATCH_MASK);
- window.targetFlags |= InputTarget::Flags::DISPATCH_AS_IS;
- i += 1;
- } else {
- windows.erase(windows.begin() + i);
- }
- }
-}
-
void TouchState::cancelPointersForWindowsExcept(DeviceId deviceId,
std::bitset<MAX_POINTER_ID + 1> pointerIds,
const sp<IBinder>& token) {
diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h
index e79c73b..e0a84e8 100644
--- a/services/inputflinger/dispatcher/TouchState.h
+++ b/services/inputflinger/dispatcher/TouchState.h
@@ -44,6 +44,7 @@
void removeTouchingPointerFromWindow(DeviceId deviceId, int32_t pointerId,
const sp<android::gui::WindowInfoHandle>& windowHandle);
void addOrUpdateWindow(const sp<android::gui::WindowInfoHandle>& windowHandle,
+ InputTarget::DispatchMode dispatchMode,
ftl::Flags<InputTarget::Flags> targetFlags, DeviceId deviceId,
std::bitset<MAX_POINTER_ID + 1> touchingPointerIds,
std::optional<nsecs_t> firstDownTimeInTarget = std::nullopt);
@@ -54,7 +55,6 @@
void removeAllPointersForDevice(DeviceId deviceId);
void removeWindowByToken(const sp<IBinder>& token);
- void filterNonAsIsTouchWindows();
// Cancel pointers for current set of windows except the window with particular binder token.
void cancelPointersForWindowsExcept(DeviceId deviceId,
diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h
index 9a31678..c604353 100644
--- a/services/inputflinger/dispatcher/TouchedWindow.h
+++ b/services/inputflinger/dispatcher/TouchedWindow.h
@@ -31,6 +31,7 @@
// Focus tracking for touch.
struct TouchedWindow {
sp<gui::WindowInfoHandle> windowHandle;
+ InputTarget::DispatchMode dispatchMode = InputTarget::DispatchMode::AS_IS;
ftl::Flags<InputTarget::Flags> targetFlags;
// Hovering
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index bc7b644..001dc6c 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -223,6 +223,12 @@
*/
virtual void setKeyRepeatConfiguration(std::chrono::nanoseconds timeout,
std::chrono::nanoseconds delay) = 0;
+
+ /*
+ * Determine if a pointer from a device is being dispatched to the given window.
+ */
+ virtual bool isPointerInWindow(const sp<IBinder>& token, int32_t displayId, DeviceId deviceId,
+ int32_t pointerId) = 0;
};
} // namespace android
diff --git a/services/inputflinger/include/PointerControllerInterface.h b/services/inputflinger/include/PointerControllerInterface.h
index ef74a55..c44486f 100644
--- a/services/inputflinger/include/PointerControllerInterface.h
+++ b/services/inputflinger/include/PointerControllerInterface.h
@@ -22,6 +22,8 @@
namespace android {
+struct SpriteIcon;
+
struct FloatPoint {
float x;
float y;
@@ -135,6 +137,12 @@
/* Sets the associated display of this pointer. Pointer should show on that display. */
virtual void setDisplayViewport(const DisplayViewport& displayViewport) = 0;
+
+ /* Sets the pointer icon type for mice or styluses. */
+ virtual void updatePointerIcon(PointerIconStyle iconId) = 0;
+
+ /* Sets the custom pointer icon for mice or styluses. */
+ virtual void setCustomPointerIcon(const SpriteIcon& icon) = 0;
};
} // namespace android
diff --git a/services/inputflinger/tests/FakePointerController.cpp b/services/inputflinger/tests/FakePointerController.cpp
index 8043812..80319f2 100644
--- a/services/inputflinger/tests/FakePointerController.cpp
+++ b/services/inputflinger/tests/FakePointerController.cpp
@@ -54,6 +54,16 @@
viewport.logicalBottom - 1);
}
+void FakePointerController::updatePointerIcon(PointerIconStyle iconId) {
+ ASSERT_FALSE(mIconStyle.has_value()) << "Pointer icon was set more than once";
+ mIconStyle = iconId;
+}
+
+void FakePointerController::setCustomPointerIcon(const SpriteIcon& icon) {
+ ASSERT_FALSE(mCustomIconStyle.has_value()) << "Custom pointer icon was set more than once";
+ mCustomIconStyle = icon.style;
+}
+
void FakePointerController::assertViewportSet(int32_t displayId) {
ASSERT_TRUE(mDisplayId);
ASSERT_EQ(displayId, mDisplayId);
@@ -75,6 +85,26 @@
ASSERT_EQ(static_cast<size_t>(count), it->second.size());
}
+void FakePointerController::assertPointerIconSet(PointerIconStyle iconId) {
+ ASSERT_TRUE(mIconStyle) << "Pointer icon style was not set";
+ ASSERT_EQ(iconId, mIconStyle);
+ mIconStyle.reset();
+}
+
+void FakePointerController::assertPointerIconNotSet() {
+ ASSERT_EQ(std::nullopt, mIconStyle);
+}
+
+void FakePointerController::assertCustomPointerIconSet(PointerIconStyle iconId) {
+ ASSERT_TRUE(mCustomIconStyle) << "Custom pointer icon was not set";
+ ASSERT_EQ(iconId, mCustomIconStyle);
+ mCustomIconStyle.reset();
+}
+
+void FakePointerController::assertCustomPointerIconNotSet() {
+ ASSERT_EQ(std::nullopt, mCustomIconStyle);
+}
+
bool FakePointerController::isPointerShown() {
return mIsPointerShown;
}
diff --git a/services/inputflinger/tests/FakePointerController.h b/services/inputflinger/tests/FakePointerController.h
index 9be6a6c..7668011 100644
--- a/services/inputflinger/tests/FakePointerController.h
+++ b/services/inputflinger/tests/FakePointerController.h
@@ -24,6 +24,10 @@
namespace android {
+struct SpriteIcon {
+ PointerIconStyle style;
+};
+
class FakePointerController : public PointerControllerInterface {
public:
virtual ~FakePointerController() {}
@@ -35,11 +39,17 @@
FloatPoint getPosition() const override;
int32_t getDisplayId() const override;
void setDisplayViewport(const DisplayViewport& viewport) override;
+ void updatePointerIcon(PointerIconStyle iconId) override;
+ void setCustomPointerIcon(const SpriteIcon& icon) override;
void assertViewportSet(int32_t displayId);
void assertViewportNotSet();
void assertPosition(float x, float y);
void assertSpotCount(int32_t displayId, int32_t count);
+ void assertPointerIconSet(PointerIconStyle iconId);
+ void assertPointerIconNotSet();
+ void assertCustomPointerIconSet(PointerIconStyle iconId);
+ void assertCustomPointerIconNotSet();
bool isPointerShown();
private:
@@ -58,6 +68,8 @@
float mX{0}, mY{0};
std::optional<int32_t> mDisplayId;
bool mIsPointerShown{false};
+ std::optional<PointerIconStyle> mIconStyle;
+ std::optional<PointerIconStyle> mCustomIconStyle;
std::map<int32_t, std::vector<int32_t>> mSpotsByDisplay;
};
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index e220133..5002391 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -3413,6 +3413,44 @@
}
/**
+ * A stale stylus HOVER_EXIT event is injected. Since it's a stale event, it should generally be
+ * rejected. But since we already have an ongoing gesture, this event should be processed.
+ * This prevents inconsistent events being handled inside the dispatcher.
+ */
+TEST_F(InputDispatcherTest, StaleStylusHoverGestureIsComplete) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+
+ sp<FakeWindowHandle> window =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
+ window->setFrame(Rect(0, 0, 200, 200));
+
+ mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
+
+ // Start hovering with stylus
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
+ .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
+ .build());
+ window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
+
+ NotifyMotionArgs hoverExit = MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
+ .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50))
+ .build();
+ // Make this 'hoverExit' event stale
+ mFakePolicy->setStaleEventTimeout(100ms);
+ std::this_thread::sleep_for(100ms);
+
+ // It shouldn't be dropped by the dispatcher, even though it's stale.
+ mDispatcher->notifyMotion(hoverExit);
+ window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
+
+ // Stylus starts hovering again! There should be no crash.
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
+ .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(51))
+ .build());
+ window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
+}
+
+/**
* Start hovering with a mouse, and then tap with a touch device. Pilfer the touch stream.
* Next, click with the mouse device. Both windows (spy and regular) should receive the new mouse
* ACTION_DOWN event because that's a new gesture, and pilfering should no longer be active.
@@ -4320,6 +4358,12 @@
// Therefore, we should offset them by (100, 100) relative to the screen's top left corner.
outsideWindow->consumeMotionEvent(
AllOf(WithMotionAction(ACTION_OUTSIDE), WithCoords(-50, -50)));
+
+ // Ensure outsideWindow doesn't get any more events for the gesture.
+ mDispatcher->notifyMotion(generateMotionArgs(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {PointF{51, 51}}));
+ window->consumeMotionMove();
+ outsideWindow->assertNoEvents();
}
/**
@@ -11248,4 +11292,243 @@
randosWindow->assertNoEvents();
}
+using InputDispatcherPointerInWindowTest = InputDispatcherTest;
+
+TEST_F(InputDispatcherPointerInWindowTest, PointerInWindowWhenHovering) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+
+ sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
+ ADISPLAY_ID_DEFAULT);
+ left->setFrame(Rect(0, 0, 100, 100));
+ sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Right Window", ADISPLAY_ID_DEFAULT);
+ right->setFrame(Rect(100, 0, 200, 100));
+ sp<FakeWindowHandle> spy =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
+ spy->setFrame(Rect(0, 0, 200, 100));
+ spy->setTrustedOverlay(true);
+ spy->setSpy(true);
+
+ mDispatcher->onWindowInfosChanged(
+ {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
+
+ // Hover into the left window.
+ mDispatcher->notifyMotion(
+ MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
+ .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(50).y(50))
+ .build());
+
+ left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
+ spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
+
+ ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+
+ // Hover move to the right window.
+ mDispatcher->notifyMotion(
+ MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS)
+ .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(50))
+ .build());
+
+ left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
+ right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
+ spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
+
+ ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_TRUE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+
+ // Stop hovering.
+ mDispatcher->notifyMotion(
+ MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
+ .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS).x(150).y(50))
+ .build());
+
+ right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
+ spy->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
+
+ ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+}
+
+TEST_F(InputDispatcherPointerInWindowTest, PointerInWindowWithSplitTouch) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+
+ sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
+ ADISPLAY_ID_DEFAULT);
+ left->setFrame(Rect(0, 0, 100, 100));
+ sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Right Window", ADISPLAY_ID_DEFAULT);
+ right->setFrame(Rect(100, 0, 200, 100));
+ sp<FakeWindowHandle> spy =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Spy Window", ADISPLAY_ID_DEFAULT);
+ spy->setFrame(Rect(0, 0, 200, 100));
+ spy->setTrustedOverlay(true);
+ spy->setSpy(true);
+
+ mDispatcher->onWindowInfosChanged(
+ {{*spy->getInfo(), *left->getInfo(), *right->getInfo()}, {}, 0, 0});
+
+ // First pointer down on left window.
+ mDispatcher->notifyMotion(
+ MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
+ .build());
+
+ left->consumeMotionDown();
+ spy->consumeMotionDown();
+
+ ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+
+ // Second pointer down on right window.
+ mDispatcher->notifyMotion(
+ MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
+ .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
+ .build());
+
+ left->consumeMotionMove();
+ right->consumeMotionDown();
+ spy->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
+
+ ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/1));
+ ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/1));
+ ASSERT_TRUE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/1));
+
+ // Second pointer up.
+ mDispatcher->notifyMotion(
+ MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
+ .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
+ .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50))
+ .build());
+
+ left->consumeMotionMove();
+ right->consumeMotionUp();
+ spy->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
+
+ ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_TRUE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/1));
+ ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/1));
+ ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/1));
+
+ // First pointer up.
+ mDispatcher->notifyMotion(
+ MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
+ .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
+ .build());
+
+ left->consumeMotionUp();
+ spy->consumeMotionUp();
+
+ ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_FALSE(mDispatcher->isPointerInWindow(spy->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+}
+
+TEST_F(InputDispatcherPointerInWindowTest, MultipleDevicesControllingOneMouse) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+
+ sp<FakeWindowHandle> left = sp<FakeWindowHandle>::make(application, mDispatcher, "Left Window",
+ ADISPLAY_ID_DEFAULT);
+ left->setFrame(Rect(0, 0, 100, 100));
+ sp<FakeWindowHandle> right = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Right Window", ADISPLAY_ID_DEFAULT);
+ right->setFrame(Rect(100, 0, 200, 100));
+
+ mDispatcher->onWindowInfosChanged({{*left->getInfo(), *right->getInfo()}, {}, 0, 0});
+
+ ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_FALSE(mDispatcher->isPointerInWindow(right->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+
+ // Hover move into the window.
+ mDispatcher->notifyMotion(
+ MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50))
+ .rawXCursorPosition(50)
+ .rawYCursorPosition(50)
+ .deviceId(DEVICE_ID)
+ .build());
+
+ left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
+
+ ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+
+ // Move the mouse with another device. This cancels the hovering pointer from the first device.
+ mDispatcher->notifyMotion(
+ MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(51).y(50))
+ .rawXCursorPosition(51)
+ .rawYCursorPosition(50)
+ .deviceId(SECOND_DEVICE_ID)
+ .build());
+
+ left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
+ left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
+
+ // TODO(b/313689709): InputDispatcher's touch state is not updated, even though the window gets
+ // a HOVER_EXIT from the first device.
+ ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
+ SECOND_DEVICE_ID,
+ /*pointerId=*/0));
+
+ // Move the mouse outside the window. Document the current behavior, where the window does not
+ // receive HOVER_EXIT even though the mouse left the window.
+ mDispatcher->notifyMotion(
+ MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(150).y(50))
+ .rawXCursorPosition(150)
+ .rawYCursorPosition(50)
+ .deviceId(SECOND_DEVICE_ID)
+ .build());
+
+ left->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
+ right->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
+ ASSERT_TRUE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_FALSE(mDispatcher->isPointerInWindow(left->getToken(), ADISPLAY_ID_DEFAULT,
+ SECOND_DEVICE_ID,
+ /*pointerId=*/0));
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/tests/PointerChoreographer_test.cpp b/services/inputflinger/tests/PointerChoreographer_test.cpp
index 1efb797..2457f7c 100644
--- a/services/inputflinger/tests/PointerChoreographer_test.cpp
+++ b/services/inputflinger/tests/PointerChoreographer_test.cpp
@@ -1511,4 +1511,278 @@
ASSERT_FALSE(pc->isPointerShown());
}
+TEST_F(PointerChoreographerTest, SetsPointerIconForMouse) {
+ // Make sure there is a PointerController.
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+ mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE)}});
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(MOUSE_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(ADISPLAY_ID_NONE)
+ .build());
+ auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
+ pc->assertPointerIconNotSet();
+
+ // Set pointer icon for the device.
+ ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID));
+ pc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
+}
+
+TEST_F(PointerChoreographerTest, DoesNotSetMousePointerIconForWrongDisplayId) {
+ // Make sure there is a PointerController.
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+ mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE)}});
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(MOUSE_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(ADISPLAY_ID_NONE)
+ .build());
+ auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
+ pc->assertPointerIconNotSet();
+
+ // Set pointer icon for wrong display id. This should be ignored.
+ ASSERT_FALSE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, ANOTHER_DISPLAY_ID,
+ SECOND_DEVICE_ID));
+ pc->assertPointerIconNotSet();
+}
+
+TEST_F(PointerChoreographerTest, DoesNotSetPointerIconForWrongDeviceId) {
+ // Make sure there is a PointerController.
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+ mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE)}});
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(MOUSE_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(ADISPLAY_ID_NONE)
+ .build());
+ auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
+ pc->assertPointerIconNotSet();
+
+ // Set pointer icon for wrong device id. This should be ignored.
+ ASSERT_FALSE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID,
+ SECOND_DEVICE_ID));
+ pc->assertPointerIconNotSet();
+}
+
+TEST_F(PointerChoreographerTest, DoesNotSetPointerIconForDeviceWithoutPointerController) {
+ // Add two devices, one with a PointerController and the other without PointerController.
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+ mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0,
+ {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE),
+ generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_MOUSE, ANOTHER_DISPLAY_ID)}});
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(MOUSE_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(ADISPLAY_ID_NONE)
+ .build());
+ auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
+ pc->assertPointerIconNotSet();
+
+ // Set pointer icon for the device without PointerController. This should be ignored.
+ ASSERT_FALSE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, ANOTHER_DISPLAY_ID,
+ SECOND_DEVICE_ID));
+ pc->assertPointerIconNotSet();
+}
+
+TEST_F(PointerChoreographerTest, SetsCustomPointerIconForMouse) {
+ // Make sure there is a PointerController.
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+ mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE)}});
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(MOUSE_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(ADISPLAY_ID_NONE)
+ .build());
+ auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
+ pc->assertCustomPointerIconNotSet();
+
+ // Set custom pointer icon for the device.
+ ASSERT_TRUE(mChoreographer.setPointerIcon(std::make_unique<SpriteIcon>(
+ PointerIconStyle::TYPE_CUSTOM),
+ DISPLAY_ID, DEVICE_ID));
+ pc->assertCustomPointerIconSet(PointerIconStyle::TYPE_CUSTOM);
+
+ // Set custom pointer icon for wrong device id. This should be ignored.
+ ASSERT_FALSE(mChoreographer.setPointerIcon(std::make_unique<SpriteIcon>(
+ PointerIconStyle::TYPE_CUSTOM),
+ DISPLAY_ID, SECOND_DEVICE_ID));
+ pc->assertCustomPointerIconNotSet();
+}
+
+TEST_F(PointerChoreographerTest, SetsPointerIconForMouseOnTwoDisplays) {
+ // Make sure there are two PointerControllers on different displays.
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
+ mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0,
+ {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE),
+ generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_MOUSE, ANOTHER_DISPLAY_ID)}});
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(MOUSE_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(ADISPLAY_ID_NONE)
+ .build());
+ auto firstMousePc = assertPointerControllerCreated(ControllerType::MOUSE);
+ ASSERT_EQ(DISPLAY_ID, firstMousePc->getDisplayId());
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(MOUSE_POINTER)
+ .deviceId(SECOND_DEVICE_ID)
+ .displayId(ANOTHER_DISPLAY_ID)
+ .build());
+ auto secondMousePc = assertPointerControllerCreated(ControllerType::MOUSE);
+ ASSERT_EQ(ANOTHER_DISPLAY_ID, secondMousePc->getDisplayId());
+
+ // Set pointer icon for one mouse.
+ ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID));
+ firstMousePc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
+ secondMousePc->assertPointerIconNotSet();
+
+ // Set pointer icon for another mouse.
+ ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, ANOTHER_DISPLAY_ID,
+ SECOND_DEVICE_ID));
+ secondMousePc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
+ firstMousePc->assertPointerIconNotSet();
+}
+
+TEST_F(PointerChoreographerTest, SetsPointerIconForStylus) {
+ // Make sure there is a PointerController.
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}});
+ mChoreographer.setStylusPointerIconEnabled(true);
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
+ .pointer(STYLUS_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+ auto pc = assertPointerControllerCreated(ControllerType::STYLUS);
+ pc->assertPointerIconNotSet();
+
+ // Set pointer icon for the device.
+ ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID));
+ pc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
+
+ // Set pointer icon for wrong device id. This should be ignored.
+ ASSERT_FALSE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID,
+ SECOND_DEVICE_ID));
+ pc->assertPointerIconNotSet();
+}
+
+TEST_F(PointerChoreographerTest, SetsCustomPointerIconForStylus) {
+ // Make sure there is a PointerController.
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}});
+ mChoreographer.setStylusPointerIconEnabled(true);
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
+ .pointer(STYLUS_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+ auto pc = assertPointerControllerCreated(ControllerType::STYLUS);
+ pc->assertCustomPointerIconNotSet();
+
+ // Set custom pointer icon for the device.
+ ASSERT_TRUE(mChoreographer.setPointerIcon(std::make_unique<SpriteIcon>(
+ PointerIconStyle::TYPE_CUSTOM),
+ DISPLAY_ID, DEVICE_ID));
+ pc->assertCustomPointerIconSet(PointerIconStyle::TYPE_CUSTOM);
+
+ // Set custom pointer icon for wrong device id. This should be ignored.
+ ASSERT_FALSE(mChoreographer.setPointerIcon(std::make_unique<SpriteIcon>(
+ PointerIconStyle::TYPE_CUSTOM),
+ DISPLAY_ID, SECOND_DEVICE_ID));
+ pc->assertCustomPointerIconNotSet();
+}
+
+TEST_F(PointerChoreographerTest, SetsPointerIconForTwoStyluses) {
+ // Make sure there are two StylusPointerControllers. They can be on a same display.
+ mChoreographer.setStylusPointerIconEnabled(true);
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0,
+ {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID),
+ generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}});
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
+ .pointer(STYLUS_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+ auto firstStylusPc = assertPointerControllerCreated(ControllerType::STYLUS);
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
+ .pointer(STYLUS_POINTER)
+ .deviceId(SECOND_DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+ auto secondStylusPc = assertPointerControllerCreated(ControllerType::STYLUS);
+
+ // Set pointer icon for one stylus.
+ ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID));
+ firstStylusPc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
+ secondStylusPc->assertPointerIconNotSet();
+
+ // Set pointer icon for another stylus.
+ ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID,
+ SECOND_DEVICE_ID));
+ secondStylusPc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
+ firstStylusPc->assertPointerIconNotSet();
+}
+
+TEST_F(PointerChoreographerTest, SetsPointerIconForMouseAndStylus) {
+ // Make sure there are PointerControllers for a mouse and a stylus.
+ mChoreographer.setStylusPointerIconEnabled(true);
+ mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0,
+ {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE),
+ generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}});
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(MOUSE_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(ADISPLAY_ID_NONE)
+ .build());
+ auto mousePc = assertPointerControllerCreated(ControllerType::MOUSE);
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
+ .pointer(STYLUS_POINTER)
+ .deviceId(SECOND_DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+ auto stylusPc = assertPointerControllerCreated(ControllerType::STYLUS);
+
+ // Set pointer icon for the mouse.
+ ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID));
+ mousePc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
+ stylusPc->assertPointerIconNotSet();
+
+ // Set pointer icon for the stylus.
+ ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID,
+ SECOND_DEVICE_ID));
+ stylusPc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
+ mousePc->assertPointerIconNotSet();
+}
+
} // namespace android
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
index 2f84497..81c570d 100644
--- a/services/inputflinger/tests/fuzzers/MapperHelpers.h
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -275,6 +275,8 @@
void clearSpots() override {}
int32_t getDisplayId() const override { return mFdp->ConsumeIntegral<int32_t>(); }
void setDisplayViewport(const DisplayViewport& displayViewport) override {}
+ void updatePointerIcon(PointerIconStyle iconId) override {}
+ void setCustomPointerIcon(const SpriteIcon& icon) override {}
std::string dump() override { return ""; }
};
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index e316190..ae2f2db 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -37,6 +37,7 @@
"libSurfaceFlingerProp",
"libui",
"libutils",
+ "server_configurable_flags",
],
static_libs: [
"liblayers_proto",
@@ -60,13 +61,8 @@
],
}
-cc_library {
- name: "libcompositionengine",
- defaults: ["libcompositionengine_defaults"],
- static_libs: [
- "libsurfaceflinger_common",
- "libsurfaceflingerflags",
- ],
+filegroup {
+ name: "libcompositionengine_sources",
srcs: [
"src/planner/CachedSet.cpp",
"src/planner/Flattener.cpp",
@@ -89,6 +85,18 @@
"src/OutputLayerCompositionState.cpp",
"src/RenderSurface.cpp",
],
+}
+
+cc_library {
+ name: "libcompositionengine",
+ defaults: ["libcompositionengine_defaults"],
+ static_libs: [
+ "libsurfaceflinger_common",
+ "libsurfaceflingerflags",
+ ],
+ srcs: [
+ ":libcompositionengine_sources",
+ ],
local_include_dirs: ["include"],
export_include_dirs: ["include"],
shared_libs: [
@@ -133,6 +141,7 @@
],
defaults: ["libcompositionengine_defaults"],
srcs: [
+ ":libcompositionengine_sources",
"tests/planner/CachedSetTest.cpp",
"tests/planner/FlattenerTest.cpp",
"tests/planner/LayerStateTest.cpp",
@@ -151,7 +160,6 @@
"tests/RenderSurfaceTest.cpp",
],
static_libs: [
- "libcompositionengine",
"libcompositionengine_mocks",
"libgui_mocks",
"librenderengine_mocks",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
index 98c4af4..6e60839 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
@@ -42,6 +42,10 @@
// True if this display should be considered secure
bool isSecure = false;
+ // True if this display should be considered protected, as in this display should render DRM
+ // content.
+ bool isProtected = false;
+
// Optional pointer to the power advisor interface, if one is needed for
// this display.
Hwc2::PowerAdvisor* powerAdvisor = nullptr;
@@ -73,6 +77,11 @@
return *this;
}
+ DisplayCreationArgsBuilder& setIsProtected(bool isProtected) {
+ mArgs.isProtected = isProtected;
+ return *this;
+ }
+
DisplayCreationArgsBuilder& setPowerAdvisor(Hwc2::PowerAdvisor* powerAdvisor) {
mArgs.powerAdvisor = powerAdvisor;
return *this;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
index ca86f4c..643b458 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
@@ -60,7 +60,7 @@
//
// advanceFrame must be followed by a call to onFrameCommitted before
// advanceFrame may be called again.
- virtual status_t advanceFrame() = 0;
+ virtual status_t advanceFrame(float hdrSdrRatio) = 0;
// onFrameCommitted is called after the frame has been committed to the
// hardware composer. The surface collects the release fence for this
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index ccff1ec..a1d6132 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -97,7 +97,7 @@
const bool isSecure;
// If set to true, the target buffer has protected content support.
- const bool supportsProtectedContent;
+ const bool isProtected;
// Viewport of the target being rendered to. This is used to determine
// the shadow light position.
@@ -167,8 +167,7 @@
static inline bool operator==(const LayerFE::ClientCompositionTargetSettings& lhs,
const LayerFE::ClientCompositionTargetSettings& rhs) {
return lhs.clip.hasSameRects(rhs.clip) && lhs.needsFiltering == rhs.needsFiltering &&
- lhs.isSecure == rhs.isSecure &&
- lhs.supportsProtectedContent == rhs.supportsProtectedContent &&
+ lhs.isSecure == rhs.isSecure && lhs.isProtected == rhs.isProtected &&
lhs.viewport == rhs.viewport && lhs.dataspace == rhs.dataspace &&
lhs.realContentIsVisible == rhs.realContentIsVisible &&
lhs.clearContent == rhs.clearContent;
@@ -189,7 +188,7 @@
PrintTo(settings.clip, os);
*os << "\n .needsFiltering = " << settings.needsFiltering;
*os << "\n .isSecure = " << settings.isSecure;
- *os << "\n .supportsProtectedContent = " << settings.supportsProtectedContent;
+ *os << "\n .isProtected = " << settings.isProtected;
*os << "\n .viewport = ";
PrintTo(settings.viewport, os);
*os << "\n .dataspace = ";
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index 5854674..02cea0d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -86,7 +86,7 @@
// Queues the drawn buffer for consumption by HWC. readyFence is the fence
// which will fire when the buffer is ready for consumption.
- virtual void queueBuffer(base::unique_fd readyFence) = 0;
+ virtual void queueBuffer(base::unique_fd readyFence, float hdrSdrRatio) = 0;
// Called after the HWC calls are made to present the display
virtual void onPresentDisplayCompleted() = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index ec6a4e9..911d67b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -137,7 +137,8 @@
void applyCompositionStrategy(const std::optional<DeviceRequestedChanges>&) override{};
bool getSkipColorTransform() const override;
compositionengine::Output::FrameFences presentFrame() override;
- virtual renderengine::DisplaySettings generateClientCompositionDisplaySettings() const;
+ virtual renderengine::DisplaySettings generateClientCompositionDisplaySettings(
+ const std::shared_ptr<renderengine::ExternalTexture>& buffer) const;
std::vector<LayerFE::LayerSettings> generateClientCompositionRequests(
bool supportsProtectedContent, ui::Dataspace outputDataspace,
std::vector<LayerFE*>& outLayerFEs) override;
@@ -168,6 +169,7 @@
compositionengine::Output::ColorProfile pickColorProfile(
const compositionengine::CompositionRefreshArgs&) const;
void updateHwcAsyncWorker();
+ float getHdrSdrRatio(const std::shared_ptr<renderengine::ExternalTexture>& buffer) const;
std::string mName;
std::string mNamePlusId;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index 692ed24..6b1c318 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -53,6 +53,9 @@
// If false, this output is not considered secure
bool isSecure{false};
+ // If false, this output is not considered protected
+ bool isProtected{false};
+
// If true, the current frame on this output uses client composition
bool usesClientComposition{false};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index 1c14a43..202145e 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -60,7 +60,7 @@
void prepareFrame(bool usesClientComposition, bool usesDeviceComposition) override;
std::shared_ptr<renderengine::ExternalTexture> dequeueBuffer(
base::unique_fd* bufferFence) override;
- void queueBuffer(base::unique_fd readyFence) override;
+ void queueBuffer(base::unique_fd readyFence, float hdrSdrRatio) override;
void onPresentDisplayCompleted() override;
bool supportsCompositionStrategyPrediction() const override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h
index 168e433..08d8ff7 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h
@@ -30,7 +30,7 @@
MOCK_METHOD1(beginFrame, status_t(bool mustRecompose));
MOCK_METHOD1(prepareFrame, status_t(CompositionType compositionType));
- MOCK_METHOD0(advanceFrame, status_t());
+ MOCK_METHOD((status_t), advanceFrame, (float), (override));
MOCK_METHOD0(onFrameCommitted, void());
MOCK_CONST_METHOD1(dumpAsString, void(String8& result));
MOCK_METHOD1(resizeBuffers, void(const ui::Size&));
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index af8d4bc..c35fd3f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -40,7 +40,7 @@
MOCK_METHOD1(beginFrame, status_t(bool mustRecompose));
MOCK_METHOD2(prepareFrame, void(bool, bool));
MOCK_METHOD1(dequeueBuffer, std::shared_ptr<renderengine::ExternalTexture>(base::unique_fd*));
- MOCK_METHOD1(queueBuffer, void(base::unique_fd));
+ MOCK_METHOD(void, queueBuffer, (base::unique_fd, float), (override));
MOCK_METHOD0(onPresentDisplayCompleted, void());
MOCK_CONST_METHOD1(dump, void(std::string& result));
MOCK_CONST_METHOD0(supportsCompositionStrategyPrediction, bool());
diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
index 7be5fe3..d87eae3 100644
--- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
@@ -101,6 +101,9 @@
// Not HWC-enabled, so it is always client-composited. No need to offload.
continue;
}
+ if (!output->getState().isEnabled) {
+ continue;
+ }
// Only run present in multiple threads if all HWC-enabled displays
// being refreshed support it.
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 0475881..690d35f 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -57,6 +57,7 @@
mId = args.id;
mPowerAdvisor = args.powerAdvisor;
editState().isSecure = args.isSecure;
+ editState().isProtected = args.isProtected;
editState().displaySpace.setBounds(args.pixels);
setName(args.name);
}
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index e4d7578..09c7c99 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1176,7 +1176,7 @@
updateProtectedContentState();
dequeueRenderBuffer(&bufferFence, &buffer);
static_cast<void>(composeSurfaces(dirtyRegion, buffer, bufferFence));
- mRenderSurface->queueBuffer(base::unique_fd());
+ mRenderSurface->queueBuffer(base::unique_fd(), getHdrSdrRatio(buffer));
}
}
@@ -1224,7 +1224,7 @@
std::make_unique<FenceTime>(sp<Fence>::make(dup(optReadyFence->get()))));
}
// swap buffers (presentation)
- mRenderSurface->queueBuffer(std::move(*optReadyFence));
+ mRenderSurface->queueBuffer(std::move(*optReadyFence), getHdrSdrRatio(buffer));
}
void Output::updateProtectedContentState() {
@@ -1232,10 +1232,18 @@
auto& renderEngine = getCompositionEngine().getRenderEngine();
const bool supportsProtectedContent = renderEngine.supportsProtectedContent();
- // If we the display is secure, protected content support is enabled, and at
- // least one layer has protected content, we need to use a secure back
- // buffer.
- if (outputState.isSecure && supportsProtectedContent) {
+ bool isProtected;
+ if (FlagManager::getInstance().display_protected()) {
+ isProtected = outputState.isProtected;
+ } else {
+ isProtected = outputState.isSecure;
+ }
+
+ // We need to set the render surface as protected (DRM) if all the following conditions are met:
+ // 1. The display is protected (in legacy, check if the display is secure)
+ // 2. Protected content is supported
+ // 3. At least one layer has protected content.
+ if (isProtected && supportsProtectedContent) {
auto layers = getOutputLayersOrderedByZ();
bool needsProtected = std::any_of(layers.begin(), layers.end(), [](auto* layer) {
return layer->getLayerFE().getCompositionState()->hasProtectedContent;
@@ -1290,7 +1298,7 @@
ALOGV("hasClientComposition");
renderengine::DisplaySettings clientCompositionDisplay =
- generateClientCompositionDisplaySettings();
+ generateClientCompositionDisplaySettings(tex);
// Generate the client composition requests for the layers on this output.
auto& renderEngine = getCompositionEngine().getRenderEngine();
@@ -1371,7 +1379,8 @@
return base::unique_fd(fence->dup());
}
-renderengine::DisplaySettings Output::generateClientCompositionDisplaySettings() const {
+renderengine::DisplaySettings Output::generateClientCompositionDisplaySettings(
+ const std::shared_ptr<renderengine::ExternalTexture>& buffer) const {
const auto& outputState = getState();
renderengine::DisplaySettings clientCompositionDisplay;
@@ -1391,8 +1400,10 @@
: mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
clientCompositionDisplay.maxLuminance =
mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
- clientCompositionDisplay.targetLuminanceNits =
- outputState.clientTargetBrightness * outputState.displayBrightnessNits;
+
+ float hdrSdrRatioMultiplier = 1.0f / getHdrSdrRatio(buffer);
+ clientCompositionDisplay.targetLuminanceNits = outputState.clientTargetBrightness *
+ outputState.displayBrightnessNits * hdrSdrRatioMultiplier;
clientCompositionDisplay.dimmingStage = outputState.clientTargetDimmingStage;
clientCompositionDisplay.renderIntent =
static_cast<aidl::android::hardware::graphics::composer3::RenderIntent>(
@@ -1475,12 +1486,16 @@
BlurRegionsOnly
: LayerFE::ClientCompositionTargetSettings::BlurSetting::
Enabled);
+ bool isProtected = supportsProtectedContent;
+ if (FlagManager::getInstance().display_protected()) {
+ isProtected = outputState.isProtected && supportsProtectedContent;
+ }
compositionengine::LayerFE::ClientCompositionTargetSettings
targetSettings{.clip = clip,
.needsFiltering = layer->needsFiltering() ||
outputState.needsFiltering,
.isSecure = outputState.isSecure,
- .supportsProtectedContent = supportsProtectedContent,
+ .isProtected = isProtected,
.viewport = outputState.layerStackSpace.getContent(),
.dataspace = outputDataspace,
.realContentIsVisible = realContentIsVisible,
@@ -1703,5 +1718,25 @@
return mMustRecompose;
}
+float Output::getHdrSdrRatio(const std::shared_ptr<renderengine::ExternalTexture>& buffer) const {
+ if (buffer == nullptr) {
+ return 1.0f;
+ }
+
+ if (!FlagManager::getInstance().fp16_client_target()) {
+ return 1.0f;
+ }
+
+ if (getState().displayBrightnessNits < 0.0f || getState().sdrWhitePointNits <= 0.0f ||
+ buffer->getPixelFormat() != PIXEL_FORMAT_RGBA_FP16 ||
+ (static_cast<int32_t>(getState().dataspace) &
+ static_cast<int32_t>(ui::Dataspace::RANGE_MASK)) !=
+ static_cast<int32_t>(ui::Dataspace::RANGE_EXTENDED)) {
+ return 1.0f;
+ }
+
+ return getState().displayBrightnessNits / getState().sdrWhitePointNits;
+}
+
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index 0fe55db..c0b23d9 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -198,7 +198,7 @@
return mTexture;
}
-void RenderSurface::queueBuffer(base::unique_fd readyFence) {
+void RenderSurface::queueBuffer(base::unique_fd readyFence, float hdrSdrRatio) {
auto& state = mDisplay.getState();
if (state.usesClientComposition || state.flipClientTarget) {
@@ -241,7 +241,7 @@
}
}
- status_t result = mDisplaySurface->advanceFrame();
+ status_t result = mDisplaySurface->advanceFrame(hdrSdrRatio);
if (result != NO_ERROR) {
ALOGE("[%s] failed pushing new frame to HWC: %d", mDisplay.getName().c_str(), result);
}
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index 579c6ba..869dda6 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -184,7 +184,7 @@
targetSettings{.clip = Region(viewport),
.needsFiltering = false,
.isSecure = outputState.isSecure,
- .supportsProtectedContent = false,
+ .isProtected = false,
.viewport = viewport,
.dataspace = outputDataspace,
.realContentIsVisible = true,
diff --git a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
index 602dd23..da578e2 100644
--- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
@@ -288,6 +288,8 @@
static constexpr GpuVirtualDisplayId kGpuVirtualDisplayId{789u};
static constexpr HalVirtualDisplayId kHalVirtualDisplayId{456u};
+ std::array<impl::OutputCompositionState, 4> mOutputStates;
+
void SetUp() override {
EXPECT_CALL(*mDisplay1, getDisplayId)
.WillRepeatedly(Return(std::make_optional<DisplayId>(kDisplayId1)));
@@ -297,6 +299,16 @@
.WillRepeatedly(Return(std::make_optional<DisplayId>(kGpuVirtualDisplayId)));
EXPECT_CALL(*mHalVirtualDisplay, getDisplayId)
.WillRepeatedly(Return(std::make_optional<DisplayId>(kHalVirtualDisplayId)));
+
+ // Most tests will depend on the outputs being enabled.
+ for (auto& state : mOutputStates) {
+ state.isEnabled = true;
+ }
+
+ EXPECT_CALL(*mDisplay1, getState).WillRepeatedly(ReturnRef(mOutputStates[0]));
+ EXPECT_CALL(*mDisplay2, getState).WillRepeatedly(ReturnRef(mOutputStates[1]));
+ EXPECT_CALL(*mVirtualDisplay, getState).WillRepeatedly(ReturnRef(mOutputStates[2]));
+ EXPECT_CALL(*mHalVirtualDisplay, getState).WillRepeatedly(ReturnRef(mOutputStates[3]));
}
void setOutputs(std::initializer_list<std::shared_ptr<mock::Output>> outputs) {
@@ -433,5 +445,43 @@
mEngine.present(mRefreshArgs);
}
+TEST_F(CompositionEngineOffloadTest, dependsOnEnabled) {
+ // Disable mDisplay2.
+ mOutputStates[1].isEnabled = false;
+ EXPECT_CALL(*mDisplay1, supportsOffloadPresent).WillOnce(Return(true));
+
+ // This is not actually called, because it is not enabled, but this distinguishes
+ // from the case where it did not return true.
+ EXPECT_CALL(*mDisplay2, supportsOffloadPresent).WillRepeatedly(Return(true));
+
+ EXPECT_CALL(*mDisplay1, offloadPresentNextFrame).Times(0);
+ EXPECT_CALL(*mDisplay2, offloadPresentNextFrame).Times(0);
+
+ SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
+ setOutputs({mDisplay1, mDisplay2});
+
+ mEngine.present(mRefreshArgs);
+}
+
+TEST_F(CompositionEngineOffloadTest, disabledDisplaysDoNotPreventOthersFromOffloading) {
+ // Disable mDisplay2.
+ mOutputStates[1].isEnabled = false;
+ EXPECT_CALL(*mDisplay1, supportsOffloadPresent).WillOnce(Return(true));
+
+ // This is not actually called, because it is not enabled, but this distinguishes
+ // from the case where it did not return true.
+ EXPECT_CALL(*mDisplay2, supportsOffloadPresent).WillRepeatedly(Return(true));
+ EXPECT_CALL(*mHalVirtualDisplay, supportsOffloadPresent).WillOnce(Return(true));
+
+ EXPECT_CALL(*mDisplay1, offloadPresentNextFrame).Times(1);
+ EXPECT_CALL(*mDisplay2, offloadPresentNextFrame).Times(0);
+ EXPECT_CALL(*mHalVirtualDisplay, offloadPresentNextFrame).Times(0);
+
+ SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
+ setOutputs({mDisplay1, mDisplay2, mHalVirtualDisplay});
+
+ mEngine.present(mRefreshArgs);
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 4a778d4..a95a5c6 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -936,7 +936,7 @@
mDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
// We expect no calls to queueBuffer if composition was skipped.
- EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(1);
+ EXPECT_CALL(*renderSurface, queueBuffer(_, _)).Times(1);
// Expect a call to signal no expensive rendering since there is no client composition.
EXPECT_CALL(mPowerAdvisor, setExpensiveRenderingExpected(DEFAULT_DISPLAY_ID, false));
@@ -957,7 +957,7 @@
gpuDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
// We expect no calls to queueBuffer if composition was skipped.
- EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(0);
+ EXPECT_CALL(*renderSurface, queueBuffer(_, _)).Times(0);
EXPECT_CALL(*renderSurface, beginFrame(false));
gpuDisplay->editState().isEnabled = true;
@@ -978,7 +978,7 @@
gpuDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
// We expect no calls to queueBuffer if composition was skipped.
- EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(0);
+ EXPECT_CALL(*renderSurface, queueBuffer(_, _)).Times(0);
EXPECT_CALL(*renderSurface, beginFrame(false));
gpuDisplay->editState().isEnabled = true;
@@ -999,7 +999,7 @@
gpuDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
// We expect a single call to queueBuffer when composition is not skipped.
- EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(1);
+ EXPECT_CALL(*renderSurface, queueBuffer(_, _)).Times(1);
EXPECT_CALL(*renderSurface, beginFrame(true));
gpuDisplay->editState().isEnabled = true;
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index b2491d8..8b736be 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -57,9 +57,10 @@
MOCK_METHOD(status_t, getDeviceCompositionChanges,
(HalDisplayId, bool, std::optional<std::chrono::steady_clock::time_point>, nsecs_t,
Fps, std::optional<android::HWComposer::DeviceRequestedChanges>*));
- MOCK_METHOD5(setClientTarget,
- status_t(HalDisplayId, uint32_t, const sp<Fence>&, const sp<GraphicBuffer>&,
- ui::Dataspace));
+ MOCK_METHOD(status_t, setClientTarget,
+ (HalDisplayId, uint32_t, const sp<Fence>&, const sp<GraphicBuffer>&, ui::Dataspace,
+ float),
+ (override));
MOCK_METHOD2(presentAndGetReleaseFences,
status_t(HalDisplayId, std::optional<std::chrono::steady_clock::time_point>));
MOCK_METHOD2(setPowerMode, status_t(PhysicalDisplayId, hal::PowerMode));
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 5006e7d..bf7ed87 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -15,6 +15,7 @@
*/
#include <android-base/stringprintf.h>
+#include <com_android_graphics_surfaceflinger_flags.h>
#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/impl/Output.h>
#include <compositionengine/impl/OutputCompositionState.h>
@@ -37,6 +38,8 @@
#include <cstdint>
#include <variant>
+#include <common/FlagManager.h>
+#include <common/test/FlagUtils.h>
#include "CallOrderStateMachineHelper.h"
#include "MockHWC2.h"
#include "RegionMatcher.h"
@@ -44,6 +47,8 @@
namespace android::compositionengine {
namespace {
+using namespace com::android::graphics::surfaceflinger;
+
using testing::_;
using testing::ByMove;
using testing::ByRef;
@@ -2961,7 +2966,7 @@
EXPECT_CALL(mOutput, updateProtectedContentState());
EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _));
EXPECT_CALL(mOutput, composeSurfaces(RegionEq(kNotEmptyRegion), _, _));
- EXPECT_CALL(*mRenderSurface, queueBuffer(_));
+ EXPECT_CALL(*mRenderSurface, queueBuffer(_, 1.f));
EXPECT_CALL(mOutput, presentFrameAndReleaseLayers());
EXPECT_CALL(mOutput, prepareFrame());
@@ -2990,11 +2995,15 @@
mOutput.setDisplayColorProfileForTest(
std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
+ EXPECT_CALL(mOutput, getCompositionEngine()).WillRepeatedly(ReturnRef(mCompositionEngine));
+ EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
}
StrictMock<OutputPartialMock> mOutput;
mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+ StrictMock<renderengine::mock::RenderEngine> mRenderEngine;
};
TEST_F(OutputFinishFrameTest, ifNotEnabledDoesNothing) {
@@ -3022,7 +3031,34 @@
EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(true));
EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _, _))
.WillOnce(Return(ByMove(base::unique_fd())));
- EXPECT_CALL(*mRenderSurface, queueBuffer(_));
+ EXPECT_CALL(*mRenderSurface, queueBuffer(_, 1.f));
+
+ impl::GpuCompositionResult result;
+ mOutput.finishFrame(std::move(result));
+}
+
+TEST_F(OutputFinishFrameTest, queuesBufferWithHdrSdrRatio) {
+ SET_FLAG_FOR_TEST(flags::fp16_client_target, true);
+ mOutput.mState.isEnabled = true;
+
+ InSequence seq;
+ auto texture = std::make_shared<
+ renderengine::impl::
+ ExternalTexture>(sp<GraphicBuffer>::make(1u, 1u, PIXEL_FORMAT_RGBA_FP16,
+ GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_SW_READ_OFTEN),
+ mRenderEngine,
+ renderengine::impl::ExternalTexture::Usage::READABLE |
+ renderengine::impl::ExternalTexture::Usage::WRITEABLE);
+ mOutput.mState.displayBrightnessNits = 400.f;
+ mOutput.mState.sdrWhitePointNits = 200.f;
+ mOutput.mState.dataspace = ui::Dataspace::V0_SCRGB;
+ EXPECT_CALL(mOutput, updateProtectedContentState());
+ EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _))
+ .WillOnce(DoAll(SetArgPointee<1>(texture), Return(true)));
+ EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _, _))
+ .WillOnce(Return(ByMove(base::unique_fd())));
+ EXPECT_CALL(*mRenderSurface, queueBuffer(_, 2.f));
impl::GpuCompositionResult result;
mOutput.finishFrame(std::move(result));
@@ -3032,7 +3068,7 @@
mOutput.mState.isEnabled = true;
mOutput.mState.strategyPrediction = CompositionStrategyPredictionState::SUCCESS;
InSequence seq;
- EXPECT_CALL(*mRenderSurface, queueBuffer(_));
+ EXPECT_CALL(*mRenderSurface, queueBuffer(_, 1.f));
impl::GpuCompositionResult result;
mOutput.finishFrame(std::move(result));
@@ -3054,7 +3090,7 @@
composeSurfaces(RegionEq(Region::INVALID_REGION), result.buffer,
Eq(ByRef(result.fence))))
.WillOnce(Return(ByMove(base::unique_fd())));
- EXPECT_CALL(*mRenderSurface, queueBuffer(_));
+ EXPECT_CALL(*mRenderSurface, queueBuffer(_, 1.f));
mOutput.finishFrame(std::move(result));
}
@@ -3324,6 +3360,7 @@
static constexpr float kDefaultAvgLuminance = 0.7f;
static constexpr float kDefaultMinLuminance = 0.1f;
static constexpr float kDisplayLuminance = 400.f;
+ static constexpr float kWhitePointLuminance = 300.f;
static constexpr float kClientTargetLuminanceNits = 200.f;
static constexpr float kClientTargetBrightness = 0.5f;
@@ -3634,7 +3671,7 @@
OutputComposeSurfacesTest_UsesExpectedDisplaySettings() {
EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
- EXPECT_CALL(mOutput, generateClientCompositionRequests(_, kDefaultOutputDataspace, _))
+ EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, _))
.WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{}));
EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
.WillRepeatedly(Return());
@@ -3661,6 +3698,14 @@
: public CallOrderStateMachineHelper<TestType, OutputWithDisplayBrightnessNits> {
auto withDisplayBrightnessNits(float nits) {
getInstance()->mOutput.mState.displayBrightnessNits = nits;
+ return nextState<OutputWithSdrWhitePointNits>();
+ }
+ };
+
+ struct OutputWithSdrWhitePointNits
+ : public CallOrderStateMachineHelper<TestType, OutputWithSdrWhitePointNits> {
+ auto withSdrWhitePointNits(float nits) {
+ getInstance()->mOutput.mState.sdrWhitePointNits = nits;
return nextState<OutputWithDimmingStage>();
}
};
@@ -3690,6 +3735,35 @@
// May be called zero or one times.
EXPECT_CALL(getInstance()->mOutput, getSkipColorTransform())
.WillRepeatedly(Return(skip));
+ return nextState<PixelFormatState>();
+ }
+ };
+
+ struct PixelFormatState : public CallOrderStateMachineHelper<TestType, PixelFormatState> {
+ auto withPixelFormat(std::optional<PixelFormat> format) {
+ // May be called zero or one times.
+ if (format) {
+ auto outputBuffer = std::make_shared<
+ renderengine::impl::
+ ExternalTexture>(sp<GraphicBuffer>::
+ make(1u, 1u, *format,
+ GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_SW_READ_OFTEN),
+ getInstance()->mRenderEngine,
+ renderengine::impl::ExternalTexture::Usage::
+ READABLE |
+ renderengine::impl::ExternalTexture::
+ Usage::WRITEABLE);
+ EXPECT_CALL(*getInstance()->mRenderSurface, dequeueBuffer(_))
+ .WillRepeatedly(Return(outputBuffer));
+ }
+ return nextState<DataspaceState>();
+ }
+ };
+
+ struct DataspaceState : public CallOrderStateMachineHelper<TestType, DataspaceState> {
+ auto withDataspace(ui::Dataspace dataspace) {
+ getInstance()->mOutput.mState.dataspace = dataspace;
return nextState<ExpectDisplaySettingsState>();
}
};
@@ -3711,10 +3785,13 @@
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(true)
.withDisplayBrightnessNits(kDisplayLuminance)
+ .withSdrWhitePointNits(kWhitePointLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(
aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
.andIfSkipColorTransform(false)
+ .withPixelFormat(std::nullopt)
+ .withDataspace(kDefaultOutputDataspace)
.thenExpectDisplaySettingsUsed(
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
@@ -3738,10 +3815,13 @@
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(true)
.withDisplayBrightnessNits(kDisplayLuminance)
+ .withSdrWhitePointNits(kWhitePointLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(
aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
.andIfSkipColorTransform(false)
+ .withPixelFormat(std::nullopt)
+ .withDataspace(kDefaultOutputDataspace)
.thenExpectDisplaySettingsUsed(
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
@@ -3765,11 +3845,14 @@
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(true)
.withDisplayBrightnessNits(kDisplayLuminance)
+ .withSdrWhitePointNits(kWhitePointLuminance)
.withDimmingStage(
aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF)
.withRenderIntent(
aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
.andIfSkipColorTransform(false)
+ .withPixelFormat(std::nullopt)
+ .withDataspace(kDefaultOutputDataspace)
.thenExpectDisplaySettingsUsed(
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
@@ -3793,9 +3876,12 @@
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(true)
.withDisplayBrightnessNits(kDisplayLuminance)
+ .withSdrWhitePointNits(kWhitePointLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(aidl::android::hardware::graphics::composer3::RenderIntent::ENHANCE)
.andIfSkipColorTransform(false)
+ .withPixelFormat(std::nullopt)
+ .withDataspace(kDefaultOutputDataspace)
.thenExpectDisplaySettingsUsed(
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
@@ -3818,10 +3904,13 @@
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(false)
.withDisplayBrightnessNits(kDisplayLuminance)
+ .withSdrWhitePointNits(kWhitePointLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(
aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
.andIfSkipColorTransform(false)
+ .withPixelFormat(std::nullopt)
+ .withDataspace(kDefaultOutputDataspace)
.thenExpectDisplaySettingsUsed(
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
@@ -3844,10 +3933,13 @@
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(true)
.withDisplayBrightnessNits(kDisplayLuminance)
+ .withSdrWhitePointNits(kWhitePointLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(
aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
.andIfSkipColorTransform(false)
+ .withPixelFormat(std::nullopt)
+ .withDataspace(kDefaultOutputDataspace)
.thenExpectDisplaySettingsUsed(
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
@@ -3870,10 +3962,13 @@
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(false)
.withDisplayBrightnessNits(kDisplayLuminance)
+ .withSdrWhitePointNits(kWhitePointLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(
aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
.andIfSkipColorTransform(false)
+ .withPixelFormat(std::nullopt)
+ .withDataspace(kDefaultOutputDataspace)
.thenExpectDisplaySettingsUsed(
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
@@ -3897,10 +3992,13 @@
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(true)
.withDisplayBrightnessNits(kDisplayLuminance)
+ .withSdrWhitePointNits(kWhitePointLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(
aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
.andIfSkipColorTransform(true)
+ .withPixelFormat(std::nullopt)
+ .withDataspace(kDefaultOutputDataspace)
.thenExpectDisplaySettingsUsed(
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
@@ -3919,6 +4017,38 @@
.expectAFenceWasReturned();
}
+TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings,
+ usesExpectedDisplaySettingsWithFp16Buffer) {
+ SET_FLAG_FOR_TEST(flags::fp16_client_target, true);
+ ALOGE("alecmouri: %d", flags::fp16_client_target());
+ verify().ifMixedCompositionIs(false)
+ .andIfUsesHdr(true)
+ .withDisplayBrightnessNits(kDisplayLuminance)
+ .withSdrWhitePointNits(kWhitePointLuminance)
+ .withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
+ .withRenderIntent(
+ aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
+ .andIfSkipColorTransform(true)
+ .withPixelFormat(PIXEL_FORMAT_RGBA_FP16)
+ .withDataspace(ui::Dataspace::V0_SCRGB)
+ .thenExpectDisplaySettingsUsed(
+ {.physicalDisplay = kDefaultOutputDestinationClip,
+ .clip = kDefaultOutputViewport,
+ .maxLuminance = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
+ .outputDataspace = ui::Dataspace::V0_SCRGB,
+ .colorTransform = kDefaultColorTransformMat,
+ .deviceHandlesColorTransform = true,
+ .orientation = kDefaultOutputOrientationFlags,
+ .targetLuminanceNits = kClientTargetLuminanceNits * 0.75f,
+ .dimmingStage =
+ aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR,
+ .renderIntent = aidl::android::hardware::graphics::composer3::RenderIntent::
+ COLORIMETRIC})
+ .execute()
+ .expectAFenceWasReturned();
+}
+
struct OutputComposeSurfacesTest_HandlesProtectedContent : public OutputComposeSurfacesTest {
struct Layer {
Layer() {
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index 83937a6..edfaa26 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -263,9 +263,9 @@
state.flipClientTarget = false;
EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
- EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+ EXPECT_CALL(*mDisplaySurface, advanceFrame(0.5f)).Times(1);
- mSurface.queueBuffer(base::unique_fd());
+ mSurface.queueBuffer(base::unique_fd(), 0.5f);
EXPECT_EQ(buffer.get(), mSurface.mutableTextureForTest().get());
}
@@ -283,9 +283,9 @@
EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getBuffer()->getNativeBuffer(), -1))
.WillOnce(Return(NO_ERROR));
- EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+ EXPECT_CALL(*mDisplaySurface, advanceFrame(0.5f)).Times(1);
- mSurface.queueBuffer(base::unique_fd());
+ mSurface.queueBuffer(base::unique_fd(), 0.5f);
EXPECT_EQ(nullptr, mSurface.mutableTextureForTest().get());
}
@@ -303,9 +303,9 @@
EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getBuffer()->getNativeBuffer(), -1))
.WillOnce(Return(NO_ERROR));
- EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+ EXPECT_CALL(*mDisplaySurface, advanceFrame(0.5f)).Times(1);
- mSurface.queueBuffer(base::unique_fd());
+ mSurface.queueBuffer(base::unique_fd(), 0.5f);
EXPECT_EQ(nullptr, mSurface.mutableTextureForTest().get());
}
@@ -323,9 +323,9 @@
DoAll(SetArgPointee<0>(buffer.get()), SetArgPointee<1>(-1), Return(NO_ERROR)));
EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
.WillOnce(Return(NO_ERROR));
- EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+ EXPECT_CALL(*mDisplaySurface, advanceFrame(0.5f)).Times(1);
- mSurface.queueBuffer(base::unique_fd());
+ mSurface.queueBuffer(base::unique_fd(), 0.5f);
EXPECT_EQ(nullptr, mSurface.mutableTextureForTest().get());
}
@@ -345,9 +345,9 @@
EXPECT_CALL(mDisplay, isVirtual()).WillOnce(Return(true));
EXPECT_CALL(*mNativeWindow, cancelBuffer(buffer->getBuffer()->getNativeBuffer(), -1))
.WillOnce(Return(NO_ERROR));
- EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+ EXPECT_CALL(*mDisplaySurface, advanceFrame(0.5f)).Times(1);
- mSurface.queueBuffer(base::unique_fd());
+ mSurface.queueBuffer(base::unique_fd(), 0.5f);
EXPECT_EQ(nullptr, mSurface.mutableTextureForTest().get());
}
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 249c40b..950b05e 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -72,6 +72,7 @@
mRefreshRateSelector(std::move(args.refreshRateSelector)),
mHasDesiredModeTrace(concatId("HasDesiredMode"), false) {
mCompositionDisplay->editState().isSecure = args.isSecure;
+ mCompositionDisplay->editState().isProtected = args.isProtected;
mCompositionDisplay->createRenderSurface(
compositionengine::RenderSurfaceCreationArgsBuilder()
.setDisplayWidth(ANativeWindow_getWidth(args.nativeWindow.get()))
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 51c7be0..ac390cb 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -332,6 +332,7 @@
uint32_t height = 0;
std::string displayName;
bool isSecure = false;
+ bool isProtected = false;
// Refer to DisplayDevice::mRequestedRefreshRate, for virtual display only
Fps requestedRefreshRate;
@@ -353,6 +354,7 @@
int32_t sequenceId{0};
bool isSecure{false};
+ bool isProtected{false};
sp<ANativeWindow> nativeWindow;
sp<compositionengine::DisplaySurface> displaySurface;
ui::Rotation physicalOrientation{ui::ROTATION_0};
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index 3690219..c25f9dd 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -666,7 +666,8 @@
Error AidlComposer::setClientTarget(Display display, uint32_t slot, const sp<GraphicBuffer>& target,
int acquireFence, Dataspace dataspace,
- const std::vector<IComposerClient::Rect>& damage) {
+ const std::vector<IComposerClient::Rect>& damage,
+ float hdrSdrRatio) {
const native_handle_t* handle = nullptr;
if (target.get()) {
handle = target->getNativeBuffer()->handle;
@@ -679,7 +680,7 @@
.setClientTarget(translate<int64_t>(display), slot, handle, acquireFence,
translate<aidl::android::hardware::graphics::common::Dataspace>(
dataspace),
- translate<AidlRect>(damage));
+ translate<AidlRect>(damage), hdrSdrRatio);
} else {
error = Error::BAD_DISPLAY;
}
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index 1635a16..51ac1f5 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -124,7 +124,8 @@
*/
Error setClientTarget(Display display, uint32_t slot, const sp<GraphicBuffer>& target,
int acquireFence, Dataspace dataspace,
- const std::vector<IComposerClient::Rect>& damage) override;
+ const std::vector<IComposerClient::Rect>& damage,
+ float hdrSdrRatio) override;
Error setColorMode(Display display, ColorMode mode, RenderIntent renderIntent) override;
Error setColorTransform(Display display, const float* matrix) override;
Error setOutputBuffer(Display display, const native_handle_t* buffer,
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 082717a..1a24222 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -163,7 +163,8 @@
*/
virtual Error setClientTarget(Display display, uint32_t slot, const sp<GraphicBuffer>& target,
int acquireFence, Dataspace dataspace,
- const std::vector<IComposerClient::Rect>& damage) = 0;
+ const std::vector<IComposerClient::Rect>& damage,
+ float hdrSdrRatio) = 0;
virtual Error setColorMode(Display display, ColorMode mode, RenderIntent renderIntent) = 0;
virtual Error setColorTransform(Display display, const float* matrix) = 0;
virtual Error setOutputBuffer(Display display, const native_handle_t* buffer,
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index ce602a8..c77cdd4 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -91,7 +91,7 @@
return NO_ERROR;
}
-status_t FramebufferSurface::advanceFrame() {
+status_t FramebufferSurface::advanceFrame(float hdrSdrRatio) {
Mutex::Autolock lock(mMutex);
BufferItem item;
@@ -131,7 +131,7 @@
hwcBuffer = mCurrentBuffer; // HWC hasn't previously seen this buffer in this slot
}
status_t result = mHwc.setClientTarget(mDisplayId, mCurrentBufferSlot, mCurrentFence, hwcBuffer,
- mDataspace);
+ mDataspace, hdrSdrRatio);
if (result != NO_ERROR) {
ALOGE("error posting framebuffer: %s (%d)", strerror(-result), result);
return result;
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 0b863da..2728cf6 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -46,7 +46,7 @@
virtual status_t beginFrame(bool mustRecompose);
virtual status_t prepareFrame(CompositionType compositionType);
- virtual status_t advanceFrame();
+ virtual status_t advanceFrame(float hdrSdrRatio);
virtual void onFrameCommitted();
virtual void dumpAsString(String8& result) const;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index bc763b2..24a9e22 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -446,12 +446,13 @@
}
Error Display::setClientTarget(uint32_t slot, const sp<GraphicBuffer>& target,
- const sp<Fence>& acquireFence, Dataspace dataspace)
-{
+ const sp<Fence>& acquireFence, Dataspace dataspace,
+ float hdrSdrRatio) {
// TODO: Properly encode client target surface damage
int32_t fenceFd = acquireFence->dup();
- auto intError = mComposer.setClientTarget(mId, slot, target,
- fenceFd, dataspace, std::vector<Hwc2::IComposerClient::Rect>());
+ auto intError =
+ mComposer.setClientTarget(mId, slot, target, fenceFd, dataspace,
+ std::vector<Hwc2::IComposerClient::Rect>(), hdrSdrRatio);
return static_cast<Error>(intError);
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 29fe380..f907061 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -141,7 +141,8 @@
[[nodiscard]] virtual hal::Error present(android::sp<android::Fence>* outPresentFence) = 0;
[[nodiscard]] virtual hal::Error setClientTarget(
uint32_t slot, const android::sp<android::GraphicBuffer>& target,
- const android::sp<android::Fence>& acquireFence, hal::Dataspace dataspace) = 0;
+ const android::sp<android::Fence>& acquireFence, hal::Dataspace dataspace,
+ float hdrSdrRatio) = 0;
[[nodiscard]] virtual hal::Error setColorMode(hal::ColorMode mode,
hal::RenderIntent renderIntent) = 0;
[[nodiscard]] virtual hal::Error setColorTransform(const android::mat4& matrix) = 0;
@@ -229,7 +230,7 @@
hal::Error present(android::sp<android::Fence>* outPresentFence) override;
hal::Error setClientTarget(uint32_t slot, const android::sp<android::GraphicBuffer>& target,
const android::sp<android::Fence>& acquireFence,
- hal::Dataspace dataspace) override;
+ hal::Dataspace dataspace, float hdrSdrRatio) override;
hal::Error setColorMode(hal::ColorMode, hal::RenderIntent) override;
hal::Error setColorTransform(const android::mat4& matrix) override;
hal::Error setOutputBuffer(const android::sp<android::GraphicBuffer>&,
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 10df216..6b67865 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -485,12 +485,12 @@
status_t HWComposer::setClientTarget(HalDisplayId displayId, uint32_t slot,
const sp<Fence>& acquireFence, const sp<GraphicBuffer>& target,
- ui::Dataspace dataspace) {
+ ui::Dataspace dataspace, float hdrSdrRatio) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
ALOGV("%s for display %s", __FUNCTION__, to_string(displayId).c_str());
auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
- auto error = hwcDisplay->setClientTarget(slot, target, acquireFence, dataspace);
+ auto error = hwcDisplay->setClientTarget(slot, target, acquireFence, dataspace, hdrSdrRatio);
RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE);
return NO_ERROR;
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 5846c07..af62731 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -151,7 +151,8 @@
std::optional<DeviceRequestedChanges>* outChanges) = 0;
virtual status_t setClientTarget(HalDisplayId, uint32_t slot, const sp<Fence>& acquireFence,
- const sp<GraphicBuffer>& target, ui::Dataspace) = 0;
+ const sp<GraphicBuffer>& target, ui::Dataspace,
+ float hdrSdrRatio) = 0;
// Present layers to the display and read releaseFences.
virtual status_t presentAndGetReleaseFences(
@@ -352,7 +353,8 @@
std::optional<DeviceRequestedChanges>* outChanges) override;
status_t setClientTarget(HalDisplayId, uint32_t slot, const sp<Fence>& acquireFence,
- const sp<GraphicBuffer>& target, ui::Dataspace) override;
+ const sp<GraphicBuffer>& target, ui::Dataspace,
+ float hdrSdrRatio) override;
// Present layers to the display and read releaseFences.
status_t presentAndGetReleaseFences(
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index ed52b95..5f1d5f8 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -608,7 +608,8 @@
Error HidlComposer::setClientTarget(Display display, uint32_t slot, const sp<GraphicBuffer>& target,
int acquireFence, Dataspace dataspace,
- const std::vector<IComposerClient::Rect>& damage) {
+ const std::vector<IComposerClient::Rect>& damage,
+ float /*hdrSdrRatio*/) {
mWriter.selectDisplay(display);
const native_handle_t* handle = nullptr;
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index 5c19b47..c768d27 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -226,7 +226,8 @@
*/
Error setClientTarget(Display display, uint32_t slot, const sp<GraphicBuffer>& target,
int acquireFence, Dataspace dataspace,
- const std::vector<IComposerClient::Rect>& damage) override;
+ const std::vector<IComposerClient::Rect>& damage,
+ float hdrSdrRatio) override;
Error setColorMode(Display display, ColorMode mode, RenderIntent renderIntent) override;
Error setColorTransform(Display display, const float* matrix) override;
Error setOutputBuffer(Display display, const native_handle_t* buffer,
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index d62075e..4b5a68c 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -175,7 +175,7 @@
return NO_ERROR;
}
-status_t VirtualDisplaySurface::advanceFrame() {
+status_t VirtualDisplaySurface::advanceFrame(float hdrSdrRatio) {
if (GpuVirtualDisplayId::tryCast(mDisplayId)) {
return NO_ERROR;
}
@@ -223,7 +223,7 @@
}
// TODO: Correctly propagate the dataspace from GL composition
result = mHwc.setClientTarget(*halDisplayId, mFbProducerSlot, mFbFence, hwcBuffer,
- ui::Dataspace::UNKNOWN);
+ ui::Dataspace::UNKNOWN, hdrSdrRatio);
}
return result;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index be06e2b..90426f7 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -84,7 +84,7 @@
//
virtual status_t beginFrame(bool mustRecompose);
virtual status_t prepareFrame(CompositionType);
- virtual status_t advanceFrame();
+ virtual status_t advanceFrame(float hdrSdrRatio);
virtual void onFrameCommitted();
virtual void dumpAsString(String8& result) const;
virtual void resizeBuffers(const ui::Size&) override;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index a92cc03..ad5e42b 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -708,7 +708,7 @@
ftl::Flags<RequestedLayerState::Changes> parentChanges = parentSnapshot.changes &
(RequestedLayerState::Changes::Hierarchy | RequestedLayerState::Changes::Geometry |
RequestedLayerState::Changes::Visibility | RequestedLayerState::Changes::Metadata |
- RequestedLayerState::Changes::AffectsChildren |
+ RequestedLayerState::Changes::AffectsChildren | RequestedLayerState::Changes::Input |
RequestedLayerState::Changes::FrameRate | RequestedLayerState::Changes::GameMode);
snapshot.changes |= parentChanges;
if (args.displayChanges) snapshot.changes |= RequestedLayerState::Changes::Geometry;
@@ -1041,6 +1041,19 @@
snapshot.inputInfo.id = static_cast<int32_t>(snapshot.uniqueSequence);
snapshot.inputInfo.displayId = static_cast<int32_t>(snapshot.outputFilter.layerStack.id);
+ snapshot.inputInfo.touchOcclusionMode = requested.hasInputInfo()
+ ? requested.windowInfoHandle->getInfo()->touchOcclusionMode
+ : parentSnapshot.inputInfo.touchOcclusionMode;
+ if (requested.dropInputMode == gui::DropInputMode::ALL ||
+ parentSnapshot.dropInputMode == gui::DropInputMode::ALL) {
+ snapshot.dropInputMode = gui::DropInputMode::ALL;
+ } else if (requested.dropInputMode == gui::DropInputMode::OBSCURED ||
+ parentSnapshot.dropInputMode == gui::DropInputMode::OBSCURED) {
+ snapshot.dropInputMode = gui::DropInputMode::OBSCURED;
+ } else {
+ snapshot.dropInputMode = gui::DropInputMode::NONE;
+ }
+
updateVisibility(snapshot, snapshot.isVisible);
if (!needsInputInfo(snapshot, requested)) {
return;
@@ -1064,18 +1077,6 @@
}
snapshot.inputInfo.alpha = snapshot.color.a;
- snapshot.inputInfo.touchOcclusionMode = requested.hasInputInfo()
- ? requested.windowInfoHandle->getInfo()->touchOcclusionMode
- : parentSnapshot.inputInfo.touchOcclusionMode;
- if (requested.dropInputMode == gui::DropInputMode::ALL ||
- parentSnapshot.dropInputMode == gui::DropInputMode::ALL) {
- snapshot.dropInputMode = gui::DropInputMode::ALL;
- } else if (requested.dropInputMode == gui::DropInputMode::OBSCURED ||
- parentSnapshot.dropInputMode == gui::DropInputMode::OBSCURED) {
- snapshot.dropInputMode = gui::DropInputMode::OBSCURED;
- } else {
- snapshot.dropInputMode = gui::DropInputMode::NONE;
- }
handleDropInputMode(snapshot, parentSnapshot);
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index 21172ca..209df79 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -417,6 +417,8 @@
if (!obj.handleAlive) out << " handleNotAlive";
if (obj.requestedFrameRate.isValid())
out << " requestedFrameRate: {" << obj.requestedFrameRate << "}";
+ if (obj.dropInputMode != gui::DropInputMode::NONE)
+ out << " dropInputMode=" << static_cast<uint32_t>(obj.dropInputMode);
return out;
}
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 949a161..f7800bb 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -3264,7 +3264,7 @@
// If the layer had been updated a TextureView, this would make sure the present time could be
// same to TextureView update when it's a small dirty, and get the correct heuristic rate.
- if (mFlinger->mScheduler->supportSmallDirtyDetection()) {
+ if (mFlinger->mScheduler->supportSmallDirtyDetection(mOwnerAppId)) {
if (mDrawingState.useVsyncIdForRefreshRateSelection) {
mUsedVsyncIdForRefreshRateSelection = true;
}
@@ -3297,7 +3297,7 @@
}
}
- if (!mFlinger->mScheduler->supportSmallDirtyDetection()) {
+ if (!mFlinger->mScheduler->supportSmallDirtyDetection(mOwnerAppId)) {
return static_cast<nsecs_t>(0);
}
@@ -4440,7 +4440,7 @@
void Layer::setIsSmallDirty(const Region& damageRegion,
const ui::Transform& layerToDisplayTransform) {
mSmallDirty = false;
- if (!mFlinger->mScheduler->supportSmallDirtyDetection()) {
+ if (!mFlinger->mScheduler->supportSmallDirtyDetection(mOwnerAppId)) {
return;
}
diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp
index f25619a..2dbcb84 100644
--- a/services/surfaceflinger/LayerFE.cpp
+++ b/services/surfaceflinger/LayerFE.cpp
@@ -208,9 +208,15 @@
// activeBuffer, then we need to return LayerSettings.
return;
}
- const bool blackOutLayer =
- (mSnapshot->hasProtectedContent && !targetSettings.supportsProtectedContent) ||
- ((mSnapshot->isSecure || mSnapshot->hasProtectedContent) && !targetSettings.isSecure);
+ bool blackOutLayer;
+ if (FlagManager::getInstance().display_protected()) {
+ blackOutLayer = (mSnapshot->hasProtectedContent && !targetSettings.isProtected) ||
+ (mSnapshot->isSecure && !targetSettings.isSecure);
+ } else {
+ blackOutLayer = (mSnapshot->hasProtectedContent && !targetSettings.isProtected) ||
+ ((mSnapshot->isSecure || mSnapshot->hasProtectedContent) &&
+ !targetSettings.isSecure);
+ }
const bool bufferCanBeUsedAsHwTexture =
mSnapshot->externalTexture->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE;
if (blackOutLayer || !bufferCanBeUsedAsHwTexture) {
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 6db39f1..c888ccc 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -374,10 +374,11 @@
constexpr bool kRegionSampling = true;
constexpr bool kGrayscale = false;
+ constexpr bool kIsProtected = false;
if (const auto fenceResult =
mFlinger.captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, buffer,
- kRegionSampling, kGrayscale, nullptr)
+ kRegionSampling, kGrayscale, kIsProtected, nullptr)
.get();
fenceResult.ok()) {
fenceResult.value()->waitForever(LOG_TAG);
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 738fd4e..aa8d54d 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -92,12 +92,12 @@
using namespace sysprop;
using namespace std::string_literals;
- const int32_t defaultTouchTouchTimerValue =
+ const int32_t defaultTouchTimerValue =
FlagManager::getInstance().enable_fro_dependent_features() &&
sysprop::enable_frame_rate_override(true)
? 200
: 0;
- if (const int32_t millis = set_touch_timer_ms(defaultTouchTouchTimerValue); millis > 0) {
+ if (const int32_t millis = set_touch_timer_ms(defaultTouchTimerValue); millis > 0) {
// Touch events are coming to SF every 100ms, so the timer needs to be higher than that
mTouchTimer.emplace(
"TouchTimer", std::chrono::milliseconds(millis),
@@ -1248,7 +1248,7 @@
}
void Scheduler::setSmallAreaDetectionThreshold(int32_t appId, float threshold) {
- mSmallAreaDetectionAllowMappings.setThesholdForAppId(appId, threshold);
+ mSmallAreaDetectionAllowMappings.setThresholdForAppId(appId, threshold);
}
bool Scheduler::isSmallDirtyArea(int32_t appId, uint32_t dirtyArea) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 6547048..454ef83 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -323,9 +323,10 @@
bool updateFrameRateOverrides(GlobalSignals, Fps displayRefreshRate) EXCLUDES(mPolicyLock);
- // Returns true if the small dirty detection is enabled.
- bool supportSmallDirtyDetection() const {
- return mFeatures.test(Feature::kSmallDirtyContentDetection);
+ // Returns true if the small dirty detection is enabled for the appId.
+ bool supportSmallDirtyDetection(int32_t appId) {
+ return mFeatures.test(Feature::kSmallDirtyContentDetection) &&
+ mSmallAreaDetectionAllowMappings.getThresholdForAppId(appId).has_value();
}
// Injects a delay that is a fraction of the predicted frame duration for the next frame.
diff --git a/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.cpp b/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.cpp
index 38c6da4..7510ebf 100644
--- a/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.cpp
+++ b/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.cpp
@@ -29,7 +29,7 @@
}
}
-void SmallAreaDetectionAllowMappings::setThesholdForAppId(int32_t appId, float threshold) {
+void SmallAreaDetectionAllowMappings::setThresholdForAppId(int32_t appId, float threshold) {
if (!isValidThreshold(threshold)) return;
std::lock_guard lock(mLock);
diff --git a/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.h b/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.h
index e10301c..4ec5e3b 100644
--- a/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.h
+++ b/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.h
@@ -28,7 +28,7 @@
public:
void update(std::vector<std::pair<int32_t, float>>& appIdThresholdMappings);
- void setThesholdForAppId(int32_t appId, float threshold) EXCLUDES(mLock);
+ void setThresholdForAppId(int32_t appId, float threshold) EXCLUDES(mLock);
std::optional<float> getThresholdForAppId(int32_t uid) EXCLUDES(mLock);
private:
diff --git a/services/surfaceflinger/ScreenCaptureOutput.cpp b/services/surfaceflinger/ScreenCaptureOutput.cpp
index 57b0d5e..dd03366 100644
--- a/services/surfaceflinger/ScreenCaptureOutput.cpp
+++ b/services/surfaceflinger/ScreenCaptureOutput.cpp
@@ -32,6 +32,7 @@
bool>(args.compositionEngine, args.renderArea, args.colorProfile, args.regionSampling,
args.dimInGammaSpaceForEnhancedScreenshots);
output->editState().isSecure = args.renderArea.isSecure();
+ output->editState().isProtected = args.isProtected;
output->setCompositionEnabled(true);
output->setLayerFilter({args.layerStack});
output->setRenderSurface(std::make_unique<ScreenCaptureRenderSurface>(std::move(args.buffer)));
@@ -74,10 +75,10 @@
outputState.renderIntent = mColorProfile.renderIntent;
}
-renderengine::DisplaySettings ScreenCaptureOutput::generateClientCompositionDisplaySettings()
- const {
+renderengine::DisplaySettings ScreenCaptureOutput::generateClientCompositionDisplaySettings(
+ const std::shared_ptr<renderengine::ExternalTexture>& buffer) const {
auto clientCompositionDisplay =
- compositionengine::impl::Output::generateClientCompositionDisplaySettings();
+ compositionengine::impl::Output::generateClientCompositionDisplaySettings(buffer);
clientCompositionDisplay.clip = mRenderArea.getSourceCrop();
auto renderIntent = static_cast<ui::RenderIntent>(clientCompositionDisplay.renderIntent);
diff --git a/services/surfaceflinger/ScreenCaptureOutput.h b/services/surfaceflinger/ScreenCaptureOutput.h
index fc095de..069f458 100644
--- a/services/surfaceflinger/ScreenCaptureOutput.h
+++ b/services/surfaceflinger/ScreenCaptureOutput.h
@@ -38,6 +38,7 @@
bool regionSampling;
bool treat170mAsSrgb;
bool dimInGammaSpaceForEnhancedScreenshots;
+ bool isProtected = false;
};
// ScreenCaptureOutput is used to compose a set of layers into a preallocated buffer.
@@ -58,7 +59,8 @@
protected:
bool getSkipColorTransform() const override { return false; }
- renderengine::DisplaySettings generateClientCompositionDisplaySettings() const override;
+ renderengine::DisplaySettings generateClientCompositionDisplaySettings(
+ const std::shared_ptr<renderengine::ExternalTexture>& buffer) const override;
private:
const RenderArea& mRenderArea;
diff --git a/services/surfaceflinger/ScreenCaptureRenderSurface.h b/services/surfaceflinger/ScreenCaptureRenderSurface.h
index 2097300..50ba9bf 100644
--- a/services/surfaceflinger/ScreenCaptureRenderSurface.h
+++ b/services/surfaceflinger/ScreenCaptureRenderSurface.h
@@ -37,7 +37,7 @@
return mBuffer;
}
- void queueBuffer(base::unique_fd readyFence) override {
+ void queueBuffer(base::unique_fd readyFence, float) override {
mRenderFence = sp<Fence>::make(readyFence.release());
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index b1598b4..8311617 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -565,6 +565,9 @@
// Display ID is assigned when virtual display is allocated by HWC.
DisplayDeviceState state;
state.isSecure = secure;
+ // 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 = secure;
state.displayName = displayName;
state.requestedRefreshRate = Fps::fromValue(requestedRefreshRate);
mCurrentState.displays.add(token, state);
@@ -2219,7 +2222,7 @@
continue;
}
- const bool updateSmallDirty = mScheduler->supportSmallDirtyDetection() &&
+ const bool updateSmallDirty = FlagManager::getInstance().enable_small_area_detection() &&
((snapshot->clientChanges & layer_state_t::eSurfaceDamageRegionChanged) ||
snapshot->changes.any(Changes::Geometry));
@@ -3383,6 +3386,7 @@
.hwcDisplayId = hwcDisplayId,
.activeMode = std::move(activeMode)};
state.isSecure = true; // All physical displays are currently considered secure.
+ state.isProtected = true;
state.displayName = std::move(info.name);
mCurrentState.displays.add(token, state);
@@ -3414,6 +3418,7 @@
displayToken, compositionDisplay);
creationArgs.sequenceId = state.sequenceId;
creationArgs.isSecure = state.isSecure;
+ creationArgs.isProtected = state.isProtected;
creationArgs.displaySurface = displaySurface;
creationArgs.hasWideColorGamut = false;
creationArgs.supportedPerFrameMetadata = 0;
@@ -3545,6 +3550,7 @@
builder.setPixels(resolution);
builder.setIsSecure(state.isSecure);
+ builder.setIsProtected(state.isProtected);
builder.setPowerAdvisor(mPowerAdvisor.get());
builder.setName(state.displayName);
auto compositionDisplay = getCompositionEngine().createDisplay(builder.build());
@@ -5823,12 +5829,15 @@
}
getHwComposer().setPowerMode(displayId, mode);
- if (displayId == mActiveDisplayId && mode != hal::PowerMode::DOZE_SUSPEND) {
+ if (mode != hal::PowerMode::DOZE_SUSPEND &&
+ (displayId == mActiveDisplayId || FlagManager::getInstance().multithreaded_present())) {
const bool enable =
mScheduler->getVsyncSchedule(displayId)->getPendingHardwareVsyncState();
requestHardwareVsync(displayId, enable);
- mScheduler->enableSyntheticVsync(false);
+ if (displayId == mActiveDisplayId) {
+ mScheduler->enableSyntheticVsync(false);
+ }
constexpr bool kAllowToEnable = true;
mScheduler->resyncToHardwareVsync(displayId, kAllowToEnable, activeMode.get());
@@ -5837,8 +5846,8 @@
mVisibleRegionsDirty = true;
scheduleComposite(FrameHint::kActive);
} else if (mode == hal::PowerMode::OFF) {
+ const bool currentModeNotDozeSuspend = (*currentModeOpt != hal::PowerMode::DOZE_SUSPEND);
// Turn off the display
-
if (displayId == mActiveDisplayId) {
if (const auto display = getActivatableDisplay()) {
onActiveDisplayChangedLocked(activeDisplay.get(), *display);
@@ -5852,14 +5861,24 @@
strerror(errno));
}
- if (*currentModeOpt != hal::PowerMode::DOZE_SUSPEND) {
- mScheduler->disableHardwareVsync(displayId, true);
+ if (currentModeNotDozeSuspend) {
+ if (!FlagManager::getInstance().multithreaded_present()) {
+ mScheduler->disableHardwareVsync(displayId, true);
+ }
mScheduler->enableSyntheticVsync();
}
}
}
+ if (currentModeNotDozeSuspend && FlagManager::getInstance().multithreaded_present()) {
+ constexpr bool kDisallow = true;
+ mScheduler->disableHardwareVsync(displayId, kDisallow);
+ }
- // Disable VSYNC before turning off the display.
+ // We must disable VSYNC *before* turning off the display. The call to
+ // disableHardwareVsync, above, schedules a task to turn it off after
+ // this method returns. But by that point, the display is OFF, so the
+ // call just updates the pending state, without actually disabling
+ // VSYNC.
requestHardwareVsync(displayId, false);
getHwComposer().setPowerMode(displayId, mode);
@@ -5868,18 +5887,24 @@
} else if (mode == hal::PowerMode::DOZE || mode == hal::PowerMode::ON) {
// Update display while dozing
getHwComposer().setPowerMode(displayId, mode);
- if (displayId == mActiveDisplayId && *currentModeOpt == hal::PowerMode::DOZE_SUSPEND) {
- ALOGI("Force repainting for DOZE_SUSPEND -> DOZE or ON.");
- mVisibleRegionsDirty = true;
- scheduleRepaint();
- mScheduler->enableSyntheticVsync(false);
- mScheduler->resyncToHardwareVsync(displayId, true /* allowToEnable */,
- activeMode.get());
+ if (*currentModeOpt == hal::PowerMode::DOZE_SUSPEND &&
+ (displayId == mActiveDisplayId || FlagManager::getInstance().multithreaded_present())) {
+ if (displayId == mActiveDisplayId) {
+ ALOGI("Force repainting for DOZE_SUSPEND -> DOZE or ON.");
+ mVisibleRegionsDirty = true;
+ scheduleRepaint();
+ mScheduler->enableSyntheticVsync(false);
+ }
+ constexpr bool kAllowToEnable = true;
+ mScheduler->resyncToHardwareVsync(displayId, kAllowToEnable, activeMode.get());
}
} else if (mode == hal::PowerMode::DOZE_SUSPEND) {
// Leave display going to doze
+ if (displayId == mActiveDisplayId || FlagManager::getInstance().multithreaded_present()) {
+ constexpr bool kDisallow = true;
+ mScheduler->disableHardwareVsync(displayId, kDisallow);
+ }
if (displayId == mActiveDisplayId) {
- mScheduler->disableHardwareVsync(displayId, true);
mScheduler->enableSyntheticVsync();
}
getHwComposer().setPowerMode(displayId, mode);
@@ -7545,6 +7570,12 @@
return;
}
+ if (args.captureSecureLayers && !hasCaptureBlackoutContentPermission()) {
+ ALOGE("Attempting to capture secure layers without CAPTURE_BLACKOUT_CONTENT");
+ invokeScreenCaptureError(PERMISSION_DENIED, captureListener);
+ return;
+ }
+
wp<const DisplayDevice> displayWeak;
ui::LayerStack layerStack;
ui::Size reqSize(args.width, args.height);
@@ -7675,8 +7706,11 @@
std::unordered_set<uint32_t> excludeLayerIds;
ui::Dataspace dataspace = args.dataspace;
- // Call this before holding mStateLock to avoid any deadlocking.
- bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();
+ if (args.captureSecureLayers && !hasCaptureBlackoutContentPermission()) {
+ ALOGE("Attempting to capture secure layers without CAPTURE_BLACKOUT_CONTENT");
+ invokeScreenCaptureError(PERMISSION_DENIED, captureListener);
+ return;
+ }
{
Mutex::Autolock lock(mStateLock);
@@ -7688,13 +7722,6 @@
return;
}
- if (!canCaptureBlackoutContent &&
- parent->getDrawingState().flags & layer_state_t::eLayerSecure) {
- ALOGW("Attempting to capture secure layer: PERMISSION_DENIED");
- invokeScreenCaptureError(PERMISSION_DENIED, captureListener);
- return;
- }
-
Rect parentSourceBounds = parent->getCroppedBufferSize(parent->getDrawingState());
if (args.sourceCrop.width() <= 0) {
crop.left = 0;
@@ -7837,12 +7864,11 @@
})
.get();
}
-
+ const bool isProtected = hasProtectedLayer && allowProtected && supportsProtected;
const uint32_t usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER |
GRALLOC_USAGE_HW_TEXTURE |
- (hasProtectedLayer && allowProtected && supportsProtected
- ? GRALLOC_USAGE_PROTECTED
- : GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+ (isProtected ? GRALLOC_USAGE_PROTECTED
+ : GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
sp<GraphicBuffer> buffer =
getFactory().createGraphicBuffer(bufferSize.getWidth(), bufferSize.getHeight(),
static_cast<android_pixel_format>(reqPixelFormat),
@@ -7862,18 +7888,17 @@
renderengine::impl::ExternalTexture::Usage::
WRITEABLE);
auto fence = captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, texture,
- false /* regionSampling */, grayscale, captureListener);
+ false /* regionSampling */, grayscale, isProtected,
+ captureListener);
fence.get();
}
ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenCommon(
RenderAreaFuture renderAreaFuture, GetLayerSnapshotsFunction getLayerSnapshots,
const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling,
- bool grayscale, const sp<IScreenCaptureListener>& captureListener) {
+ bool grayscale, bool isProtected, const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();
- bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();
-
auto future = mScheduler->schedule(
[=, renderAreaFuture = std::move(renderAreaFuture)]() FTL_FAKE_GUARD(
kMainThreadContext) mutable -> ftl::SharedFuture<FenceResult> {
@@ -7890,9 +7915,9 @@
ftl::SharedFuture<FenceResult> renderFuture;
renderArea->render([&]() FTL_FAKE_GUARD(kMainThreadContext) {
- renderFuture = renderScreenImpl(renderArea, getLayerSnapshots, buffer,
- canCaptureBlackoutContent, regionSampling,
- grayscale, captureResults);
+ renderFuture =
+ renderScreenImpl(renderArea, getLayerSnapshots, buffer, regionSampling,
+ grayscale, isProtected, captureResults);
});
if (captureListener) {
@@ -7919,9 +7944,8 @@
ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl(
std::shared_ptr<const RenderArea> renderArea, GetLayerSnapshotsFunction getLayerSnapshots,
- const std::shared_ptr<renderengine::ExternalTexture>& buffer,
- bool canCaptureBlackoutContent, bool regionSampling, bool grayscale,
- ScreenCaptureResults& captureResults) {
+ const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling,
+ bool grayscale, bool isProtected, ScreenCaptureResults& captureResults) {
ATRACE_CALL();
auto layers = getLayerSnapshots();
@@ -7936,14 +7960,6 @@
layerFE->mSnapshot->geomLayerTransform.inverse();
}
- // We allow the system server to take screenshots of secure layers for
- // use in situations like the Screen-rotation animation and place
- // the impetus on WindowManager to not persist them.
- if (captureResults.capturedSecureLayers && !canCaptureBlackoutContent) {
- ALOGW("FB is protected: PERMISSION_DENIED");
- return ftl::yield<FenceResult>(base::unexpected(PERMISSION_DENIED)).share();
- }
-
auto capturedBuffer = buffer;
auto requestedDataspace = renderArea->getReqDataSpace();
@@ -8024,9 +8040,9 @@
};
auto present = [this, buffer = capturedBuffer, dataspace = captureResults.capturedDataspace,
- sdrWhitePointNits, displayBrightnessNits, grayscale, layerFEs = copyLayerFEs(),
- layerStack, regionSampling, renderArea = std::move(renderArea),
- renderIntent]() -> FenceResult {
+ sdrWhitePointNits, displayBrightnessNits, grayscale, isProtected,
+ layerFEs = copyLayerFEs(), layerStack, regionSampling,
+ renderArea = std::move(renderArea), renderIntent]() -> FenceResult {
std::unique_ptr<compositionengine::CompositionEngine> compositionEngine =
mFactory.createCompositionEngine();
compositionEngine->setRenderEngine(mRenderEngine.get());
@@ -8060,7 +8076,8 @@
.regionSampling = regionSampling,
.treat170mAsSrgb = mTreat170mAsSrgb,
.dimInGammaSpaceForEnhancedScreenshots =
- dimInGammaSpaceForEnhancedScreenshots});
+ dimInGammaSpaceForEnhancedScreenshots,
+ .isProtected = isProtected});
const float colorSaturation = grayscale ? 0 : 1;
compositionengine::CompositionRefreshArgs refreshArgs{
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 788fe73..6909055 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -855,11 +855,11 @@
ftl::SharedFuture<FenceResult> captureScreenCommon(
RenderAreaFuture, GetLayerSnapshotsFunction,
const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling,
- bool grayscale, const sp<IScreenCaptureListener>&);
+ bool grayscale, bool isProtected, const sp<IScreenCaptureListener>&);
ftl::SharedFuture<FenceResult> renderScreenImpl(
std::shared_ptr<const RenderArea>, GetLayerSnapshotsFunction,
- const std::shared_ptr<renderengine::ExternalTexture>&, bool canCaptureBlackoutContent,
- bool regionSampling, bool grayscale, ScreenCaptureResults&) EXCLUDES(mStateLock)
+ const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling,
+ bool grayscale, bool isProtected, ScreenCaptureResults&) EXCLUDES(mStateLock)
REQUIRES(kMainThreadContext);
// If the uid provided is not UNSET_UID, the traverse will skip any layers that don't have a
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp
index 9d6d87e..ce8119e 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.cpp
+++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp
@@ -16,12 +16,10 @@
#undef LOG_TAG
#define LOG_TAG "TransactionTracing"
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <android-base/stringprintf.h>
#include <log/log.h>
#include <utils/SystemClock.h>
-#include <utils/Trace.h>
#include "Client.h"
#include "FrontEnd/LayerCreationArgs.h"
@@ -230,7 +228,6 @@
void TransactionTracing::addEntry(const std::vector<CommittedUpdates>& committedUpdates,
const std::vector<uint32_t>& destroyedLayers) {
- ATRACE_CALL();
std::scoped_lock lock(mTraceLock);
std::vector<std::string> removedEntries;
perfetto::protos::TransactionTraceEntry entryProto;
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index 07a606c..adb4974 100644
--- a/services/surfaceflinger/common/FlagManager.cpp
+++ b/services/surfaceflinger/common/FlagManager.cpp
@@ -124,6 +124,8 @@
DUMP_READ_ONLY_FLAG(use_known_refresh_rate_for_fps_consistency);
DUMP_READ_ONLY_FLAG(cache_if_source_crop_layer_only_moved);
DUMP_READ_ONLY_FLAG(enable_fro_dependent_features);
+ DUMP_READ_ONLY_FLAG(display_protected);
+ DUMP_READ_ONLY_FLAG(fp16_client_target);
#undef DUMP_READ_ONLY_FLAG
#undef DUMP_SERVER_FLAG
@@ -197,6 +199,8 @@
FLAG_MANAGER_READ_ONLY_FLAG(cache_if_source_crop_layer_only_moved,
"debug.sf.cache_source_crop_only_moved")
FLAG_MANAGER_READ_ONLY_FLAG(enable_fro_dependent_features, "")
+FLAG_MANAGER_READ_ONLY_FLAG(display_protected, "")
+FLAG_MANAGER_READ_ONLY_FLAG(fp16_client_target, "debug.sf.fp16_client_target")
/// Trunk stable server flags ///
FLAG_MANAGER_SERVER_FLAG(late_boot_misc2, "")
diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index 38cb43a..cdab461 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -63,6 +63,8 @@
bool use_known_refresh_rate_for_fps_consistency() const;
bool cache_if_source_crop_layer_only_moved() const;
bool enable_fro_dependent_features() const;
+ bool display_protected() const;
+ bool fp16_client_target() const;
protected:
// overridden for unit tests
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
index afb5f5c..68237c8 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
@@ -286,7 +286,7 @@
composer.setClientTarget(display, mFdp.ConsumeIntegral<uint32_t>(), sp<GraphicBuffer>(),
mFdp.ConsumeIntegral<int32_t>(), mFdp.PickValueInArray(kDataspaces),
- {});
+ {}, mFdp.ConsumeFloatingPoint<float>());
composer.setColorMode(display, mFdp.PickValueInArray(kColormodes),
mFdp.PickValueInArray(kRenderIntents));
@@ -494,7 +494,7 @@
surface->beginFrame(mFdp.ConsumeBool());
surface->prepareFrame(mFdp.PickValueInArray(kCompositionTypes));
- surface->advanceFrame();
+ surface->advanceFrame(mFdp.ConsumeFloatingPoint<float>());
surface->onFrameCommitted();
String8 result = String8(mFdp.ConsumeRandomLengthString().c_str());
surface->dumpAsString(result);
@@ -530,7 +530,7 @@
surface->prepareFrame(mFdp.PickValueInArray(kCompositionTypes));
surface->resizeBuffers(getFuzzedSize());
surface->getClientTargetAcquireFence();
- surface->advanceFrame();
+ surface->advanceFrame(mFdp.ConsumeFloatingPoint<float>());
surface->onFrameCommitted();
String8 result = String8(mFdp.ConsumeRandomLengthString().c_str());
surface->dumpAsString(result);
@@ -561,7 +561,8 @@
getDeviceCompositionChanges(halDisplayID);
mHwc.setClientTarget(halDisplayID, mFdp.ConsumeIntegral<uint32_t>(), Fence::NO_FENCE,
- sp<GraphicBuffer>::make(), mFdp.PickValueInArray(kDataspaces));
+ sp<GraphicBuffer>::make(), mFdp.PickValueInArray(kDataspaces),
+ mFdp.ConsumeFloatingPoint<float>());
mHwc.presentAndGetReleaseFences(halDisplayID, std::chrono::steady_clock::now());
diff --git a/services/surfaceflinger/surfaceflinger_flags.aconfig b/services/surfaceflinger/surfaceflinger_flags.aconfig
index fcb52c7..88737c1 100644
--- a/services/surfaceflinger/surfaceflinger_flags.aconfig
+++ b/services/surfaceflinger/surfaceflinger_flags.aconfig
@@ -90,7 +90,6 @@
namespace: "core_graphics"
description: "Whether to use the closest known refresh rate to determine the fps consistency."
bug: "299201319"
- is_fixed_read_only: true
}
flag {
@@ -98,6 +97,7 @@
namespace: "core_graphics"
description: "do not flatten layers if source crop is only moved"
bug: "305718400"
+ is_fixed_read_only: true
}
flag {
@@ -107,3 +107,19 @@
bug: "314217419"
is_fixed_read_only: true
}
+
+flag {
+ name: "display_protected"
+ namespace: "core_graphics"
+ description: "Introduce protected displays to specify whether they should render protected content"
+ bug: "301647974"
+ is_fixed_read_only: true
+}
+
+flag {
+ name: "fp16_client_target"
+ namespace: "core_graphics"
+ description: "Controls whether we render to fp16 client targets"
+ bug: "236745178"
+ is_fixed_read_only: true
+}
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index 061e121..18262f6 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -99,25 +99,42 @@
ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
}
- UIDFaker f(AID_SYSTEM);
-
- // By default the system can capture screenshots with secure layers but they
- // will be blacked out
- ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
-
{
- SCOPED_TRACE("as system");
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ UIDFaker f(AID_SYSTEM);
+
+ // By default the system can capture screenshots with secure layers but they
+ // will be blacked out
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
+
+ {
+ SCOPED_TRACE("as system");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+
+ mCaptureArgs.captureSecureLayers = true;
+ // AID_SYSTEM is allowed to capture secure content.
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
+ ASSERT_TRUE(mCaptureResults.capturedSecureLayers);
+ ScreenCapture sc(mCaptureResults.buffer, mCaptureResults.capturedHdrLayers);
+ sc.expectColor(Rect(0, 0, 32, 32), Color::RED);
}
- // Here we pass captureSecureLayers = true and since we are AID_SYSTEM we should be able
- // to receive them...we are expected to take care with the results.
- mCaptureArgs.captureSecureLayers = true;
- ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
- ASSERT_TRUE(mCaptureResults.capturedSecureLayers);
- ScreenCapture sc(mCaptureResults.buffer, mCaptureResults.capturedHdrLayers);
- sc.expectColor(Rect(0, 0, 32, 32), Color::RED);
+ {
+ // Attempt secure screenshot from shell since it doesn't have CAPTURE_BLACKOUT_CONTENT
+ // permission, but is allowed normal screenshots.
+ UIDFaker faker(AID_SHELL);
+ ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
+ }
+
+ // Remove flag secure from the layer.
+ Transaction().setFlags(layer, 0, layer_state_t::eLayerSecure).apply(true);
+ {
+ // Assert that screenshot fails without CAPTURE_BLACKOUT_CONTENT when requesting
+ // captureSecureLayers even if there are no actual secure layers on screen.
+ UIDFaker faker(AID_SHELL);
+ ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
+ }
}
TEST_F(ScreenCaptureTest, CaptureChildSetParentFlagsSecureEUidSystem) {
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index ee967979..beb2147 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -194,7 +194,6 @@
LayerCase::setupForScreenCapture(this);
const Rect sourceCrop(0, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT);
- constexpr bool forSystem = true;
constexpr bool regionSampling = false;
auto renderArea = DisplayRenderArea::create(mDisplay, sourceCrop, sourceCrop.getSize(),
@@ -216,7 +215,7 @@
usage);
auto future = mFlinger.renderScreenImpl(std::move(renderArea), getLayerSnapshots,
- mCaptureScreenBuffer, forSystem, regionSampling);
+ mCaptureScreenBuffer, regionSampling);
ASSERT_TRUE(future.valid());
const auto fenceResult = future.get();
@@ -316,7 +315,7 @@
EXPECT_CALL(*test->mComposer, getReleaseFences(HWC_DISPLAY, _, _)).Times(1);
EXPECT_CALL(*test->mDisplaySurface, onFrameCommitted()).Times(1);
- EXPECT_CALL(*test->mDisplaySurface, advanceFrame()).Times(1);
+ EXPECT_CALL(*test->mDisplaySurface, advanceFrame(_)).Times(1);
Case::CompositionType::setupHwcSetCallExpectations(test);
Case::CompositionType::setupHwcGetCallExpectations(test);
diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
index 48f8923..7e9abce 100644
--- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
@@ -478,6 +478,17 @@
mLifecycleManager.applyTransactions(transactions);
}
+ void setDropInputMode(uint32_t id, gui::DropInputMode dropInputMode) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eDropInputModeChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.dropInputMode = dropInputMode;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
LayerLifecycleManager mLifecycleManager;
};
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 040a3bf..50cd784 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -1162,4 +1162,25 @@
EXPECT_TRUE(getSnapshot(11)->isSecure);
}
+// b/314350323
+TEST_F(LayerSnapshotTest, propagateDropInputMode) {
+ setDropInputMode(1, gui::DropInputMode::ALL);
+ LayerSnapshotBuilder::Args args{.root = mHierarchyBuilder.getHierarchy(),
+ .layerLifecycleManager = mLifecycleManager,
+ .includeMetadata = false,
+ .displays = mFrontEndDisplayInfos,
+ .displayChanges = false,
+ .globalShadowSettings = globalShadowSettings,
+ .supportsBlur = true,
+ .supportedLayerGenericMetadata = {},
+ .genericLayerMetadataKeyMap = {}};
+ args.rootSnapshot.isSecure = true;
+ update(mSnapshotBuilder, args);
+
+ EXPECT_EQ(getSnapshot(1)->dropInputMode, gui::DropInputMode::ALL);
+ // Ensure child also has the correct drop input mode regardless of whether either layer has
+ // an input channel
+ EXPECT_EQ(getSnapshot(11)->dropInputMode, gui::DropInputMode::ALL);
+}
+
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/SmallAreaDetectionAllowMappingsTest.cpp b/services/surfaceflinger/tests/unittests/SmallAreaDetectionAllowMappingsTest.cpp
index 05f9eed..8615035 100644
--- a/services/surfaceflinger/tests/unittests/SmallAreaDetectionAllowMappingsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SmallAreaDetectionAllowMappingsTest.cpp
@@ -44,8 +44,8 @@
ASSERT_EQ(mMappings.getThresholdForAppId(kAppId2).value(), kThreshold2);
}
-TEST_F(SmallAreaDetectionAllowMappingsTest, testSetThesholdForAppId) {
- mMappings.setThesholdForAppId(kAppId1, kThreshold1);
+TEST_F(SmallAreaDetectionAllowMappingsTest, testSetThresholdForAppId) {
+ mMappings.setThresholdForAppId(kAppId1, kThreshold1);
ASSERT_EQ(mMappings.getThresholdForAppId(kAppId1), kThreshold1);
}
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
index 94d517a..b620830 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
@@ -110,7 +110,7 @@
EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), display.isPrimary());
std::optional<DisplayDeviceState::Physical> expectedPhysical;
- if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) {
+ if (Case::Display::CONNECTION_TYPE::value) {
const auto displayId = PhysicalDisplayId::tryCast(Case::Display::DISPLAY_ID::get());
ASSERT_TRUE(displayId);
const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value;
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp
index ed8d909..844b96c 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp
@@ -188,5 +188,38 @@
scheduler.onHardwareVsyncRequest(mOuterDisplay->getPhysicalId(), true);
}
+TEST_F(FoldableTest, requestVsyncOnPowerOn) {
+ EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kInnerDisplayId, true))
+ .Times(1);
+ EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kOuterDisplayId, true))
+ .Times(1);
+
+ mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
+ mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
+}
+
+TEST_F(FoldableTest, disableVsyncOnPowerOffPacesetter) {
+ // When the device boots, the inner display should be the pacesetter.
+ ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
+
+ testing::InSequence seq;
+ EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kInnerDisplayId, true))
+ .Times(1);
+ EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kOuterDisplayId, true))
+ .Times(1);
+
+ // Turning off the pacesetter will result in disabling VSYNC.
+ EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kInnerDisplayId, false))
+ .Times(1);
+
+ mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
+ mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
+
+ mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::OFF);
+
+ // Other display is now the pacesetter.
+ ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId);
+}
+
} // namespace
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
index 31e1330..15fe600 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
@@ -73,11 +73,13 @@
struct EventThreadNotSupportedVariant : public EventThreadBaseSupportedVariant {
static void setupEnableVsyncCallExpectations(DisplayTransactionTest* test) {
- setupVsyncNoCallExpectations(test);
+ EXPECT_CALL(test->mFlinger.scheduler()->mockRequestHardwareVsync, Call(_, true)).Times(1);
+ EXPECT_CALL(*test->mEventThread, enableSyntheticVsync(_)).Times(0);
}
static void setupDisableVsyncCallExpectations(DisplayTransactionTest* test) {
- setupVsyncNoCallExpectations(test);
+ EXPECT_CALL(test->mFlinger.scheduler()->mockRequestHardwareVsync, Call(_, false)).Times(1);
+ EXPECT_CALL(*test->mEventThread, enableSyntheticVsync(_)).Times(0);
}
};
@@ -298,6 +300,11 @@
// A sample configuration for the external display.
// In addition to not having event thread support, we emulate not having doze
// support.
+// TODO (b/267483230): ExternalDisplay supports the features tracked in
+// DispSyncIsSupportedVariant, but is the follower, so the
+// expectations set by DispSyncIsSupportedVariant don't match (wrong schedule).
+// We need a way to retrieve the proper DisplayId from
+// setupResetModelCallExpectations (or pass it in).
template <typename TransitionVariant>
using ExternalDisplayPowerCase =
DisplayPowerCase<ExternalDisplayVariant, DozeNotSupportedVariant<ExternalDisplayVariant>,
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 0909178..8ba6bf8 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -493,12 +493,13 @@
auto renderScreenImpl(std::shared_ptr<const RenderArea> renderArea,
SurfaceFlinger::GetLayerSnapshotsFunction traverseLayers,
const std::shared_ptr<renderengine::ExternalTexture>& buffer,
- bool forSystem, bool regionSampling) {
+ bool regionSampling) {
ScreenCaptureResults captureResults;
return FTL_FAKE_GUARD(kMainThreadContext,
mFlinger->renderScreenImpl(std::move(renderArea), traverseLayers,
- buffer, forSystem, regionSampling,
- false /* grayscale */, captureResults));
+ buffer, regionSampling,
+ false /* grayscale */,
+ false /* isProtected */, captureResults));
}
auto traverseLayersInLayerStack(ui::LayerStack layerStack, int32_t uid,
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 3b74f0a..d649679 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -86,9 +86,10 @@
MOCK_METHOD3(getReleaseFences, Error(Display, std::vector<Layer>*, std::vector<int>*));
MOCK_METHOD2(presentDisplay, Error(Display, int*));
MOCK_METHOD2(setActiveConfig, Error(Display, Config));
- MOCK_METHOD6(setClientTarget,
- Error(Display, uint32_t, const sp<GraphicBuffer>&, int, Dataspace,
- const std::vector<IComposerClient::Rect>&));
+ MOCK_METHOD(Error, setClientTarget,
+ (Display, uint32_t, const sp<GraphicBuffer>&, int, Dataspace,
+ const std::vector<IComposerClient::Rect>&, float),
+ (override));
MOCK_METHOD3(setColorMode, Error(Display, ColorMode, RenderIntent));
MOCK_METHOD2(setColorTransform, Error(Display, const float*));
MOCK_METHOD3(setOutputBuffer, Error(Display, const native_handle_t*, int));
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
index a7ddb6d..7413235 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
@@ -66,8 +66,8 @@
((std::unordered_map<Layer *, android::sp<android::Fence>> *)), (const, override));
MOCK_METHOD(hal::Error, present, (android::sp<android::Fence> *), (override));
MOCK_METHOD(hal::Error, setClientTarget,
- (uint32_t, const android::sp<android::GraphicBuffer> &,
- const android::sp<android::Fence> &, hal::Dataspace),
+ (uint32_t, const android::sp<android::GraphicBuffer>&,
+ const android::sp<android::Fence>&, hal::Dataspace, float),
(override));
MOCK_METHOD(hal::Error, setColorMode, (hal::ColorMode, hal::RenderIntent), (override));
MOCK_METHOD(hal::Error, setColorTransform, (const android::mat4 &), (override));