Merge "Split ASurfaceTransaction_setGeometry api" into sc-dev
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index a8c0500..922367f 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -8,8 +8,7 @@
include/input/
include/powermanager/
libs/binder/fuzzer/
- libs/binder/ndk/
- libs/binder/tests/fuzzers/
+ libs/binder/
libs/binderthreadstate/
libs/graphicsenv/
libs/gui/
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 3184843..cedff0b 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -62,7 +62,7 @@
using std::string;
-#define MAX_SYS_FILES 11
+#define MAX_SYS_FILES 12
const char* k_traceTagsProperty = "debug.atrace.tags.enableflags";
const char* k_userInitiatedTraceProperty = "debug.atrace.user_initiated";
@@ -177,6 +177,7 @@
{ OPT, "events/power/suspend_resume/enable" },
{ OPT, "events/cpuhp/cpuhp_enter/enable" },
{ OPT, "events/cpuhp/cpuhp_exit/enable" },
+ { OPT, "events/cpuhp/cpuhp_pause/enable" },
} },
{ "membus", "Memory Bus Utilization", 0, {
{ REQ, "events/memory_bus/enable" },
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 006e532..37fc9a9 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -57,6 +57,8 @@
chmod 0666 /sys/kernel/tracing/events/cpuhp/cpuhp_enter/enable
chmod 0666 /sys/kernel/debug/tracing/events/cpuhp/cpuhp_exit/enable
chmod 0666 /sys/kernel/tracing/events/cpuhp/cpuhp_exit/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/cpuhp/cpuhp_pause/enable
+ chmod 0666 /sys/kernel/tracing/events/cpuhp/cpuhp_pause/enable
chmod 0666 /sys/kernel/debug/tracing/events/power/gpu_frequency/enable
chmod 0666 /sys/kernel/tracing/events/power/gpu_frequency/enable
chmod 0666 /sys/kernel/debug/tracing/events/power/suspend_resume/enable
diff --git a/cmds/dumpstate/DumpPool.cpp b/cmds/dumpstate/DumpPool.cpp
index e15ac3f..c2c8a72 100644
--- a/cmds/dumpstate/DumpPool.cpp
+++ b/cmds/dumpstate/DumpPool.cpp
@@ -64,8 +64,8 @@
if (shutdown_ || threads_.empty()) {
return;
}
- while (!tasks_.empty()) tasks_.pop();
futures_map_.clear();
+ while (!tasks_.empty()) tasks_.pop();
shutdown_ = true;
condition_variable_.notify_all();
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index a999c9f..7ab2a8d 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -3027,11 +3027,14 @@
}
void Dumpstate::MaybeSnapshotWinTrace() {
- RunCommand(
- // Empty name because it's not intended to be classified as a bugreport section.
- // Actual tracing files can be found in "/data/misc/wmtrace/" in the bugreport.
- "", {"cmd", "window", "tracing", "save-for-bugreport"},
- CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
+ // Currently WindowManagerService and InputMethodManagerSerivice support WinScope protocol.
+ for (const auto& service : {"window", "input_method"}) {
+ RunCommand(
+ // Empty name because it's not intended to be classified as a bugreport section.
+ // Actual tracing files can be found in "/data/misc/wmtrace/" in the bugreport.
+ "", {"cmd", service, "tracing", "save-for-bugreport"},
+ CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
+ }
}
void Dumpstate::onUiIntensiveBugreportDumpsFinished(int32_t calling_uid) {
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index c62d302..0712c0a 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -411,7 +411,6 @@
}
TEST_F(BugreportSectionTest, ConnectivitySectionsGenerated) {
- SectionExists("HIGH connectivity", /* bytes= */ 3000);
SectionExists("connectivity", /* bytes= */ 5000);
}
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index b2518ad..2c573e4 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -1762,6 +1762,27 @@
EXPECT_THAT(getTempFileCounts(kTestDataPath), Eq(0));
}
+TEST_F(DumpPoolTest, Shutdown_withoutCrash) {
+ bool run_1 = false;
+ auto dump_func_1 = [&]() {
+ run_1 = true;
+ };
+ auto dump_func = []() {
+ sleep(1);
+ };
+
+ dump_pool_->start(/* thread_counts = */1);
+ dump_pool_->enqueueTask(/* task_name = */"1", dump_func_1);
+ dump_pool_->enqueueTask(/* task_name = */"2", dump_func);
+ dump_pool_->enqueueTask(/* task_name = */"3", dump_func);
+ dump_pool_->enqueueTask(/* task_name = */"4", dump_func);
+ dump_pool_->waitForTask("1", "", out_fd_.get());
+ dump_pool_->shutdown();
+
+ EXPECT_TRUE(run_1);
+ EXPECT_THAT(getTempFileCounts(kTestDataPath), Eq(0));
+}
+
class TaskQueueTest : public DumpstateBaseTest {
public:
void SetUp() {
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index 3c53c02..bbbe6f7 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -495,7 +495,7 @@
Rect r = Rect(cc.rectangle().left(), cc.rectangle().top(), cc.rectangle().right(),
cc.rectangle().bottom());
- t.setCrop_legacy(mLayers[id], r);
+ t.setCrop(mLayers[id], r);
}
void Replayer::setCornerRadius(SurfaceComposerClient::Transaction& t,
diff --git a/headers/media_plugin/media/openmax/OMX_Core.h b/headers/media_plugin/media/openmax/OMX_Core.h
index 9ff934e..4b69130 100644
--- a/headers/media_plugin/media/openmax/OMX_Core.h
+++ b/headers/media_plugin/media/openmax/OMX_Core.h
@@ -556,6 +556,12 @@
*/
OMX_EventConfigUpdate,
+ /**
+ * Event fired by a tunneled decoder when the first frame is decoded and
+ * ready to be rendered.
+ */
+ OMX_EventOnFirstTunnelFrameReady,
+
OMX_EventMax = 0x7FFFFFFF
} OMX_EVENTTYPE;
diff --git a/headers/media_plugin/media/openmax/OMX_IndexExt.h b/headers/media_plugin/media/openmax/OMX_IndexExt.h
index a427db7..07bd749 100644
--- a/headers/media_plugin/media/openmax/OMX_IndexExt.h
+++ b/headers/media_plugin/media/openmax/OMX_IndexExt.h
@@ -103,6 +103,7 @@
OMX_IndexParamConsumerUsageBits, /**< reference: OMX_PARAM_U32TYPE */
OMX_IndexConfigLatency, /**< reference: OMX_PARAM_U32TYPE */
OMX_IndexConfigLowLatency, /**< reference: OMX_CONFIG_BOOLEANTYPE */
+ OMX_IndexConfigAndroidTunnelPeek, /**< reference: OMX_CONFIG_BOOLEANTYPE */
OMX_IndexExtOtherEndUnused,
/* Time configurations */
diff --git a/include/android/input.h b/include/android/input.h
index 6fe95c0..bb98beb 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -678,7 +678,7 @@
/**
* Axis constant: The movement of y position of a motion event.
*
- * Same as {@link RELATIVE_X}, but for y position.
+ * Same as {@link AMOTION_EVENT_AXIS_RELATIVE_X}, but for y position.
*/
AMOTION_EVENT_AXIS_RELATIVE_Y = 28,
/**
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index 424299d..509ee0e 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -83,7 +83,7 @@
*
* To clear a previous process binding, invoke with NETWORK_UNSPECIFIED.
*
- * This is the equivalent of: [android.net.ConnectivityManager#setProcessDefaultNetwork()](https://developer.android.com/reference/android/net/ConnectivityManager.html#setProcessDefaultNetwork(android.net.Network))
+ * This is the equivalent of: [android.net.ConnectivityManager#bindProcessToNetwork()](https://developer.android.com/reference/android/net/ConnectivityManager.html#bindProcessToNetwork(android.net.Network))
*
* Available since API level 23.
*/
@@ -91,6 +91,41 @@
/**
+ * Gets the |network| bound to the current process, as per android_setprocnetwork.
+ *
+ * This is the equivalent of: [android.net.ConnectivityManager#getBoundNetworkForProcess()](https://developer.android.com/reference/android/net/ConnectivityManager.html#getBoundNetworkForProcess(android.net.Network))
+ * Returns 0 on success, or -1 setting errno to EINVAL if a null pointer is
+ * passed in.
+ *
+ *
+ * Available since API level 31.
+ */
+int android_getprocnetwork(net_handle_t *network) __INTRODUCED_IN(31);
+
+/**
+ * Binds domain name resolutions performed by this process to |network|.
+ * android_setprocnetwork takes precedence over this setting.
+ *
+ * To clear a previous process binding, invoke with NETWORK_UNSPECIFIED.
+ * On success 0 is returned. On error -1 is returned, and errno is set.
+ *
+ * Available since API level 31.
+ */
+int android_setprocdns(net_handle_t network) __INTRODUCED_IN(31);
+
+/**
+ * Gets the |network| to which domain name resolutions are bound on the
+ * current process.
+ *
+ * Returns 0 on success, or -1 setting errno to EINVAL if a null pointer is
+ * passed in.
+ *
+ * Available since API level 31.
+ */
+int android_getprocdns(net_handle_t *network) __INTRODUCED_IN(31);
+
+
+/**
* Perform hostname resolution via the DNS servers associated with |network|.
*
* All arguments (apart from |network|) are used identically as those passed
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 6447844..92b79c7 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -448,12 +448,14 @@
float data[16];
ASensorVector vector;
ASensorVector acceleration;
+ ASensorVector gyro;
ASensorVector magnetic;
float temperature;
float distance;
float light;
float pressure;
float relative_humidity;
+ AUncalibratedEvent uncalibrated_acceleration;
AUncalibratedEvent uncalibrated_gyro;
AUncalibratedEvent uncalibrated_magnetic;
AMetaDataEvent meta_data;
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index 6789280..eb9c528 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -499,3 +499,5 @@
__END_DECLS
#endif // ANDROID_SURFACE_CONTROL_H
+
+/** @} */
diff --git a/include/android/surface_texture.h b/include/android/surface_texture.h
index b227b32..4757254 100644
--- a/include/android/surface_texture.h
+++ b/include/android/surface_texture.h
@@ -176,3 +176,5 @@
__END_DECLS
#endif /* ANDROID_NATIVE_SURFACE_TEXTURE_H */
+
+/** @} */
diff --git a/include/android/surface_texture_jni.h b/include/android/surface_texture_jni.h
index e40686d..8448d8c 100644
--- a/include/android/surface_texture_jni.h
+++ b/include/android/surface_texture_jni.h
@@ -53,3 +53,5 @@
__END_DECLS
#endif /* ANDROID_NATIVE_SURFACE_TEXTURE_JNI_H */
+
+/** @} */
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index f1b2258..3e5674e 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -33,6 +33,7 @@
#include <unordered_map>
#include <android-base/chrono_utils.h>
+#include <android-base/result.h>
#include <android-base/unique_fd.h>
#include <binder/IBinder.h>
@@ -374,20 +375,24 @@
*/
status_t publishDragEvent(uint32_t seq, int32_t eventId, float x, float y, bool isExiting);
+ struct Finished {
+ uint32_t seq;
+ bool handled;
+ nsecs_t consumeTime;
+ };
+
/* Receives the finished signal from the consumer in reply to the original dispatch signal.
- * If a signal was received, returns the message sequence number,
- * whether the consumer handled the message, and the time the event was first read by the
- * consumer.
+ * If a signal was received, returns a Finished object.
*
* The returned sequence number is never 0 unless the operation failed.
*
- * Returns OK on success.
- * Returns WOULD_BLOCK if there is no signal present.
- * Returns DEAD_OBJECT if the channel's peer has been closed.
- * Other errors probably indicate that the channel is broken.
+ * Returned error codes:
+ * OK on success.
+ * WOULD_BLOCK if there is no signal present.
+ * DEAD_OBJECT if the channel's peer has been closed.
+ * Other errors probably indicate that the channel is broken.
*/
- status_t receiveFinishedSignal(
- const std::function<void(uint32_t seq, bool handled, nsecs_t consumeTime)>& callback);
+ android::base::Result<Finished> receiveFinishedSignal();
private:
std::shared_ptr<InputChannel> mChannel;
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
index f1085cf..eac1bb2 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -138,7 +138,12 @@
OP_RECORD_AUDIO_HOTWORD = 102,
// Ops 103-105 are currently unused in native, and intentionally omitted
OP_RECORD_AUDIO_OUTPUT = 106,
- _NUM_OP = 107
+ OP_SCHEDULE_EXACT_ALARM = 107,
+ OP_FINE_LOCATION_SOURCE = 108,
+ OP_COARSE_LOCATION_SOURCE = 109,
+ OP_MANAGE_MEDIA = 110,
+ OP_BLUETOOTH_CONNECT = 111,
+ _NUM_OP = 112
};
AppOpsManager();
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index 05eb64b..6c44726 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -82,7 +82,10 @@
*/
template <class T, class... Args>
static std::shared_ptr<T> make(Args&&... args) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
T* t = new T(std::forward<Args>(args)...);
+#pragma clang diagnostic pop
// warning: Potential leak of memory pointed to by 't' [clang-analyzer-unix.Malloc]
return t->template ref<T>(); // NOLINT(clang-analyzer-unix.Malloc)
}
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index d53a88f..3899d47 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -33,13 +33,13 @@
/// Binder action to perform.
///
-/// This must be a number between [`IBinder::FIRST_CALL_TRANSACTION`] and
-/// [`IBinder::LAST_CALL_TRANSACTION`].
+/// This must be a number between [`FIRST_CALL_TRANSACTION`] and
+/// [`LAST_CALL_TRANSACTION`].
pub type TransactionCode = u32;
/// Additional operation flags.
///
-/// `IBinder::FLAG_*` values.
+/// `FLAG_*` values.
pub type TransactionFlags = u32;
/// Super-trait for Binder interfaces.
@@ -85,20 +85,22 @@
fn get_class() -> InterfaceClass;
}
-/// Interface of binder local or remote objects.
+/// First transaction code available for user commands (inclusive)
+pub const FIRST_CALL_TRANSACTION: TransactionCode = sys::FIRST_CALL_TRANSACTION;
+/// Last transaction code available for user commands (inclusive)
+pub const LAST_CALL_TRANSACTION: TransactionCode = sys::LAST_CALL_TRANSACTION;
+
+/// Corresponds to TF_ONE_WAY -- an asynchronous call.
+pub const FLAG_ONEWAY: TransactionFlags = sys::FLAG_ONEWAY;
+/// Corresponds to TF_CLEAR_BUF -- clear transaction buffers after call is made.
+pub const FLAG_CLEAR_BUF: TransactionFlags = sys::FLAG_CLEAR_BUF;
+
+/// Internal interface of binder local or remote objects for making
+/// transactions.
///
-/// This trait corresponds to the interface of the C++ `IBinder` class.
-pub trait IBinder {
- /// First transaction code available for user commands (inclusive)
- const FIRST_CALL_TRANSACTION: TransactionCode = sys::FIRST_CALL_TRANSACTION;
- /// Last transaction code available for user commands (inclusive)
- const LAST_CALL_TRANSACTION: TransactionCode = sys::LAST_CALL_TRANSACTION;
-
- /// Corresponds to TF_ONE_WAY -- an asynchronous call.
- const FLAG_ONEWAY: TransactionFlags = sys::FLAG_ONEWAY;
- /// Corresponds to TF_CLEAR_BUF -- clear transaction buffers after call is made.
- const FLAG_CLEAR_BUF: TransactionFlags = sys::FLAG_CLEAR_BUF;
-
+/// This trait corresponds to the parts of the interface of the C++ `IBinder`
+/// class which are internal implementation details.
+pub trait IBinderInternal: IBinder {
/// Is this object still alive?
fn is_binder_alive(&self) -> bool;
@@ -122,19 +124,24 @@
/// * `data` - [`Parcel`] with input data
/// * `reply` - Optional [`Parcel`] for reply data
/// * `flags` - Transaction flags, e.g. marking the transaction as
- /// asynchronous ([`FLAG_ONEWAY`](IBinder::FLAG_ONEWAY))
+ /// asynchronous ([`FLAG_ONEWAY`](FLAG_ONEWAY))
fn transact<F: FnOnce(&mut Parcel) -> Result<()>>(
&self,
code: TransactionCode,
flags: TransactionFlags,
input_callback: F,
) -> Result<Parcel>;
+}
+/// Interface of binder local or remote objects.
+///
+/// This trait corresponds to the parts of the interface of the C++ `IBinder`
+/// class which are public.
+pub trait IBinder {
/// Register the recipient for a notification if this binder
/// goes away. If this binder object unexpectedly goes away
/// (typically because its hosting process has been killed),
- /// then DeathRecipient::binder_died() will be called with a reference
- /// to this.
+ /// then the `DeathRecipient`'s callback will be called.
///
/// You will only receive death notifications for remote binders,
/// as local binders by definition can't die without you dying as well.
@@ -142,11 +149,6 @@
/// INVALID_OPERATION code being returned and nothing happening.
///
/// This link always holds a weak reference to its recipient.
- ///
- /// You will only receive a weak reference to the dead
- /// binder. You should not try to promote this to a strong reference.
- /// (Nor should you need to, as there is nothing useful you can
- /// directly do with it now that it has passed on.)
fn link_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()>;
/// Remove a previously registered death notification.
@@ -222,7 +224,8 @@
// the number of u16 elements before the null terminator.
let raw_descriptor: *const c_char = sys::AIBinder_Class_getDescriptor(self.0);
- CStr::from_ptr(raw_descriptor).to_str()
+ CStr::from_ptr(raw_descriptor)
+ .to_str()
.expect("Expected valid UTF-8 string from AIBinder_Class_getDescriptor")
.into()
}
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 43a237a..5bbd2a3 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -107,8 +107,9 @@
pub mod parcel;
pub use crate::binder::{
- FromIBinder, IBinder, Interface, InterfaceClass, Remotable, Strong, TransactionCode,
- TransactionFlags, Weak,
+ FromIBinder, IBinder, IBinderInternal, Interface, InterfaceClass, Remotable, Strong,
+ TransactionCode, TransactionFlags, Weak, FIRST_CALL_TRANSACTION, FLAG_CLEAR_BUF, FLAG_ONEWAY,
+ LAST_CALL_TRANSACTION,
};
pub use error::{status_t, ExceptionCode, Result, Status, StatusCode};
pub use native::add_service;
@@ -123,8 +124,8 @@
pub use super::parcel::ParcelFileDescriptor;
pub use super::{add_service, get_interface};
pub use super::{
- ExceptionCode, Interface, ProcessState, SpIBinder, Status, StatusCode, Strong, ThreadState,
- Weak, WpIBinder,
+ DeathRecipient, ExceptionCode, IBinder, Interface, ProcessState, SpIBinder, Status,
+ StatusCode, Strong, ThreadState, Weak, WpIBinder,
};
/// Binder result containing a [`Status`] on error.
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 132e075..52036f5 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -17,7 +17,8 @@
//! Rust API for interacting with a remote binder service.
use crate::binder::{
- AsNative, FromIBinder, IBinder, Interface, InterfaceClass, Strong, TransactionCode, TransactionFlags,
+ AsNative, FromIBinder, IBinder, IBinderInternal, Interface, InterfaceClass, Strong,
+ TransactionCode, TransactionFlags,
};
use crate::error::{status_result, Result, StatusCode};
use crate::parcel::{
@@ -26,8 +27,8 @@
};
use crate::sys;
-use std::convert::TryInto;
use std::cmp::Ordering;
+use std::convert::TryInto;
use std::ffi::{c_void, CString};
use std::fmt;
use std::os::unix::io::AsRawFd;
@@ -211,7 +212,7 @@
}
}
-impl<T: AsNative<sys::AIBinder>> IBinder for T {
+impl<T: AsNative<sys::AIBinder>> IBinderInternal for T {
/// Perform a binder transaction
fn transact<F: FnOnce(&mut Parcel) -> Result<()>>(
&self,
@@ -300,9 +301,7 @@
}
fn set_requesting_sid(&mut self, enable: bool) {
- unsafe {
- sys::AIBinder_setRequestingSid(self.as_native_mut(), enable)
- };
+ unsafe { sys::AIBinder_setRequestingSid(self.as_native_mut(), enable) };
}
fn dump<F: AsRawFd>(&mut self, fp: &F, args: &[&str]) -> Result<()> {
@@ -351,7 +350,9 @@
status_result(status)?;
Ok(ibinder)
}
+}
+impl<T: AsNative<sys::AIBinder>> IBinder for T {
fn link_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()> {
status_result(unsafe {
// Safety: `SpIBinder` guarantees that `self` always contains a
@@ -472,7 +473,10 @@
// WpIBinder object from it.
sys::AIBinder_Weak_clone(self.0)
};
- assert!(!ptr.is_null(), "Unexpected null pointer from AIBinder_Weak_clone");
+ assert!(
+ !ptr.is_null(),
+ "Unexpected null pointer from AIBinder_Weak_clone"
+ );
Self(ptr)
}
}
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index 719229c..60e3502 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -18,7 +18,10 @@
use binder::declare_binder_interface;
use binder::parcel::Parcel;
-use binder::{Binder, IBinder, Interface, SpIBinder, StatusCode, ThreadState, TransactionCode};
+use binder::{
+ Binder, IBinderInternal, Interface, StatusCode, ThreadState, TransactionCode,
+ FIRST_CALL_TRANSACTION,
+};
use std::convert::{TryFrom, TryInto};
/// Name of service runner.
@@ -83,7 +86,7 @@
#[repr(u32)]
enum TestTransactionCode {
- Test = SpIBinder::FIRST_CALL_TRANSACTION,
+ Test = FIRST_CALL_TRANSACTION,
GetSelinuxContext,
}
@@ -196,7 +199,6 @@
impl ITestSameDescriptor for Binder<BnTestSameDescriptor> {}
-
#[cfg(test)]
mod tests {
use selinux_bindgen as selinux_sys;
@@ -209,9 +211,12 @@
use std::thread;
use std::time::Duration;
- use binder::{Binder, DeathRecipient, FromIBinder, IBinder, Interface, SpIBinder, StatusCode, Strong};
+ use binder::{
+ Binder, DeathRecipient, FromIBinder, IBinder, IBinderInternal, Interface, SpIBinder,
+ StatusCode, Strong,
+ };
- use super::{BnTest, ITest, ITestSameDescriptor, RUST_SERVICE_BINARY, TestService};
+ use super::{BnTest, ITest, ITestSameDescriptor, TestService, RUST_SERVICE_BINARY};
pub struct ScopedServiceProcess(Child);
@@ -290,7 +295,9 @@
};
assert_eq!(
test_client.get_selinux_context().unwrap(),
- expected_context.to_str().expect("context was invalid UTF-8"),
+ expected_context
+ .to_str()
+ .expect("context was invalid UTF-8"),
);
}
@@ -479,18 +486,22 @@
// This should succeed although we will have to treat the service as
// remote.
- let _interface: Strong<dyn ITestSameDescriptor> = FromIBinder::try_from(service.as_binder())
- .expect("Could not re-interpret service as the ITestSameDescriptor interface");
+ let _interface: Strong<dyn ITestSameDescriptor> =
+ FromIBinder::try_from(service.as_binder())
+ .expect("Could not re-interpret service as the ITestSameDescriptor interface");
}
/// Test that we can round-trip a rust service through a generic IBinder
#[test]
fn reassociate_rust_binder() {
let service_name = "testing_service";
- let service_ibinder = BnTest::new_binder(TestService { s: service_name.to_string() })
- .as_binder();
+ let service_ibinder = BnTest::new_binder(TestService {
+ s: service_name.to_string(),
+ })
+ .as_binder();
- let service: Strong<dyn ITest> = service_ibinder.into_interface()
+ let service: Strong<dyn ITest> = service_ibinder
+ .into_interface()
.expect("Could not reassociate the generic ibinder");
assert_eq!(service.test().unwrap(), service_name);
@@ -499,7 +510,9 @@
#[test]
fn weak_binder_upgrade() {
let service_name = "testing_service";
- let service = BnTest::new_binder(TestService { s: service_name.to_string() });
+ let service = BnTest::new_binder(TestService {
+ s: service_name.to_string(),
+ });
let weak = Strong::downgrade(&service);
@@ -512,7 +525,9 @@
fn weak_binder_upgrade_dead() {
let service_name = "testing_service";
let weak = {
- let service = BnTest::new_binder(TestService { s: service_name.to_string() });
+ let service = BnTest::new_binder(TestService {
+ s: service_name.to_string(),
+ });
Strong::downgrade(&service)
};
@@ -523,7 +538,9 @@
#[test]
fn weak_binder_clone() {
let service_name = "testing_service";
- let service = BnTest::new_binder(TestService { s: service_name.to_string() });
+ let service = BnTest::new_binder(TestService {
+ s: service_name.to_string(),
+ });
let weak = Strong::downgrade(&service);
let cloned = weak.clone();
@@ -539,8 +556,12 @@
#[test]
#[allow(clippy::eq_op)]
fn binder_ord() {
- let service1 = BnTest::new_binder(TestService { s: "testing_service1".to_string() });
- let service2 = BnTest::new_binder(TestService { s: "testing_service2".to_string() });
+ let service1 = BnTest::new_binder(TestService {
+ s: "testing_service1".to_string(),
+ });
+ let service2 = BnTest::new_binder(TestService {
+ s: "testing_service2".to_string(),
+ });
assert!(!(service1 < service1));
assert!(!(service1 > service1));
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 82c9268..8da97bb 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -130,8 +130,7 @@
}
BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface,
- int width, int height, int32_t format,
- bool enableTripleBuffering)
+ int width, int height, int32_t format)
: mName(name),
mSurfaceControl(surface),
mSize(width, height),
@@ -143,9 +142,8 @@
// explicitly so that dequeueBuffer will block
mProducer->setDequeueTimeout(std::numeric_limits<int64_t>::max());
- if (enableTripleBuffering) {
- mProducer->setMaxDequeuedBufferCount(2);
- }
+ // safe default, most producers are expected to override this
+ mProducer->setMaxDequeuedBufferCount(2);
mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer,
GraphicBuffer::USAGE_HW_COMPOSER |
GraphicBuffer::USAGE_HW_TEXTURE,
@@ -169,8 +167,6 @@
mNumAcquired = 0;
mNumFrameAvailable = 0;
- mPendingReleaseItem.item = BufferItem();
- mPendingReleaseItem.releaseFence = nullptr;
}
BLASTBufferQueue::~BLASTBufferQueue() {
@@ -242,7 +238,6 @@
std::unique_lock _lock{mMutex};
ATRACE_CALL();
BQA_LOGV("transactionCallback");
- mInitialCallbackReceived = true;
if (!stats.empty()) {
mTransformHint = stats[0].transformHint;
@@ -255,38 +250,20 @@
stats[0].frameEventStats.compositorTiming,
stats[0].latchTime,
stats[0].frameEventStats.dequeueReadyTime);
- }
- if (mPendingReleaseItem.item.mGraphicBuffer != nullptr) {
- if (!stats.empty()) {
- mPendingReleaseItem.releaseFence = stats[0].previousReleaseFence;
- } else {
- BQA_LOGE("Warning: no SurfaceControlStats returned in BLASTBufferQueue callback");
- mPendingReleaseItem.releaseFence = nullptr;
+ currFrameNumber = stats[0].frameEventStats.frameNumber;
+
+ if (mTransactionCompleteCallback &&
+ currFrameNumber >= mTransactionCompleteFrameNumber) {
+ if (currFrameNumber > mTransactionCompleteFrameNumber) {
+ BQA_LOGE("transactionCallback received for a newer framenumber=%" PRIu64
+ " than expected=%" PRIu64,
+ currFrameNumber, mTransactionCompleteFrameNumber);
+ }
+ transactionCompleteCallback = std::move(mTransactionCompleteCallback);
+ mTransactionCompleteFrameNumber = 0;
}
- mBufferItemConsumer->releaseBuffer(mPendingReleaseItem.item,
- mPendingReleaseItem.releaseFence
- ? mPendingReleaseItem.releaseFence
- : Fence::NO_FENCE);
- mNumAcquired--;
- mPendingReleaseItem.item = BufferItem();
- mPendingReleaseItem.releaseFence = nullptr;
}
- if (mSubmitted.empty()) {
- BQA_LOGE("ERROR: callback with no corresponding submitted buffer item");
- }
- mPendingReleaseItem.item = std::move(mSubmitted.front());
- mSubmitted.pop();
-
- processNextBufferLocked(false /* useNextTransaction */);
-
- currFrameNumber = mPendingReleaseItem.item.mFrameNumber;
- if (mTransactionCompleteCallback && mTransactionCompleteFrameNumber == currFrameNumber) {
- transactionCompleteCallback = std::move(mTransactionCompleteCallback);
- mTransactionCompleteFrameNumber = 0;
- }
-
- mCallbackCV.notify_all();
decStrong((void*)transactionCallbackThunk);
}
@@ -295,15 +272,46 @@
}
}
+// Unlike transactionCallbackThunk the release buffer callback does not extend the life of the
+// BBQ. This is because if the BBQ is destroyed, then the buffers will be released by the client.
+// So we pass in a weak pointer to the BBQ and if it still alive, then we release the buffer.
+// Otherwise, this is a no-op.
+static void releaseBufferCallbackThunk(wp<BLASTBufferQueue> context, uint64_t graphicBufferId,
+ const sp<Fence>& releaseFence) {
+ sp<BLASTBufferQueue> blastBufferQueue = context.promote();
+ ALOGV("releaseBufferCallbackThunk graphicBufferId=%" PRIu64 " blastBufferQueue=%s",
+ graphicBufferId, blastBufferQueue ? "alive" : "dead");
+ if (blastBufferQueue) {
+ blastBufferQueue->releaseBufferCallback(graphicBufferId, releaseFence);
+ }
+}
+
+void BLASTBufferQueue::releaseBufferCallback(uint64_t graphicBufferId,
+ const sp<Fence>& releaseFence) {
+ ATRACE_CALL();
+ std::unique_lock _lock{mMutex};
+ BQA_LOGV("releaseBufferCallback graphicBufferId=%" PRIu64, graphicBufferId);
+
+ auto it = mSubmitted.find(graphicBufferId);
+ if (it == mSubmitted.end()) {
+ BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %" PRIu64,
+ graphicBufferId);
+ return;
+ }
+
+ mBufferItemConsumer->releaseBuffer(it->second, releaseFence);
+ mSubmitted.erase(it);
+ mNumAcquired--;
+ processNextBufferLocked(false /* useNextTransaction */);
+ mCallbackCV.notify_all();
+}
+
void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
ATRACE_CALL();
- BQA_LOGV("processNextBufferLocked useNextTransaction=%s", toString(useNextTransaction));
-
// If the next transaction is set, we want to guarantee the our acquire will not fail, so don't
// include the extra buffer when checking if we can acquire the next buffer.
const bool includeExtraAcquire = !useNextTransaction;
if (mNumFrameAvailable == 0 || maxBuffersAcquired(includeExtraAcquire)) {
- BQA_LOGV("processNextBufferLocked waiting for frame available or callback");
mCallbackCV.notify_all();
return;
}
@@ -353,7 +361,7 @@
}
mNumAcquired++;
- mSubmitted.push(bufferItem);
+ mSubmitted[buffer->getId()] = bufferItem;
bool needsDisconnect = false;
mBufferItemConsumer->getConnectionEvents(bufferItem.mFrameNumber, &needsDisconnect);
@@ -369,7 +377,10 @@
mLastBufferScalingMode = bufferItem.mScalingMode;
mLastAcquiredFrameNumber = bufferItem.mFrameNumber;
- t->setBuffer(mSurfaceControl, buffer);
+ auto releaseBufferCallback =
+ std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */,
+ std::placeholders::_1, std::placeholders::_2);
+ t->setBuffer(mSurfaceControl, buffer, releaseBufferCallback);
t->setDataspace(mSurfaceControl, static_cast<ui::Dataspace>(bufferItem.mDataSpace));
t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata);
t->setSurfaceDamageRegion(mSurfaceControl, bufferItem.mSurfaceDamage);
@@ -388,7 +399,7 @@
t->setFrameNumber(mSurfaceControl, bufferItem.mFrameNumber);
if (!mNextFrameTimelineInfoQueue.empty()) {
- t->setFrameTimelineInfo(mSurfaceControl, mNextFrameTimelineInfoQueue.front());
+ t->setFrameTimelineInfo(mNextFrameTimelineInfoQueue.front());
mNextFrameTimelineInfoQueue.pop();
}
@@ -427,9 +438,12 @@
}
BQA_LOGV("processNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64
- " applyTransaction=%s mTimestamp=%" PRId64 " mPendingTransactions.size=%d",
+ " applyTransaction=%s mTimestamp=%" PRId64 "%s mPendingTransactions.size=%d"
+ " graphicBufferId=%" PRIu64,
mSize.width, mSize.height, bufferItem.mFrameNumber, toString(applyTransaction),
- bufferItem.mTimestamp, static_cast<uint32_t>(mPendingTransactions.size()));
+ bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp ? "(auto)" : "",
+ static_cast<uint32_t>(mPendingTransactions.size()),
+ bufferItem.mGraphicBuffer->getId());
}
Rect BLASTBufferQueue::computeCrop(const BufferItem& item) {
@@ -444,18 +458,17 @@
std::unique_lock _lock{mMutex};
const bool nextTransactionSet = mNextTransaction != nullptr;
- BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " nextTransactionSet=%s mFlushShadowQueue=%s",
- item.mFrameNumber, toString(nextTransactionSet), toString(mFlushShadowQueue));
-
- if (nextTransactionSet || mFlushShadowQueue) {
+ if (nextTransactionSet) {
while (mNumFrameAvailable > 0 || maxBuffersAcquired(false /* includeExtraAcquire */)) {
BQA_LOGV("waiting in onFrameAvailable...");
mCallbackCV.wait(_lock);
}
}
- mFlushShadowQueue = false;
// add to shadow queue
mNumFrameAvailable++;
+
+ BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " nextTransactionSet=%s", item.mFrameNumber,
+ toString(nextTransactionSet));
processNextBufferLocked(nextTransactionSet /* useNextTransaction */);
}
@@ -514,14 +527,12 @@
}
// Check if we have acquired the maximum number of buffers.
-// As a special case, we wait for the first callback before acquiring the second buffer so we
-// can ensure the first buffer is presented if multiple buffers are queued in succession.
// Consumer can acquire an additional buffer if that buffer is not droppable. Set
// includeExtraAcquire is true to include this buffer to the count. Since this depends on the state
// of the buffer, the next acquire may return with NO_BUFFER_AVAILABLE.
bool BLASTBufferQueue::maxBuffersAcquired(bool includeExtraAcquire) const {
int maxAcquiredBuffers = MAX_ACQUIRED_BUFFERS + (includeExtraAcquire ? 2 : 1);
- return mNumAcquired == maxAcquiredBuffers || (!mInitialCallbackReceived && mNumAcquired == 1);
+ return mNumAcquired == maxAcquiredBuffers;
}
class BBQSurface : public Surface {
diff --git a/libs/gui/FrameTimelineInfo.cpp b/libs/gui/FrameTimelineInfo.cpp
index f400774..9231a57 100644
--- a/libs/gui/FrameTimelineInfo.cpp
+++ b/libs/gui/FrameTimelineInfo.cpp
@@ -21,6 +21,7 @@
#include <android/os/IInputConstants.h>
#include <gui/FrameTimelineInfo.h>
#include <gui/LayerState.h>
+#include <private/gui/ParcelUtils.h>
#include <utils/Errors.h>
#include <cmath>
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 989abd9..ceab6ec 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -28,6 +28,7 @@
#include <gui/ISurfaceComposerClient.h>
#include <gui/LayerDebugInfo.h>
#include <gui/LayerState.h>
+#include <private/gui/ParcelUtils.h>
#include <stdint.h>
#include <sys/types.h>
#include <system/graphics.h>
@@ -935,7 +936,8 @@
return NO_ERROR;
}
- status_t setDisplayBrightness(const sp<IBinder>& displayToken, float brightness) override {
+ status_t setDisplayBrightness(const sp<IBinder>& displayToken,
+ const gui::DisplayBrightness& brightness) override {
Parcel data, reply;
status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
if (error != NO_ERROR) {
@@ -947,7 +949,7 @@
ALOGE("setDisplayBrightness: failed to write display token: %d", error);
return error;
}
- error = data.writeFloat(brightness);
+ error = data.writeParcelable(brightness);
if (error != NO_ERROR) {
ALOGE("setDisplayBrightness: failed to write brightness: %d", error);
return error;
@@ -1832,8 +1834,8 @@
ALOGE("setDisplayBrightness: failed to read display token: %d", error);
return error;
}
- float brightness = -1.0f;
- error = data.readFloat(&brightness);
+ gui::DisplayBrightness brightness;
+ error = data.readParcelable(&brightness);
if (error != NO_ERROR) {
ALOGE("setDisplayBrightness: failed to read brightness: %d", error);
return error;
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index 0ded936..b42793b 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -17,9 +17,10 @@
#define LOG_TAG "ITransactionCompletedListener"
//#define LOG_NDEBUG 0
-#include <gui/LayerState.h>
#include <gui/ISurfaceComposer.h>
#include <gui/ITransactionCompletedListener.h>
+#include <gui/LayerState.h>
+#include <private/gui/ParcelUtils.h>
namespace android {
@@ -27,7 +28,8 @@
enum class Tag : uint32_t {
ON_TRANSACTION_COMPLETED = IBinder::FIRST_CALL_TRANSACTION,
- LAST = ON_TRANSACTION_COMPLETED,
+ ON_RELEASE_BUFFER,
+ LAST = ON_RELEASE_BUFFER,
};
} // Anonymous namespace
@@ -122,6 +124,7 @@
for (const auto& data : jankData) {
SAFE_PARCEL(output->writeParcelable, data);
}
+ SAFE_PARCEL(output->writeUint64, previousBufferId);
return NO_ERROR;
}
@@ -144,6 +147,7 @@
SAFE_PARCEL(input->readParcelable, &data);
jankData.push_back(data);
}
+ SAFE_PARCEL(input->readUint64, &previousBufferId);
return NO_ERROR;
}
@@ -245,6 +249,12 @@
onTransactionCompleted)>(Tag::ON_TRANSACTION_COMPLETED,
stats);
}
+
+ void onReleaseBuffer(uint64_t graphicBufferId, sp<Fence> releaseFence) override {
+ callRemoteAsync<decltype(
+ &ITransactionCompletedListener::onReleaseBuffer)>(Tag::ON_RELEASE_BUFFER,
+ graphicBufferId, releaseFence);
+ }
};
// Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see
@@ -263,6 +273,8 @@
case Tag::ON_TRANSACTION_COMPLETED:
return callLocalAsync(data, reply,
&ITransactionCompletedListener::onTransactionCompleted);
+ case Tag::ON_RELEASE_BUFFER:
+ return callLocalAsync(data, reply, &ITransactionCompletedListener::onReleaseBuffer);
}
}
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 288bf92..d653ae7 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -23,6 +23,7 @@
#include <gui/IGraphicBufferProducer.h>
#include <gui/ISurfaceComposerClient.h>
#include <gui/LayerState.h>
+#include <private/gui/ParcelUtils.h>
#include <utils/Errors.h>
#include <cmath>
@@ -41,7 +42,6 @@
flags(0),
mask(0),
reserved(0),
- crop_legacy(Rect::INVALID_RECT),
cornerRadius(0.0f),
backgroundBlurRadius(0),
barrierFrameNumber(0),
@@ -63,8 +63,8 @@
shouldBeSeamless(true),
fixedTransformHint(ui::Transform::ROT_INVALID),
frameNumber(0),
- frameTimelineInfo(),
- autoRefresh(false) {
+ autoRefresh(false),
+ releaseBufferListener(nullptr) {
matrix.dsdx = matrix.dtdy = 1.0f;
matrix.dsdy = matrix.dtdx = 0.0f;
hdrMetadata.validTypes = 0;
@@ -85,7 +85,7 @@
SAFE_PARCEL(output.writeUint32, flags);
SAFE_PARCEL(output.writeUint32, mask);
SAFE_PARCEL(matrix.write, output);
- SAFE_PARCEL(output.write, crop_legacy);
+ SAFE_PARCEL(output.write, crop);
SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, barrierSurfaceControl_legacy);
SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, reparentSurfaceControl);
SAFE_PARCEL(output.writeUint64, barrierFrameNumber);
@@ -151,8 +151,8 @@
SAFE_PARCEL(output.writeBool, shouldBeSeamless);
SAFE_PARCEL(output.writeUint32, fixedTransformHint);
SAFE_PARCEL(output.writeUint64, frameNumber);
- SAFE_PARCEL(frameTimelineInfo.write, output);
SAFE_PARCEL(output.writeBool, autoRefresh);
+ SAFE_PARCEL(output.writeStrongBinder, IInterface::asBinder(releaseBufferListener));
SAFE_PARCEL(output.writeUint32, blurRegions.size());
for (auto region : blurRegions) {
@@ -191,7 +191,7 @@
SAFE_PARCEL(input.readUint32, &mask);
SAFE_PARCEL(matrix.read, input);
- SAFE_PARCEL(input.read, crop_legacy);
+ SAFE_PARCEL(input.read, crop);
SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &barrierSurfaceControl_legacy);
SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &reparentSurfaceControl);
SAFE_PARCEL(input.readUint64, &barrierFrameNumber);
@@ -273,9 +273,14 @@
SAFE_PARCEL(input.readUint32, &tmpUint32);
fixedTransformHint = static_cast<ui::Transform::RotationFlags>(tmpUint32);
SAFE_PARCEL(input.readUint64, &frameNumber);
- SAFE_PARCEL(frameTimelineInfo.read, input);
SAFE_PARCEL(input.readBool, &autoRefresh);
+ tmpBinder = nullptr;
+ SAFE_PARCEL(input.readNullableStrongBinder, &tmpBinder);
+ if (tmpBinder) {
+ releaseBufferListener = checked_interface_cast<ITransactionCompletedListener>(tmpBinder);
+ }
+
uint32_t numRegions = 0;
SAFE_PARCEL(input.readUint32, &numRegions);
blurRegions.clear();
@@ -407,10 +412,6 @@
what |= eLayerStackChanged;
layerStack = other.layerStack;
}
- if (other.what & eCropChanged_legacy) {
- what |= eCropChanged_legacy;
- crop_legacy = other.crop_legacy;
- }
if (other.what & eCornerRadiusChanged) {
what |= eCornerRadiusChanged;
cornerRadius = other.cornerRadius;
@@ -540,14 +541,17 @@
what |= eFrameNumberChanged;
frameNumber = other.frameNumber;
}
- if (other.what & eFrameTimelineInfoChanged) {
- what |= eFrameTimelineInfoChanged;
- frameTimelineInfo.merge(other.frameTimelineInfo);
- }
if (other.what & eAutoRefreshChanged) {
what |= eAutoRefreshChanged;
autoRefresh = other.autoRefresh;
}
+ if (other.what & eReleaseBufferListenerChanged) {
+ if (releaseBufferListener) {
+ ALOGW("Overriding releaseBufferListener");
+ }
+ what |= eReleaseBufferListenerChanged;
+ releaseBufferListener = other.releaseBufferListener;
+ }
if (other.what & eStretchChanged) {
what |= eStretchChanged;
stretchEffect = other.stretchEffect;
diff --git a/libs/gui/ScreenCaptureResults.cpp b/libs/gui/ScreenCaptureResults.cpp
index f3849bc..e91f74f 100644
--- a/libs/gui/ScreenCaptureResults.cpp
+++ b/libs/gui/ScreenCaptureResults.cpp
@@ -16,6 +16,8 @@
#include <gui/ScreenCaptureResults.h>
+#include <private/gui/ParcelUtils.h>
+
namespace android::gui {
status_t ScreenCaptureResults::writeToParcel(android::Parcel* parcel) const {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 5e8ab92..d7b2c2e 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -39,6 +39,7 @@
#include <gui/LayerState.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
+#include <private/gui/ParcelUtils.h>
#include <ui/DisplayMode.h>
#include <ui/DynamicDisplayInfo.h>
@@ -195,6 +196,17 @@
}
}
+void TransactionCompletedListener::setReleaseBufferCallback(uint64_t graphicBufferId,
+ ReleaseBufferCallback listener) {
+ std::scoped_lock<std::mutex> lock(mMutex);
+ mReleaseBufferCallbacks[graphicBufferId] = listener;
+}
+
+void TransactionCompletedListener::removeReleaseBufferCallback(uint64_t graphicBufferId) {
+ std::scoped_lock<std::mutex> lock(mMutex);
+ mReleaseBufferCallbacks.erase(graphicBufferId);
+}
+
void TransactionCompletedListener::addSurfaceStatsListener(void* context, void* cookie,
sp<SurfaceControl> surfaceControl, SurfaceStatsCallback listener) {
std::lock_guard<std::mutex> lock(mMutex);
@@ -275,6 +287,23 @@
.surfaceControls[surfaceStats.surfaceControl]
->setTransformHint(surfaceStats.transformHint);
}
+ // If there is buffer id set, we look up any pending client release buffer callbacks
+ // and call them. This is a performance optimization when we have a transaction
+ // callback and a release buffer callback happening at the same time to avoid an
+ // additional ipc call from the server.
+ if (surfaceStats.previousBufferId) {
+ ReleaseBufferCallback callback;
+ {
+ std::scoped_lock<std::mutex> lock(mMutex);
+ callback = popReleaseBufferCallbackLocked(surfaceStats.previousBufferId);
+ }
+ if (callback) {
+ callback(surfaceStats.previousBufferId,
+ surfaceStats.previousReleaseFence
+ ? surfaceStats.previousReleaseFence
+ : Fence::NO_FENCE);
+ }
+ }
}
callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
@@ -297,6 +326,32 @@
}
}
+void TransactionCompletedListener::onReleaseBuffer(uint64_t graphicBufferId,
+ sp<Fence> releaseFence) {
+ ReleaseBufferCallback callback;
+ {
+ std::scoped_lock<std::mutex> lock(mMutex);
+ callback = popReleaseBufferCallbackLocked(graphicBufferId);
+ }
+ if (!callback) {
+ ALOGE("Could not call release buffer callback, buffer not found %" PRIu64, graphicBufferId);
+ return;
+ }
+ callback(graphicBufferId, releaseFence);
+}
+
+ReleaseBufferCallback TransactionCompletedListener::popReleaseBufferCallbackLocked(
+ uint64_t graphicBufferId) {
+ ReleaseBufferCallback callback;
+ auto itr = mReleaseBufferCallbacks.find(graphicBufferId);
+ if (itr == mReleaseBufferCallbacks.end()) {
+ return nullptr;
+ }
+ callback = itr->second;
+ mReleaseBufferCallbacks.erase(itr);
+ return callback;
+}
+
// ---------------------------------------------------------------------------
void removeDeadBufferCallback(void* /*context*/, uint64_t graphicBufferId);
@@ -419,9 +474,8 @@
mForceSynchronous(other.mForceSynchronous),
mTransactionNestCount(other.mTransactionNestCount),
mAnimation(other.mAnimation),
- mEarlyWakeup(other.mEarlyWakeup),
- mExplicitEarlyWakeupStart(other.mExplicitEarlyWakeupStart),
- mExplicitEarlyWakeupEnd(other.mExplicitEarlyWakeupEnd),
+ mEarlyWakeupStart(other.mEarlyWakeupStart),
+ mEarlyWakeupEnd(other.mEarlyWakeupEnd),
mContainsBuffer(other.mContainsBuffer),
mDesiredPresentTime(other.mDesiredPresentTime),
mIsAutoTimestamp(other.mIsAutoTimestamp),
@@ -450,9 +504,8 @@
const uint32_t forceSynchronous = parcel->readUint32();
const uint32_t transactionNestCount = parcel->readUint32();
const bool animation = parcel->readBool();
- const bool earlyWakeup = parcel->readBool();
- const bool explicitEarlyWakeupStart = parcel->readBool();
- const bool explicitEarlyWakeupEnd = parcel->readBool();
+ const bool earlyWakeupStart = parcel->readBool();
+ const bool earlyWakeupEnd = parcel->readBool();
const bool containsBuffer = parcel->readBool();
const int64_t desiredPresentTime = parcel->readInt64();
const bool isAutoTimestamp = parcel->readBool();
@@ -527,9 +580,8 @@
mForceSynchronous = forceSynchronous;
mTransactionNestCount = transactionNestCount;
mAnimation = animation;
- mEarlyWakeup = earlyWakeup;
- mExplicitEarlyWakeupStart = explicitEarlyWakeupStart;
- mExplicitEarlyWakeupEnd = explicitEarlyWakeupEnd;
+ mEarlyWakeupStart = earlyWakeupStart;
+ mEarlyWakeupEnd = earlyWakeupEnd;
mContainsBuffer = containsBuffer;
mDesiredPresentTime = desiredPresentTime;
mIsAutoTimestamp = isAutoTimestamp;
@@ -559,9 +611,8 @@
parcel->writeUint32(mForceSynchronous);
parcel->writeUint32(mTransactionNestCount);
parcel->writeBool(mAnimation);
- parcel->writeBool(mEarlyWakeup);
- parcel->writeBool(mExplicitEarlyWakeupStart);
- parcel->writeBool(mExplicitEarlyWakeupEnd);
+ parcel->writeBool(mEarlyWakeupStart);
+ parcel->writeBool(mEarlyWakeupEnd);
parcel->writeBool(mContainsBuffer);
parcel->writeInt64(mDesiredPresentTime);
parcel->writeBool(mIsAutoTimestamp);
@@ -639,9 +690,8 @@
mInputWindowCommands.merge(other.mInputWindowCommands);
mContainsBuffer |= other.mContainsBuffer;
- mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup;
- mExplicitEarlyWakeupStart = mExplicitEarlyWakeupStart || other.mExplicitEarlyWakeupStart;
- mExplicitEarlyWakeupEnd = mExplicitEarlyWakeupEnd || other.mExplicitEarlyWakeupEnd;
+ mEarlyWakeupStart = mEarlyWakeupStart || other.mEarlyWakeupStart;
+ mEarlyWakeupEnd = mEarlyWakeupEnd || other.mEarlyWakeupEnd;
mApplyToken = other.mApplyToken;
mFrameTimelineInfo.merge(other.mFrameTimelineInfo);
@@ -659,9 +709,8 @@
mForceSynchronous = 0;
mTransactionNestCount = 0;
mAnimation = false;
- mEarlyWakeup = false;
- mExplicitEarlyWakeupStart = false;
- mExplicitEarlyWakeupEnd = false;
+ mEarlyWakeupStart = false;
+ mEarlyWakeupEnd = false;
mDesiredPresentTime = 0;
mIsAutoTimestamp = true;
mFrameTimelineInfo.clear();
@@ -780,17 +829,14 @@
if (mAnimation) {
flags |= ISurfaceComposer::eAnimation;
}
- if (mEarlyWakeup) {
- flags |= ISurfaceComposer::eEarlyWakeup;
- }
- // If both mExplicitEarlyWakeupStart and mExplicitEarlyWakeupEnd are set
+ // If both mEarlyWakeupStart and mEarlyWakeupEnd are set
// it is equivalent for none
- if (mExplicitEarlyWakeupStart && !mExplicitEarlyWakeupEnd) {
- flags |= ISurfaceComposer::eExplicitEarlyWakeupStart;
+ if (mEarlyWakeupStart && !mEarlyWakeupEnd) {
+ flags |= ISurfaceComposer::eEarlyWakeupStart;
}
- if (mExplicitEarlyWakeupEnd && !mExplicitEarlyWakeupStart) {
- flags |= ISurfaceComposer::eExplicitEarlyWakeupEnd;
+ if (mEarlyWakeupEnd && !mEarlyWakeupStart) {
+ flags |= ISurfaceComposer::eEarlyWakeupEnd;
}
sp<IBinder> applyToken = mApplyToken
@@ -841,16 +887,12 @@
mAnimation = true;
}
-void SurfaceComposerClient::Transaction::setEarlyWakeup() {
- mEarlyWakeup = true;
+void SurfaceComposerClient::Transaction::setEarlyWakeupStart() {
+ mEarlyWakeupStart = true;
}
-void SurfaceComposerClient::Transaction::setExplicitEarlyWakeupStart() {
- mExplicitEarlyWakeupStart = true;
-}
-
-void SurfaceComposerClient::Transaction::setExplicitEarlyWakeupEnd() {
- mExplicitEarlyWakeupEnd = true;
+void SurfaceComposerClient::Transaction::setEarlyWakeupEnd() {
+ mEarlyWakeupEnd = true;
}
layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl>& sc) {
@@ -1048,15 +1090,15 @@
return *this;
}
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop_legacy(
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop(
const sp<SurfaceControl>& sc, const Rect& crop) {
layer_state_t* s = getLayerState(sc);
if (!s) {
mStatus = BAD_INDEX;
return *this;
}
- s->what |= layer_state_t::eCropChanged_legacy;
- s->crop_legacy = crop;
+ s->what |= layer_state_t::eCropChanged;
+ s->crop = crop;
registerSurfaceControlForCallback(sc);
return *this;
@@ -1204,20 +1246,6 @@
return *this;
}
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop(
- const sp<SurfaceControl>& sc, const Rect& crop) {
- layer_state_t* s = getLayerState(sc);
- if (!s) {
- mStatus = BAD_INDEX;
- return *this;
- }
- s->what |= layer_state_t::eCropChanged;
- s->crop = crop;
-
- registerSurfaceControlForCallback(sc);
- return *this;
-}
-
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame(
const sp<SurfaceControl>& sc, const Rect& frame) {
layer_state_t* s = getLayerState(sc);
@@ -1233,17 +1261,20 @@
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffer(
- const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer) {
+ const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer,
+ ReleaseBufferCallback callback) {
layer_state_t* s = getLayerState(sc);
if (!s) {
mStatus = BAD_INDEX;
return *this;
}
+ removeReleaseBufferCallback(s);
s->what |= layer_state_t::eBufferChanged;
s->buffer = buffer;
if (mIsAutoTimestamp) {
mDesiredPresentTime = systemTime();
}
+ setReleaseBufferCallback(s, callback);
registerSurfaceControlForCallback(sc);
@@ -1251,6 +1282,34 @@
return *this;
}
+void SurfaceComposerClient::Transaction::removeReleaseBufferCallback(layer_state_t* s) {
+ if (!s->releaseBufferListener) {
+ return;
+ }
+
+ s->what &= ~static_cast<uint64_t>(layer_state_t::eReleaseBufferListenerChanged);
+ s->releaseBufferListener = nullptr;
+ TransactionCompletedListener::getInstance()->removeReleaseBufferCallback(s->buffer->getId());
+}
+
+void SurfaceComposerClient::Transaction::setReleaseBufferCallback(layer_state_t* s,
+ ReleaseBufferCallback callback) {
+ if (!callback) {
+ return;
+ }
+
+ if (!s->buffer) {
+ ALOGW("Transaction::setReleaseBufferCallback"
+ "ignored trying to set a callback on a null buffer.");
+ return;
+ }
+
+ s->what |= layer_state_t::eReleaseBufferListenerChanged;
+ s->releaseBufferListener = TransactionCompletedListener::getIInstance();
+ auto listener = TransactionCompletedListener::getInstance();
+ listener->setReleaseBufferCallback(s->buffer->getId(), callback);
+}
+
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAcquireFence(
const sp<SurfaceControl>& sc, const sp<Fence>& fence) {
layer_state_t* s = getLayerState(sc);
@@ -1458,7 +1517,7 @@
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setGeometry(
const sp<SurfaceControl>& sc, const Rect& source, const Rect& dst, int transform) {
- setCrop_legacy(sc, source);
+ setCrop(sc, source);
int x = dst.left;
int y = dst.top;
@@ -1562,20 +1621,7 @@
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineInfo(
const FrameTimelineInfo& frameTimelineInfo) {
- mFrameTimelineInfo = frameTimelineInfo;
- return *this;
-}
-
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineInfo(
- const sp<SurfaceControl>& sc, const FrameTimelineInfo& frameTimelineInfo) {
- layer_state_t* s = getLayerState(sc);
- if (!s) {
- mStatus = BAD_INDEX;
- return *this;
- }
-
- s->what |= layer_state_t::eFrameTimelineInfoChanged;
- s->frameTimelineInfo = frameTimelineInfo;
+ mFrameTimelineInfo.merge(frameTimelineInfo);
return *this;
}
@@ -1998,7 +2044,7 @@
}
status_t SurfaceComposerClient::setDisplayBrightness(const sp<IBinder>& displayToken,
- float brightness) {
+ const gui::DisplayBrightness& brightness) {
return ComposerService::getComposerService()->setDisplayBrightness(displayToken, brightness);
}
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 1dcfe2e..7e2f8f9 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -39,6 +39,7 @@
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/SurfaceControl.h>
+#include <private/gui/ParcelUtils.h>
namespace android {
diff --git a/libs/gui/aidl/android/gui/DisplayBrightness.aidl b/libs/gui/aidl/android/gui/DisplayBrightness.aidl
new file mode 100644
index 0000000..bdb8c63
--- /dev/null
+++ b/libs/gui/aidl/android/gui/DisplayBrightness.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.gui;
+
+/** @hide */
+parcelable DisplayBrightness {
+ // Range 0-1f, the desired sdr white point brightness
+ float sdrWhitePoint = 0f;
+
+ // The SDR white point in nits. -1 if unknown
+ float sdrWhitePointNits = -1f;
+
+ // Range 0-1f, the desired brightness of the display itself. -1f to turn the backlight off
+ float displayBrightness = 0f;
+
+ // The desired brightness of the display in nits. -1 if unknown
+ float displayBrightnessNits = -1f;
+}
\ No newline at end of file
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index dd8e714..fbd16f4 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -74,7 +74,7 @@
{
public:
BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface, int width,
- int height, int32_t format, bool enableTripleBuffering = true);
+ int height, int32_t format);
sp<IGraphicBufferProducer> getIGraphicBufferProducer() const {
return mProducer;
@@ -89,13 +89,14 @@
void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
const std::vector<SurfaceControlStats>& stats);
+ void releaseBufferCallback(uint64_t graphicBufferId, const sp<Fence>& releaseFence);
void setNextTransaction(SurfaceComposerClient::Transaction *t);
void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber);
void setTransactionCompleteCallback(uint64_t frameNumber,
std::function<void(int64_t)>&& transactionCompleteCallback);
void update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, int32_t format);
- void flushShadowQueue() { mFlushShadowQueue = true; }
+ void flushShadowQueue() {}
status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless);
status_t setFrameTimelineInfo(const FrameTimelineInfo& info);
@@ -132,16 +133,10 @@
int32_t mNumFrameAvailable GUARDED_BY(mMutex);
int32_t mNumAcquired GUARDED_BY(mMutex);
- bool mInitialCallbackReceived GUARDED_BY(mMutex) = false;
- struct PendingReleaseItem {
- BufferItem item;
- sp<Fence> releaseFence;
- };
- std::queue<const BufferItem> mSubmitted GUARDED_BY(mMutex);
- // Keep a reference to the currently presented buffer so we can release it when the next buffer
- // is ready to be presented.
- PendingReleaseItem mPendingReleaseItem GUARDED_BY(mMutex);
+ // Keep a reference to the submitted buffers so we can release when surfaceflinger drops the
+ // buffer or the buffer has been presented and a new buffer is ready to be presented.
+ std::unordered_map<uint64_t /* bufferId */, BufferItem> mSubmitted GUARDED_BY(mMutex);
ui::Size mSize GUARDED_BY(mMutex);
ui::Size mRequestedSize GUARDED_BY(mMutex);
@@ -157,9 +152,6 @@
std::vector<std::tuple<uint64_t /* framenumber */, SurfaceComposerClient::Transaction>>
mPendingTransactions GUARDED_BY(mMutex);
- // If set to true, the next queue buffer will wait until the shadow queue has been processed by
- // the adapter.
- bool mFlushShadowQueue = false;
// Last requested auto refresh state set by the producer. The state indicates that the consumer
// should acquire the next frame as soon as it can and not wait for a frame to become available.
// This is only relevant for shared buffer mode.
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 88cfe4b..35990d1 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -16,6 +16,7 @@
#pragma once
+#include <android/gui/DisplayBrightness.h>
#include <android/gui/IFpsListener.h>
#include <android/gui/IScreenCaptureListener.h>
#include <android/gui/ITransactionTraceListener.h>
@@ -89,18 +90,15 @@
eSynchronous = 0x01,
eAnimation = 0x02,
- // DEPRECATED - use eExplicitEarlyWakeup[Start|End]
- eEarlyWakeup = 0x04,
-
// Explicit indication that this transaction and others to follow will likely result in a
// lot of layers being composed, and thus, SurfaceFlinger should wake-up earlier to avoid
// missing frame deadlines. In this case SurfaceFlinger will wake up at
// (sf vsync offset - debug.sf.early_phase_offset_ns). SurfaceFlinger will continue to be
- // in the early configuration until it receives eExplicitEarlyWakeupEnd. These flags are
+ // in the early configuration until it receives eEarlyWakeupEnd. These flags are
// expected to be used by WindowManager only and are guarded by
// android.permission.ACCESS_SURFACE_FLINGER
- eExplicitEarlyWakeupStart = 0x08,
- eExplicitEarlyWakeupEnd = 0x10,
+ eEarlyWakeupStart = 0x08,
+ eEarlyWakeupEnd = 0x10,
};
enum VsyncSource {
@@ -415,15 +413,15 @@
* displayToken
* The token of the display whose brightness is set.
* brightness
- * A number between 0.0f (minimum brightness) and 1.0 (maximum brightness), or -1.0f to
- * turn the backlight off.
+ * The DisplayBrightness info to set on the desired display.
*
* Returns NO_ERROR upon success. Otherwise,
* NAME_NOT_FOUND if the display is invalid, or
* BAD_VALUE if the brightness is invalid, or
* INVALID_OPERATION if brightness operations are not supported.
*/
- virtual status_t setDisplayBrightness(const sp<IBinder>& displayToken, float brightness) = 0;
+ virtual status_t setDisplayBrightness(const sp<IBinder>& displayToken,
+ const gui::DisplayBrightness& brightness) = 0;
/*
* Sends a power boost to the composer. This function is asynchronous.
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index cb17cee..098760e 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -87,13 +87,14 @@
SurfaceStats() = default;
SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence,
uint32_t hint, FrameEventHistoryStats frameEventStats,
- std::vector<JankData> jankData)
+ std::vector<JankData> jankData, uint64_t previousBufferId)
: surfaceControl(sc),
acquireTime(time),
previousReleaseFence(prevReleaseFence),
transformHint(hint),
eventStats(frameEventStats),
- jankData(std::move(jankData)) {}
+ jankData(std::move(jankData)),
+ previousBufferId(previousBufferId) {}
sp<IBinder> surfaceControl;
nsecs_t acquireTime = -1;
@@ -101,6 +102,7 @@
uint32_t transformHint = 0;
FrameEventHistoryStats eventStats;
std::vector<JankData> jankData;
+ uint64_t previousBufferId;
};
class TransactionStats : public Parcelable {
@@ -139,6 +141,8 @@
DECLARE_META_INTERFACE(TransactionCompletedListener)
virtual void onTransactionCompleted(ListenerStats stats) = 0;
+
+ virtual void onReleaseBuffer(uint64_t graphicBufferId, sp<Fence> releaseFence) = 0;
};
class BnTransactionCompletedListener : public SafeBnInterface<ITransactionCompletedListener> {
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index b273805..9274777 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -16,23 +16,7 @@
#ifndef ANDROID_SF_LAYER_STATE_H
#define ANDROID_SF_LAYER_STATE_H
-#define SAFE_PARCEL(FUNC, ...) \
- { \
- status_t error = FUNC(__VA_ARGS__); \
- if (error) { \
- ALOGE("ERROR(%d). Failed to call parcel %s(%s)", error, #FUNC, #__VA_ARGS__); \
- return error; \
- } \
- }
-#define SAFE_PARCEL_READ_SIZE(FUNC, COUNT, SIZE) \
- { \
- SAFE_PARCEL(FUNC, COUNT); \
- if (static_cast<unsigned int>(*COUNT) > SIZE) { \
- ALOGE("ERROR(BAD_VALUE). %s was greater than dataSize", #COUNT); \
- return BAD_VALUE; \
- } \
- }
#include <stdint.h>
#include <sys/types.h>
@@ -98,9 +82,9 @@
eTransparentRegionChanged = 0x00000020,
eFlagsChanged = 0x00000040,
eLayerStackChanged = 0x00000080,
- eCropChanged_legacy = 0x00000100,
+ /* was eCropChanged_legacy, now available 0x00000100, */
eDeferTransaction_legacy = 0x00000200,
- /* was ScalingModeChanged, now available 0x00000400, */
+ eReleaseBufferListenerChanged = 0x00000400,
eShadowRadiusChanged = 0x00000800,
eReparentChildren = 0x00001000,
/* was eDetachChildren, now available 0x00002000, */
@@ -133,10 +117,9 @@
eProducerDisconnect = 0x100'00000000,
eFixedTransformHintChanged = 0x200'00000000,
eFrameNumberChanged = 0x400'00000000,
- eFrameTimelineInfoChanged = 0x800'00000000,
- eBlurRegionsChanged = 0x1000'00000000,
- eAutoRefreshChanged = 0x2000'00000000,
- eStretchChanged = 0x4000'00000000,
+ eBlurRegionsChanged = 0x800'00000000,
+ eAutoRefreshChanged = 0x1000'00000000,
+ eStretchChanged = 0x2000'00000000,
};
layer_state_t();
@@ -167,7 +150,6 @@
uint32_t mask;
uint8_t reserved;
matrix22_t matrix;
- Rect crop_legacy;
float cornerRadius;
uint32_t backgroundBlurRadius;
sp<SurfaceControl> barrierSurfaceControl_legacy;
@@ -240,8 +222,6 @@
// graphics producer.
uint64_t frameNumber;
- FrameTimelineInfo frameTimelineInfo;
-
// Indicates that the consumer should acquire the next frame as soon as it
// can and not wait for a frame to become available. This is only relevant
// in shared buffer mode.
@@ -249,6 +229,11 @@
// Stretch effect to be applied to this layer
StretchEffect stretchEffect;
+
+ // Listens to when the buffer is safe to be released. This is used for blast
+ // layers only. The callback includes a release fence as well as the graphic
+ // buffer id to identify the buffer.
+ sp<ITransactionCompletedListener> releaseBufferListener;
};
struct ComposerState {
diff --git a/libs/gui/include/gui/ScreenCaptureResults.h b/libs/gui/include/gui/ScreenCaptureResults.h
index 0ccc6e8..99c35c1 100644
--- a/libs/gui/include/gui/ScreenCaptureResults.h
+++ b/libs/gui/include/gui/ScreenCaptureResults.h
@@ -16,15 +16,6 @@
#pragma once
-#define SAFE_PARCEL(FUNC, ...) \
- { \
- status_t error = FUNC(__VA_ARGS__); \
- if (error) { \
- ALOGE("ERROR(%d). Failed to call parcel %s(%s)", error, #FUNC, #__VA_ARGS__); \
- return error; \
- } \
- }
-
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
#include <ui/Fence.h>
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index de88943..a643e9e 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -80,6 +80,9 @@
using TransactionCompletedCallback =
std::function<void(nsecs_t /*latchTime*/, const sp<Fence>& /*presentFence*/,
const std::vector<SurfaceControlStats>& /*stats*/)>;
+using ReleaseBufferCallback =
+ std::function<void(uint64_t /* graphicsBufferId */, const sp<Fence>& /*releaseFence*/)>;
+
using SurfaceStatsCallback =
std::function<void(void* /*context*/, nsecs_t /*latchTime*/,
const sp<Fence>& /*presentFence*/,
@@ -209,7 +212,8 @@
* BAD_VALUE if the brightness value is invalid, or
* INVALID_OPERATION if brightness operaetions are not supported.
*/
- static status_t setDisplayBrightness(const sp<IBinder>& displayToken, float brightness);
+ static status_t setDisplayBrightness(const sp<IBinder>& displayToken,
+ const gui::DisplayBrightness& brightness);
/*
* Sends a power boost to the composer. This function is asynchronous.
@@ -349,9 +353,8 @@
uint32_t mForceSynchronous = 0;
uint32_t mTransactionNestCount = 0;
bool mAnimation = false;
- bool mEarlyWakeup = false;
- bool mExplicitEarlyWakeupStart = false;
- bool mExplicitEarlyWakeupEnd = false;
+ bool mEarlyWakeupStart = false;
+ bool mEarlyWakeupEnd = false;
// Indicates that the Transaction contains a buffer that should be cached
bool mContainsBuffer = false;
@@ -387,6 +390,8 @@
void cacheBuffers();
void registerSurfaceControlForCallback(const sp<SurfaceControl>& sc);
+ void setReleaseBufferCallback(layer_state_t* state, ReleaseBufferCallback callback);
+ void removeReleaseBufferCallback(layer_state_t* state);
public:
Transaction();
@@ -436,7 +441,7 @@
float alpha);
Transaction& setMatrix(const sp<SurfaceControl>& sc,
float dsdx, float dtdx, float dtdy, float dsdy);
- Transaction& setCrop_legacy(const sp<SurfaceControl>& sc, const Rect& crop);
+ Transaction& setCrop(const sp<SurfaceControl>& sc, const Rect& crop);
Transaction& setCornerRadius(const sp<SurfaceControl>& sc, float cornerRadius);
Transaction& setBackgroundBlurRadius(const sp<SurfaceControl>& sc,
int backgroundBlurRadius);
@@ -469,9 +474,9 @@
Transaction& setTransform(const sp<SurfaceControl>& sc, uint32_t transform);
Transaction& setTransformToDisplayInverse(const sp<SurfaceControl>& sc,
bool transformToDisplayInverse);
- Transaction& setCrop(const sp<SurfaceControl>& sc, const Rect& crop);
Transaction& setFrame(const sp<SurfaceControl>& sc, const Rect& frame);
- Transaction& setBuffer(const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer);
+ Transaction& setBuffer(const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer,
+ ReleaseBufferCallback callback = nullptr);
Transaction& setCachedBuffer(const sp<SurfaceControl>& sc, int32_t bufferId);
Transaction& setAcquireFence(const sp<SurfaceControl>& sc, const sp<Fence>& fence);
Transaction& setDataspace(const sp<SurfaceControl>& sc, ui::Dataspace dataspace);
@@ -524,9 +529,6 @@
// to the transaction, and the input event id that identifies the input event that caused
// the current frame.
Transaction& setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo);
- // Variant that only applies to a specific SurfaceControl.
- Transaction& setFrameTimelineInfo(const sp<SurfaceControl>& sc,
- const FrameTimelineInfo& frameTimelineInfo);
// Indicates that the consumer should acquire the next frame as soon as it
// can and not wait for a frame to become available. This is only relevant
@@ -561,9 +563,8 @@
const Rect& layerStackRect, const Rect& displayRect);
void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height);
void setAnimationTransaction();
- void setEarlyWakeup();
- void setExplicitEarlyWakeupStart();
- void setExplicitEarlyWakeupEnd();
+ void setEarlyWakeupStart();
+ void setEarlyWakeupEnd();
};
status_t clearLayerFrameStats(const sp<IBinder>& token) const;
@@ -650,6 +651,8 @@
std::unordered_map<CallbackId, CallbackTranslation> mCallbacks GUARDED_BY(mMutex);
std::multimap<sp<IBinder>, sp<JankDataListener>> mJankListeners GUARDED_BY(mMutex);
+ std::unordered_map<uint64_t /* graphicsBufferId */, ReleaseBufferCallback>
+ mReleaseBufferCallbacks GUARDED_BY(mMutex);
std::multimap<sp<IBinder>, SurfaceStatsCallbackEntry>
mSurfaceStatsListeners GUARDED_BY(mMutex);
@@ -683,8 +686,15 @@
SurfaceStatsCallback listener);
void removeSurfaceStatsListener(void* context, void* cookie);
- // Overrides BnTransactionCompletedListener's onTransactionCompleted
+ void setReleaseBufferCallback(uint64_t /* graphicsBufferId */, ReleaseBufferCallback);
+ void removeReleaseBufferCallback(uint64_t /* graphicsBufferId */);
+
+ // BnTransactionCompletedListener overrides
void onTransactionCompleted(ListenerStats stats) override;
+ void onReleaseBuffer(uint64_t /* graphicsBufferId */, sp<Fence> releaseFence) override;
+
+private:
+ ReleaseBufferCallback popReleaseBufferCallbackLocked(uint64_t /* graphicsBufferId */);
};
} // namespace android
diff --git a/libs/gui/include/private/gui/ParcelUtils.h b/libs/gui/include/private/gui/ParcelUtils.h
new file mode 100644
index 0000000..1cdd07e
--- /dev/null
+++ b/libs/gui/include/private/gui/ParcelUtils.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstring>
+
+#define SAFE_PARCEL(FUNC, ...) \
+ { \
+ status_t error = FUNC(__VA_ARGS__); \
+ if (error) { \
+ ALOGE("ERROR(%s, %d). Failed to call parcel %s(%s)", strerror(-error), error, #FUNC, \
+ #__VA_ARGS__); \
+ return error; \
+ } \
+ }
+
+#define SAFE_PARCEL_READ_SIZE(FUNC, COUNT, SIZE) \
+ { \
+ SAFE_PARCEL(FUNC, COUNT); \
+ if (static_cast<unsigned int>(*COUNT) > SIZE) { \
+ ALOGE("ERROR(BAD_VALUE). %s was greater than dataSize", #COUNT); \
+ return BAD_VALUE; \
+ } \
+ }
\ No newline at end of file
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index fb07a19..fe48d88 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -73,13 +73,34 @@
void waitForCallbacks() {
std::unique_lock lock{mBlastBufferQueueAdapter->mMutex};
- while (mBlastBufferQueueAdapter->mSubmitted.size() > 0) {
+ // Wait until all but one of the submitted buffers have been released.
+ while (mBlastBufferQueueAdapter->mSubmitted.size() > 1) {
mBlastBufferQueueAdapter->mCallbackCV.wait(lock);
}
}
+ void setTransactionCompleteCallback(int64_t frameNumber) {
+ mBlastBufferQueueAdapter->setTransactionCompleteCallback(frameNumber, [&](int64_t frame) {
+ std::unique_lock lock{mMutex};
+ mLastTransactionCompleteFrameNumber = frame;
+ mCallbackCV.notify_all();
+ });
+ }
+
+ void waitForCallback(int64_t frameNumber) {
+ std::unique_lock lock{mMutex};
+ // Wait until all but one of the submitted buffers have been released.
+ while (mLastTransactionCompleteFrameNumber < frameNumber) {
+ mCallbackCV.wait(lock);
+ }
+ }
+
private:
sp<BLASTBufferQueue> mBlastBufferQueueAdapter;
+
+ std::mutex mMutex;
+ std::condition_variable mCallbackCV;
+ int64_t mLastTransactionCompleteFrameNumber = -1;
};
class BLASTBufferQueueTest : public ::testing::Test {
@@ -128,7 +149,7 @@
mCaptureArgs.dataspace = ui::Dataspace::V0_SRGB;
}
- void setUpProducer(BLASTBufferQueueHelper adapter, sp<IGraphicBufferProducer>& producer) {
+ void setUpProducer(BLASTBufferQueueHelper& adapter, sp<IGraphicBufferProducer>& producer) {
producer = adapter.getIGraphicBufferProducer();
setUpProducer(producer);
}
@@ -205,10 +226,10 @@
EXPECT_GE(epsilon, abs(g - *(pixel + 1)));
EXPECT_GE(epsilon, abs(b - *(pixel + 2)));
}
+ ASSERT_EQ(false, ::testing::Test::HasFailure());
}
}
captureBuf->unlock();
- ASSERT_EQ(false, ::testing::Test::HasFailure());
}
static status_t captureDisplay(DisplayCaptureArgs& captureArgs,
@@ -315,7 +336,8 @@
nsecs_t desiredPresentTime = systemTime() + nsecs_t(5 * 1e8);
IGraphicBufferProducer::QueueBufferOutput qbOutput;
- IGraphicBufferProducer::QueueBufferInput input(desiredPresentTime, false, HAL_DATASPACE_UNKNOWN,
+ IGraphicBufferProducer::QueueBufferInput input(desiredPresentTime, true /* autotimestamp */,
+ HAL_DATASPACE_UNKNOWN,
Rect(mDisplayWidth, mDisplayHeight),
NATIVE_WINDOW_SCALING_MODE_FREEZE, 0,
Fence::NO_FENCE);
@@ -351,7 +373,8 @@
buf->unlock();
IGraphicBufferProducer::QueueBufferOutput qbOutput;
- IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN,
+ IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */,
+ HAL_DATASPACE_UNKNOWN,
Rect(mDisplayWidth, mDisplayHeight),
NATIVE_WINDOW_SCALING_MODE_FREEZE, 0,
Fence::NO_FENCE);
@@ -396,7 +419,8 @@
nullptr, nullptr);
ASSERT_EQ(NO_ERROR, ret);
IGraphicBufferProducer::QueueBufferOutput qbOutput;
- IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN,
+ IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */,
+ HAL_DATASPACE_UNKNOWN,
Rect(mDisplayWidth, mDisplayHeight),
NATIVE_WINDOW_SCALING_MODE_FREEZE, 0,
Fence::NO_FENCE);
@@ -429,7 +453,8 @@
buf->unlock();
IGraphicBufferProducer::QueueBufferOutput qbOutput;
- IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN,
+ IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */,
+ HAL_DATASPACE_UNKNOWN,
Rect(mDisplayWidth, mDisplayHeight / 2),
NATIVE_WINDOW_SCALING_MODE_FREEZE, 0,
Fence::NO_FENCE);
@@ -458,7 +483,7 @@
ASSERT_NE(nullptr, bg.get());
Transaction t;
t.setLayerStack(bg, 0)
- .setCrop_legacy(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight))
+ .setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight))
.setColor(bg, half3{0, 0, 0})
.setLayer(bg, 0)
.apply();
@@ -486,7 +511,8 @@
buf->unlock();
IGraphicBufferProducer::QueueBufferOutput qbOutput;
- IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN,
+ IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */,
+ HAL_DATASPACE_UNKNOWN,
Rect(bufferSideLength, finalCropSideLength),
NATIVE_WINDOW_SCALING_MODE_SCALE_CROP, 0,
Fence::NO_FENCE);
@@ -537,7 +563,8 @@
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret);
ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf));
IGraphicBufferProducer::QueueBufferOutput qbOutput;
- IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN,
+ IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */,
+ HAL_DATASPACE_UNKNOWN,
Rect(mDisplayWidth, mDisplayHeight),
NATIVE_WINDOW_SCALING_MODE_FREEZE, 0,
Fence::NO_FENCE);
@@ -577,7 +604,7 @@
sp<IGraphicBufferProducer> slowIgbProducer;
setUpProducer(slowAdapter, slowIgbProducer);
nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count();
- queueBuffer(slowIgbProducer, 0 /* r */, 0 /* g */, 0 /* b */, presentTimeDelay);
+ queueBuffer(slowIgbProducer, 0 /* r */, 255 /* g */, 0 /* b */, presentTimeDelay);
BLASTBufferQueueHelper fastAdapter(bgSurface, mDisplayWidth, mDisplayHeight);
sp<IGraphicBufferProducer> fastIgbProducer;
@@ -617,7 +644,8 @@
fillQuadrants(buf);
IGraphicBufferProducer::QueueBufferOutput qbOutput;
- IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN,
+ IGraphicBufferProducer::QueueBufferInput input(systemTime(), true /* autotimestamp */,
+ HAL_DATASPACE_UNKNOWN,
Rect(bufWidth, bufHeight),
NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW,
tr, Fence::NO_FENCE);
@@ -838,6 +866,7 @@
IGraphicBufferProducer::QueueBufferOutput qbOutput;
nsecs_t requestedPresentTimeA = 0;
nsecs_t postedTimeA = 0;
+ adapter.setTransactionCompleteCallback(1);
setUpAndQueueBuffer(igbProducer, &requestedPresentTimeA, &postedTimeA, &qbOutput, true);
history.applyDelta(qbOutput.frameTimestamps);
@@ -848,7 +877,7 @@
ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
ASSERT_GE(events->postedTime, postedTimeA);
- adapter.waitForCallbacks();
+ adapter.waitForCallback(1);
// queue another buffer so we query for frame event deltas
nsecs_t requestedPresentTimeB = 0;
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index d65a40b..59e5c13 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -195,7 +195,7 @@
t.setInputWindowInfo(mSurfaceControl, mInputInfo);
t.setLayer(mSurfaceControl, LAYER_BASE);
t.setPosition(mSurfaceControl, x, y);
- t.setCrop_legacy(mSurfaceControl, crop);
+ t.setCrop(mSurfaceControl, crop);
t.setAlpha(mSurfaceControl, 1);
t.apply(true);
}
@@ -670,7 +670,7 @@
parentSurface->showAt(100, 100);
nonTouchableSurface->doTransaction([&](auto &t, auto &sc) {
- t.setCrop_legacy(parentSurface->mSurfaceControl, Rect(0, 0, 50, 50));
+ t.setCrop(parentSurface->mSurfaceControl, Rect(0, 0, 50, 50));
t.reparent(sc, parentSurface->mSurfaceControl);
});
@@ -694,7 +694,7 @@
parentSurface->showAt(50, 50);
nonTouchableSurface->doTransaction([&](auto &t, auto &sc) {
- t.setCrop_legacy(parentSurface->mSurfaceControl, Rect(0, 0, 50, 50));
+ t.setCrop(parentSurface->mSurfaceControl, Rect(0, 0, 50, 50));
t.reparent(sc, parentSurface->mSurfaceControl);
});
diff --git a/libs/gui/tests/SamplingDemo.cpp b/libs/gui/tests/SamplingDemo.cpp
index 5c1bebb..0cd150d 100644
--- a/libs/gui/tests/SamplingDemo.cpp
+++ b/libs/gui/tests/SamplingDemo.cpp
@@ -46,8 +46,7 @@
SurfaceComposerClient::Transaction{}
.setLayer(mButton, 0x7fffffff)
- .setCrop_legacy(mButton,
- {0, 0, width - 2 * BUTTON_PADDING, height - 2 * BUTTON_PADDING})
+ .setCrop(mButton, {0, 0, width - 2 * BUTTON_PADDING, height - 2 * BUTTON_PADDING})
.setPosition(mButton, samplingArea.left + BUTTON_PADDING,
samplingArea.top + BUTTON_PADDING)
.setColor(mButton, half3{1, 1, 1})
@@ -59,9 +58,8 @@
SurfaceComposerClient::Transaction{}
.setLayer(mButtonBlend, 0x7ffffffe)
- .setCrop_legacy(mButtonBlend,
- {0, 0, width - 2 * SAMPLE_AREA_PADDING,
- height - 2 * SAMPLE_AREA_PADDING})
+ .setCrop(mButtonBlend,
+ {0, 0, width - 2 * SAMPLE_AREA_PADDING, height - 2 * SAMPLE_AREA_PADDING})
.setPosition(mButtonBlend, samplingArea.left + SAMPLE_AREA_PADDING,
samplingArea.top + SAMPLE_AREA_PADDING)
.setColor(mButtonBlend, half3{1, 1, 1})
@@ -77,7 +75,7 @@
SurfaceComposerClient::Transaction{}
.setLayer(mSamplingArea, 0x7ffffffd)
- .setCrop_legacy(mSamplingArea, {0, 0, 100, 32})
+ .setCrop(mSamplingArea, {0, 0, 100, 32})
.setPosition(mSamplingArea, 490, 1606)
.setColor(mSamplingArea, half3{0, 1, 0})
.setAlpha(mSamplingArea, 0.1)
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index e8fb71d..8d7f8c9 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -811,7 +811,7 @@
return NO_ERROR;
}
status_t setDisplayBrightness(const sp<IBinder>& /*displayToken*/,
- float /*brightness*/) override {
+ const gui::DisplayBrightness& /*brightness*/) override {
return NO_ERROR;
}
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 6ef0173..c2a3cf1 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -629,24 +629,26 @@
return mChannel->sendMessage(&msg);
}
-status_t InputPublisher::receiveFinishedSignal(
- const std::function<void(uint32_t seq, bool handled, nsecs_t consumeTime)>& callback) {
+android::base::Result<InputPublisher::Finished> InputPublisher::receiveFinishedSignal() {
if (DEBUG_TRANSPORT_ACTIONS) {
- ALOGD("channel '%s' publisher ~ receiveFinishedSignal", mChannel->getName().c_str());
+ ALOGD("channel '%s' publisher ~ %s", mChannel->getName().c_str(), __func__);
}
InputMessage msg;
status_t result = mChannel->receiveMessage(&msg);
if (result) {
- return result;
+ return android::base::Error(result);
}
if (msg.header.type != InputMessage::Type::FINISHED) {
ALOGE("channel '%s' publisher ~ Received unexpected %s message from consumer",
mChannel->getName().c_str(), NamedEnum::string(msg.header.type).c_str());
- return UNKNOWN_ERROR;
+ return android::base::Error(UNKNOWN_ERROR);
}
- callback(msg.header.seq, msg.body.finished.handled, msg.body.finished.consumeTime);
- return OK;
+ return Finished{
+ .seq = msg.header.seq,
+ .handled = msg.body.finished.handled,
+ .consumeTime = msg.body.finished.consumeTime,
+ };
}
// --- InputConsumer ---
diff --git a/libs/input/tests/Flags_test.cpp b/libs/input/tests/Flags_test.cpp
index 0dbb4cf..6de030f 100644
--- a/libs/input/tests/Flags_test.cpp
+++ b/libs/input/tests/Flags_test.cpp
@@ -148,6 +148,11 @@
ASSERT_NE(flags1, flags2);
}
+TEST(Flags, GetValue) {
+ Flags<TestFlags> flags = TestFlags::ONE | TestFlags::TWO;
+ ASSERT_EQ(flags.get(), 0x3);
+}
+
TEST(Flags, String_NoFlags) {
Flags<TestFlags> flags;
ASSERT_EQ(flags.string(), "0x0");
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index b5ed8d7..fc31715 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -27,6 +27,8 @@
#include <utils/StopWatch.h>
#include <utils/Timers.h>
+using android::base::Result;
+
namespace android {
class InputPublisherAndConsumerTest : public testing::Test {
@@ -122,23 +124,13 @@
ASSERT_EQ(OK, status)
<< "consumer sendFinishedSignal should return OK";
- uint32_t finishedSeq = 0;
- bool handled = false;
- nsecs_t consumeTime;
- status = mPublisher->receiveFinishedSignal(
- [&finishedSeq, &handled, &consumeTime](uint32_t inSeq, bool inHandled,
- nsecs_t inConsumeTime) -> void {
- finishedSeq = inSeq;
- handled = inHandled;
- consumeTime = inConsumeTime;
- });
- ASSERT_EQ(OK, status)
- << "publisher receiveFinishedSignal should return OK";
- ASSERT_EQ(seq, finishedSeq)
- << "publisher receiveFinishedSignal should have returned the original sequence number";
- ASSERT_TRUE(handled)
- << "publisher receiveFinishedSignal should have set handled to consumer's reply";
- ASSERT_GE(consumeTime, publishTime)
+ Result<InputPublisher::Finished> result = mPublisher->receiveFinishedSignal();
+ ASSERT_TRUE(result.ok()) << "publisher receiveFinishedSignal should return OK";
+ ASSERT_EQ(seq, result->seq)
+ << "receiveFinishedSignal should have returned the original sequence number";
+ ASSERT_TRUE(result->handled)
+ << "receiveFinishedSignal should have set handled to consumer's reply";
+ ASSERT_GE(result->consumeTime, publishTime)
<< "finished signal's consume time should be greater than publish time";
}
@@ -272,23 +264,13 @@
ASSERT_EQ(OK, status)
<< "consumer sendFinishedSignal should return OK";
- uint32_t finishedSeq = 0;
- bool handled = true;
- nsecs_t consumeTime;
- status = mPublisher->receiveFinishedSignal(
- [&finishedSeq, &handled, &consumeTime](uint32_t inSeq, bool inHandled,
- nsecs_t inConsumeTime) -> void {
- finishedSeq = inSeq;
- handled = inHandled;
- consumeTime = inConsumeTime;
- });
- ASSERT_EQ(OK, status)
- << "publisher receiveFinishedSignal should return OK";
- ASSERT_EQ(seq, finishedSeq)
- << "publisher receiveFinishedSignal should have returned the original sequence number";
- ASSERT_FALSE(handled)
- << "publisher receiveFinishedSignal should have set handled to consumer's reply";
- ASSERT_GE(consumeTime, publishTime)
+ Result<InputPublisher::Finished> result = mPublisher->receiveFinishedSignal();
+ ASSERT_TRUE(result.ok()) << "receiveFinishedSignal should return OK";
+ ASSERT_EQ(seq, result->seq)
+ << "receiveFinishedSignal should have returned the original sequence number";
+ ASSERT_FALSE(result->handled)
+ << "receiveFinishedSignal should have set handled to consumer's reply";
+ ASSERT_GE(result->consumeTime, publishTime)
<< "finished signal's consume time should be greater than publish time";
}
@@ -322,22 +304,14 @@
status = mConsumer->sendFinishedSignal(seq, true);
ASSERT_EQ(OK, status) << "consumer sendFinishedSignal should return OK";
- uint32_t finishedSeq = 0;
- bool handled = false;
- nsecs_t consumeTime;
- status = mPublisher->receiveFinishedSignal(
- [&finishedSeq, &handled, &consumeTime](uint32_t inSeq, bool inHandled,
- nsecs_t inConsumeTime) -> void {
- finishedSeq = inSeq;
- handled = inHandled;
- consumeTime = inConsumeTime;
- });
- ASSERT_EQ(OK, status) << "publisher receiveFinishedSignal should return OK";
- ASSERT_EQ(seq, finishedSeq)
- << "publisher receiveFinishedSignal should have returned the original sequence number";
- ASSERT_TRUE(handled)
- << "publisher receiveFinishedSignal should have set handled to consumer's reply";
- ASSERT_GE(consumeTime, publishTime)
+ Result<InputPublisher::Finished> result = mPublisher->receiveFinishedSignal();
+
+ ASSERT_TRUE(result.ok()) << "receiveFinishedSignal should return OK";
+ ASSERT_EQ(seq, result->seq)
+ << "receiveFinishedSignal should have returned the original sequence number";
+ ASSERT_TRUE(result->handled)
+ << "receiveFinishedSignal should have set handled to consumer's reply";
+ ASSERT_GE(result->consumeTime, publishTime)
<< "finished signal's consume time should be greater than publish time";
}
@@ -369,22 +343,13 @@
status = mConsumer->sendFinishedSignal(seq, true);
ASSERT_EQ(OK, status) << "consumer sendFinishedSignal should return OK";
- uint32_t finishedSeq = 0;
- bool handled = false;
- nsecs_t consumeTime;
- status = mPublisher->receiveFinishedSignal(
- [&finishedSeq, &handled, &consumeTime](uint32_t inSeq, bool inHandled,
- nsecs_t inConsumeTime) -> void {
- finishedSeq = inSeq;
- handled = inHandled;
- consumeTime = inConsumeTime;
- });
- ASSERT_EQ(OK, status) << "publisher receiveFinishedSignal should return OK";
- ASSERT_EQ(seq, finishedSeq)
- << "publisher receiveFinishedSignal should have returned the original sequence number";
- ASSERT_TRUE(handled)
- << "publisher receiveFinishedSignal should have set handled to consumer's reply";
- ASSERT_GE(consumeTime, publishTime)
+ android::base::Result<InputPublisher::Finished> result = mPublisher->receiveFinishedSignal();
+ ASSERT_TRUE(result.ok()) << "publisher receiveFinishedSignal should return OK";
+ ASSERT_EQ(seq, result->seq)
+ << "receiveFinishedSignal should have returned the original sequence number";
+ ASSERT_TRUE(result->handled)
+ << "receiveFinishedSignal should have set handled to consumer's reply";
+ ASSERT_GE(result->consumeTime, publishTime)
<< "finished signal's consume time should be greater than publish time";
}
@@ -410,32 +375,23 @@
ASSERT_EQ(AINPUT_EVENT_TYPE_DRAG, event->getType())
<< "consumer should have returned a drag event";
- DragEvent* dragEvent = static_cast<DragEvent*>(event);
+ const DragEvent& dragEvent = static_cast<const DragEvent&>(*event);
EXPECT_EQ(seq, consumeSeq);
- EXPECT_EQ(eventId, dragEvent->getId());
- EXPECT_EQ(isExiting, dragEvent->isExiting());
- EXPECT_EQ(x, dragEvent->getX());
- EXPECT_EQ(y, dragEvent->getY());
+ EXPECT_EQ(eventId, dragEvent.getId());
+ EXPECT_EQ(isExiting, dragEvent.isExiting());
+ EXPECT_EQ(x, dragEvent.getX());
+ EXPECT_EQ(y, dragEvent.getY());
status = mConsumer->sendFinishedSignal(seq, true);
ASSERT_EQ(OK, status) << "consumer sendFinishedSignal should return OK";
- uint32_t finishedSeq = 0;
- bool handled = false;
- nsecs_t consumeTime;
- status = mPublisher->receiveFinishedSignal(
- [&finishedSeq, &handled, &consumeTime](uint32_t inSeq, bool inHandled,
- nsecs_t inConsumeTime) -> void {
- finishedSeq = inSeq;
- handled = inHandled;
- consumeTime = inConsumeTime;
- });
- ASSERT_EQ(OK, status) << "publisher receiveFinishedSignal should return OK";
- ASSERT_EQ(seq, finishedSeq)
+ android::base::Result<InputPublisher::Finished> result = mPublisher->receiveFinishedSignal();
+ ASSERT_TRUE(result.ok()) << "publisher receiveFinishedSignal should return OK";
+ ASSERT_EQ(seq, result->seq)
<< "publisher receiveFinishedSignal should have returned the original sequence number";
- ASSERT_TRUE(handled)
+ ASSERT_TRUE(result->handled)
<< "publisher receiveFinishedSignal should have set handled to consumer's reply";
- ASSERT_GE(consumeTime, publishTime)
+ ASSERT_GE(result->consumeTime, publishTime)
<< "finished signal's consume time should be greater than publish time";
}
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index a375d43..79b47a1 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -51,13 +51,13 @@
std::string("AHardwareBuffer pid [") + std::to_string(getpid()) + "]"));
status_t err = gbuffer->initCheck();
- if (err != 0 || gbuffer->handle == 0) {
+ if (err != 0 || gbuffer->handle == nullptr) {
if (err == NO_MEMORY) {
GraphicBuffer::dumpAllocationsToSystemLog();
}
ALOGE("GraphicBuffer(w=%u, h=%u, lc=%u) failed (%s), handle=%p",
desc->width, desc->height, desc->layers, strerror(-err), gbuffer->handle);
- return err;
+ return err == 0 ? UNKNOWN_ERROR : err;
}
*outBuffer = AHardwareBuffer_from_GraphicBuffer(gbuffer.get());
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index 4fdae74..f8dd7f5 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -55,6 +55,7 @@
// generate the slower (more general case) version. If we also need a
// slow version without color correction, we should use this matrix with
// display.outputDataspace set to SRGB.
+ bool identity = true;
for (const mat4 transform : { mat4(), mat4(0.728872f, 0.f, 0.f, 0.f,
0.f, 0.727627f, 0.f, 0.f,
0.f, 0.f, 1.f, 0.f,
@@ -62,6 +63,8 @@
layer.geometry.positionTransform = transform;
renderengine->drawLayers(display, layers, dstBuffer, false /* useFrameBufferCache*/,
base::unique_fd(), nullptr);
+ renderengine->assertShadersCompiled(identity ? 1 : 2);
+ identity = false;
}
}
@@ -105,6 +108,7 @@
renderengine->drawLayers(display, layers, dstBuffer,
false /* useFrameBufferCache*/, base::unique_fd(),
nullptr);
+ renderengine->assertShadersCompiled(1);
}
}
}
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 66efb09..7d711c1 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -268,6 +268,23 @@
return config;
}
+sk_sp<SkData> SkiaGLRenderEngine::SkSLCacheMonitor::load(const SkData& key) {
+ // This "cache" does not actually cache anything. It just allows us to
+ // monitor Skia's internal cache. So this method always returns null.
+ return nullptr;
+}
+
+void SkiaGLRenderEngine::SkSLCacheMonitor::store(const SkData& key, const SkData& data,
+ const SkString& description) {
+ mShadersCachedSinceLastCall++;
+}
+
+void SkiaGLRenderEngine::assertShadersCompiled(int numShaders) {
+ const int cached = mSkSLCacheMonitor.shadersCachedSinceLastCall();
+ LOG_ALWAYS_FATAL_IF(cached != numShaders, "Attempted to cache %i shaders; cached %i",
+ numShaders, cached);
+}
+
SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display,
EGLContext ctxt, EGLSurface placeholder,
EGLContext protectedContext, EGLSurface protectedPlaceholder)
@@ -284,6 +301,7 @@
GrContextOptions options;
options.fPreferExternalImagesOverES3 = true;
options.fDisableDistanceFieldPaths = true;
+ options.fPersistentCache = &mSkSLCacheMonitor;
mGrContext = GrDirectContext::MakeGL(glInterface, options);
if (useProtectedContext(true)) {
mProtectedGrContext = GrDirectContext::MakeGL(glInterface, options);
@@ -298,11 +316,9 @@
}
SkiaGLRenderEngine::~SkiaGLRenderEngine() {
- std::lock_guard<std::mutex> lock(mRenderingMutex);
- mRuntimeEffects.clear();
- mProtectedTextureCache.clear();
- mTextureCache.clear();
+ cleanFramebufferCache();
+ std::lock_guard<std::mutex> lock(mRenderingMutex);
if (mBlurFilter) {
delete mBlurFilter;
}
@@ -651,9 +667,8 @@
if (mBlurFilter) {
bool requiresCompositionLayer = false;
for (const auto& layer : layers) {
- if (layer->backgroundBlurRadius > 0) {
- // when skbug.com/11208 and b/176903027 are resolved we can add the additional
- // restriction for layer->backgroundBlurRadius < BlurFilter::kMaxCrossFadeRadius
+ if (layer->backgroundBlurRadius > 0 &&
+ layer->backgroundBlurRadius < BlurFilter::kMaxCrossFadeRadius) {
requiresCompositionLayer = true;
}
for (auto region : layer->blurRegions) {
@@ -798,6 +813,8 @@
const auto rect = layer->geometry.roundedCornersRadius > 0
? getSkRect(layer->geometry.roundedCornersCrop)
: bounds;
+ // This would require a new parameter/flag to SkShadowUtils::DrawShadow
+ LOG_ALWAYS_FATAL_IF(layer->disableBlending, "Cannot disableBlending with a shadow");
drawShadow(canvas, rect, layer->geometry.roundedCornersRadius, layer->shadow);
continue;
}
@@ -807,7 +824,7 @@
needsToneMapping(layer->sourceDataspace, display.outputDataspace));
// quick abort from drawing the remaining portion of the layer
- if (layer->alpha == 0 && !requiresLinearEffect &&
+ if (layer->alpha == 0 && !requiresLinearEffect && !layer->disableBlending &&
(!displayColorTransform || displayColorTransform->isAlphaUnchanged())) {
continue;
}
@@ -913,6 +930,10 @@
requiresLinearEffect));
}
+ if (layer->disableBlending) {
+ paint.setBlendMode(SkBlendMode::kSrc);
+ }
+
paint.setColorFilter(displayColorTransform);
if (layer->geometry.roundedCornersRadius > 0) {
@@ -1138,7 +1159,14 @@
return eglCreatePbufferSurface(display, placeholderConfig, attributes.data());
}
-void SkiaGLRenderEngine::cleanFramebufferCache() {}
+void SkiaGLRenderEngine::cleanFramebufferCache() {
+ // TODO(b/180767535) Remove this method and use b/180767535 instead, which would allow
+ // SF to control texture lifecycle more tightly rather than through custom hooks into RE.
+ std::lock_guard<std::mutex> lock(mRenderingMutex);
+ mRuntimeEffects.clear();
+ mProtectedTextureCache.clear();
+ mTextureCache.clear();
+}
int SkiaGLRenderEngine::getContextPriority() {
int value;
@@ -1158,6 +1186,8 @@
StringAppendF(&result, "RenderEngine supports protected context: %d\n",
supportsProtectedContent());
StringAppendF(&result, "RenderEngine is in protected context: %d\n", mInProtectedContext);
+ StringAppendF(&result, "RenderEngine shaders cached since last dump/primeCache: %d\n",
+ mSkSLCacheMonitor.shadersCachedSinceLastCall());
{
std::lock_guard<std::mutex> lock(mRenderingMutex);
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 15d834d..7605df9 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -31,6 +31,7 @@
#include "AutoBackendTexture.h"
#include "EGL/egl.h"
+#include "GrContextOptions.h"
#include "SkImageInfo.h"
#include "SkiaRenderEngine.h"
#include "android-base/macros.h"
@@ -63,6 +64,7 @@
bool supportsProtectedContent() const override;
bool useProtectedContext(bool useProtectedContext) override;
bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; }
+ void assertShadersCompiled(int numShaders) override;
protected:
void dump(std::string& result) override;
@@ -131,6 +133,29 @@
bool mInProtectedContext = false;
// Object to capture commands send to Skia.
std::unique_ptr<SkiaCapture> mCapture;
+
+ // Implements PersistentCache as a way to monitor what SkSL shaders Skia has
+ // cached.
+ class SkSLCacheMonitor : public GrContextOptions::PersistentCache {
+ public:
+ SkSLCacheMonitor() = default;
+ ~SkSLCacheMonitor() override = default;
+
+ sk_sp<SkData> load(const SkData& key) override;
+
+ void store(const SkData& key, const SkData& data, const SkString& description) override;
+
+ int shadersCachedSinceLastCall() {
+ const int shadersCachedSinceLastCall = mShadersCachedSinceLastCall;
+ mShadersCachedSinceLastCall = 0;
+ return shadersCachedSinceLastCall;
+ }
+
+ private:
+ int mShadersCachedSinceLastCall = 0;
+ };
+
+ SkSLCacheMonitor mSkSLCacheMonitor;
};
} // namespace skia
diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h
index f403725..59d7e2f 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -58,6 +58,7 @@
};
virtual bool cleanupPostRender(CleanupMode) override { return true; };
virtual int getContextPriority() override { return 0; }
+ virtual void assertShadersCompiled(int numShaders) {}
};
} // namespace skia
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 500a90b..7846156 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -1920,6 +1920,83 @@
0, 255, 0, 255);
}
+TEST_P(RenderEngineTest, testClear) {
+ initializeRenderEngine();
+
+ const auto rect = fullscreenRect();
+ const renderengine::DisplaySettings display{
+ .physicalDisplay = rect,
+ .clip = rect,
+ };
+
+ const renderengine::LayerSettings redLayer{
+ .geometry.boundaries = rect.toFloatRect(),
+ .source.solidColor = half3(1.0f, 0.0f, 0.0f),
+ .alpha = 1.0f,
+ };
+
+ // This mimics prepareClearClientComposition. This layer should overwrite
+ // the redLayer, so that the buffer is transparent, rather than red.
+ const renderengine::LayerSettings clearLayer{
+ .geometry.boundaries = rect.toFloatRect(),
+ .source.solidColor = half3(0.0f, 0.0f, 0.0f),
+ .alpha = 0.0f,
+ .disableBlending = true,
+ };
+
+ std::vector<const renderengine::LayerSettings*> layers{&redLayer, &clearLayer};
+ invokeDraw(display, layers);
+ expectBufferColor(rect, 0, 0, 0, 0);
+}
+
+TEST_P(RenderEngineTest, testDisableBlendingBuffer) {
+ initializeRenderEngine();
+
+ const auto rect = Rect(0, 0, 1, 1);
+ const renderengine::DisplaySettings display{
+ .physicalDisplay = rect,
+ .clip = rect,
+ };
+
+ const renderengine::LayerSettings redLayer{
+ .geometry.boundaries = rect.toFloatRect(),
+ .source.solidColor = half3(1.0f, 0.0f, 0.0f),
+ .alpha = 1.0f,
+ };
+
+ // The next layer will overwrite redLayer with a GraphicBuffer that is green
+ // applied with a translucent alpha.
+ auto buf = allocateSourceBuffer(1, 1);
+ {
+ uint8_t* pixels;
+ buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ reinterpret_cast<void**>(&pixels));
+ pixels[0] = 0;
+ pixels[1] = 255;
+ pixels[2] = 0;
+ pixels[3] = 255;
+ buf->unlock();
+ }
+
+ const renderengine::LayerSettings greenLayer{
+ .geometry.boundaries = rect.toFloatRect(),
+ .source =
+ renderengine::PixelSource{
+ .buffer =
+ renderengine::Buffer{
+ .buffer = buf,
+ .usePremultipliedAlpha = true,
+ },
+ },
+ .alpha = 0.5f,
+ .disableBlending = true,
+ };
+
+ std::vector<const renderengine::LayerSettings*> layers{&redLayer, &greenLayer};
+ invokeDraw(display, layers);
+ expectBufferColor(rect, 0, 128, 0, 128);
+}
+
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index df0551d..7694328 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -73,7 +73,7 @@
/* ------------------------------------------------------------------------
* Threading
*/
- const char* const mThreadName = "RenderEngineThread";
+ const char* const mThreadName = "RenderEngine";
// Protects the creation and destruction of mThread.
mutable std::mutex mThreadMutex;
std::thread mThread GUARDED_BY(mThreadMutex);
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index b2ddb42..7bd0c6b 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -113,6 +113,8 @@
void setPointerCapture(bool enabled) override {}
+ void notifyDropWindow(const sp<IBinder>&, float x, float y) override {}
+
InputDispatcherConfiguration mConfig;
};
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index e5fb26c..f3ef64b 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -287,6 +287,8 @@
int32_t pid;
nsecs_t consumeTime; // time when the event was consumed by InputConsumer
int32_t displayId;
+ float x;
+ float y;
};
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 3e80bd7..397a9d7 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -80,6 +80,7 @@
#define INDENT4 " "
using android::base::HwTimeoutMultiplier;
+using android::base::Result;
using android::base::StringPrintf;
using android::os::BlockUntrustedTouchesMode;
using android::os::IInputConstants;
@@ -2344,6 +2345,10 @@
}
} else if (maskedAction == AMOTION_EVENT_ACTION_UP ||
maskedAction == AMOTION_EVENT_ACTION_CANCEL) {
+ if (state.dragHoverWindowHandle && maskedAction == AMOTION_EVENT_ACTION_UP) {
+ vec2 local = state.dragHoverWindowHandle->getInfo()->transform.transform(x, y);
+ notifyDropWindowLocked(state.dragHoverWindowHandle->getToken(), local.x, local.y);
+ }
state.dragWindow = nullptr;
state.dragHoverWindowHandle = nullptr;
}
@@ -3283,17 +3288,17 @@
nsecs_t currentTime = now();
bool gotOne = false;
- status_t status;
+ status_t status = OK;
for (;;) {
- std::function<void(uint32_t seq, bool handled, nsecs_t consumeTime)> callback =
- std::bind(&InputDispatcher::finishDispatchCycleLocked, d, currentTime,
- connection, std::placeholders::_1, std::placeholders::_2,
- std::placeholders::_3);
-
- status = connection->inputPublisher.receiveFinishedSignal(callback);
- if (status) {
+ Result<InputPublisher::Finished> result =
+ connection->inputPublisher.receiveFinishedSignal();
+ if (!result.ok()) {
+ status = result.error().code();
break;
}
+ const InputPublisher::Finished& finished = *result;
+ d->finishDispatchCycleLocked(currentTime, connection, finished.seq,
+ finished.handled, finished.consumeTime);
gotOne = true;
}
if (gotOne) {
@@ -4998,8 +5003,7 @@
}
}
-base::Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(
- const std::string& name) {
+Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(const std::string& name) {
#if DEBUG_CHANNEL_CREATION
ALOGD("channel '%s' ~ createInputChannel", name.c_str());
#endif
@@ -5028,8 +5032,10 @@
return clientChannel;
}
-base::Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputMonitor(
- int32_t displayId, bool isGestureMonitor, const std::string& name, int32_t pid) {
+Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputMonitor(int32_t displayId,
+ bool isGestureMonitor,
+ const std::string& name,
+ int32_t pid) {
std::shared_ptr<InputChannel> serverChannel;
std::unique_ptr<InputChannel> clientChannel;
status_t result = openInputChannelPair(name, serverChannel, clientChannel);
@@ -5300,6 +5306,15 @@
postCommandLocked(std::move(commandEntry));
}
+void InputDispatcher::notifyDropWindowLocked(const sp<IBinder>& token, float x, float y) {
+ std::unique_ptr<CommandEntry> commandEntry =
+ std::make_unique<CommandEntry>(&InputDispatcher::doNotifyDropWindowLockedInterruptible);
+ commandEntry->newToken = token;
+ commandEntry->x = x;
+ commandEntry->y = y;
+ postCommandLocked(std::move(commandEntry));
+}
+
void InputDispatcher::onAnrLocked(const sp<Connection>& connection) {
if (connection == nullptr) {
LOG_ALWAYS_FATAL("Caller must check for nullness");
@@ -5409,6 +5424,13 @@
mLock.lock();
}
+void InputDispatcher::doNotifyDropWindowLockedInterruptible(CommandEntry* commandEntry) {
+ sp<IBinder> newToken = commandEntry->newToken;
+ mLock.unlock();
+ mPolicy->notifyDropWindow(newToken, commandEntry->x, commandEntry->y);
+ mLock.lock();
+}
+
void InputDispatcher::doNotifyNoFocusedWindowAnrLockedInterruptible(CommandEntry* commandEntry) {
mLock.unlock();
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index b2f3625..593ec23 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -592,6 +592,7 @@
void onFocusChangedLocked(const FocusResolver::FocusChanges& changes) REQUIRES(mLock);
void notifyFocusChangedLocked(const sp<IBinder>& oldFocus, const sp<IBinder>& newFocus)
REQUIRES(mLock);
+ void notifyDropWindowLocked(const sp<IBinder>& token, float x, float y) REQUIRES(mLock);
void onAnrLocked(const sp<Connection>& connection) REQUIRES(mLock);
void onAnrLocked(std::shared_ptr<InputApplicationHandle> application) REQUIRES(mLock);
void onUntrustedTouchLocked(const std::string& obscuringPackage) REQUIRES(mLock);
@@ -607,6 +608,8 @@
REQUIRES(mLock);
void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
void doNotifyFocusChangedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
+ void doNotifyDropWindowLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
+
// ANR-related callbacks - start
void doNotifyNoFocusedWindowAnrLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
void doNotifyWindowUnresponsiveLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index 439d85e..219f45a 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -157,6 +157,9 @@
* InputDispatcher is solely responsible for updating the Pointer Capture state.
*/
virtual void setPointerCapture(bool enabled) = 0;
+
+ /* Notifies the policy that the drag window has moved over to another window */
+ virtual void notifyDropWindow(const sp<IBinder>& token, float x, float y) = 0;
};
} // namespace android
diff --git a/services/inputflinger/host/Android.bp b/services/inputflinger/host/Android.bp
index 18d0226..743587c 100644
--- a/services/inputflinger/host/Android.bp
+++ b/services/inputflinger/host/Android.bp
@@ -67,6 +67,7 @@
cflags: ["-Wall", "-Werror"],
shared_libs: [
+ "libbase",
"libbinder",
"libinputflingerhost",
"libutils",
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index 8a2828c..1af70a4 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -68,6 +68,7 @@
"libcutils",
"libinput",
"liblog",
+ "libstatslog",
"libui",
"libutils",
],
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 1a7fcd5..07011f5 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -37,13 +37,14 @@
// #define LOG_NDEBUG 0
#include <android-base/file.h>
-#include <android-base/strings.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <cutils/properties.h>
#include <input/KeyCharacterMap.h>
#include <input/KeyLayoutMap.h>
#include <input/VirtualKeyMap.h>
#include <openssl/sha.h>
+#include <statslog.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/Timers.h>
@@ -1461,7 +1462,7 @@
for (auto it = mUnattachedVideoDevices.begin(); it != mUnattachedVideoDevices.end();
it++) {
std::unique_ptr<TouchVideoDevice>& videoDevice = *it;
- if (tryAddVideoDevice(*device, videoDevice)) {
+ if (tryAddVideoDeviceLocked(*device, videoDevice)) {
// videoDevice was transferred to 'device'
it = mUnattachedVideoDevices.erase(it);
break;
@@ -1771,6 +1772,13 @@
}
}
+void EventHub::reportDeviceAddedForStatisticsLocked(const InputDeviceIdentifier& identifier,
+ Flags<InputDeviceClass> classes) {
+ android::util::stats_write(android::util::INPUTDEVICE_REGISTERED, identifier.name.c_str(),
+ identifier.vendor, identifier.product, identifier.version,
+ identifier.bus, identifier.uniqueId.c_str(), classes.get());
+}
+
void EventHub::openDeviceLocked(const std::string& devicePath) {
// If an input device happens to register around the time when EventHub's constructor runs, it
// is possible that the same input event node (for example, /dev/input/event3) will be noticed
@@ -2076,7 +2084,7 @@
}
// Transfer ownership of this video device to a matching input device
for (const auto& [id, device] : mDevices) {
- if (tryAddVideoDevice(*device, videoDevice)) {
+ if (tryAddVideoDeviceLocked(*device, videoDevice)) {
return; // 'device' now owns 'videoDevice'
}
}
@@ -2088,8 +2096,8 @@
mUnattachedVideoDevices.push_back(std::move(videoDevice));
}
-bool EventHub::tryAddVideoDevice(EventHub::Device& device,
- std::unique_ptr<TouchVideoDevice>& videoDevice) {
+bool EventHub::tryAddVideoDeviceLocked(EventHub::Device& device,
+ std::unique_ptr<TouchVideoDevice>& videoDevice) {
if (videoDevice->getName() != device.identifier.name) {
return false;
}
@@ -2163,6 +2171,7 @@
}
void EventHub::addDeviceLocked(std::unique_ptr<Device> device) {
+ reportDeviceAddedForStatisticsLocked(device->identifier, device->classes);
mOpeningDevices.push_back(std::move(device));
}
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 5e5f85e..2afaa85 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -570,8 +570,8 @@
/**
* Create a new device for the provided path.
*/
- void openDeviceLocked(const std::string& devicePath);
- void openVideoDeviceLocked(const std::string& devicePath);
+ void openDeviceLocked(const std::string& devicePath) REQUIRES(mLock);
+ void openVideoDeviceLocked(const std::string& devicePath) REQUIRES(mLock);
/**
* Try to associate a video device with an input device. If the association succeeds,
* the videoDevice is moved into the input device. 'videoDevice' will become null if this
@@ -579,39 +579,42 @@
* Return true if the association succeeds.
* Return false otherwise.
*/
- bool tryAddVideoDevice(Device& device, std::unique_ptr<TouchVideoDevice>& videoDevice);
- void createVirtualKeyboardLocked();
- void addDeviceLocked(std::unique_ptr<Device> device);
- void assignDescriptorLocked(InputDeviceIdentifier& identifier);
+ bool tryAddVideoDeviceLocked(Device& device, std::unique_ptr<TouchVideoDevice>& videoDevice)
+ REQUIRES(mLock);
+ void createVirtualKeyboardLocked() REQUIRES(mLock);
+ void addDeviceLocked(std::unique_ptr<Device> device) REQUIRES(mLock);
+ void assignDescriptorLocked(InputDeviceIdentifier& identifier) REQUIRES(mLock);
- void closeDeviceByPathLocked(const std::string& devicePath);
- void closeVideoDeviceByPathLocked(const std::string& devicePath);
- void closeDeviceLocked(Device& device);
- void closeAllDevicesLocked();
+ void closeDeviceByPathLocked(const std::string& devicePath) REQUIRES(mLock);
+ void closeVideoDeviceByPathLocked(const std::string& devicePath) REQUIRES(mLock);
+ void closeDeviceLocked(Device& device) REQUIRES(mLock);
+ void closeAllDevicesLocked() REQUIRES(mLock);
status_t registerFdForEpoll(int fd);
status_t unregisterFdFromEpoll(int fd);
- status_t registerDeviceForEpollLocked(Device& device);
- void registerVideoDeviceForEpollLocked(const TouchVideoDevice& videoDevice);
- status_t unregisterDeviceFromEpollLocked(Device& device);
- void unregisterVideoDeviceFromEpollLocked(const TouchVideoDevice& videoDevice);
+ status_t registerDeviceForEpollLocked(Device& device) REQUIRES(mLock);
+ void registerVideoDeviceForEpollLocked(const TouchVideoDevice& videoDevice) REQUIRES(mLock);
+ status_t unregisterDeviceFromEpollLocked(Device& device) REQUIRES(mLock);
+ void unregisterVideoDeviceFromEpollLocked(const TouchVideoDevice& videoDevice) REQUIRES(mLock);
- status_t scanDirLocked(const std::string& dirname);
- status_t scanVideoDirLocked(const std::string& dirname);
- void scanDevicesLocked();
- status_t readNotifyLocked();
+ status_t scanDirLocked(const std::string& dirname) REQUIRES(mLock);
+ status_t scanVideoDirLocked(const std::string& dirname) REQUIRES(mLock);
+ void scanDevicesLocked() REQUIRES(mLock);
+ status_t readNotifyLocked() REQUIRES(mLock);
- Device* getDeviceByDescriptorLocked(const std::string& descriptor) const;
- Device* getDeviceLocked(int32_t deviceId) const;
- Device* getDeviceByPathLocked(const std::string& devicePath) const;
+ Device* getDeviceByDescriptorLocked(const std::string& descriptor) const REQUIRES(mLock);
+ Device* getDeviceLocked(int32_t deviceId) const REQUIRES(mLock);
+ Device* getDeviceByPathLocked(const std::string& devicePath) const REQUIRES(mLock);
/**
* Look through all available fd's (both for input devices and for video devices),
* and return the device pointer.
*/
- Device* getDeviceByFdLocked(int fd) const;
+ Device* getDeviceByFdLocked(int fd) const REQUIRES(mLock);
- int32_t getNextControllerNumberLocked(const std::string& name);
- void releaseControllerNumberLocked(int32_t num);
+ int32_t getNextControllerNumberLocked(const std::string& name) REQUIRES(mLock);
+ void releaseControllerNumberLocked(int32_t num) REQUIRES(mLock);
+ void reportDeviceAddedForStatisticsLocked(const InputDeviceIdentifier& identifier,
+ Flags<InputDeviceClass> classes) REQUIRES(mLock);
// Protect all internal state.
mutable std::mutex mLock;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 32f9b69..cedda6e 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -266,6 +266,11 @@
mPointerCaptureEnabled.reset();
}
+ void assertDropTargetEquals(const sp<IBinder>& targetToken) {
+ std::scoped_lock lock(mLock);
+ ASSERT_EQ(targetToken, mDropTargetWindowToken);
+ }
+
private:
std::mutex mLock;
std::unique_ptr<InputEvent> mFilteredEvent GUARDED_BY(mLock);
@@ -284,6 +289,8 @@
std::queue<int32_t> mResponsiveMonitorPids GUARDED_BY(mLock);
std::condition_variable mNotifyAnr;
+ sp<IBinder> mDropTargetWindowToken GUARDED_BY(mLock);
+
void notifyConfigurationChanged(nsecs_t when) override {
std::scoped_lock lock(mLock);
mConfigurationChangedTime = when;
@@ -392,6 +399,11 @@
mPointerCaptureChangedCondition.notify_all();
}
+ void notifyDropWindow(const sp<IBinder>& token, float x, float y) override {
+ std::scoped_lock lock(mLock);
+ mDropTargetWindowToken = token;
+ }
+
void assertFilterInputEventWasCalled(int type, nsecs_t eventTime, int32_t action,
int32_t displayId) {
std::scoped_lock lock(mLock);
@@ -4789,4 +4801,36 @@
mSecondWindow->assertNoEvents();
}
+TEST_F(InputDispatcherDragTests, DragAndDrop) {
+ performDrag();
+
+ // Move on window.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {50, 50}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
+ mWindow->consumeDragEvent(false, 50, 50);
+ mSecondWindow->assertNoEvents();
+
+ // Move to another window.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {150, 50}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
+ mWindow->consumeDragEvent(true, 150, 50);
+ mSecondWindow->consumeDragEvent(false, 50, 50);
+
+ // drop to another window.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {150, 50}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
+ mFakePolicy->assertDropTargetEquals(mSecondWindow->getToken());
+ mWindow->assertNoEvents();
+ mSecondWindow->assertNoEvents();
+}
+
} // namespace android::inputdispatcher
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 5225dd7..9ce8d9b 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -287,29 +287,6 @@
}
}
-// TODO(b/179649922): A better algorithm to guarantee that capped connections will get a sampling
-// rate close to 200 Hz. With the current algorithm, apps might be punished unfairly: E.g.,two apps
-// make requests to the sensor service at the same time, one is not capped and uses 250 Hz, and one
-//is capped, the capped connection will only get 125 Hz.
-void SensorService::SensorEventConnection::addSensorEventsToBuffer(bool shouldResample,
- const sensors_event_t& sensorEvent, sensors_event_t* buffer, int* index) {
- if (!shouldResample || !mService->isSensorInCappedSet(sensorEvent.type)) {
- buffer[(*index)++] = sensorEvent;
- } else {
- int64_t lastTimestamp = -1;
- auto entry = mSensorLastTimestamp.find(sensorEvent.sensor);
- if (entry != mSensorLastTimestamp.end()) {
- lastTimestamp = entry->second;
- }
- // Allow 10% headroom here because the clocks are not perfect.
- if (lastTimestamp == -1 || sensorEvent.timestamp - lastTimestamp
- >= 0.9 * SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) {
- mSensorLastTimestamp[sensorEvent.sensor] = sensorEvent.timestamp;
- buffer[(*index)++] = sensorEvent;
- }
- }
-}
-
status_t SensorService::SensorEventConnection::sendEvents(
sensors_event_t const* buffer, size_t numEvents,
sensors_event_t* scratch,
@@ -318,8 +295,6 @@
std::unique_ptr<sensors_event_t[]> sanitizedBuffer;
- bool shouldResample = mService->isMicSensorPrivacyEnabledForUid(mUid) ||
- mIsRateCappedBasedOnPermission;
int count = 0;
Mutex::Autolock _l(mConnectionLock);
if (scratch) {
@@ -373,7 +348,7 @@
// Regular sensor event, just copy it to the scratch buffer after checking
// the AppOp.
if (hasSensorAccess() && noteOpIfRequired(buffer[i])) {
- addSensorEventsToBuffer(shouldResample, buffer[i], scratch, &count);
+ scratch[count++] = buffer[i];
}
}
i++;
@@ -383,13 +358,12 @@
buffer[i].meta_data.sensor == sensor_handle)));
}
} else {
- sanitizedBuffer.reset(new sensors_event_t[numEvents]);
- scratch = sanitizedBuffer.get();
if (hasSensorAccess()) {
- for (size_t i = 0; i < numEvents; i++) {
- addSensorEventsToBuffer(shouldResample, buffer[i], scratch, &count);
- }
+ scratch = const_cast<sensors_event_t *>(buffer);
+ count = numEvents;
} else {
+ sanitizedBuffer.reset(new sensors_event_t[numEvents]);
+ scratch = sanitizedBuffer.get();
for (size_t i = 0; i < numEvents; i++) {
if (buffer[i].type == SENSOR_TYPE_META_DATA) {
scratch[count++] = buffer[i++];
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 4e3f120..909053b 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -145,16 +145,10 @@
void capRates();
// Recover sensor connection previously capped by capRates().
void uncapRates();
-
- // Add sensorEvent to buffer at position index if the sensorEvent satisfies throttling rules.
- void addSensorEventsToBuffer(bool shouldResample, const sensors_event_t& sensorEvent,
- sensors_event_t* buffer, int* index);
sp<SensorService> const mService;
sp<BitTube> mChannel;
uid_t mUid;
std::atomic_bool mIsRateCappedBasedOnPermission;
- // Store a mapping of sensor to the timestamp of their last sensor event.
- std::unordered_map<int, int64_t> mSensorLastTimestamp;
mutable Mutex mConnectionLock;
// Number of events from wake up sensors which are still pending and haven't been delivered to
// the corresponding application. It is incremented by one unit for each write to the socket.
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 942b7ae..9955cdb 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -2129,12 +2129,14 @@
}
void SensorService::SensorPrivacyPolicy::registerSelf() {
+ AutoCallerClear acc;
SensorPrivacyManager spm;
mSensorPrivacyEnabled = spm.isSensorPrivacyEnabled();
spm.addSensorPrivacyListener(this);
}
void SensorService::SensorPrivacyPolicy::unregisterSelf() {
+ AutoCallerClear acc;
SensorPrivacyManager spm;
spm.removeSensorPrivacyListener(this);
}
@@ -2167,7 +2169,7 @@
status_t SensorService::SensorPrivacyPolicy::registerSelfForIndividual(int userId) {
Mutex::Autolock _l(mSensorPrivacyLock);
-
+ AutoCallerClear acc;
SensorPrivacyManager spm;
status_t err = spm.addIndividualSensorPrivacyListener(userId,
SensorPrivacyManager::INDIVIDUAL_SENSOR_MICROPHONE, this);
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 9c5060a..a563a60 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -242,6 +242,22 @@
userid_t mUserId;
};
+ // A class automatically clearing and restoring binder caller identity inside
+ // a code block (scoped variable).
+ // Declare one systematically before calling SensorPrivacyManager methods so that they are
+ // executed with the same level of privilege as the SensorService process.
+ class AutoCallerClear {
+ public:
+ AutoCallerClear() :
+ mToken(IPCThreadState::self()->clearCallingIdentity()) {}
+ ~AutoCallerClear() {
+ IPCThreadState::self()->restoreCallingIdentity(mToken);
+ }
+
+ private:
+ const int64_t mToken;
+ };
+
enum Mode {
// The regular operating mode where any application can register/unregister/call flush on
// sensors.
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index eac3d95..b3f9792 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -424,24 +424,6 @@
return isBufferDue(expectedPresentTime);
}
-bool BufferLayer::frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) const {
- // TODO(b/169901895): kEarlyLatchVsyncThreshold should be based on the
- // vsync period. We can do this change as soon as ag/13100772 is merged.
- constexpr static std::chrono::nanoseconds kEarlyLatchVsyncThreshold = 5ms;
-
- const auto presentTime = nextPredictedPresentTime(vsyncId);
- if (!presentTime.has_value()) {
- return false;
- }
-
- if (std::abs(*presentTime - expectedPresentTime) >= kEarlyLatchMaxThreshold.count()) {
- return false;
- }
-
- return *presentTime >= expectedPresentTime &&
- *presentTime - expectedPresentTime >= kEarlyLatchVsyncThreshold.count();
-}
-
bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
nsecs_t expectedPresentTime) {
ATRACE_CALL();
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 5fed79f..b8d3f12 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -189,10 +189,6 @@
// specific logic
virtual bool isBufferDue(nsecs_t /*expectedPresentTime*/) const = 0;
- // Returns true if the next frame is considered too early to present
- // at the given expectedPresentTime
- bool frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) const;
-
std::atomic<bool> mAutoRefresh{false};
std::atomic<bool> mSidebandStreamChanged{false};
@@ -236,13 +232,6 @@
std::unique_ptr<compositionengine::LayerFECompositionState> mCompositionState;
FloatRect computeSourceBounds(const FloatRect& parentBounds) const override;
-
- // Returns the predicted present time of the next frame if available
- virtual std::optional<nsecs_t> nextPredictedPresentTime(int64_t vsyncId) const = 0;
-
- // The amount of time SF can delay a frame if it is considered early based
- // on the VsyncModulator::VsyncConfig::appWorkDuration
- static constexpr std::chrono::nanoseconds kEarlyLatchMaxThreshold = 100ms;
};
} // namespace android
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 63dd25f..e7f373f 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -215,21 +215,6 @@
return mQueuedFrames > 0;
}
-std::optional<nsecs_t> BufferQueueLayer::nextPredictedPresentTime(int64_t /*vsyncId*/) const {
- Mutex::Autolock lock(mQueueItemLock);
- if (mQueueItems.empty()) {
- return std::nullopt;
- }
-
- const auto& bufferData = mQueueItems[0];
-
- if (!bufferData.item.mIsAutoTimestamp || !bufferData.surfaceFrame) {
- return std::nullopt;
- }
-
- return bufferData.surfaceFrame->getPredictions().presentTime;
-}
-
status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
nsecs_t expectedPresentTime) {
// This boolean is used to make sure that SurfaceFlinger's shadow copy
@@ -521,10 +506,7 @@
mConsumer->setContentsChangedListener(mContentsChangedListener);
mConsumer->setName(String8(mName.data(), mName.size()));
- // BufferQueueCore::mMaxDequeuedBufferCount is default to 1
- if (!mFlinger->isLayerTripleBufferingDisabled()) {
- mProducer->setMaxDequeuedBufferCount(2);
- }
+ mProducer->setMaxDequeuedBufferCount(2);
}
status_t BufferQueueLayer::setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format) {
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 3a34b95..b3b7948 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -117,8 +117,6 @@
// Temporary - Used only for LEGACY camera mode.
uint32_t getProducerStickyTransform() const;
- std::optional<nsecs_t> nextPredictedPresentTime(int64_t vsyncId) const override;
-
sp<BufferLayerConsumer> mConsumer;
sp<IGraphicBufferProducer> mProducer;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 96a0c3c..4cd9400 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -41,6 +41,16 @@
namespace android {
using PresentState = frametimeline::SurfaceFrame::PresentState;
+namespace {
+void callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
+ const sp<GraphicBuffer>& buffer, const sp<Fence>& releaseFence) {
+ if (!listener) {
+ return;
+ }
+ listener->onReleaseBuffer(buffer->getId(), releaseFence ? releaseFence : Fence::NO_FENCE);
+}
+} // namespace
+
// clang-format off
const std::array<float, 16> BufferStateLayer::IDENTITY_MATRIX{
1, 0, 0, 0,
@@ -65,7 +75,10 @@
// RenderEngine may have been using the buffer as an external texture
// after the client uncached the buffer.
auto& engine(mFlinger->getRenderEngine());
- engine.unbindExternalTextureBuffer(mBufferInfo.mBuffer->getId());
+ const uint64_t bufferId = mBufferInfo.mBuffer->getId();
+ engine.unbindExternalTextureBuffer(bufferId);
+ callReleaseBufferCallback(mDrawingState.releaseBufferListener, mBufferInfo.mBuffer,
+ mBufferInfo.mFence);
}
}
@@ -74,6 +87,7 @@
if (ch == nullptr) {
return OK;
}
+ ch->previousBufferId = mPreviousBufferId;
if (!ch->previousReleaseFence.get()) {
ch->previousReleaseFence = fence;
return OK;
@@ -190,6 +204,19 @@
handle->dequeueReadyTime = dequeueReadyTime;
}
+ // If there are multiple transactions in this frame, set the previous id on the earliest
+ // transacton. We don't need to pass in the released buffer id to multiple transactions.
+ // The buffer id does not have to correspond to any particular transaction as long as the
+ // listening end point is the same but the client expects the first transaction callback that
+ // replaces the presented buffer to contain the release fence. This follows the same logic.
+ // see BufferStateLayer::onLayerDisplayed.
+ for (auto& handle : mDrawingState.callbackHandles) {
+ if (handle->releasePreviousBuffer) {
+ handle->previousBufferId = mPreviousBufferId;
+ break;
+ }
+ }
+
std::vector<JankData> jankData;
jankData.reserve(mPendingJankClassifications.size());
while (!mPendingJankClassifications.empty()
@@ -344,8 +371,8 @@
bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence,
nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp,
const client_cache_t& clientCacheId, uint64_t frameNumber,
- std::optional<nsecs_t> dequeueTime,
- const FrameTimelineInfo& info) {
+ std::optional<nsecs_t> dequeueTime, const FrameTimelineInfo& info,
+ const sp<ITransactionCompletedListener>& releaseBufferListener) {
ATRACE_CALL();
if (mCurrentState.buffer) {
@@ -353,7 +380,10 @@
if (mCurrentState.buffer != mDrawingState.buffer) {
// If mCurrentState has a buffer, and we are about to update again
// before swapping to drawing state, then the first buffer will be
- // dropped and we should decrement the pending buffer count.
+ // dropped and we should decrement the pending buffer count and
+ // call any release buffer callbacks if set.
+ callReleaseBufferCallback(mCurrentState.releaseBufferListener, mCurrentState.buffer,
+ mCurrentState.acquireFence);
decrementPendingBufferCount();
if (mCurrentState.bufferSurfaceFrameTX != nullptr) {
addSurfaceFrameDroppedForBuffer(mCurrentState.bufferSurfaceFrameTX);
@@ -361,9 +391,8 @@
}
}
}
-
mCurrentState.frameNumber = frameNumber;
-
+ mCurrentState.releaseBufferListener = releaseBufferListener;
mCurrentState.buffer = buffer;
mCurrentState.clientCacheId = clientCacheId;
mCurrentState.modified = true;
@@ -375,7 +404,16 @@
mCurrentState.desiredPresentTime = desiredPresentTime;
mCurrentState.isAutoTimestamp = isAutoTimestamp;
- mFlinger->mScheduler->recordLayerHistory(this, isAutoTimestamp ? 0 : desiredPresentTime,
+ const nsecs_t presentTime = [&] {
+ if (!isAutoTimestamp) return desiredPresentTime;
+
+ const auto prediction =
+ mFlinger->mFrameTimeline->getTokenManager()->getPredictionsForToken(info.vsyncId);
+ if (prediction.has_value()) return prediction->presentTime;
+
+ return static_cast<nsecs_t>(0);
+ }();
+ mFlinger->mScheduler->recordLayerHistory(this, presentTime,
LayerHistory::LayerUpdateType::Buffer);
addFrameEvent(acquireFence, postTime, isAutoTimestamp ? 0 : desiredPresentTime);
@@ -615,16 +653,6 @@
return mCurrentStateModified && (c.buffer != nullptr || c.bgColorLayer != nullptr);
}
-std::optional<nsecs_t> BufferStateLayer::nextPredictedPresentTime(int64_t vsyncId) const {
- const auto prediction =
- mFlinger->mFrameTimeline->getTokenManager()->getPredictionsForToken(vsyncId);
- if (!prediction.has_value()) {
- return std::nullopt;
- }
-
- return prediction->presentTime;
-}
-
status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime,
nsecs_t /*expectedPresentTime*/) {
const State& s(getDrawingState());
@@ -889,15 +917,16 @@
ATRACE_INT(mBlastTransactionName.c_str(), pendingBuffers);
}
-uint32_t BufferStateLayer::doTransaction(uint32_t flags) {
- if (mDrawingState.buffer != nullptr && mDrawingState.buffer != mBufferInfo.mBuffer) {
+void BufferStateLayer::bufferMayChange(sp<GraphicBuffer>& newBuffer) {
+ if (mDrawingState.buffer != nullptr && mDrawingState.buffer != mBufferInfo.mBuffer &&
+ newBuffer != mDrawingState.buffer) {
// If we are about to update mDrawingState.buffer but it has not yet latched
- // then we will drop a buffer and should decrement the pending buffer count.
- // This logic may not work perfectly in the face of a BufferStateLayer being the
- // deferred side of a deferred transaction, but we don't expect this use case.
+ // then we will drop a buffer and should decrement the pending buffer count and
+ // call any release buffer callbacks if set.
+ callReleaseBufferCallback(mDrawingState.releaseBufferListener, mDrawingState.buffer,
+ mDrawingState.acquireFence);
decrementPendingBufferCount();
}
- return Layer::doTransaction(flags);
}
} // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 93fb2cd..7a3da6f 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -70,7 +70,8 @@
bool setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence, nsecs_t postTime,
nsecs_t desiredPresentTime, bool isAutoTimestamp,
const client_cache_t& clientCacheId, uint64_t frameNumber,
- std::optional<nsecs_t> dequeueTime, const FrameTimelineInfo& info) override;
+ std::optional<nsecs_t> dequeueTime, const FrameTimelineInfo& info,
+ const sp<ITransactionCompletedListener>& transactionListener) override;
bool setAcquireFence(const sp<Fence>& fence) override;
bool setDataspace(ui::Dataspace dataspace) override;
bool setHdrMetadata(const HdrMetadata& hdrMetadata) override;
@@ -89,7 +90,6 @@
bool /*allowNonRectPreservingTransforms*/) override {
return false;
}
- bool setCrop_legacy(const Rect& /*crop*/) override { return false; }
void deferTransactionUntil_legacy(const sp<IBinder>& /*barrierHandle*/,
uint64_t /*frameNumber*/) override {}
void deferTransactionUntil_legacy(const sp<Layer>& /*barrierLayer*/,
@@ -112,7 +112,7 @@
// See mPendingBufferTransactions
void decrementPendingBufferCount();
- uint32_t doTransaction(uint32_t flags) override;
+ void bufferMayChange(sp<GraphicBuffer>& newBuffer) override;
std::atomic<int32_t>* getPendingBufferCounter() override { return &mPendingBufferTransactions; }
std::string getPendingBufferCounterName() override { return mBlastTransactionName; }
@@ -156,8 +156,6 @@
bool bufferNeedsFiltering() const override;
- std::optional<nsecs_t> nextPredictedPresentTime(int64_t vsyncId) const override;
-
static const std::array<float, 16> IDENTITY_MATRIX;
std::unique_ptr<renderengine::Image> mTextureImage;
@@ -171,6 +169,9 @@
mutable bool mCurrentStateModified = false;
bool mReleasePreviousBuffer = false;
+
+ // Stores the last set acquire fence signal time used to populate the callback handle's acquire
+ // time.
nsecs_t mCallbackHandleAcquireTime = -1;
std::deque<std::shared_ptr<android::frametimeline::SurfaceFrame>> mPendingJankClassifications;
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index d297d74..08147ed 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -106,6 +106,7 @@
"tests/planner/CachedSetTest.cpp",
"tests/planner/FlattenerTest.cpp",
"tests/planner/LayerStateTest.cpp",
+ "tests/planner/PredictorTest.cpp",
"tests/CompositionEngineTest.cpp",
"tests/DisplayColorProfileTest.cpp",
"tests/DisplayTest.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index 5f834be..a3e84e2 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -89,6 +89,7 @@
sp<GraphicBuffer> buffer = nullptr;
sp<Fence> acquireFence = nullptr;
Rect displayFrame = {};
+ ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
} overrideInfo;
/*
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
index 00424b2..b0e42b7 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
@@ -17,15 +17,12 @@
#pragma once
#include <compositionengine/impl/planner/LayerState.h>
+#include <renderengine/RenderEngine.h>
#include <chrono>
namespace android {
-namespace renderengine {
-class RenderEngine;
-} // namespace renderengine
-
namespace compositionengine::impl::planner {
std::string durationString(std::chrono::milliseconds duration);
@@ -63,8 +60,9 @@
const Layer& getFirstLayer() const { return mLayers[0]; }
const Rect& getBounds() const { return mBounds; }
size_t getAge() const { return mAge; }
- const sp<GraphicBuffer>& getBuffer() const { return mBuffer; }
+ const sp<GraphicBuffer>& getBuffer() const { return mTexture.getBuffer(); }
const sp<Fence>& getDrawFence() const { return mDrawFence; }
+ ui::Dataspace getOutputDataspace() const { return mOutputDataspace; }
NonBufferHash getNonBufferHash() const;
@@ -82,7 +80,8 @@
void setLastUpdate(std::chrono::steady_clock::time_point now) { mLastUpdate = now; }
void append(const CachedSet& other) {
- mBuffer = nullptr;
+ mTexture.setBuffer(nullptr, nullptr);
+ mOutputDataspace = ui::Dataspace::UNKNOWN;
mDrawFence = nullptr;
mLayers.insert(mLayers.end(), other.mLayers.cbegin(), other.mLayers.cend());
@@ -93,7 +92,8 @@
}
void incrementAge() { ++mAge; }
- void render(renderengine::RenderEngine&);
+ // Renders the cached set with the supplied output dataspace.
+ void render(renderengine::RenderEngine&, ui::Dataspace outputDataspace);
void dump(std::string& result) const;
@@ -105,8 +105,34 @@
std::vector<Layer> mLayers;
Rect mBounds = Rect::EMPTY_RECT;
size_t mAge = 0;
- sp<GraphicBuffer> mBuffer;
+
+ class Texture {
+ public:
+ ~Texture() { setBuffer(nullptr, nullptr); }
+
+ void setBuffer(const sp<GraphicBuffer>& buffer, renderengine::RenderEngine* re) {
+ if (mRE && mBuffer) {
+ mRE->unbindExternalTextureBuffer(mBuffer->getId());
+ }
+
+ mBuffer = buffer;
+ mRE = re;
+
+ if (mRE && mBuffer) {
+ mRE->cacheExternalTextureBuffer(mBuffer);
+ }
+ }
+
+ const sp<GraphicBuffer>& getBuffer() const { return mBuffer; }
+
+ private:
+ sp<GraphicBuffer> mBuffer = nullptr;
+ renderengine::RenderEngine* mRE = nullptr;
+ };
+
+ Texture mTexture;
sp<Fence> mDrawFence;
+ ui::Dataspace mOutputDataspace;
static const bool sDebugHighlighLayers;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
index 582723d..5b9a9f0 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
@@ -42,7 +42,8 @@
NonBufferHash flattenLayers(const std::vector<const LayerState*>& layers, NonBufferHash,
std::chrono::steady_clock::time_point now);
- void renderCachedSets(renderengine::RenderEngine&);
+ // Renders the newest cached sets with the supplied output dataspace
+ void renderCachedSets(renderengine::RenderEngine&, ui::Dataspace outputDataspace);
void reset();
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
index 7f8cb4e..a3beadc 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
@@ -278,8 +278,8 @@
}};
using DataspaceState = OutputLayerState<ui::Dataspace, LayerStateField::Dataspace>;
- DataspaceState mDataspace{[](auto layer) { return layer->getState().dataspace; },
- DataspaceState::getHalToStrings()};
+ DataspaceState mOutputDataspace{[](auto layer) { return layer->getState().dataspace; },
+ DataspaceState::getHalToStrings()};
// TODO(b/180638831): Buffer format
@@ -341,7 +341,7 @@
std::array<const StateInterface*, 13> getNonUniqueFields() const {
return {
&mDisplayFrame, &mSourceCrop, &mZOrder, &mBufferTransform,
- &mBlendMode, &mAlpha, &mVisibleRegion, &mDataspace,
+ &mBlendMode, &mAlpha, &mVisibleRegion, &mOutputDataspace,
&mColorTransform, &mCompositionType, &mSidebandStream, &mBuffer,
&mSolidColor,
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
index e96abb7..89de34d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
@@ -59,7 +59,7 @@
compositionengine::Output::OutputLayersEnumerator<compositionengine::Output>&& layers);
// The planner will call to the Flattener to render any pending cached set
- void renderCachedSets(renderengine::RenderEngine&);
+ void renderCachedSets(renderengine::RenderEngine&, ui::Dataspace outputDataspace);
void dump(const Vector<String16>& args, std::string&);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h
index 422af77..fe486d3 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Predictor.h
@@ -24,16 +24,28 @@
public:
LayerStack(const std::vector<const LayerState*>& layers) : mLayers(copyLayers(layers)) {}
+ // Describes an approximate match between two layer stacks
struct ApproximateMatch {
bool operator==(const ApproximateMatch& other) const {
return differingIndex == other.differingIndex &&
differingFields == other.differingFields;
}
+ // The index of the single differing layer between the two stacks.
+ // This implies that only one layer is allowed to differ in an approximate match.
size_t differingIndex;
+ // Set of fields that differ for the differing layer in the approximate match.
Flags<LayerStateField> differingFields;
};
+ // Returns an approximate match when comparing this layer stack with the provided list of
+ // layers, for the purposes of scoring how closely the two layer stacks will match composition
+ // strategies.
+ //
+ // If the two layer stacks are identical, then an approximate match is still returned, but the
+ // differing fields will be empty to represent an exact match.
+ //
+ // If the two layer stacks differ by too much, then an empty optional is returned.
std::optional<ApproximateMatch> getApproximateMatch(
const std::vector<const LayerState*>& other) const;
@@ -108,6 +120,10 @@
}
friend bool operator!=(const Plan& lhs, const Plan& rhs) { return !(lhs == rhs); }
+ friend std::ostream& operator<<(std::ostream& os, const Plan& plan) {
+ return os << to_string(plan);
+ }
+
private:
std::vector<hardware::graphics::composer::hal::Composition> mLayerTypes;
};
@@ -146,6 +162,10 @@
}
}
+ friend std::ostream& operator<<(std::ostream& os, const Type& type) {
+ return os << to_string(type);
+ }
+
Prediction(const std::vector<const LayerState*>& layers, Plan plan)
: mExampleLayerStack(layers), mPlan(std::move(plan)) {}
@@ -205,11 +225,25 @@
NonBufferHash hash;
Plan plan;
Prediction::Type type;
+
+ friend bool operator==(const PredictedPlan& lhs, const PredictedPlan& rhs) {
+ return lhs.hash == rhs.hash && lhs.plan == rhs.plan && lhs.type == rhs.type;
+ }
};
- std::optional<PredictedPlan> getPredictedPlan(const std::vector<const LayerState*>&,
- NonBufferHash) const;
+ // Retrieves the predicted plan based on a layer stack alongside its hash.
+ //
+ // If the exact layer stack has previously been seen by the predictor, then report the plan used
+ // for that layer stack.
+ //
+ // Otherwise, try to match to the best approximate stack to retireve the most likely plan.
+ std::optional<PredictedPlan> getPredictedPlan(const std::vector<const LayerState*>& layers,
+ NonBufferHash hash) const;
+ // Records a comparison between the predicted plan and the resulting plan, alongside the layer
+ // stack we used.
+ //
+ // This method is intended to help with scoring how effective the prediction engine is.
void recordResult(std::optional<PredictedPlan> predictedPlan, NonBufferHash flattenedHash,
const std::vector<const LayerState*>&, bool hasSkippedLayers, Plan result);
@@ -275,4 +309,13 @@
mutable size_t mMissCount = 0;
};
+// Defining PrintTo helps with Google Tests.
+inline void PrintTo(Predictor::PredictedPlan plan, ::std::ostream* os) {
+ *os << "PredictedPlan {";
+ *os << "\n .hash = " << plan.hash;
+ *os << "\n .plan = " << plan.plan;
+ *os << "\n .type = " << plan.type;
+ *os << "\n}";
+}
+
} // namespace android::compositionengine::impl::planner
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index dc1aacc..ded2dcc 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1252,7 +1252,7 @@
void Output::renderCachedSets() {
if (mPlanner) {
- mPlanner->renderCachedSets(getCompositionEngine().getRenderEngine());
+ mPlanner->renderCachedSets(getCompositionEngine().getRenderEngine(), getState().dataspace);
}
}
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 54784a2..b364649 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -681,6 +681,7 @@
.buffer = getState().overrideInfo.buffer,
.fence = getState().overrideInfo.acquireFence,
}};
+ settings.sourceDataspace = getState().overrideInfo.dataspace;
settings.alpha = 1.0f;
return {static_cast<LayerFE::LayerSettings>(settings)};
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
index 165e320..45dce98 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
@@ -68,6 +68,10 @@
dumpVal(out, "bufferTransform", toString(bufferTransform), bufferTransform);
dumpVal(out, "dataspace", toString(dataspace), dataspace);
dumpVal(out, "z-index", z);
+ dumpVal(out, "override buffer", overrideInfo.buffer.get());
+ dumpVal(out, "override acquire fence", overrideInfo.acquireFence.get());
+ dumpVal(out, "override display frame", overrideInfo.displayFrame);
+ dumpVal(out, "override dataspace", toString(overrideInfo.dataspace), overrideInfo.dataspace);
if (hwc) {
dumpHwc(*hwc, out);
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index ab3fe9e..137697b 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -79,10 +79,11 @@
return mFingerprint;
}
- // TODO(b/181192080): Add all fields which contribute to geometry of override layer (e.g.,
- // dataspace)
+ // TODO(b/182614524): We sometimes match this with LayerState hashes. Determine if that is
+ // necessary (and therefore we need to match implementations).
size_t hash = 0;
android::hashCombineSingle(hash, mBounds);
+ android::hashCombineSingle(hash, mOutputDataspace);
return hash;
}
@@ -126,7 +127,7 @@
}
bool CachedSet::hasReadyBuffer() const {
- return mBuffer != nullptr && mDrawFence->getStatus() == Fence::Status::Signaled;
+ return mTexture.getBuffer() != nullptr && mDrawFence->getStatus() == Fence::Status::Signaled;
}
std::vector<CachedSet> CachedSet::decompose() const {
@@ -148,10 +149,11 @@
}
}
-void CachedSet::render(renderengine::RenderEngine& renderEngine) {
+void CachedSet::render(renderengine::RenderEngine& renderEngine, ui::Dataspace outputDataspace) {
renderengine::DisplaySettings displaySettings{
.physicalDisplay = Rect(0, 0, mBounds.getWidth(), mBounds.getHeight()),
.clip = mBounds,
+ .outputDataspace = outputDataspace,
};
Region clearRegion = Region::INVALID_REGION;
@@ -163,8 +165,7 @@
.supportsProtectedContent = false,
.clearRegion = clearRegion,
.viewport = viewport,
- // TODO(181192086): Propagate the Output's dataspace instead of using UNKNOWN
- .dataspace = ui::Dataspace::UNKNOWN,
+ .dataspace = outputDataspace,
.realContentIsVisible = true,
.clearContent = false,
.disableBlurs = false,
@@ -209,12 +210,14 @@
HAL_PIXEL_FORMAT_RGBA_8888, 1, usageFlags);
LOG_ALWAYS_FATAL_IF(buffer->initCheck() != OK);
base::unique_fd drawFence;
+
status_t result = renderEngine.drawLayers(displaySettings, layerSettingsPointers, buffer, false,
base::unique_fd(), &drawFence);
if (result == NO_ERROR) {
- mBuffer = buffer;
+ mTexture.setBuffer(buffer, &renderEngine);
mDrawFence = new Fence(drawFence.release());
+ mOutputDataspace = outputDataspace;
}
}
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index d304c9f..30b5761 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -51,12 +51,13 @@
return hash;
}
-void Flattener::renderCachedSets(renderengine::RenderEngine& renderEngine) {
+void Flattener::renderCachedSets(renderengine::RenderEngine& renderEngine,
+ ui::Dataspace outputDataspace) {
if (!mNewCachedSet) {
return;
}
- mNewCachedSet->render(renderEngine);
+ mNewCachedSet->render(renderEngine, outputDataspace);
}
void Flattener::reset() {
@@ -223,6 +224,7 @@
.buffer = mNewCachedSet->getBuffer(),
.acquireFence = mNewCachedSet->getDrawFence(),
.displayFrame = mNewCachedSet->getBounds(),
+ .dataspace = mNewCachedSet->getOutputDataspace(),
};
++incomingLayerIter;
}
@@ -253,6 +255,7 @@
.buffer = currentLayerIter->getBuffer(),
.acquireFence = currentLayerIter->getDrawFence(),
.displayFrame = currentLayerIter->getBounds(),
+ .dataspace = currentLayerIter->getOutputDataspace(),
};
++incomingLayerIter;
}
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
index f3746de..222b2be 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
@@ -158,7 +158,8 @@
lhs.mSourceCrop == rhs.mSourceCrop && lhs.mZOrder == rhs.mZOrder &&
lhs.mBufferTransform == rhs.mBufferTransform && lhs.mBlendMode == rhs.mBlendMode &&
lhs.mAlpha == rhs.mAlpha && lhs.mVisibleRegion == rhs.mVisibleRegion &&
- lhs.mDataspace == rhs.mDataspace && lhs.mColorTransform == rhs.mColorTransform &&
+ lhs.mOutputDataspace == rhs.mOutputDataspace &&
+ lhs.mColorTransform == rhs.mColorTransform &&
lhs.mCompositionType == rhs.mCompositionType &&
lhs.mSidebandStream == rhs.mSidebandStream && lhs.mBuffer == rhs.mBuffer &&
(lhs.mCompositionType.get() != hal::Composition::SOLID_COLOR ||
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
index 4570253..87721c7 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
@@ -133,8 +133,9 @@
finalPlan);
}
-void Planner::renderCachedSets(renderengine::RenderEngine& renderEngine) {
- mFlattener.renderCachedSets(renderEngine);
+void Planner::renderCachedSets(renderengine::RenderEngine& renderEngine,
+ ui::Dataspace outputDataspace) {
+ mFlattener.renderCachedSets(renderEngine, outputDataspace);
}
void Planner::dump(const Vector<String16>& args, std::string& result) {
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp
index ba5e64d..07920b8 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp
@@ -50,8 +50,8 @@
return std::nullopt;
}
- // If layers are not identical, but we already have a prior approximate match,
- // the LayerStacks differ by too much, so return nothing
+ // If layers are not identical, but we already detected a prior approximate match for a
+ // previous layer, the LayerStacks differ by too much, so return nothing
if (approximateMatch) {
return std::nullopt;
}
@@ -72,6 +72,10 @@
}
}
+ if (approximateMatch) {
+ return approximateMatch;
+ }
+
// If we make it through the layer-by-layer comparison without an approximate match,
// it means that all layers were either identical or had client-composited layers in common,
// which don't affect the composition strategy, so return a successful result with
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index 6d1ce4c..377f817 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -303,6 +303,7 @@
EXPECT_EQ(Rect(0, 0, 2, 2), displaySettings.clip);
EXPECT_EQ(0.5f, layers[0]->alpha);
EXPECT_EQ(0.75f, layers[1]->alpha);
+ EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace);
return NO_ERROR;
};
@@ -310,8 +311,14 @@
EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1));
EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2));
EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
- cachedSet.render(mRenderEngine);
+ EXPECT_CALL(mRenderEngine, cacheExternalTextureBuffer(_));
+ cachedSet.render(mRenderEngine, ui::Dataspace::SRGB);
expectReadyBuffer(cachedSet);
+
+ // Now check that appending a new cached set properly cleans up RenderEngine resources.
+ EXPECT_CALL(mRenderEngine, unbindExternalTextureBuffer(_));
+ CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();
+ cachedSet.append(CachedSet(layer3));
}
} // namespace
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index 42bbfcc..bd77559 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -55,8 +55,10 @@
// TODO(b/181192467): Once Flattener starts to do something useful with Predictor,
// mPredictor should be mocked and checked for expectations.
Predictor mPredictor;
- std::unique_ptr<Flattener> mFlattener;
+
+ // mRenderEngine may be held as a pointer to mFlattener, so mFlattener must be destroyed first.
renderengine::mock::RenderEngine mRenderEngine;
+ std::unique_ptr<Flattener> mFlattener;
const std::chrono::steady_clock::time_point kStartTime = std::chrono::steady_clock::now();
std::chrono::steady_clock::time_point mTime = kStartTime;
@@ -132,13 +134,13 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine);
+ mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
// same geometry, update the internal layer stack
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine);
+ mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
}
void FlattenerTest::expectAllLayersFlattened(const std::vector<const LayerState*>& layers) {
@@ -148,7 +150,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine);
+ mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
for (const auto layer : layers) {
EXPECT_EQ(nullptr, layer->getOutputLayer()->getState().overrideInfo.buffer);
@@ -158,7 +160,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine);
+ mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
const auto buffer = layers[0]->getOutputLayer()->getState().overrideInfo.buffer;
EXPECT_NE(nullptr, buffer);
@@ -193,7 +195,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine);
+ mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
}
TEST_F(FlattenerTest, flattenLayers_basicFlatten) {
@@ -239,7 +241,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine);
+ mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -274,7 +276,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine);
+ mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_EQ(nullptr, overrideBuffer2);
@@ -311,7 +313,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine);
+ mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_EQ(nullptr, overrideBuffer2);
@@ -320,7 +322,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine);
+ mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_NE(nullptr, overrideBuffer2);
@@ -333,7 +335,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine);
+ mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_NE(nullptr, overrideBuffer2);
@@ -342,7 +344,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine);
+ mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -384,7 +386,7 @@
initializeOverrideBuffer(layers);
EXPECT_EQ(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine);
+ mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
EXPECT_EQ(nullptr, overrideBuffer1);
EXPECT_EQ(nullptr, overrideBuffer2);
@@ -397,7 +399,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine);
+ mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -409,7 +411,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine);
+ mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -424,7 +426,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine);
+ mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
@@ -435,7 +437,7 @@
initializeOverrideBuffer(layers);
EXPECT_NE(getNonBufferHash(layers),
mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
- mFlattener->renderCachedSets(mRenderEngine);
+ mFlattener->renderCachedSets(mRenderEngine, ui::Dataspace::SRGB);
EXPECT_NE(nullptr, overrideBuffer1);
EXPECT_EQ(overrideBuffer1, overrideBuffer2);
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp
new file mode 100644
index 0000000..43e119f
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp
@@ -0,0 +1,528 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DisplayHardware/Hal.h"
+#undef LOG_TAG
+#define LOG_TAG "PredictorTest"
+
+#include <compositionengine/impl/planner/Predictor.h>
+#include <compositionengine/mock/LayerFE.h>
+#include <compositionengine/mock/OutputLayer.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+
+namespace android::compositionengine::impl::planner {
+namespace {
+
+const FloatRect sFloatRectOne = FloatRect(100.f, 200.f, 300.f, 400.f);
+const FloatRect sFloatRectTwo = FloatRect(400.f, 300.f, 200.f, 100.f);
+const Rect sRectOne = Rect(1, 2, 3, 4);
+const Rect sRectTwo = Rect(4, 3, 2, 1);
+const constexpr int32_t sZOne = 100;
+const constexpr int32_t sZTwo = 101;
+const constexpr float sAlphaOne = 0.25f;
+const constexpr float sAlphaTwo = 0.5f;
+const Region sRegionOne = Region(sRectOne);
+const Region sRegionTwo = Region(sRectTwo);
+const mat4 sMat4One = mat4::scale(vec4(2.f, 3.f, 1.f, 1.f));
+
+using testing::Return;
+using testing::ReturnRef;
+
+const std::string sDebugName = std::string("Test LayerFE");
+const constexpr int32_t sSequenceId = 12345;
+
+void setupMocksForLayer(mock::OutputLayer& layer, mock::LayerFE& layerFE,
+ const OutputLayerCompositionState& outputLayerState,
+ const LayerFECompositionState& layerFEState) {
+ EXPECT_CALL(layer, getLayerFE()).WillRepeatedly(ReturnRef(layerFE));
+ EXPECT_CALL(layer, getState()).WillRepeatedly(ReturnRef(outputLayerState));
+ EXPECT_CALL(layerFE, getSequence()).WillRepeatedly(Return(sSequenceId));
+ EXPECT_CALL(layerFE, getDebugName()).WillRepeatedly(Return(sDebugName.c_str()));
+ EXPECT_CALL(layerFE, getCompositionState()).WillRepeatedly(Return(&layerFEState));
+}
+
+struct LayerStackTest : public testing::Test {
+ LayerStackTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+
+ ~LayerStackTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+};
+
+TEST_F(LayerStackTest, getApproximateMatch_doesNotMatchSizeDifferences) {
+ mock::OutputLayer outputLayerOne;
+ mock::LayerFE layerFEOne;
+ OutputLayerCompositionState outputLayerCompositionStateOne;
+ LayerFECompositionState layerFECompositionStateOne;
+ setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
+ layerFECompositionStateOne);
+ LayerState layerStateOne(&outputLayerOne);
+
+ mock::OutputLayer outputLayerTwo;
+ mock::LayerFE layerFETwo;
+ OutputLayerCompositionState outputLayerCompositionStateTwo;
+ LayerFECompositionState layerFECompositionStateTwo;
+ setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo,
+ layerFECompositionStateTwo);
+ LayerState layerStateTwo(&outputLayerTwo);
+
+ mock::OutputLayer outputLayerThree;
+ mock::LayerFE layerFEThree;
+ OutputLayerCompositionState outputLayerCompositionStateThree;
+ LayerFECompositionState layerFECompositionStateThree;
+ setupMocksForLayer(outputLayerThree, layerFEThree, outputLayerCompositionStateThree,
+ layerFECompositionStateThree);
+ LayerState layerStateThree(&outputLayerThree);
+
+ LayerStack stack({&layerStateOne});
+
+ EXPECT_FALSE(stack.getApproximateMatch({}));
+ EXPECT_FALSE(stack.getApproximateMatch({&layerStateOne, &layerStateThree}));
+}
+
+TEST_F(LayerStackTest, getApproximateMatch_doesNotMatchDifferentCompositionTypes) {
+ mock::OutputLayer outputLayerOne;
+ mock::LayerFE layerFEOne;
+ OutputLayerCompositionState outputLayerCompositionStateOne;
+ LayerFECompositionState layerFECompositionStateOne;
+ layerFECompositionStateOne.compositionType = hal::Composition::DEVICE;
+ setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
+ layerFECompositionStateOne);
+ LayerState layerStateOne(&outputLayerOne);
+
+ mock::OutputLayer outputLayerTwo;
+ mock::LayerFE layerFETwo;
+ OutputLayerCompositionState outputLayerCompositionStateTwo;
+ LayerFECompositionState layerFECompositionStateTwo;
+ layerFECompositionStateTwo.compositionType = hal::Composition::SOLID_COLOR;
+ setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo,
+ layerFECompositionStateTwo);
+ LayerState layerStateTwo(&outputLayerTwo);
+
+ LayerStack stack({&layerStateOne});
+
+ EXPECT_FALSE(stack.getApproximateMatch({&layerStateTwo}));
+}
+
+TEST_F(LayerStackTest, getApproximateMatch_matchesSingleDifferenceInSingleLayer) {
+ mock::OutputLayer outputLayerOne;
+ mock::LayerFE layerFEOne;
+ OutputLayerCompositionState outputLayerCompositionStateOne{
+ .sourceCrop = sFloatRectOne,
+ };
+ LayerFECompositionState layerFECompositionStateOne;
+ setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
+ layerFECompositionStateOne);
+ LayerState layerStateOne(&outputLayerOne);
+
+ mock::OutputLayer outputLayerTwo;
+ mock::LayerFE layerFETwo;
+ OutputLayerCompositionState outputLayerCompositionStateTwo{
+ .sourceCrop = sFloatRectTwo,
+ };
+ LayerFECompositionState layerFECompositionStateTwo;
+ setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo,
+ layerFECompositionStateTwo);
+ LayerState layerStateTwo(&outputLayerTwo);
+
+ LayerStack stack({&layerStateOne});
+
+ const auto match = stack.getApproximateMatch({&layerStateTwo});
+ EXPECT_TRUE(match);
+ LayerStack::ApproximateMatch expectedMatch;
+ expectedMatch.differingIndex = 0;
+ expectedMatch.differingFields = LayerStateField::SourceCrop;
+ EXPECT_EQ(expectedMatch, *match);
+}
+
+TEST_F(LayerStackTest, getApproximateMatch_matchesSingleDifferenceInMultiLayerStack) {
+ mock::OutputLayer outputLayerOne;
+ mock::LayerFE layerFEOne;
+ OutputLayerCompositionState outputLayerCompositionStateOne{
+ .sourceCrop = sFloatRectOne,
+ };
+ LayerFECompositionState layerFECompositionStateOne;
+ setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
+ layerFECompositionStateOne);
+ LayerState layerStateOne(&outputLayerOne);
+
+ mock::OutputLayer outputLayerTwo;
+ mock::LayerFE layerFETwo;
+ OutputLayerCompositionState outputLayerCompositionStateTwo{
+ .sourceCrop = sFloatRectTwo,
+ };
+ LayerFECompositionState layerFECompositionStateTwo;
+ setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo,
+ layerFECompositionStateTwo);
+ LayerState layerStateTwo(&outputLayerTwo);
+
+ LayerStack stack({&layerStateOne, &layerStateOne});
+
+ const auto match = stack.getApproximateMatch({&layerStateOne, &layerStateTwo});
+ EXPECT_TRUE(match);
+ LayerStack::ApproximateMatch expectedMatch;
+ expectedMatch.differingIndex = 1;
+ expectedMatch.differingFields = LayerStateField::SourceCrop;
+ EXPECT_EQ(expectedMatch, *match);
+}
+
+TEST_F(LayerStackTest, getApproximateMatch_doesNotMatchManyDifferences) {
+ mock::OutputLayer outputLayerOne;
+ mock::LayerFE layerFEOne;
+ OutputLayerCompositionState outputLayerCompositionStateOne{
+ .visibleRegion = sRegionOne,
+ .displayFrame = sRectOne,
+ .sourceCrop = sFloatRectOne,
+ .dataspace = ui::Dataspace::SRGB,
+ .z = sZOne,
+ };
+ LayerFECompositionState layerFECompositionStateOne;
+ layerFECompositionStateOne.alpha = sAlphaOne;
+ layerFECompositionStateOne.colorTransformIsIdentity = true;
+ setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
+ layerFECompositionStateOne);
+ LayerState layerStateOne(&outputLayerOne);
+
+ mock::OutputLayer outputLayerTwo;
+ mock::LayerFE layerFETwo;
+ OutputLayerCompositionState outputLayerCompositionStateTwo{
+ .visibleRegion = sRegionTwo,
+ .displayFrame = sRectTwo,
+ .sourceCrop = sFloatRectTwo,
+ .dataspace = ui::Dataspace::DISPLAY_P3,
+ .z = sZTwo,
+ };
+ LayerFECompositionState layerFECompositionStateTwo;
+ layerFECompositionStateTwo.alpha = sAlphaTwo;
+ layerFECompositionStateTwo.colorTransformIsIdentity = false;
+ layerFECompositionStateTwo.colorTransform = sMat4One;
+ setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo,
+ layerFECompositionStateTwo);
+ LayerState layerStateTwo(&outputLayerTwo);
+
+ LayerStack stack({&layerStateOne});
+
+ EXPECT_FALSE(stack.getApproximateMatch({&layerStateTwo}));
+}
+
+TEST_F(LayerStackTest, getApproximateMatch_exactMatchesSameBuffer) {
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+ mock::OutputLayer outputLayerOne;
+ mock::LayerFE layerFEOne;
+ OutputLayerCompositionState outputLayerCompositionStateOne;
+ LayerFECompositionState layerFECompositionStateOne;
+ layerFECompositionStateOne.buffer = buffer;
+ setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
+ layerFECompositionStateOne);
+ LayerState layerStateOne(&outputLayerOne);
+
+ mock::OutputLayer outputLayerTwo;
+ mock::LayerFE layerFETwo;
+ OutputLayerCompositionState outputLayerCompositionStateTwo;
+ LayerFECompositionState layerFECompositionStateTwo;
+ layerFECompositionStateTwo.buffer = buffer;
+ setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo,
+ layerFECompositionStateTwo);
+ LayerState layerStateTwo(&outputLayerTwo);
+
+ LayerStack stack({&layerStateOne});
+
+ const auto match = stack.getApproximateMatch({&layerStateTwo});
+ EXPECT_TRUE(match);
+ LayerStack::ApproximateMatch expectedMatch;
+ expectedMatch.differingIndex = 0;
+ expectedMatch.differingFields = LayerStateField::None;
+ EXPECT_EQ(expectedMatch, *match);
+}
+
+TEST_F(LayerStackTest, getApproximateMatch_alwaysMatchesClientComposition) {
+ mock::OutputLayer outputLayerOne;
+ mock::LayerFE layerFEOne;
+ OutputLayerCompositionState outputLayerCompositionStateOne{
+ .visibleRegion = sRegionOne,
+ .forceClientComposition = true,
+ .displayFrame = sRectOne,
+ .sourceCrop = sFloatRectOne,
+ .dataspace = ui::Dataspace::SRGB,
+ .z = sZOne,
+ };
+ LayerFECompositionState layerFECompositionStateOne;
+ layerFECompositionStateOne.buffer = new GraphicBuffer();
+ layerFECompositionStateOne.alpha = sAlphaOne;
+ layerFECompositionStateOne.colorTransformIsIdentity = true;
+ setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
+ layerFECompositionStateOne);
+ LayerState layerStateOne(&outputLayerOne);
+
+ mock::OutputLayer outputLayerTwo;
+ mock::LayerFE layerFETwo;
+ OutputLayerCompositionState outputLayerCompositionStateTwo{
+ .visibleRegion = sRegionTwo,
+ .forceClientComposition = true,
+ .displayFrame = sRectTwo,
+ .sourceCrop = sFloatRectTwo,
+ .dataspace = ui::Dataspace::DISPLAY_P3,
+ .z = sZTwo,
+ };
+ LayerFECompositionState layerFECompositionStateTwo;
+ layerFECompositionStateTwo.buffer = new GraphicBuffer();
+ layerFECompositionStateTwo.alpha = sAlphaTwo;
+ layerFECompositionStateTwo.colorTransformIsIdentity = false;
+ layerFECompositionStateTwo.colorTransform = sMat4One;
+ setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo,
+ layerFECompositionStateTwo);
+ LayerState layerStateTwo(&outputLayerTwo);
+
+ LayerStack stack({&layerStateOne});
+
+ const auto match = stack.getApproximateMatch({&layerStateTwo});
+ EXPECT_TRUE(match);
+ LayerStack::ApproximateMatch expectedMatch;
+ expectedMatch.differingIndex = 0;
+ expectedMatch.differingFields = LayerStateField::None;
+ EXPECT_EQ(expectedMatch, *match);
+}
+
+TEST_F(LayerStackTest, getApproximateMatch_doesNotMatchMultipleApproximations) {
+ mock::OutputLayer outputLayerOne;
+ mock::LayerFE layerFEOne;
+ OutputLayerCompositionState outputLayerCompositionStateOne{
+ .sourceCrop = sFloatRectOne,
+ };
+ LayerFECompositionState layerFECompositionStateOne;
+ layerFECompositionStateOne.buffer = new GraphicBuffer();
+ setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
+ layerFECompositionStateOne);
+ LayerState layerStateOne(&outputLayerOne);
+
+ mock::OutputLayer outputLayerTwo;
+ mock::LayerFE layerFETwo;
+ OutputLayerCompositionState outputLayerCompositionStateTwo{
+ .sourceCrop = sFloatRectTwo,
+ };
+ LayerFECompositionState layerFECompositionStateTwo;
+ layerFECompositionStateTwo.buffer = new GraphicBuffer();
+ setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo,
+ layerFECompositionStateTwo);
+ LayerState layerStateTwo(&outputLayerTwo);
+
+ EXPECT_TRUE(LayerStack({&layerStateOne}).getApproximateMatch({&layerStateTwo}));
+
+ LayerStack stack({&layerStateOne, &layerStateOne});
+ EXPECT_FALSE(stack.getApproximateMatch({&layerStateTwo, &layerStateTwo}));
+}
+
+struct PredictionTest : public testing::Test {
+ PredictionTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+
+ ~PredictionTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+};
+
+TEST_F(PredictionTest, constructPrediction) {
+ Plan plan;
+ plan.addLayerType(hal::Composition::DEVICE);
+
+ Prediction prediction({}, plan);
+
+ EXPECT_EQ(plan, prediction.getPlan());
+
+ // check that dump doesn't crash
+ std::string result;
+ prediction.dump(result);
+}
+
+TEST_F(PredictionTest, recordHits) {
+ Prediction prediction({}, {});
+
+ const constexpr uint32_t kExactMatches = 2;
+ for (uint32_t i = 0; i < kExactMatches; i++) {
+ prediction.recordHit(Prediction::Type::Exact);
+ }
+
+ const constexpr uint32_t kApproximateMatches = 3;
+ for (uint32_t i = 0; i < kApproximateMatches; i++) {
+ prediction.recordHit(Prediction::Type::Approximate);
+ }
+
+ EXPECT_EQ(kExactMatches, prediction.getHitCount(Prediction::Type::Exact));
+ EXPECT_EQ(kApproximateMatches, prediction.getHitCount(Prediction::Type::Approximate));
+ EXPECT_EQ(kExactMatches + kApproximateMatches, prediction.getHitCount(Prediction::Type::Total));
+}
+
+TEST_F(PredictionTest, recordMisses) {
+ Prediction prediction({}, {});
+
+ const constexpr uint32_t kExactMatches = 2;
+ for (uint32_t i = 0; i < kExactMatches; i++) {
+ prediction.recordMiss(Prediction::Type::Exact);
+ }
+
+ const constexpr uint32_t kApproximateMatches = 3;
+ for (uint32_t i = 0; i < kApproximateMatches; i++) {
+ prediction.recordMiss(Prediction::Type::Approximate);
+ }
+
+ EXPECT_EQ(kExactMatches, prediction.getMissCount(Prediction::Type::Exact));
+ EXPECT_EQ(kApproximateMatches, prediction.getMissCount(Prediction::Type::Approximate));
+ EXPECT_EQ(kExactMatches + kApproximateMatches,
+ prediction.getMissCount(Prediction::Type::Total));
+}
+
+struct PredictorTest : public testing::Test {
+ PredictorTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+
+ ~PredictorTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+};
+
+TEST_F(PredictorTest, getPredictedPlan_emptyLayersWithoutExactMatch_returnsNullopt) {
+ Predictor predictor;
+ EXPECT_FALSE(predictor.getPredictedPlan({}, 0));
+}
+
+TEST_F(PredictorTest, getPredictedPlan_recordCandidateAndRetrieveExactMatch) {
+ mock::OutputLayer outputLayerOne;
+ mock::LayerFE layerFEOne;
+ OutputLayerCompositionState outputLayerCompositionStateOne;
+ LayerFECompositionState layerFECompositionStateOne;
+ layerFECompositionStateOne.compositionType = hal::Composition::DEVICE;
+ setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
+ layerFECompositionStateOne);
+ LayerState layerStateOne(&outputLayerOne);
+
+ Plan plan;
+ plan.addLayerType(hal::Composition::DEVICE);
+
+ Predictor predictor;
+
+ NonBufferHash hash = getNonBufferHash({&layerStateOne});
+
+ predictor.recordResult(std::nullopt, hash, {&layerStateOne}, false, plan);
+
+ auto predictedPlan = predictor.getPredictedPlan({}, hash);
+ EXPECT_TRUE(predictedPlan);
+ Predictor::PredictedPlan expectedPlan{hash, plan, Prediction::Type::Exact};
+ EXPECT_EQ(expectedPlan, predictedPlan);
+}
+
+TEST_F(PredictorTest, getPredictedPlan_recordCandidateAndRetrieveApproximateMatch) {
+ mock::OutputLayer outputLayerOne;
+ mock::LayerFE layerFEOne;
+ OutputLayerCompositionState outputLayerCompositionStateOne{
+ .sourceCrop = sFloatRectOne,
+ };
+ LayerFECompositionState layerFECompositionStateOne;
+ setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
+ layerFECompositionStateOne);
+ LayerState layerStateOne(&outputLayerOne);
+
+ mock::OutputLayer outputLayerTwo;
+ mock::LayerFE layerFETwo;
+ OutputLayerCompositionState outputLayerCompositionStateTwo{
+ .sourceCrop = sFloatRectTwo,
+ };
+ LayerFECompositionState layerFECompositionStateTwo;
+ setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo,
+ layerFECompositionStateTwo);
+ LayerState layerStateTwo(&outputLayerTwo);
+
+ Plan plan;
+ plan.addLayerType(hal::Composition::DEVICE);
+
+ Predictor predictor;
+
+ NonBufferHash hashOne = getNonBufferHash({&layerStateOne});
+ NonBufferHash hashTwo = getNonBufferHash({&layerStateTwo});
+
+ predictor.recordResult(std::nullopt, hashOne, {&layerStateOne}, false, plan);
+
+ auto predictedPlan = predictor.getPredictedPlan({&layerStateTwo}, hashTwo);
+ EXPECT_TRUE(predictedPlan);
+ Predictor::PredictedPlan expectedPlan{hashOne, plan, Prediction::Type::Approximate};
+ EXPECT_EQ(expectedPlan, predictedPlan);
+}
+
+TEST_F(PredictorTest, recordMissedPlan_skipsApproximateMatch) {
+ mock::OutputLayer outputLayerOne;
+ mock::LayerFE layerFEOne;
+ OutputLayerCompositionState outputLayerCompositionStateOne{
+ .sourceCrop = sFloatRectOne,
+ };
+ LayerFECompositionState layerFECompositionStateOne;
+ setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
+ layerFECompositionStateOne);
+ LayerState layerStateOne(&outputLayerOne);
+
+ mock::OutputLayer outputLayerTwo;
+ mock::LayerFE layerFETwo;
+ OutputLayerCompositionState outputLayerCompositionStateTwo{
+ .sourceCrop = sFloatRectTwo,
+ };
+ LayerFECompositionState layerFECompositionStateTwo;
+ setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo,
+ layerFECompositionStateTwo);
+ LayerState layerStateTwo(&outputLayerTwo);
+
+ Plan plan;
+ plan.addLayerType(hal::Composition::DEVICE);
+
+ Predictor predictor;
+
+ NonBufferHash hashOne = getNonBufferHash({&layerStateOne});
+ NonBufferHash hashTwo = getNonBufferHash({&layerStateTwo});
+
+ predictor.recordResult(std::nullopt, hashOne, {&layerStateOne}, false, plan);
+
+ auto predictedPlan = predictor.getPredictedPlan({&layerStateTwo}, hashTwo);
+ ASSERT_TRUE(predictedPlan);
+ EXPECT_EQ(Prediction::Type::Approximate, predictedPlan->type);
+
+ Plan planTwo;
+ planTwo.addLayerType(hal::Composition::CLIENT);
+ predictor.recordResult(predictedPlan, hashTwo, {&layerStateTwo}, false, planTwo);
+ // Now trying to retrieve the predicted plan again returns a nullopt instead.
+ // TODO(b/158790260): Even though this is enforced in this test, we might want to reassess this.
+ // One of the implications around this implementation is that if we miss a prediction then we
+ // can never actually correct our mistake if we see the same layer stack again, which doesn't
+ // seem robust.
+ auto predictedPlanTwo = predictor.getPredictedPlan({&layerStateTwo}, hashTwo);
+ EXPECT_FALSE(predictedPlanTwo);
+}
+
+} // namespace
+} // namespace android::compositionengine::impl::planner
\ No newline at end of file
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 44f1a70..cd3e8ad 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -102,8 +102,8 @@
mCurrentState.active_legacy.h = args.h;
mCurrentState.flags = layerFlags;
mCurrentState.active_legacy.transform.set(0, 0);
- mCurrentState.crop_legacy.makeInvalid();
- mCurrentState.requestedCrop_legacy = mCurrentState.crop_legacy;
+ mCurrentState.crop.makeInvalid();
+ mCurrentState.requestedCrop = mCurrentState.crop;
mCurrentState.z = 0;
mCurrentState.color.a = 1.0f;
mCurrentState.layerStack = 0;
@@ -949,13 +949,12 @@
" requested={ wh={%4u,%4u} }}\n",
this, getName().c_str(), getBufferTransform(), getEffectiveScalingMode(),
stateToCommit->active_legacy.w, stateToCommit->active_legacy.h,
- stateToCommit->crop_legacy.left, stateToCommit->crop_legacy.top,
- stateToCommit->crop_legacy.right, stateToCommit->crop_legacy.bottom,
- stateToCommit->crop_legacy.getWidth(), stateToCommit->crop_legacy.getHeight(),
- stateToCommit->requested_legacy.w, stateToCommit->requested_legacy.h,
- s.active_legacy.w, s.active_legacy.h, s.crop_legacy.left, s.crop_legacy.top,
- s.crop_legacy.right, s.crop_legacy.bottom, s.crop_legacy.getWidth(),
- s.crop_legacy.getHeight(), s.requested_legacy.w, s.requested_legacy.h);
+ stateToCommit->crop.left, stateToCommit->crop.top, stateToCommit->crop.right,
+ stateToCommit->crop.bottom, stateToCommit->crop.getWidth(),
+ stateToCommit->crop.getHeight(), stateToCommit->requested_legacy.w,
+ stateToCommit->requested_legacy.h, s.active_legacy.w, s.active_legacy.h,
+ s.crop.left, s.crop.top, s.crop.right, s.crop.bottom, s.crop.getWidth(),
+ s.crop.getHeight(), s.requested_legacy.w, s.requested_legacy.h);
}
// Don't let Layer::doTransaction update the drawing state
@@ -1049,6 +1048,9 @@
c.callbackHandles.push_back(handle);
}
+ // Allow BufferStateLayer to release any unlatched buffers in drawing state.
+ bufferMayChange(c.buffer);
+
// Commit the transaction
commitTransaction(c);
mPendingStatesSnapshot = mPendingStates;
@@ -1335,11 +1337,11 @@
return true;
}
-bool Layer::setCrop_legacy(const Rect& crop) {
- if (mCurrentState.requestedCrop_legacy == crop) return false;
+bool Layer::setCrop(const Rect& crop) {
+ if (mCurrentState.requestedCrop == crop) return false;
mCurrentState.sequence++;
- mCurrentState.requestedCrop_legacy = crop;
- mCurrentState.crop_legacy = crop;
+ mCurrentState.requestedCrop = crop;
+ mCurrentState.crop = crop;
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
@@ -1744,7 +1746,7 @@
info.mZ = ds.z;
info.mWidth = ds.active_legacy.w;
info.mHeight = ds.active_legacy.h;
- info.mCrop = ds.crop_legacy;
+ info.mCrop = ds.crop;
info.mColor = ds.color;
info.mFlags = ds.flags;
info.mPixelFormat = getPixelFormat();
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 4a114e2..1c5d6ec 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -214,8 +214,8 @@
bool modified;
// Crop is expressed in layer space coordinate.
- Rect crop_legacy;
- Rect requestedCrop_legacy;
+ Rect crop;
+ Rect requestedCrop;
// If set, defers this state update until the identified Layer
// receives a frame with the given frameNumber
@@ -257,7 +257,6 @@
uint32_t bufferTransform;
bool transformToDisplayInverse;
- Rect crop;
Region transparentRegionHint;
sp<GraphicBuffer> buffer;
@@ -313,6 +312,7 @@
// When the transaction was posted
nsecs_t postTime;
+ sp<ITransactionCompletedListener> releaseBufferListener;
// SurfaceFrame that tracks the timeline of Transactions that contain a Buffer. Only one
// such SurfaceFrame exists because only one buffer can be presented on the layer per vsync.
// If multiple buffers are queued, the prior ones will be dropped, along with the
@@ -423,7 +423,7 @@
// space for top-level layers.
virtual bool setPosition(float x, float y);
// Buffer space
- virtual bool setCrop_legacy(const Rect& crop);
+ virtual bool setCrop(const Rect& crop);
// TODO(b/38182121): Could we eliminate the various latching modes by
// using the layer hierarchy?
@@ -462,13 +462,13 @@
// Used only to set BufferStateLayer state
virtual bool setTransform(uint32_t /*transform*/) { return false; };
virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; };
- virtual bool setCrop(const Rect& /*crop*/) { return false; };
virtual bool setFrame(const Rect& /*frame*/) { return false; };
virtual bool setBuffer(const sp<GraphicBuffer>& /*buffer*/, const sp<Fence>& /*acquireFence*/,
nsecs_t /*postTime*/, nsecs_t /*desiredPresentTime*/,
bool /*isAutoTimestamp*/, const client_cache_t& /*clientCacheId*/,
uint64_t /* frameNumber */, std::optional<nsecs_t> /* dequeueTime */,
- const FrameTimelineInfo& /*info*/) {
+ const FrameTimelineInfo& /*info*/,
+ const sp<ITransactionCompletedListener>& /* releaseBufferListener */) {
return false;
};
virtual bool setAcquireFence(const sp<Fence>& /*fence*/) { return false; };
@@ -549,7 +549,7 @@
virtual Region getActiveTransparentRegion(const Layer::State& s) const {
return s.activeTransparentRegion_legacy;
}
- virtual Rect getCrop(const Layer::State& s) const { return s.crop_legacy; }
+ virtual Rect getCrop(const Layer::State& s) const { return s.crop; }
virtual bool needsFiltering(const DisplayDevice*) const { return false; }
// True if this layer requires filtering
@@ -776,6 +776,12 @@
virtual uint32_t doTransaction(uint32_t transactionFlags);
/*
+ * Called before updating the drawing state buffer. Used by BufferStateLayer to release any
+ * unlatched buffers in the drawing state.
+ */
+ virtual void bufferMayChange(sp<GraphicBuffer>& /* newBuffer */){};
+
+ /*
* Remove relative z for the layer if its relative parent is not part of the
* provided layer tree.
*/
@@ -924,10 +930,6 @@
pid_t getOwnerPid() { return mOwnerPid; }
- virtual bool frameIsEarly(nsecs_t /*expectedPresentTime*/, int64_t /*vsyncId*/) const {
- return false;
- }
-
// This layer is not a clone, but it's the parent to the cloned hierarchy. The
// variable mClonedChild represents the top layer that will be cloned so this
// layer will be the parent of mClonedChild.
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
index 053b7f7..1c0263b 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -80,24 +80,23 @@
// recompute visible region
mRecomputeVisibleRegions = true;
- if (mFront.crop_legacy != mFront.requestedCrop_legacy) {
- mFront.crop_legacy = mFront.requestedCrop_legacy;
- mCurrent.crop_legacy = mFront.requestedCrop_legacy;
+ if (mFront.crop != mFront.requestedCrop) {
+ mFront.crop = mFront.requestedCrop;
+ mCurrent.crop = mFront.requestedCrop;
mRecomputeVisibleRegions = true;
}
}
ALOGD_IF(DEBUG_RESIZE,
"[%s] latchBuffer/reject: buffer (%ux%u, tr=%02x), scalingMode=%d\n"
- " drawing={ active_legacy ={ wh={%4u,%4u} crop_legacy={%4d,%4d,%4d,%4d} "
+ " drawing={ active_legacy ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} "
"(%4d,%4d) "
"}\n"
" requested_legacy={ wh={%4u,%4u} }}\n",
mName.c_str(), bufWidth, bufHeight, item.mTransform, item.mScalingMode,
- mFront.active_legacy.w, mFront.active_legacy.h, mFront.crop_legacy.left,
- mFront.crop_legacy.top, mFront.crop_legacy.right, mFront.crop_legacy.bottom,
- mFront.crop_legacy.getWidth(), mFront.crop_legacy.getHeight(),
- mFront.requested_legacy.w, mFront.requested_legacy.h);
+ mFront.active_legacy.w, mFront.active_legacy.h, mFront.crop.left, mFront.crop.top,
+ mFront.crop.right, mFront.crop.bottom, mFront.crop.getWidth(),
+ mFront.crop.getHeight(), mFront.requested_legacy.w, mFront.requested_legacy.h);
}
if (!isFixedSize && !mStickyTransformSet) {
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index b29c624..1d00cc3 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -241,7 +241,8 @@
auto buffer = getOrCreateBuffers(*mCurrentFps)[mFrame];
mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {},
mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */),
- std::nullopt /* dequeueTime */, FrameTimelineInfo{});
+ std::nullopt /* dequeueTime */, FrameTimelineInfo{},
+ nullptr /* releaseBufferListener */);
mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
}
@@ -254,7 +255,8 @@
auto buffer = buffers[mFrame];
mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {},
mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */),
- std::nullopt /* dequeueTime */, FrameTimelineInfo{});
+ std::nullopt /* dequeueTime */, FrameTimelineInfo{},
+ nullptr /* releaseBufferListener */);
mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
}
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index e06bc88..d0032ac 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -176,7 +176,7 @@
mScheduler(scheduler),
mTunables(tunables),
mIdleTimer(
- "RegionSamplingIdleTimer",
+ "RegSampIdle",
std::chrono::duration_cast<std::chrono::milliseconds>(
mTunables.mSamplingTimerTimeout),
[] {}, [this] { checkForStaleLuma(); }),
@@ -184,7 +184,7 @@
tunables.mSamplingDuration)),
lastSampleTime(0ns) {
mThread = std::thread([this]() { threadMain(); });
- pthread_setname_np(mThread.native_handle(), "RegionSamplingThread");
+ pthread_setname_np(mThread.native_handle(), "RegionSampling");
mIdleTimer.start();
}
diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.cpp b/services/surfaceflinger/Scheduler/VsyncModulator.cpp
index 1f821be..194d808 100644
--- a/services/surfaceflinger/Scheduler/VsyncModulator.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncModulator.cpp
@@ -50,24 +50,23 @@
TransactionSchedule schedule) {
switch (schedule) {
case Schedule::EarlyStart:
- ALOGW_IF(mExplicitEarlyWakeup, "%s: Duplicate EarlyStart", __FUNCTION__);
- mExplicitEarlyWakeup = true;
+ ALOGW_IF(mEarlyWakeup, "%s: Duplicate EarlyStart", __FUNCTION__);
+ mEarlyWakeup = true;
break;
case Schedule::EarlyEnd:
- ALOGW_IF(!mExplicitEarlyWakeup, "%s: Unexpected EarlyEnd", __FUNCTION__);
- mExplicitEarlyWakeup = false;
+ ALOGW_IF(!mEarlyWakeup, "%s: Unexpected EarlyEnd", __FUNCTION__);
+ mEarlyWakeup = false;
break;
- case Schedule::Early:
case Schedule::Late:
- // No change to mExplicitEarlyWakeup for non-explicit states.
+ // No change to mEarlyWakeup for non-explicit states.
break;
}
if (mTraceDetailedInfo) {
- ATRACE_INT("mExplicitEarlyWakeup", mExplicitEarlyWakeup);
+ ATRACE_INT("mEarlyWakeup", mEarlyWakeup);
}
- if (!mExplicitEarlyWakeup && (schedule == Schedule::Early || schedule == Schedule::EarlyEnd)) {
+ if (!mEarlyWakeup && schedule == Schedule::EarlyEnd) {
mEarlyTransactionFrames = MIN_EARLY_TRANSACTION_FRAMES;
mEarlyTransactionStartTime = mNow();
}
@@ -129,8 +128,8 @@
const VsyncModulator::VsyncConfig& VsyncModulator::getNextVsyncConfig() const {
// Early offsets are used if we're in the middle of a refresh rate
// change, or if we recently begin a transaction.
- if (mExplicitEarlyWakeup || mTransactionSchedule == Schedule::EarlyEnd ||
- mEarlyTransactionFrames > 0 || mRefreshRateChangePending) {
+ if (mEarlyWakeup || mTransactionSchedule == Schedule::EarlyEnd || mEarlyTransactionFrames > 0 ||
+ mRefreshRateChangePending) {
return mVsyncConfigSet.early;
} else if (mEarlyGpuFrames > 0) {
return mVsyncConfigSet.earlyGpu;
diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.h b/services/surfaceflinger/Scheduler/VsyncModulator.h
index 355a14a..fcde279 100644
--- a/services/surfaceflinger/Scheduler/VsyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VsyncModulator.h
@@ -30,7 +30,6 @@
// fixed number of frames, respectively.
enum class TransactionSchedule {
Late, // Default.
- Early, // Deprecated.
EarlyStart,
EarlyEnd
};
@@ -114,7 +113,7 @@
using Schedule = TransactionSchedule;
std::atomic<Schedule> mTransactionSchedule = Schedule::Late;
- std::atomic<bool> mExplicitEarlyWakeup = false;
+ std::atomic<bool> mEarlyWakeup = false;
std::atomic<bool> mRefreshRateChangePending = false;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ac1b808..31097aa 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -23,6 +23,7 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include "SurfaceFlinger.h"
+#include "TraceUtils.h"
#include <android-base/properties.h>
#include <android/configuration.h>
@@ -79,7 +80,6 @@
#include <utils/String16.h>
#include <utils/String8.h>
#include <utils/Timers.h>
-#include <utils/Trace.h>
#include <utils/misc.h>
#include <algorithm>
@@ -441,10 +441,6 @@
mUseHwcVirtualDisplays = atoi(value);
ALOGI_IF(mUseHwcVirtualDisplays, "Enabling HWC virtual displays");
- property_get("ro.sf.disable_triple_buffer", value, "0");
- mLayerTripleBufferingDisabled = atoi(value);
- ALOGI_IF(mLayerTripleBufferingDisabled, "Disabling Triple Buffering");
-
property_get("ro.surface_flinger.supports_background_blur", value, "0");
bool supportsBlurs = atoi(value);
mSupportsBlur = supportsBlurs;
@@ -914,11 +910,6 @@
}
info->activeDisplayModeId = static_cast<int32_t>(display->getActiveMode()->getId().value());
- if (display->isPrimary()) {
- if (const auto mode = getDesiredActiveMode()) {
- info->activeDisplayModeId = static_cast<int32_t>(mode->modeId.value());
- }
- }
const auto& supportedModes = display->getSupportedModes();
info->supportedDisplayModes.clear();
@@ -1467,14 +1458,16 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::setDisplayBrightness(const sp<IBinder>& displayToken, float brightness) {
+status_t SurfaceFlinger::setDisplayBrightness(const sp<IBinder>& displayToken,
+ const gui::DisplayBrightness& brightness) {
if (!displayToken) {
return BAD_VALUE;
}
return ftl::chain(schedule([=]() MAIN_THREAD {
if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
- return getHwComposer().setDisplayBrightness(*displayId, brightness);
+ return getHwComposer().setDisplayBrightness(*displayId,
+ brightness.displayBrightness);
} else {
ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
return ftl::yield<status_t>(NAME_NOT_FOUND);
@@ -1692,7 +1685,12 @@
}
void SurfaceFlinger::onMessageReceived(int32_t what, int64_t vsyncId, nsecs_t expectedVSyncTime) {
- ATRACE_CALL();
+ const auto vsyncIn = [&] {
+ if (!ATRACE_ENABLED()) return 0.f;
+ return (expectedVSyncTime - systemTime()) / 1e6f;
+ }();
+
+ ATRACE_FORMAT("onMessageReceived %" PRId64 " vsyncIn %.2fms", vsyncId, vsyncIn);
switch (what) {
case MessageQueue::INVALIDATE: {
onMessageInvalidate(vsyncId, expectedVSyncTime);
@@ -1879,7 +1877,12 @@
// underestimated.
mFrameStartTime = frameStart;
}
- signalRefresh();
+
+ // Run the refresh immediately after invalidate as there is no point going thru the message
+ // queue again, and to ensure that we actually refresh the screen instead of handling
+ // other messages that were queued us already in the MessageQueue.
+ mRefreshPending = true;
+ onMessageRefresh();
}
}
@@ -2973,7 +2976,7 @@
mRefreshRateConfigs = std::make_unique<
scheduler::RefreshRateConfigs>(displayState.physical->supportedModes,
displayState.physical->activeMode->getId(),
- android::sysprop::enable_frame_rate_override(true));
+ android::sysprop::enable_frame_rate_override(false));
const auto currRefreshRate = displayState.physical->activeMode->getFps();
mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(*mTimeStats, currRefreshRate,
hal::PowerMode::OFF);
@@ -3041,9 +3044,8 @@
void SurfaceFlinger::commitTransaction() {
commitTransactionLocked();
- mTransactionPending = false;
+ signalSynchronousTransactions();
mAnimTransactionPending = false;
- mTransactionCV.broadcast();
}
void SurfaceFlinger::commitTransactionLocked() {
@@ -3312,15 +3314,16 @@
auto& [applyToken, transactionQueue] = *it;
while (!transactionQueue.empty()) {
- const auto& transaction = transactionQueue.front();
+ auto& transaction = transactionQueue.front();
if (!transactionIsReadyToBeApplied(transaction.frameTimelineInfo,
transaction.isAutoTimestamp,
transaction.desiredPresentTime,
- transaction.states, pendingBuffers)) {
+ transaction.originUid, transaction.states,
+ pendingBuffers)) {
setTransactionFlags(eTransactionFlushNeeded);
break;
}
- transactions.push_back(transaction);
+ transactions.emplace_back(std::move(transaction));
transactionQueue.pop();
}
@@ -3337,17 +3340,18 @@
// Case 2: push to pending when there exist a pending queue.
// Case 3: others are ready to apply.
while (!mTransactionQueue.empty()) {
- const auto& transaction = mTransactionQueue.front();
+ auto& transaction = mTransactionQueue.front();
bool pendingTransactions = mPendingTransactionQueues.find(transaction.applyToken) !=
mPendingTransactionQueues.end();
if (!transactionIsReadyToBeApplied(transaction.frameTimelineInfo,
transaction.isAutoTimestamp,
transaction.desiredPresentTime,
- transaction.states, pendingBuffers) ||
+ transaction.originUid, transaction.states,
+ pendingBuffers) ||
pendingTransactions) {
- mPendingTransactionQueues[transaction.applyToken].push(transaction);
+ mPendingTransactionQueues[transaction.applyToken].push(std::move(transaction));
} else {
- transactions.push_back(transaction);
+ transactions.emplace_back(std::move(transaction));
}
mTransactionQueue.pop();
ATRACE_INT("TransactionQueue", mTransactionQueue.size());
@@ -3363,6 +3367,10 @@
transaction.postTime, transaction.permissions,
transaction.hasListenerCallbacks, transaction.listenerCallbacks,
transaction.originPid, transaction.originUid, transaction.id);
+ if (transaction.transactionCommittedSignal) {
+ mTransactionCommittedSignals.emplace_back(
+ std::move(transaction.transactionCommittedSignal));
+ }
}
}
}
@@ -3372,16 +3380,52 @@
return !mPendingTransactionQueues.empty() || !mTransactionQueue.empty();
}
+bool SurfaceFlinger::frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) const {
+ // The amount of time SF can delay a frame if it is considered early based
+ // on the VsyncModulator::VsyncConfig::appWorkDuration
+ constexpr static std::chrono::nanoseconds kEarlyLatchMaxThreshold = 100ms;
+
+ const auto currentVsyncPeriod = mScheduler->getDisplayStatInfo(systemTime()).vsyncPeriod;
+ const auto earlyLatchVsyncThreshold = currentVsyncPeriod / 2;
+
+ const auto prediction = mFrameTimeline->getTokenManager()->getPredictionsForToken(vsyncId);
+ if (!prediction.has_value()) {
+ return false;
+ }
+
+ if (std::abs(prediction->presentTime - expectedPresentTime) >=
+ kEarlyLatchMaxThreshold.count()) {
+ return false;
+ }
+
+ return prediction->presentTime >= expectedPresentTime &&
+ prediction->presentTime - expectedPresentTime >= earlyLatchVsyncThreshold;
+}
+
bool SurfaceFlinger::transactionIsReadyToBeApplied(
const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime,
- const Vector<ComposerState>& states,
+ uid_t originUid, const Vector<ComposerState>& states,
std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>& pendingBuffers) {
+ ATRACE_CALL();
const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
bool ready = true;
// Do not present if the desiredPresentTime has not passed unless it is more than one second
// in the future. We ignore timestamps more than 1 second in the future for stability reasons.
if (!isAutoTimestamp && desiredPresentTime >= expectedPresentTime &&
desiredPresentTime < expectedPresentTime + s2ns(1)) {
+ ATRACE_NAME("not current");
+ ready = false;
+ }
+
+ if (!mScheduler->isVsyncValid(expectedPresentTime, originUid)) {
+ ATRACE_NAME("!isVsyncValid");
+ ready = false;
+ }
+
+ // If the client didn't specify desiredPresentTime, use the vsyncId to determine the expected
+ // present time of this transaction.
+ if (isAutoTimestamp && frameIsEarly(expectedPresentTime, info.vsyncId)) {
+ ATRACE_NAME("frameIsEarly");
ready = false;
}
@@ -3404,33 +3448,23 @@
continue;
}
- const bool frameTimelineInfoChanged = (s.what & layer_state_t::eFrameTimelineInfoChanged);
- const auto vsyncId = frameTimelineInfoChanged ? s.frameTimelineInfo.vsyncId : info.vsyncId;
- if (isAutoTimestamp && layer->frameIsEarly(expectedPresentTime, vsyncId)) {
- ATRACE_NAME("frameIsEarly()");
- return false;
- }
-
- if (!mScheduler->isVsyncValid(expectedPresentTime, layer->getOwnerUid())) {
- ATRACE_NAME("!isVsyncValidForUid");
- ready = false;
- }
+ ATRACE_NAME(layer->getName().c_str());
if (acquireFenceChanged) {
// If backpressure is enabled and we already have a buffer to commit, keep the
// transaction in the queue.
const bool hasPendingBuffer = pendingBuffers.find(s.surface) != pendingBuffers.end();
if (layer->backpressureEnabled() && hasPendingBuffer && isAutoTimestamp) {
+ ATRACE_NAME("hasPendingBuffer");
ready = false;
}
pendingBuffers.insert(s.surface);
}
- pendingBuffers.insert(s.surface);
}
return ready;
}
-void SurfaceFlinger::queueTransaction(TransactionState state) {
+void SurfaceFlinger::queueTransaction(TransactionState& state) {
Mutex::Autolock _l(mQueueLock);
// If its TransactionQueue already has a pending TransactionState or if it is pending
@@ -3450,52 +3484,41 @@
}
}
+ // Generate a CountDownLatch pending state if this is a synchronous transaction.
+ if ((state.flags & eSynchronous) || state.inputWindowCommands.syncInputWindows) {
+ state.transactionCommittedSignal = std::make_shared<CountDownLatch>(
+ (state.inputWindowCommands.syncInputWindows ? 2 : 1));
+ }
+
mTransactionQueue.emplace(state);
ATRACE_INT("TransactionQueue", mTransactionQueue.size());
- // TODO(b/159125966): Remove eEarlyWakeup completely as no client should use this flag
- if (state.flags & eEarlyWakeup) {
- ALOGW("eEarlyWakeup is deprecated. Use eExplicitEarlyWakeup[Start|End]");
- }
-
- if (!(state.permissions & Permission::ACCESS_SURFACE_FLINGER) &&
- (state.flags & (eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd))) {
- ALOGE("Only WindowManager is allowed to use eExplicitEarlyWakeup[Start|End] flags");
- state.flags &= ~(eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd);
- }
-
const auto schedule = [](uint32_t flags) {
- if (flags & eEarlyWakeup) return TransactionSchedule::Early;
- if (flags & eExplicitEarlyWakeupEnd) return TransactionSchedule::EarlyEnd;
- if (flags & eExplicitEarlyWakeupStart) return TransactionSchedule::EarlyStart;
+ if (flags & eEarlyWakeupEnd) return TransactionSchedule::EarlyEnd;
+ if (flags & eEarlyWakeupStart) return TransactionSchedule::EarlyStart;
return TransactionSchedule::Late;
}(state.flags);
setTransactionFlags(eTransactionFlushNeeded, schedule);
}
-void SurfaceFlinger::waitForSynchronousTransaction(bool synchronous, bool syncInput) {
- Mutex::Autolock _l(mStateLock);
- if (synchronous) {
- mTransactionPending = true;
+void SurfaceFlinger::waitForSynchronousTransaction(
+ const CountDownLatch& transactionCommittedSignal) {
+ // applyTransactionState is called on the main SF thread. While a given process may wish
+ // to wait on synchronous transactions, the main SF thread should apply the transaction and
+ // set the value to notify this after committed.
+ if (!transactionCommittedSignal.wait_until(std::chrono::seconds(5))) {
+ ALOGE("setTransactionState timed out!");
}
- if (syncInput) {
- mPendingSyncInputWindows = true;
- }
+}
- // applyTransactionState can be called by either the main SF thread or by
- // another process through setTransactionState. While a given process may wish
- // to wait on synchronous transactions, the main SF thread should never
- // be blocked. Therefore, we only wait if isMainThread is false.
- while (mTransactionPending || mPendingSyncInputWindows) {
- status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
- if (CC_UNLIKELY(err != NO_ERROR)) {
- // just in case something goes wrong in SF, return to the
- // called after a few seconds.
- ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!");
- mTransactionPending = false;
- mPendingSyncInputWindows = false;
- break;
+void SurfaceFlinger::signalSynchronousTransactions() {
+ for (auto it = mTransactionCommittedSignals.begin();
+ it != mTransactionCommittedSignals.end();) {
+ if ((*it)->countDown() == 0) {
+ it = mTransactionCommittedSignals.erase(it);
+ } else {
+ it++;
}
}
}
@@ -3524,21 +3547,30 @@
permissions |= Permission::ROTATE_SURFACE_FLINGER;
}
+ if (!(permissions & Permission::ACCESS_SURFACE_FLINGER) &&
+ (flags & (eEarlyWakeupStart | eEarlyWakeupEnd))) {
+ ALOGE("Only WindowManager is allowed to use eEarlyWakeup[Start|End] flags");
+ flags &= ~(eEarlyWakeupStart | eEarlyWakeupEnd);
+ }
+
const int64_t postTime = systemTime();
IPCThreadState* ipc = IPCThreadState::self();
const int originPid = ipc->getCallingPid();
const int originUid = ipc->getCallingUid();
+ TransactionState state{frameTimelineInfo, states,
+ displays, flags,
+ applyToken, inputWindowCommands,
+ desiredPresentTime, isAutoTimestamp,
+ uncacheBuffer, postTime,
+ permissions, hasListenerCallbacks,
+ listenerCallbacks, originPid,
+ originUid, transactionId};
+ queueTransaction(state);
- queueTransaction({frameTimelineInfo, states, displays, flags, applyToken, inputWindowCommands,
- desiredPresentTime, isAutoTimestamp, uncacheBuffer, postTime, permissions,
- hasListenerCallbacks, listenerCallbacks, originPid, originUid,
- transactionId});
-
- const bool synchronous = flags & eSynchronous;
- const bool syncInput = inputWindowCommands.syncInputWindows;
- if (synchronous || syncInput) {
- waitForSynchronousTransaction(synchronous, syncInput);
+ // Check the pending state to make sure the transaction is synchronous.
+ if (state.transactionCommittedSignal) {
+ waitForSynchronousTransaction(*state.transactionCommittedSignal);
}
return NO_ERROR;
@@ -3836,9 +3868,6 @@
if (layer->setFlags(s.flags, s.mask))
flags |= eTraversalNeeded;
}
- if (what & layer_state_t::eCropChanged_legacy) {
- if (layer->setCrop_legacy(s.crop_legacy)) flags |= eTraversalNeeded;
- }
if (what & layer_state_t::eCornerRadiusChanged) {
if (layer->setCornerRadius(s.cornerRadius))
flags |= eTraversalNeeded;
@@ -3947,12 +3976,6 @@
flags |= eTraversalNeeded;
}
}
- FrameTimelineInfo info;
- if (what & layer_state_t::eFrameTimelineInfoChanged) {
- info = s.frameTimelineInfo;
- } else if (frameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) {
- info = frameTimelineInfo;
- }
if (what & layer_state_t::eFixedTransformHintChanged) {
if (layer->setFixedTransformHint(s.fixedTransformHint)) {
flags |= eTraversalNeeded | eTransformHintUpdateNeeded;
@@ -4015,11 +4038,12 @@
: layer->getHeadFrameNumber(-1 /* expectedPresentTime */) + 1;
if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime, isAutoTimestamp,
- s.cachedBuffer, frameNumber, dequeueBufferTimestamp, info)) {
+ s.cachedBuffer, frameNumber, dequeueBufferTimestamp, frameTimelineInfo,
+ s.releaseBufferListener)) {
flags |= eTraversalNeeded;
}
- } else if (info.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) {
- layer->setFrameTimelineVsyncForBufferlessTransaction(info, postTime);
+ } else if (frameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) {
+ layer->setFrameTimelineVsyncForBufferlessTransaction(frameTimelineInfo, postTime);
}
if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded;
@@ -4539,9 +4563,6 @@
void SurfaceFlinger::appendSfConfigString(std::string& result) const {
result.append(" [sf");
- if (isLayerTripleBufferingDisabled())
- result.append(" DISABLE_TRIPLE_BUFFERING");
-
StringAppendF(&result, " PRESENT_TIME_OFFSET=%" PRId64, dispSyncPresentTimeOffset);
StringAppendF(&result, " FORCE_HWC_FOR_RBG_TO_YUV=%d", useHwcForRgbToYuv);
StringAppendF(&result, " MAX_VIRT_DISPLAY_DIM=%" PRIu64, maxVirtualDisplaySize);
@@ -6078,10 +6099,7 @@
void SurfaceFlinger::setInputWindowsFinished() {
Mutex::Autolock _l(mStateLock);
-
- mPendingSyncInputWindows = false;
-
- mTransactionCV.broadcast();
+ signalSynchronousTransactions();
}
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 40d63b2..8d2f66d 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -474,6 +474,41 @@
hal::Connection connection = hal::Connection::INVALID;
};
+ class CountDownLatch {
+ public:
+ explicit CountDownLatch(int32_t count) : mCount(count) {}
+
+ int32_t countDown() {
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (mCount == 0) {
+ return 0;
+ }
+ if (--mCount == 0) {
+ mCountDownComplete.notify_all();
+ }
+ return mCount;
+ }
+
+ // Return true if triggered.
+ bool wait_until(const std::chrono::seconds& timeout) const {
+ std::unique_lock<std::mutex> lock(mMutex);
+ const auto untilTime = std::chrono::system_clock::now() + timeout;
+ while (mCount != 0) {
+ // Conditional variables can be woken up sporadically, so we check count
+ // to verify the wakeup was triggered by |countDown|.
+ if (std::cv_status::timeout == mCountDownComplete.wait_until(lock, untilTime)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private:
+ int32_t mCount;
+ mutable std::condition_variable mCountDownComplete;
+ mutable std::mutex mMutex;
+ };
+
struct TransactionState {
TransactionState(const FrameTimelineInfo& frameTimelineInfo,
const Vector<ComposerState>& composerStates,
@@ -517,6 +552,7 @@
int originPid;
int originUid;
uint64_t id;
+ std::shared_ptr<CountDownLatch> transactionCommittedSignal;
};
template <typename F, std::enable_if_t<!std::is_member_function_pointer_v<F>>* = nullptr>
@@ -644,7 +680,8 @@
float* outAppRequestRefreshRateMax) override;
status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
bool* outSupport) const override;
- status_t setDisplayBrightness(const sp<IBinder>& displayToken, float brightness) override;
+ status_t setDisplayBrightness(const sp<IBinder>& displayToken,
+ const gui::DisplayBrightness& brightness) override;
status_t notifyPowerBoost(int32_t boostId) override;
status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
float lightPosY, float lightPosZ, float lightRadius) override;
@@ -801,12 +838,13 @@
void commitOffscreenLayers();
bool transactionIsReadyToBeApplied(
const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime,
- const Vector<ComposerState>& states,
+ uid_t originUid, const Vector<ComposerState>& states,
std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>& pendingBuffers)
REQUIRES(mStateLock);
uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands)
REQUIRES(mStateLock);
+ bool frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) const;
/*
* Layer management
*/
@@ -1057,10 +1095,6 @@
void dumpOffscreenLayers(std::string& result) EXCLUDES(mStateLock);
void dumpPlannerInfo(const DumpArgs& args, std::string& result) const REQUIRES(mStateLock);
- bool isLayerTripleBufferingDisabled() const {
- return this->mLayerTripleBufferingDisabled;
- }
-
status_t doDump(int fd, const DumpArgs& args, bool asProto);
status_t dumpCritical(int fd, const DumpArgs&, bool asProto);
@@ -1080,8 +1114,9 @@
status_t CheckTransactCodeCredentials(uint32_t code);
// Add transaction to the Transaction Queue
- void queueTransaction(TransactionState state) EXCLUDES(mQueueLock);
- void waitForSynchronousTransaction(bool synchronous, bool syncInput) EXCLUDES(mStateLock);
+ void queueTransaction(TransactionState& state) EXCLUDES(mQueueLock);
+ void waitForSynchronousTransaction(const CountDownLatch& transactionCommittedSignal);
+ void signalSynchronousTransactions();
/*
* Generic Layer Metadata
@@ -1111,8 +1146,7 @@
mutable Mutex mStateLock;
State mCurrentState{LayerVector::StateSet::Current};
std::atomic<int32_t> mTransactionFlags = 0;
- Condition mTransactionCV;
- bool mTransactionPending = false;
+ std::vector<std::shared_ptr<CountDownLatch>> mTransactionCommittedSignals;
bool mAnimTransactionPending = false;
SortedVector<sp<Layer>> mLayersPendingRemoval;
bool mForceTraversal = false;
@@ -1214,9 +1248,6 @@
TransactionCallbackInvoker mTransactionCallbackInvoker;
- // Restrict layers to use two buffers in their bufferqueues.
- bool mLayerTripleBufferingDisabled = false;
-
// these are thread safe
std::unique_ptr<MessageQueue> mEventQueue;
FrameTracker mAnimFrameTracker;
@@ -1324,7 +1355,6 @@
sp<SetInputWindowsListener> mSetInputWindowsListener;
- bool mPendingSyncInputWindows GUARDED_BY(mStateLock) = false;
Hwc2::impl::PowerAdvisor mPowerAdvisor;
// This should only be accessed on the main thread.
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index b0413f1..8a3be9f 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -137,7 +137,7 @@
addTransparentRegionLocked(transaction, layerId,
layer->mCurrentState.activeTransparentRegion_legacy);
addLayerStackLocked(transaction, layerId, layer->mCurrentState.layerStack);
- addCropLocked(transaction, layerId, layer->mCurrentState.crop_legacy);
+ addCropLocked(transaction, layerId, layer->mCurrentState.crop);
addCornerRadiusLocked(transaction, layerId, layer->mCurrentState.cornerRadius);
addBackgroundBlurRadiusLocked(transaction, layerId, layer->mCurrentState.backgroundBlurRadius);
addBlurRegionsLocked(transaction, layerId, layer->mCurrentState.blurRegions);
@@ -459,8 +459,8 @@
if (state.what & layer_state_t::eLayerStackChanged) {
addLayerStackLocked(transaction, layerId, state.layerStack);
}
- if (state.what & layer_state_t::eCropChanged_legacy) {
- addCropLocked(transaction, layerId, state.crop_legacy);
+ if (state.what & layer_state_t::eCropChanged) {
+ addCropLocked(transaction, layerId, state.crop);
}
if (state.what & layer_state_t::eCornerRadiusChanged) {
addCornerRadiusLocked(transaction, layerId, state.cornerRadius);
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 100354a..974ae84 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -1070,6 +1070,9 @@
mTimeStats.renderEngineTimingLegacy.hist.clear();
mTimeStats.refreshRateStatsLegacy.clear();
mPowerTime.prevTime = systemTime();
+ for (auto& globalRecord : mTimeStats.stats) {
+ globalRecord.second.clearGlobals();
+ }
mGlobalRecord.prevPresentTime = 0;
mGlobalRecord.presentFences.clear();
ALOGD("Cleared global stats");
@@ -1079,7 +1082,10 @@
ATRACE_CALL();
mTimeStatsTracker.clear();
- mTimeStats.stats.clear();
+
+ for (auto& globalRecord : mTimeStats.stats) {
+ globalRecord.second.stats.clear();
+ }
ALOGD("Cleared layer stats");
}
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 4556bad..5ee28ce 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -127,6 +127,12 @@
Histogram displayDeadlineDeltas;
Histogram displayPresentDeltas;
std::unordered_map<LayerStatsKey, TimeStatsLayer, LayerStatsKey::Hasher> stats;
+
+ void clearGlobals() {
+ jankPayload = {};
+ displayDeadlineDeltas = {};
+ displayPresentDeltas = {};
+ }
};
class TimeStatsGlobal {
diff --git a/services/surfaceflinger/TraceUtils.h b/services/surfaceflinger/TraceUtils.h
new file mode 100644
index 0000000..90a34a5
--- /dev/null
+++ b/services/surfaceflinger/TraceUtils.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO(b/183120308): This file is a copy of f/b/libs/hwui/utils/TraceUtils.h
+// It should be migrated to a common place where both SF and hwui could use it.
+
+#pragma once
+
+#include <cutils/trace.h>
+#include <utils/Trace.h>
+
+#define ATRACE_FORMAT(fmt, ...) \
+ TraceUtils::TraceEnder __traceEnder = \
+ (TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__), TraceUtils::TraceEnder())
+
+#define ATRACE_FORMAT_BEGIN(fmt, ...) TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__)
+
+namespace android {
+
+class TraceUtils {
+public:
+ class TraceEnder {
+ public:
+ ~TraceEnder() { ATRACE_END(); }
+ };
+
+ static void atraceFormatBegin(const char* fmt, ...) {
+ if (CC_LIKELY(!ATRACE_ENABLED())) return;
+
+ const int BUFFER_SIZE = 256;
+ va_list ap;
+ char buf[BUFFER_SIZE];
+
+ va_start(ap, fmt);
+ vsnprintf(buf, BUFFER_SIZE, fmt, ap);
+ va_end(ap);
+
+ ATRACE_BEGIN(buf);
+ }
+
+}; // class TraceUtils
+
+} /* namespace android */
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index a78510e..3590e76 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -201,7 +201,8 @@
handle->dequeueReadyTime);
transactionStats->surfaceStats.emplace_back(surfaceControl, handle->acquireTime,
handle->previousReleaseFence,
- handle->transformHint, eventStats, jankData);
+ handle->transformHint, eventStats, jankData,
+ handle->previousBufferId);
}
return NO_ERROR;
}
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index a240c82..caa8a4f 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -50,6 +50,7 @@
nsecs_t refreshStartTime = 0;
nsecs_t dequeueReadyTime = 0;
uint64_t frameNumber = 0;
+ uint64_t previousBufferId = 0;
};
class TransactionCallbackInvoker {
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 78187f7..b96725f 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -44,6 +44,7 @@
"MultiDisplayLayerBounds_test.cpp",
"RefreshRateOverlay_test.cpp",
"RelativeZ_test.cpp",
+ "ReleaseBufferCallback_test.cpp",
"ScreenCapture_test.cpp",
"SetFrameRate_test.cpp",
"SetGeometry_test.cpp",
diff --git a/services/surfaceflinger/tests/EffectLayer_test.cpp b/services/surfaceflinger/tests/EffectLayer_test.cpp
index 7a3c45d..f470eda 100644
--- a/services/surfaceflinger/tests/EffectLayer_test.cpp
+++ b/services/surfaceflinger/tests/EffectLayer_test.cpp
@@ -55,7 +55,7 @@
EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl";
asTransaction([&](Transaction& t) {
- t.setCrop_legacy(effectLayer, Rect(0, 0, 400, 400));
+ t.setCrop(effectLayer, Rect(0, 0, 400, 400));
t.show(effectLayer);
});
@@ -76,7 +76,7 @@
EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl";
asTransaction([&](Transaction& t) {
- t.setCrop_legacy(effectLayer, Rect(0, 0, 400, 400));
+ t.setCrop(effectLayer, Rect(0, 0, 400, 400));
t.show(effectLayer);
});
@@ -97,7 +97,7 @@
EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl";
asTransaction([&](Transaction& t) {
- t.setCrop_legacy(effectLayer, Rect(0, 0, 400, 400));
+ t.setCrop(effectLayer, Rect(0, 0, 400, 400));
t.setColor(effectLayer,
half3{Color::GREEN.r / 255.0f, Color::GREEN.g / 255.0f,
Color::GREEN.b / 255.0f});
@@ -127,10 +127,10 @@
asTransaction([&](Transaction& t) {
t.setLayer(leftLayer, mLayerZBase + 1);
t.reparent(leftLayer, mParentLayer);
- t.setCrop_legacy(leftLayer, leftRect);
+ t.setCrop(leftLayer, leftRect);
t.setLayer(rightLayer, mLayerZBase + 2);
t.reparent(rightLayer, mParentLayer);
- t.setCrop_legacy(rightLayer, rightRect);
+ t.setCrop(rightLayer, rightRect);
t.show(leftLayer);
t.show(rightLayer);
});
@@ -148,7 +148,7 @@
t.setLayer(blurLayer, mLayerZBase + 3);
t.reparent(blurLayer, mParentLayer);
t.setBackgroundBlurRadius(blurLayer, blurRadius);
- t.setCrop_legacy(blurLayer, blurRect);
+ t.setCrop(blurLayer, blurRect);
t.setFrame(blurLayer, blurRect);
t.setAlpha(blurLayer, 0.0f);
t.show(blurLayer);
diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp
index aa1cce2..158801a 100644
--- a/services/surfaceflinger/tests/LayerCallback_test.cpp
+++ b/services/surfaceflinger/tests/LayerCallback_test.cpp
@@ -14,10 +14,6 @@
* limitations under the License.
*/
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
#include <sys/epoll.h>
#include <gui/DisplayEventReceiver.h>
@@ -25,6 +21,8 @@
#include "LayerTransactionTest.h"
#include "utils/CallbackUtils.h"
+using namespace std::chrono_literals;
+
namespace android {
using android::hardware::graphics::common::V1_1::BufferUsage;
@@ -801,7 +799,7 @@
}
// Try to present 100ms in the future
- nsecs_t time = systemTime() + (100 * 1e6);
+ nsecs_t time = systemTime() + std::chrono::nanoseconds(100ms).count();
transaction.setDesiredPresentTime(time);
transaction.apply();
@@ -825,7 +823,7 @@
}
// Try to present 100ms in the future
- nsecs_t time = systemTime() + (100 * 1e6);
+ nsecs_t time = systemTime() + std::chrono::nanoseconds(100ms).count();
transaction.setDesiredPresentTime(time);
transaction.apply();
@@ -842,7 +840,7 @@
}
// Try to present 33ms after the first frame
- time += (33.3 * 1e6);
+ time += std::chrono::nanoseconds(33ms).count();
transaction.setDesiredPresentTime(time);
transaction.apply();
@@ -870,7 +868,7 @@
}
// Try to present 100ms in the future
- nsecs_t time = systemTime() + (100 * 1e6);
+ nsecs_t time = systemTime() + std::chrono::nanoseconds(100ms).count();
transaction.setDesiredPresentTime(time);
transaction.apply();
@@ -887,7 +885,7 @@
}
// Try to present 33ms before the previous frame
- time -= (33.3 * 1e6);
+ time -= std::chrono::nanoseconds(33ms).count();
transaction.setDesiredPresentTime(time);
transaction.apply();
@@ -914,7 +912,7 @@
}
// Try to present 100ms in the past
- nsecs_t time = systemTime() - (100 * 1e6);
+ nsecs_t time = systemTime() - std::chrono::nanoseconds(100ms).count();
transaction.setDesiredPresentTime(time);
transaction.apply();
@@ -948,6 +946,3 @@
}
} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
index b35eaa9..7505e6e 100644
--- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
@@ -515,7 +515,7 @@
ISurfaceComposerClient::eFXSurfaceEffect));
Transaction()
- .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+ .setCrop(colorLayer, Rect(0, 0, 32, 32))
.setLayer(colorLayer, mLayerZBase + 1)
.apply();
@@ -554,7 +554,7 @@
case ISurfaceComposerClient::eFXSurfaceEffect:
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 0, 0, layerType));
Transaction()
- .setCrop_legacy(layer, Rect(0, 0, width, height))
+ .setCrop(layer, Rect(0, 0, width, height))
.setColor(layer, half3(1.0f, 0, 0))
.apply();
expectedColor = fillColor;
@@ -565,7 +565,7 @@
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, fillColor, width, height));
expectedColor = fillColor;
}
- Transaction().setCrop_legacy(layer, Rect(0, 0, width, height)).apply();
+ Transaction().setCrop(layer, Rect(0, 0, width, height)).apply();
break;
case ISurfaceComposerClient::eFXSurfaceBufferState:
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height, layerType));
@@ -727,7 +727,7 @@
createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
ISurfaceComposerClient::eFXSurfaceEffect));
Transaction()
- .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+ .setCrop(colorLayer, Rect(0, 0, 32, 32))
.setColor(colorLayer, half3(2.0f, 0.0f, 0.0f))
.apply();
@@ -741,7 +741,7 @@
createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
ISurfaceComposerClient::eFXSurfaceEffect));
Transaction()
- .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+ .setCrop(colorLayer, Rect(0, 0, 32, 32))
.setColor(colorLayer, half3(1.0f, -1.0f, 0.5f))
.apply();
@@ -756,7 +756,7 @@
ASSERT_NO_FATAL_FAILURE(colorLayer =
createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
ISurfaceComposerClient::eFXSurfaceEffect));
- Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply();
+ Transaction().setCrop(colorLayer, Rect(0, 0, 32, 32)).apply();
const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
const float alpha = 0.25f;
@@ -783,7 +783,7 @@
ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("childWithColor", 0 /* buffer width */,
0 /* buffer height */,
ISurfaceComposerClient::eFXSurfaceEffect));
- Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply();
+ Transaction().setCrop(colorLayer, Rect(0, 0, 32, 32)).apply();
const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
const float alpha = 0.25f;
const ubyte3 expected((vec3(color) * alpha + vec3(1.0f, 0.0f, 0.0f) * (1.0f - alpha)) * 255.0f);
@@ -940,7 +940,7 @@
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
const Rect crop(8, 8, 24, 24);
- Transaction().setCrop_legacy(layer, crop).apply();
+ Transaction().setCrop(layer, crop).apply();
auto shot = getScreenCapture();
shot->expectColor(crop, Color::RED);
shot->expectBorder(crop, Color::BLACK);
@@ -966,13 +966,13 @@
{
SCOPED_TRACE("empty rect");
- Transaction().setCrop_legacy(layer, Rect(8, 8, 8, 8)).apply();
+ Transaction().setCrop(layer, Rect(8, 8, 8, 8)).apply();
getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
{
SCOPED_TRACE("negative rect");
- Transaction().setCrop_legacy(layer, Rect(8, 8, 0, 0)).apply();
+ Transaction().setCrop(layer, Rect(8, 8, 0, 0)).apply();
getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
}
@@ -1001,7 +1001,7 @@
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
- Transaction().setCrop_legacy(layer, Rect(-128, -64, 128, 64)).apply();
+ Transaction().setCrop(layer, Rect(-128, -64, 128, 64)).apply();
auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
@@ -1056,7 +1056,7 @@
const Point position(32, 32);
const Rect crop(8, 8, 24, 24);
- Transaction().setPosition(layer, position.x, position.y).setCrop_legacy(layer, crop).apply();
+ Transaction().setPosition(layer, position.x, position.y).setCrop(layer, crop).apply();
auto shot = getScreenCapture();
shot->expectColor(crop + position, Color::RED);
shot->expectBorder(crop + position, Color::BLACK);
@@ -1081,10 +1081,10 @@
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
- // crop_legacy is affected by matrix
+ // crop is affected by matrix
Transaction()
.setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
- .setCrop_legacy(layer, Rect(8, 8, 24, 24))
+ .setCrop(layer, Rect(8, 8, 24, 24))
.apply();
auto shot = getScreenCapture();
shot->expectColor(Rect(16, 16, 48, 48), Color::RED);
@@ -1096,8 +1096,8 @@
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
- // setCrop_legacy is applied immediately by default, with or without resize pending
- Transaction().setCrop_legacy(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply();
+ // setCrop is applied immediately by default, with or without resize pending
+ Transaction().setCrop(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply();
{
SCOPED_TRACE("resize pending");
auto shot = getScreenCapture();
@@ -1596,7 +1596,7 @@
createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
ISurfaceComposerClient::eFXSurfaceEffect));
Transaction()
- .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+ .setCrop(colorLayer, Rect(0, 0, 32, 32))
.setLayer(colorLayer, mLayerZBase + 1)
.apply();
{
@@ -1653,8 +1653,8 @@
ISurfaceComposerClient::eFXSurfaceEffect, parentLayer.get()));
Transaction()
- .setCrop_legacy(parentLayer, Rect(0, 0, 100, 100))
- .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+ .setCrop(parentLayer, Rect(0, 0, 100, 100))
+ .setCrop(colorLayer, Rect(0, 0, 32, 32))
.setLayer(parentLayer, mLayerZBase + 1)
.apply();
{
@@ -1714,8 +1714,8 @@
ISurfaceComposerClient::eFXSurfaceEffect, parentLayer.get()));
Transaction()
- .setCrop_legacy(parentLayer, Rect(0, 0, 100, 100))
- .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+ .setCrop(parentLayer, Rect(0, 0, 100, 100))
+ .setCrop(colorLayer, Rect(0, 0, 32, 32))
.setLayer(parentLayer, mLayerZBase + 1)
.apply();
{
diff --git a/services/surfaceflinger/tests/LayerState_test.cpp b/services/surfaceflinger/tests/LayerState_test.cpp
index f010786..fa1a5ed 100644
--- a/services/surfaceflinger/tests/LayerState_test.cpp
+++ b/services/surfaceflinger/tests/LayerState_test.cpp
@@ -114,34 +114,5 @@
ASSERT_EQ(results.result, results2.result);
}
-/**
- * Parcel a layer_state_t struct, and then unparcel. Ensure that the object that was parceled
- * matches the object that's unparceled.
- */
-TEST(LayerStateTest, ParcelUnparcelLayerStateT) {
- layer_state_t input;
- input.frameTimelineInfo.vsyncId = 1;
- input.frameTimelineInfo.inputEventId = 2;
- Parcel p;
- input.write(p);
- layer_state_t output;
- p.setDataPosition(0);
- output.read(p);
- ASSERT_EQ(input.frameTimelineInfo.vsyncId, output.frameTimelineInfo.vsyncId);
- ASSERT_EQ(input.frameTimelineInfo.inputEventId, output.frameTimelineInfo.inputEventId);
-}
-
-TEST(LayerStateTest, LayerStateMerge_SelectsValidInputEvent) {
- layer_state_t layer1;
- layer1.frameTimelineInfo.inputEventId = android::os::IInputConstants::INVALID_INPUT_EVENT_ID;
- layer_state_t layer2;
- layer2.frameTimelineInfo.inputEventId = 1;
- layer2.what |= layer_state_t::eFrameTimelineInfoChanged;
-
- layer1.merge(layer2);
-
- ASSERT_EQ(1, layer1.frameTimelineInfo.inputEventId);
-}
-
} // namespace test
} // namespace android
diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h
index be6665b..87c7b7d 100644
--- a/services/surfaceflinger/tests/LayerTransactionTest.h
+++ b/services/surfaceflinger/tests/LayerTransactionTest.h
@@ -298,7 +298,7 @@
// set layer stack (b/68888219)
Transaction t;
t.setDisplayLayerStack(mDisplay, mDisplayLayerStack);
- t.setCrop_legacy(mBlackBgSurface, Rect(0, 0, mDisplayWidth, mDisplayHeight));
+ t.setCrop(mBlackBgSurface, Rect(0, 0, mDisplayWidth, mDisplayHeight));
t.setLayerStack(mBlackBgSurface, mDisplayLayerStack);
t.setColor(mBlackBgSurface, half3{0, 0, 0});
t.setLayer(mBlackBgSurface, mLayerZBase);
diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
index 67db717..ac5e297 100644
--- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
@@ -145,7 +145,7 @@
sp<SurfaceControl> parent =
LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
ISurfaceComposerClient::eFXSurfaceContainer);
- Transaction().setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight)).apply();
+ Transaction().setCrop(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight)).apply();
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
@@ -199,7 +199,7 @@
if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
Transaction()
.setCornerRadius(layer, cornerRadius)
- .setCrop_legacy(layer, Rect(0, 0, size, size))
+ .setCrop(layer, Rect(0, 0, size, size))
.apply();
} else {
Transaction()
@@ -236,13 +236,13 @@
auto transaction = Transaction()
.setCornerRadius(parent, cornerRadius)
- .setCrop_legacy(parent, Rect(0, 0, size, size))
+ .setCrop(parent, Rect(0, 0, size, size))
.reparent(child, parent)
.setPosition(child, 0, size)
// Rotate by half PI
.setMatrix(child, 0.0f, -1.0f, 1.0f, 0.0f);
if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
- transaction.setCrop_legacy(parent, Rect(0, 0, size, size));
+ transaction.setCrop(parent, Rect(0, 0, size, size));
} else {
transaction.setFrame(parent, Rect(0, 0, size, size));
}
@@ -278,7 +278,7 @@
if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
Transaction()
.setCornerRadius(parent, cornerRadius)
- .setCrop_legacy(parent, Rect(0, 0, size, size))
+ .setCrop(parent, Rect(0, 0, size, size))
.reparent(child, parent)
.setPosition(child, 0, size / 2)
.apply();
@@ -351,7 +351,7 @@
Transaction()
.setLayer(blurLayer, mLayerZBase + 3)
.setBackgroundBlurRadius(blurLayer, blurRadius)
- .setCrop_legacy(blurLayer, blurRect)
+ .setCrop(blurLayer, blurRect)
.setFrame(blurLayer, blurRect)
.setSize(blurLayer, blurRect.getWidth(), blurRect.getHeight())
.setAlpha(blurLayer, 0.0f)
@@ -516,7 +516,7 @@
.setLayer(layer, INT32_MAX - 1)
.show(layer)
.setLayerStack(behindLayer, mDisplayLayerStack)
- .setCrop_legacy(behindLayer, crop)
+ .setCrop(behindLayer, crop)
.setLayer(behindLayer, INT32_MAX - 2)
.show(behindLayer)
.apply();
diff --git a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
index f8a0bc1..4753362 100644
--- a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
@@ -43,7 +43,7 @@
sp<SurfaceControl> parent =
LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
ISurfaceComposerClient::eFXSurfaceContainer);
- Transaction().setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight)).apply();
+ Transaction().setCrop(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight)).apply();
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
sp<SurfaceControl> layerB;
@@ -84,8 +84,8 @@
.setColor(parent, half3{0.0f, 0.0f, 0.0f})
.show(childLayer)
.show(parent)
- .setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight))
- .setCrop_legacy(childLayer, Rect(0, 0, 20, 30))
+ .setCrop(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight))
+ .setCrop(childLayer, Rect(0, 0, 20, 30))
.apply();
Transaction().setRelativeLayer(childLayer, parent, -1).setLayer(childLayer, 1).apply();
diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp
index ec826ae..e4a1f66 100644
--- a/services/surfaceflinger/tests/LayerUpdate_test.cpp
+++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp
@@ -131,7 +131,7 @@
asTransaction([&](Transaction& t) {
t.setSize(mFGSurfaceControl, 64, 64);
t.setPosition(mFGSurfaceControl, 64, 64);
- t.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 64, 64));
+ t.setCrop(mFGSurfaceControl, Rect(0, 0, 64, 64));
});
EXPECT_INITIAL_STATE("After restoring initial state");
@@ -225,7 +225,7 @@
PIXEL_FORMAT_RGBA_8888, 0, childNoBuffer.get());
TransactionUtils::fillSurfaceRGBA8(childBuffer, 200, 200, 200);
SurfaceComposerClient::Transaction{}
- .setCrop_legacy(childNoBuffer, Rect(0, 0, 10, 10))
+ .setCrop(childNoBuffer, Rect(0, 0, 10, 10))
.show(childNoBuffer)
.show(childBuffer)
.apply(true);
@@ -234,9 +234,7 @@
sc->expectChildColor(73, 73);
sc->expectFGColor(74, 74);
}
- SurfaceComposerClient::Transaction{}
- .setCrop_legacy(childNoBuffer, Rect(0, 0, 20, 20))
- .apply(true);
+ SurfaceComposerClient::Transaction{}.setCrop(childNoBuffer, Rect(0, 0, 20, 20)).apply(true);
{
ScreenCapture::captureScreen(&sc);
sc->expectChildColor(73, 73);
@@ -351,7 +349,7 @@
t.show(mChild);
t.setPosition(mChild, 0, 0);
t.setPosition(mFGSurfaceControl, 0, 0);
- t.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 5, 5));
+ t.setCrop(mFGSurfaceControl, Rect(0, 0, 5, 5));
});
{
@@ -947,7 +945,7 @@
ISurfaceComposerClient::eFXSurfaceEffect, cropLayer.get());
ASSERT_TRUE(colorLayer->isValid());
asTransaction([&](Transaction& t) {
- t.setCrop_legacy(cropLayer, Rect(5, 5, 10, 10));
+ t.setCrop(cropLayer, Rect(5, 5, 10, 10));
t.setColor(colorLayer, half3{0, 0, 0});
t.show(cropLayer);
t.show(colorLayer);
@@ -1007,7 +1005,7 @@
t.show(boundlessLayerRightShift);
t.setPosition(boundlessLayerDownShift, 0, 32);
t.show(boundlessLayerDownShift);
- t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
+ t.setCrop(colorLayer, Rect(0, 0, 64, 64));
t.setColor(colorLayer, half3{0, 0, 0});
t.show(colorLayer);
});
@@ -1043,7 +1041,7 @@
// expect the child layer to be cropped.
t.setPosition(boundlessLayer, 32, 32);
t.show(boundlessLayer);
- t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
+ t.setCrop(colorLayer, Rect(0, 0, 64, 64));
// undo shift by parent
t.setPosition(colorLayer, -32, -32);
t.setColor(colorLayer, half3{0, 0, 0});
@@ -1074,7 +1072,7 @@
t.setLayer(rootBoundlessLayer, INT32_MAX - 1);
t.setPosition(rootBoundlessLayer, 32, 32);
t.show(rootBoundlessLayer);
- t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
+ t.setCrop(colorLayer, Rect(0, 0, 64, 64));
t.setColor(colorLayer, half3{0, 0, 0});
t.show(colorLayer);
t.hide(mFGSurfaceControl);
diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp
index 16826c1..613b21e 100644
--- a/services/surfaceflinger/tests/MirrorLayer_test.cpp
+++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp
@@ -36,7 +36,7 @@
asTransaction([&](Transaction& t) {
t.setDisplayLayerStack(display, 0);
t.setLayer(mParentLayer, INT32_MAX - 2).show(mParentLayer);
- t.setCrop_legacy(mChildLayer, Rect(0, 0, 400, 400)).show(mChildLayer);
+ t.setCrop(mChildLayer, Rect(0, 0, 400, 400)).show(mChildLayer);
t.setPosition(mChildLayer, 50, 50);
t.setFlags(mParentLayer, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
t.setFlags(mChildLayer, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
@@ -58,7 +58,7 @@
createColorLayer("Grandchild layer", Color::BLUE, mChildLayer.get());
Transaction()
.setFlags(grandchild, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque)
- .setCrop_legacy(grandchild, Rect(0, 0, 200, 200))
+ .setCrop(grandchild, Rect(0, 0, 200, 200))
.show(grandchild)
.apply();
diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
index eaf54e3..08de01c 100644
--- a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
+++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
@@ -71,7 +71,7 @@
ASSERT_TRUE(mColorLayer->isValid());
asTransaction([&](Transaction& t) {
t.setLayerStack(mColorLayer, layerStack);
- t.setCrop_legacy(mColorLayer, Rect(0, 0, 30, 40));
+ t.setCrop(mColorLayer, Rect(0, 0, 30, 40));
t.setLayer(mColorLayer, INT32_MAX - 2);
t.setColor(mColorLayer,
half3{mExpectedColor.r / 255.0f, mExpectedColor.g / 255.0f,
diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
new file mode 100644
index 0000000..fb7d41c
--- /dev/null
+++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LayerTransactionTest.h"
+#include "utils/CallbackUtils.h"
+
+using namespace std::chrono_literals;
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+::testing::Environment* const binderEnv =
+ ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+// b/181132765 - disabled until cuttlefish failures are investigated
+class ReleaseBufferCallbackHelper {
+public:
+ static void function(void* callbackContext, uint64_t graphicsBufferId,
+ const sp<Fence>& releaseFence) {
+ if (!callbackContext) {
+ FAIL() << "failed to get callback context";
+ }
+ ReleaseBufferCallbackHelper* helper =
+ static_cast<ReleaseBufferCallbackHelper*>(callbackContext);
+ std::lock_guard lock(helper->mMutex);
+ helper->mCallbackDataQueue.emplace(graphicsBufferId, releaseFence);
+ helper->mConditionVariable.notify_all();
+ }
+
+ void getCallbackData(uint64_t* bufferId) {
+ std::unique_lock lock(mMutex);
+ if (mCallbackDataQueue.empty()) {
+ if (!mConditionVariable.wait_for(lock, std::chrono::seconds(3),
+ [&] { return !mCallbackDataQueue.empty(); })) {
+ FAIL() << "failed to get releaseBuffer callback";
+ }
+ }
+
+ auto callbackData = mCallbackDataQueue.front();
+ mCallbackDataQueue.pop();
+ *bufferId = callbackData.first;
+ }
+
+ void verifyNoCallbacks() {
+ // Wait to see if there are extra callbacks
+ std::this_thread::sleep_for(300ms);
+
+ std::lock_guard lock(mMutex);
+ EXPECT_EQ(mCallbackDataQueue.size(), 0) << "extra callbacks received";
+ mCallbackDataQueue = {};
+ }
+
+ android::ReleaseBufferCallback getCallback() {
+ return std::bind(function, static_cast<void*>(this) /* callbackContext */,
+ std::placeholders::_1, std::placeholders::_2);
+ }
+
+ std::mutex mMutex;
+ std::condition_variable mConditionVariable;
+ std::queue<std::pair<uint64_t, sp<Fence>>> mCallbackDataQueue;
+};
+
+class ReleaseBufferCallbackTest : public LayerTransactionTest {
+public:
+ virtual sp<SurfaceControl> createBufferStateLayer() {
+ return createLayer(mClient, "test", 0, 0, ISurfaceComposerClient::eFXSurfaceBufferState);
+ }
+
+ static void submitBuffer(const sp<SurfaceControl>& layer, sp<GraphicBuffer> buffer,
+ sp<Fence> fence, CallbackHelper& callback,
+ ReleaseBufferCallbackHelper& releaseCallback) {
+ Transaction t;
+ t.setBuffer(layer, buffer, releaseCallback.getCallback());
+ t.setAcquireFence(layer, fence);
+ t.addTransactionCompletedCallback(callback.function, callback.getContext());
+ t.apply();
+ }
+
+ static void waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult) {
+ CallbackData callbackData;
+ helper.getCallbackData(&callbackData);
+ expectedResult.verifyCallbackData(callbackData);
+ }
+
+ static void waitForReleaseBufferCallback(ReleaseBufferCallbackHelper& releaseCallback,
+ uint64_t expectedReleaseBufferId) {
+ uint64_t actualReleaseBufferId;
+ releaseCallback.getCallbackData(&actualReleaseBufferId);
+ EXPECT_EQ(expectedReleaseBufferId, actualReleaseBufferId);
+ releaseCallback.verifyNoCallbacks();
+ }
+ static ReleaseBufferCallbackHelper* getReleaseBufferCallbackHelper() {
+ static std::vector<ReleaseBufferCallbackHelper*> sCallbacks;
+ sCallbacks.emplace_back(new ReleaseBufferCallbackHelper());
+ return sCallbacks.back();
+ }
+
+ static sp<GraphicBuffer> getBuffer() {
+ return new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ }
+};
+
+TEST_F(ReleaseBufferCallbackTest, DISABLED_PresentBuffer) {
+ sp<SurfaceControl> layer = createBufferStateLayer();
+ CallbackHelper transactionCallback;
+ ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper();
+
+ // If a buffer is being presented, we should not emit a release callback.
+ sp<GraphicBuffer> firstBuffer = getBuffer();
+ submitBuffer(layer, firstBuffer, Fence::NO_FENCE, transactionCallback, *releaseCallback);
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED);
+ ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected));
+ EXPECT_NO_FATAL_FAILURE(releaseCallback->verifyNoCallbacks());
+
+ // if state doesn't change, no release callbacks are expected
+ Transaction t;
+ t.addTransactionCompletedCallback(transactionCallback.function,
+ transactionCallback.getContext());
+ t.apply();
+ ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, ExpectedResult()));
+ EXPECT_NO_FATAL_FAILURE(releaseCallback->verifyNoCallbacks());
+
+ // If a presented buffer is replaced, we should emit a release callback for the
+ // previously presented buffer.
+ sp<GraphicBuffer> secondBuffer = getBuffer();
+ submitBuffer(layer, secondBuffer, Fence::NO_FENCE, transactionCallback, *releaseCallback);
+ expected = ExpectedResult();
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED,
+ ExpectedResult::PreviousBuffer::RELEASED);
+ ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected));
+ ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBuffer->getId()));
+}
+
+TEST_F(ReleaseBufferCallbackTest, DISABLED_OffScreenLayer) {
+ sp<SurfaceControl> layer = createBufferStateLayer();
+
+ CallbackHelper transactionCallback;
+ ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper();
+
+ // If a buffer is being presented, we should not emit a release callback.
+ sp<GraphicBuffer> firstBuffer = getBuffer();
+ submitBuffer(layer, firstBuffer, Fence::NO_FENCE, transactionCallback, *releaseCallback);
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED);
+ ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected));
+ releaseCallback->verifyNoCallbacks();
+
+ // If a layer is parented offscreen then it should not emit a callback since sf still owns
+ // the buffer and can render it again.
+ Transaction t;
+ t.reparent(layer, nullptr);
+ t.addTransactionCompletedCallback(transactionCallback.function,
+ transactionCallback.getContext());
+ t.apply();
+ expected = ExpectedResult();
+ expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED,
+ ExpectedResult::PreviousBuffer::NOT_RELEASED);
+ ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected));
+ ASSERT_NO_FATAL_FAILURE(releaseCallback->verifyNoCallbacks());
+
+ // If a presented buffer is replaced, we should emit a release callback for the
+ // previously presented buffer.
+ sp<GraphicBuffer> secondBuffer = getBuffer();
+ submitBuffer(layer, secondBuffer, Fence::NO_FENCE, transactionCallback, *releaseCallback);
+ expected = ExpectedResult();
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED,
+ ExpectedResult::PreviousBuffer::NOT_RELEASED);
+ ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected));
+ ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBuffer->getId()));
+
+ // If continue to submit buffer we continue to get release callbacks
+ sp<GraphicBuffer> thirdBuffer = getBuffer();
+ submitBuffer(layer, thirdBuffer, Fence::NO_FENCE, transactionCallback, *releaseCallback);
+ expected = ExpectedResult();
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED,
+ ExpectedResult::PreviousBuffer::NOT_RELEASED);
+ ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected));
+ ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, secondBuffer->getId()));
+}
+
+TEST_F(ReleaseBufferCallbackTest, DISABLED_LayerLifecycle_layerdestroy) {
+ sp<SurfaceControl> layer = createBufferStateLayer();
+ CallbackHelper* transactionCallback = new CallbackHelper();
+ ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper();
+
+ // If a buffer is being presented, we should not emit a release callback.
+ sp<GraphicBuffer> firstBuffer = getBuffer();
+ submitBuffer(layer, firstBuffer, Fence::NO_FENCE, *transactionCallback, *releaseCallback);
+ {
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED);
+ ASSERT_NO_FATAL_FAILURE(waitForCallback(*transactionCallback, expected));
+ ASSERT_NO_FATAL_FAILURE(releaseCallback->verifyNoCallbacks());
+ }
+
+ // Destroying a currently presenting layer emits a callback.
+ Transaction t;
+ t.reparent(layer, nullptr);
+ t.apply();
+ layer = nullptr;
+
+ ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBuffer->getId()));
+}
+
+// Destroying a never presented layer emits a callback.
+TEST_F(ReleaseBufferCallbackTest, DISABLED_LayerLifecycle_OffScreenLayerDestroy) {
+ sp<SurfaceControl> layer = createBufferStateLayer();
+
+ // make layer offscreen
+ Transaction t;
+ t.reparent(layer, nullptr);
+ t.apply();
+
+ CallbackHelper* transactionCallback = new CallbackHelper();
+ ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper();
+
+ // Submitting a buffer does not emit a callback.
+ sp<GraphicBuffer> firstBuffer = getBuffer();
+ submitBuffer(layer, firstBuffer, Fence::NO_FENCE, *transactionCallback, *releaseCallback);
+ {
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED);
+ ASSERT_NO_FATAL_FAILURE(waitForCallback(*transactionCallback, expected));
+ ASSERT_NO_FATAL_FAILURE(releaseCallback->verifyNoCallbacks());
+ }
+
+ // Submitting a second buffer will replace the drawing state buffer and emit a callback.
+ sp<GraphicBuffer> secondBuffer = getBuffer();
+ submitBuffer(layer, secondBuffer, Fence::NO_FENCE, *transactionCallback, *releaseCallback);
+ {
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED);
+ ASSERT_NO_FATAL_FAILURE(waitForCallback(*transactionCallback, expected));
+ ASSERT_NO_FATAL_FAILURE(
+ waitForReleaseBufferCallback(*releaseCallback, firstBuffer->getId()));
+ }
+
+ // Destroying the offscreen layer emits a callback.
+ layer = nullptr;
+ ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, secondBuffer->getId()));
+}
+
+TEST_F(ReleaseBufferCallbackTest, DISABLED_FrameDropping) {
+ sp<SurfaceControl> layer = createBufferStateLayer();
+ CallbackHelper transactionCallback;
+ ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper();
+
+ // If a buffer is being presented, we should not emit a release callback.
+ sp<GraphicBuffer> firstBuffer = getBuffer();
+
+ // Try to present 100ms in the future
+ nsecs_t time = systemTime() + std::chrono::nanoseconds(100ms).count();
+
+ Transaction t;
+ t.setBuffer(layer, firstBuffer, releaseCallback->getCallback());
+ t.setAcquireFence(layer, Fence::NO_FENCE);
+ t.addTransactionCompletedCallback(transactionCallback.function,
+ transactionCallback.getContext());
+ t.setDesiredPresentTime(time);
+ t.apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED);
+ ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected));
+ EXPECT_NO_FATAL_FAILURE(releaseCallback->verifyNoCallbacks());
+
+ // Dropping frames in transaction queue emits a callback
+ sp<GraphicBuffer> secondBuffer = getBuffer();
+ t.setBuffer(layer, secondBuffer, releaseCallback->getCallback());
+ t.setAcquireFence(layer, Fence::NO_FENCE);
+ t.addTransactionCompletedCallback(transactionCallback.function,
+ transactionCallback.getContext());
+ t.setDesiredPresentTime(time);
+ t.apply();
+
+ expected = ExpectedResult();
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED,
+ ExpectedResult::PreviousBuffer::RELEASED);
+ ASSERT_NO_FATAL_FAILURE(waitForCallback(transactionCallback, expected));
+ ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBuffer->getId()));
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index 4598f9d..b0753c8 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -328,7 +328,7 @@
TEST_F(ScreenCaptureTest, CaptureBoundedLayerWithoutSourceCrop) {
sp<SurfaceControl> child = createColorLayer("Child layer", Color::RED, mFGSurfaceControl.get());
Rect layerCrop(0, 0, 10, 10);
- SurfaceComposerClient::Transaction().setCrop_legacy(child, layerCrop).show(child).apply(true);
+ SurfaceComposerClient::Transaction().setCrop(child, layerCrop).show(child).apply(true);
LayerCaptureArgs captureArgs;
captureArgs.layerHandle = child->getHandle();
@@ -623,7 +623,7 @@
.setLayerStack(layer, 0)
.setLayer(layer, INT32_MAX)
.setColor(layer, {layerColor.r / 255, layerColor.g / 255, layerColor.b / 255})
- .setCrop_legacy(layer, bounds)
+ .setCrop(layer, bounds)
.apply();
DisplayCaptureArgs captureArgs;
@@ -671,8 +671,8 @@
.setLayer(layer, INT32_MAX)
.setColor(layer, {layerColor.r / 255, layerColor.g / 255, layerColor.b / 255})
.setColor(childLayer, {childColor.r / 255, childColor.g / 255, childColor.b / 255})
- .setCrop_legacy(layer, bounds)
- .setCrop_legacy(childLayer, childBounds)
+ .setCrop(layer, bounds)
+ .setCrop(childLayer, childBounds)
.apply();
DisplayCaptureArgs captureArgs;
@@ -853,9 +853,7 @@
}
TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentCrop) {
- SurfaceComposerClient::Transaction()
- .setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 1, 1))
- .apply(true);
+ SurfaceComposerClient::Transaction().setCrop(mFGSurfaceControl, Rect(0, 0, 1, 1)).apply(true);
// Even though the parent is cropped out we should still capture the child.
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index a20d5c6..d9cab42 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -370,7 +370,7 @@
}
void SurfaceInterceptorTest::cropUpdate(Transaction& t) {
- t.setCrop_legacy(mBGSurfaceControl, CROP_UPDATE);
+ t.setCrop(mBGSurfaceControl, CROP_UPDATE);
}
void SurfaceInterceptorTest::matrixUpdate(Transaction& t) {
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 11bd9eb..820f248 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -1324,7 +1324,7 @@
{
TransactionScope ts(*sFakeComposer);
Rect cropRect(16, 16, 32, 32);
- ts.setCrop_legacy(mFGSurfaceControl, cropRect);
+ ts.setCrop(mFGSurfaceControl, cropRect);
}
ASSERT_EQ(2, sFakeComposer->getFrameCount());
@@ -1692,7 +1692,7 @@
ts.show(mChild);
ts.setPosition(mChild, 0, 0);
ts.setPosition(Base::mFGSurfaceControl, 0, 0);
- ts.setCrop_legacy(Base::mFGSurfaceControl, Rect(0, 0, 5, 5));
+ ts.setCrop(Base::mFGSurfaceControl, Rect(0, 0, 5, 5));
}
// NOTE: The foreground surface would be occluded by the child
// now, but is included in the stack because the child is
@@ -1915,7 +1915,7 @@
TransactionScope ts(*Base::sFakeComposer);
ts.setColor(Base::mChild,
{LIGHT_GRAY.r / 255.0f, LIGHT_GRAY.g / 255.0f, LIGHT_GRAY.b / 255.0f});
- ts.setCrop_legacy(Base::mChild, Rect(0, 0, 10, 10));
+ ts.setCrop(Base::mChild, Rect(0, 0, 10, 10));
}
Base::sFakeComposer->runVSyncAndWait();
@@ -2010,7 +2010,7 @@
TransactionScope ts(*Base::sFakeComposer);
ts.setSize(Base::mFGSurfaceControl, 64, 64);
ts.setPosition(Base::mFGSurfaceControl, 64, 64);
- ts.setCrop_legacy(Base::mFGSurfaceControl, Rect(0, 0, 64, 64));
+ ts.setCrop(Base::mFGSurfaceControl, Rect(0, 0, 64, 64));
}
void Test_SurfacePositionLatching() {
@@ -2043,7 +2043,7 @@
{
TransactionScope ts(*Base::sFakeComposer);
ts.setSize(Base::mFGSurfaceControl, 128, 128);
- ts.setCrop_legacy(Base::mFGSurfaceControl, Rect(0, 0, 63, 63));
+ ts.setCrop(Base::mFGSurfaceControl, Rect(0, 0, 63, 63));
}
auto referenceFrame1 = Base::mBaseFrame;
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index c3946cb..4e1c0c7 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -884,7 +884,7 @@
});
auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer);
- layerDrawingState.crop_legacy = Rect(0, 0, LayerProperties::HEIGHT, LayerProperties::WIDTH);
+ layerDrawingState.crop = Rect(0, 0, LayerProperties::HEIGHT, LayerProperties::WIDTH);
return layer;
}
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index e903664..a72ab42 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -48,6 +48,7 @@
using testing::Contains;
using testing::HasSubstr;
using testing::InSequence;
+using testing::Not;
using testing::SizeIs;
using testing::StrEq;
using testing::UnorderedElementsAre;
@@ -855,6 +856,24 @@
EXPECT_THAT(result, HasSubstr("compositionStrategyChanges = 0"));
EXPECT_THAT(result, HasSubstr("averageFrameDuration = 0.000 ms"));
EXPECT_THAT(result, HasSubstr("averageRenderEngineTiming = 0.000 ms"));
+ std::string expectedResult = "totalTimelineFrames = " + std::to_string(0);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "jankyFrames = " + std::to_string(0);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfLongCpuJankyFrames = " + std::to_string(0);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfLongGpuJankyFrames = " + std::to_string(0);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfUnattributedJankyFrames = " + std::to_string(0);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "appUnattributedJankyFrames = " + std::to_string(0);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfSchedulingJankyFrames = " + std::to_string(0);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfPredictionErrorJankyFrames = " + std::to_string(0);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "appBufferStuffingJankyFrames = " + std::to_string(0);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
}
TEST_F(TimeStatsTest, canDumpWithMaxLayers) {
@@ -1074,6 +1093,46 @@
EXPECT_EQ(0, globalProto.missed_frames());
EXPECT_EQ(0, globalProto.client_composition_frames());
EXPECT_EQ(0, globalProto.present_to_present_size());
+
+ // also check dump-only stats: expect that global stats are indeed dropped but there should
+ // still be stats for the layer
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ std::string expectedResult = "totalTimelineFrames = " + std::to_string(0);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "totalTimelineFrames = " + std::to_string(8);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "jankyFrames = " + std::to_string(0);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "jankyFrames = " + std::to_string(7);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfLongCpuJankyFrames = " + std::to_string(0);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfLongCpuJankyFrames = " + std::to_string(1);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfLongGpuJankyFrames = " + std::to_string(0);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfLongGpuJankyFrames = " + std::to_string(1);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfUnattributedJankyFrames = " + std::to_string(0);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfUnattributedJankyFrames = " + std::to_string(1);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "appUnattributedJankyFrames = " + std::to_string(0);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "appUnattributedJankyFrames = " + std::to_string(2);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfSchedulingJankyFrames = " + std::to_string(0);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfSchedulingJankyFrames = " + std::to_string(1);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfPredictionErrorJankyFrames = " + std::to_string(0);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfPredictionErrorJankyFrames = " + std::to_string(1);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "appBufferStuffingJankyFrames = " + std::to_string(0);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "appBufferStuffingJankyFrames = " + std::to_string(1);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
}
TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) {
@@ -1205,6 +1264,31 @@
ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
EXPECT_EQ(0, globalProto.stats_size());
+
+ // also check dump-only stats: expect that layer stats are indeed dropped but there should still
+ // be global stats
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ std::string expectedResult = "totalTimelineFrames = " + std::to_string(8);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "jankyFrames = " + std::to_string(7);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfLongCpuJankyFrames = " + std::to_string(1);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfLongGpuJankyFrames = " + std::to_string(1);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfUnattributedJankyFrames = " + std::to_string(1);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "appUnattributedJankyFrames = " + std::to_string(2);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfSchedulingJankyFrames = " + std::to_string(1);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "sfPredictionErrorJankyFrames = " + std::to_string(1);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+ expectedResult = "appBufferStuffingJankyFrames = " + std::to_string(1);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+
+ std::string expectedMissing = "uid = " + std::to_string(UID_0);
+ EXPECT_THAT(result, Not(HasSubstr(expectedMissing)));
}
TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleLayers) {
diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
index dbadf75..b5ef0a1 100644
--- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
@@ -123,7 +123,8 @@
traceTimestamp(layerId, bufferId, frameNumber, postTime,
FrameTracer::FrameEvent::QUEUE, /*duration*/ 0));
layer->setBuffer(buffer, fence, postTime, /*desiredPresentTime*/ 30, false, mClientCache,
- frameNumber, dequeueTime, FrameTimelineInfo{});
+ frameNumber, dequeueTime, FrameTimelineInfo{},
+ nullptr /* releaseBufferCallback */);
commitTransaction(layer.get());
bool computeVisisbleRegions;
diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
index 623a5e0..c75538f 100644
--- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
@@ -126,7 +126,7 @@
auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0});
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
acquireFence->signalForTest(12);
commitTransaction(layer.get());
@@ -151,7 +151,7 @@
auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1);
sp<GraphicBuffer> buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0});
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
const auto droppedSurfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX;
@@ -161,7 +161,7 @@
sp<GraphicBuffer> buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
nsecs_t start = systemTime();
layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0});
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
nsecs_t end = systemTime();
acquireFence2->signalForTest(12);
@@ -199,7 +199,7 @@
sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0});
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
acquireFence->signalForTest(12);
EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
@@ -225,7 +225,7 @@
sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0});
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
@@ -255,7 +255,7 @@
sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 3, /*inputEventId*/ 0});
+ {/*vsyncId*/ 3, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
EXPECT_EQ(2u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
const auto& bufferSurfaceFrameTX = layer->mCurrentState.bufferSurfaceFrameTX;
@@ -353,7 +353,7 @@
auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1);
sp<GraphicBuffer> buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0});
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
const auto droppedSurfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX;
@@ -361,7 +361,7 @@
auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2);
sp<GraphicBuffer> buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0});
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
acquireFence2->signalForTest(12);
ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
@@ -388,7 +388,7 @@
auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1);
sp<GraphicBuffer> buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0});
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
const auto droppedSurfaceFrame1 = layer->mCurrentState.bufferSurfaceFrameTX;
@@ -398,7 +398,8 @@
sp<GraphicBuffer> buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
auto dropStartTime1 = systemTime();
layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ FrameTimelineInfo::INVALID_VSYNC_ID, /*inputEventId*/ 0});
+ {/*vsyncId*/ FrameTimelineInfo::INVALID_VSYNC_ID, /*inputEventId*/ 0},
+ nullptr /* releaseBufferCallback */);
auto dropEndTime1 = systemTime();
EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
@@ -409,7 +410,7 @@
sp<GraphicBuffer> buffer3{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
auto dropStartTime2 = systemTime();
layer->setBuffer(buffer3, fence3, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 2, /*inputEventId*/ 0});
+ {/*vsyncId*/ 2, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
auto dropEndTime2 = systemTime();
acquireFence3->signalForTest(12);
@@ -448,7 +449,8 @@
sp<Fence> fence1(new Fence());
sp<GraphicBuffer> buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0});
+ {/*vsyncId*/ 1, /*inputEventId*/ 0},
+ nullptr /* releaseBufferCallback */);
layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 2,
/*inputEventId*/ 0},
10);
diff --git a/services/surfaceflinger/tests/unittests/VsyncModulatorTest.cpp b/services/surfaceflinger/tests/unittests/VsyncModulatorTest.cpp
index 106da81..17648d5 100644
--- a/services/surfaceflinger/tests/unittests/VsyncModulatorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VsyncModulatorTest.cpp
@@ -101,24 +101,6 @@
CHECK_REFRESH(1, kLate, kLate);
}
-TEST_F(VsyncModulatorTest, EarlyStartWithEarly) {
- EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyStart));
-
- CHECK_COMMIT(kEarly, kEarly);
- CHECK_REFRESH(5 * MIN_EARLY_TRANSACTION_FRAMES, std::nullopt, kEarly);
-
- EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::Early));
-
- CHECK_COMMIT(kEarly, kEarly);
- CHECK_REFRESH(5 * MIN_EARLY_TRANSACTION_FRAMES, std::nullopt, kEarly);
-
- EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyEnd));
-
- CHECK_COMMIT(kEarly, kEarly);
- CHECK_REFRESH(MIN_EARLY_TRANSACTION_FRAMES - 1, kEarly, kEarly);
- CHECK_REFRESH(1, kLate, kLate);
-}
-
TEST_F(VsyncModulatorTest, EarlyStartWithMoreTransactions) {
EXPECT_EQ(kEarly, mVsyncModulator.setTransactionSchedule(Schedule::EarlyStart));
diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
index 7efd730..ddaa5a1 100644
--- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h
+++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
@@ -85,6 +85,7 @@
void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
ASSERT_NE(nullptr, mOutBuffer);
+ ASSERT_NE(nullptr, mPixels);
ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
TransactionUtils::expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance);
}
diff --git a/services/vibratorservice/VibratorHalController.cpp b/services/vibratorservice/VibratorHalController.cpp
index 2de2e0e..70f9876 100644
--- a/services/vibratorservice/VibratorHalController.cpp
+++ b/services/vibratorservice/VibratorHalController.cpp
@@ -161,7 +161,7 @@
return apply(offFn, "off");
}
-HalResult<void> HalController::setAmplitude(int32_t amplitude) {
+HalResult<void> HalController::setAmplitude(float amplitude) {
hal_fn<void> setAmplitudeFn = [&](std::shared_ptr<HalWrapper> hal) {
return hal->setAmplitude(amplitude);
};
diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp
index 3d20fa1..baee74f 100644
--- a/services/vibratorservice/VibratorHalWrapper.cpp
+++ b/services/vibratorservice/VibratorHalWrapper.cpp
@@ -168,9 +168,8 @@
return HalResult<void>::fromStatus(getHal()->off());
}
-HalResult<void> AidlHalWrapper::setAmplitude(int32_t amplitude) {
- float convertedAmplitude = static_cast<float>(amplitude) / std::numeric_limits<uint8_t>::max();
- return HalResult<void>::fromStatus(getHal()->setAmplitude(convertedAmplitude));
+HalResult<void> AidlHalWrapper::setAmplitude(float amplitude) {
+ return HalResult<void>::fromStatus(getHal()->setAmplitude(amplitude));
}
HalResult<void> AidlHalWrapper::setExternalControl(bool enabled) {
@@ -346,8 +345,9 @@
}
template <typename I>
-HalResult<void> HidlHalWrapper<I>::setAmplitude(int32_t amplitude) {
- auto result = getHal()->setAmplitude(static_cast<uint8_t>(amplitude));
+HalResult<void> HidlHalWrapper<I>::setAmplitude(float amplitude) {
+ uint8_t amp = static_cast<uint8_t>(amplitude * std::numeric_limits<uint8_t>::max());
+ auto result = getHal()->setAmplitude(amp);
return HalResult<void>::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR));
}
diff --git a/services/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp b/services/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp
index 0acff06..f40980c 100644
--- a/services/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp
+++ b/services/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp
@@ -142,7 +142,7 @@
auto duration = 60s;
auto callback = []() {};
- auto amplitude = UINT8_MAX;
+ auto amplitude = 1.0f;
for (auto _ : state) {
state.PauseTiming();
@@ -169,7 +169,7 @@
auto duration = 6000s;
auto callback = []() {};
- auto amplitude = UINT8_MAX;
+ auto amplitude = 1.0f;
checkHalResult(mController.on(duration, callback), state);
@@ -224,7 +224,7 @@
return;
}
- auto amplitude = UINT8_MAX;
+ auto amplitude = 1.0f;
checkHalResult(mController.setExternalControl(true), state);
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalController.h b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
index 14ec7b2..f884ff0 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalController.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
@@ -61,7 +61,7 @@
const std::function<void()>& completionCallback) final override;
HalResult<void> off() final override;
- HalResult<void> setAmplitude(int32_t amplitude) final override;
+ HalResult<void> setAmplitude(float amplitude) final override;
HalResult<void> setExternalControl(bool enabled) final override;
HalResult<void> alwaysOnEnable(int32_t id, hardware::vibrator::Effect effect,
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
index 039a2d9..667702d 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
@@ -173,7 +173,7 @@
const std::function<void()>& completionCallback) = 0;
virtual HalResult<void> off() = 0;
- virtual HalResult<void> setAmplitude(int32_t amplitude) = 0;
+ virtual HalResult<void> setAmplitude(float amplitude) = 0;
virtual HalResult<void> setExternalControl(bool enabled) = 0;
virtual HalResult<void> alwaysOnEnable(int32_t id, hardware::vibrator::Effect effect,
@@ -223,7 +223,7 @@
const std::function<void()>& completionCallback) override final;
HalResult<void> off() override final;
- HalResult<void> setAmplitude(int32_t amplitude) override final;
+ HalResult<void> setAmplitude(float amplitude) override final;
HalResult<void> setExternalControl(bool enabled) override final;
HalResult<void> alwaysOnEnable(int32_t id, hardware::vibrator::Effect effect,
@@ -295,7 +295,7 @@
const std::function<void()>& completionCallback) override final;
HalResult<void> off() override final;
- HalResult<void> setAmplitude(int32_t amplitude) override final;
+ HalResult<void> setAmplitude(float amplitude) override final;
virtual HalResult<void> setExternalControl(bool enabled) override;
HalResult<void> alwaysOnEnable(int32_t id, hardware::vibrator::Effect effect,
diff --git a/services/vibratorservice/test/VibratorHalControllerTest.cpp b/services/vibratorservice/test/VibratorHalControllerTest.cpp
index 0c39247..e438d78 100644
--- a/services/vibratorservice/test/VibratorHalControllerTest.cpp
+++ b/services/vibratorservice/test/VibratorHalControllerTest.cpp
@@ -58,7 +58,7 @@
(milliseconds timeout, const std::function<void()>& completionCallback),
(override));
MOCK_METHOD(vibrator::HalResult<void>, off, (), (override));
- MOCK_METHOD(vibrator::HalResult<void>, setAmplitude, (int32_t amplitude), (override));
+ MOCK_METHOD(vibrator::HalResult<void>, setAmplitude, (float amplitude), (override));
MOCK_METHOD(vibrator::HalResult<void>, setExternalControl, (bool enabled), (override));
MOCK_METHOD(vibrator::HalResult<void>, alwaysOnEnable,
(int32_t id, Effect effect, EffectStrength strength), (override));
@@ -122,7 +122,7 @@
EXPECT_CALL(*mMockHal.get(), off())
.Times(Exactly(cardinality))
.WillRepeatedly(Return(voidResult));
- EXPECT_CALL(*mMockHal.get(), setAmplitude(Eq(255)))
+ EXPECT_CALL(*mMockHal.get(), setAmplitude(Eq(1.0f)))
.Times(Exactly(cardinality))
.WillRepeatedly(Return(voidResult));
EXPECT_CALL(*mMockHal.get(), setExternalControl(Eq(true)))
@@ -196,7 +196,7 @@
ASSERT_TRUE(mController->ping().isOk());
ASSERT_TRUE(mController->on(10ms, []() {}).isOk());
ASSERT_TRUE(mController->off().isOk());
- ASSERT_TRUE(mController->setAmplitude(255).isOk());
+ ASSERT_TRUE(mController->setAmplitude(1.0f).isOk());
ASSERT_TRUE(mController->setExternalControl(true).isOk());
ASSERT_TRUE(mController->alwaysOnEnable(1, Effect::CLICK, EffectStrength::LIGHT).isOk());
ASSERT_TRUE(mController->alwaysOnDisable(1).isOk());
@@ -249,7 +249,7 @@
ASSERT_TRUE(mController->ping().isUnsupported());
ASSERT_TRUE(mController->on(10ms, []() {}).isUnsupported());
ASSERT_TRUE(mController->off().isUnsupported());
- ASSERT_TRUE(mController->setAmplitude(255).isUnsupported());
+ ASSERT_TRUE(mController->setAmplitude(1.0f).isUnsupported());
ASSERT_TRUE(mController->setExternalControl(true).isUnsupported());
ASSERT_TRUE(
mController->alwaysOnEnable(1, Effect::CLICK, EffectStrength::LIGHT).isUnsupported());
@@ -282,7 +282,7 @@
ASSERT_TRUE(mController->ping().isFailed());
ASSERT_TRUE(mController->on(10ms, []() {}).isFailed());
ASSERT_TRUE(mController->off().isFailed());
- ASSERT_TRUE(mController->setAmplitude(255).isFailed());
+ ASSERT_TRUE(mController->setAmplitude(1.0f).isFailed());
ASSERT_TRUE(mController->setExternalControl(true).isFailed());
ASSERT_TRUE(mController->alwaysOnEnable(1, Effect::CLICK, EffectStrength::LIGHT).isFailed());
ASSERT_TRUE(mController->alwaysOnDisable(1).isFailed());
@@ -345,7 +345,7 @@
ASSERT_TRUE(mController->ping().isUnsupported());
ASSERT_TRUE(mController->on(10ms, []() {}).isUnsupported());
ASSERT_TRUE(mController->off().isUnsupported());
- ASSERT_TRUE(mController->setAmplitude(255).isUnsupported());
+ ASSERT_TRUE(mController->setAmplitude(1.0f).isUnsupported());
ASSERT_TRUE(mController->setExternalControl(true).isUnsupported());
ASSERT_TRUE(
mController->alwaysOnEnable(1, Effect::CLICK, EffectStrength::LIGHT).isUnsupported());
diff --git a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
index 5d77595..99f592f 100644
--- a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
@@ -215,19 +215,19 @@
TEST_F(VibratorHalWrapperAidlTest, TestSetAmplitude) {
{
InSequence seq;
- EXPECT_CALL(*mMockHal.get(), setAmplitude(FloatNear(0.1, 1e-2))).Times(Exactly(1));
- EXPECT_CALL(*mMockHal.get(), setAmplitude(FloatNear(0.2, 1e-2)))
+ EXPECT_CALL(*mMockHal.get(), setAmplitude(Eq(0.1f))).Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), setAmplitude(Eq(0.2f)))
.Times(Exactly(1))
.WillRepeatedly(Return(
Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
- EXPECT_CALL(*mMockHal.get(), setAmplitude(FloatNear(0.5, 1e-2)))
+ EXPECT_CALL(*mMockHal.get(), setAmplitude(Eq(0.5f)))
.Times(Exactly(1))
.WillRepeatedly(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)));
}
- ASSERT_TRUE(mWrapper->setAmplitude(std::numeric_limits<uint8_t>::max() / 10).isOk());
- ASSERT_TRUE(mWrapper->setAmplitude(std::numeric_limits<uint8_t>::max() / 5).isUnsupported());
- ASSERT_TRUE(mWrapper->setAmplitude(std::numeric_limits<uint8_t>::max() / 2).isFailed());
+ ASSERT_TRUE(mWrapper->setAmplitude(0.1f).isOk());
+ ASSERT_TRUE(mWrapper->setAmplitude(0.2f).isUnsupported());
+ ASSERT_TRUE(mWrapper->setAmplitude(0.5f).isFailed());
}
TEST_F(VibratorHalWrapperAidlTest, TestSetExternalControl) {
diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
index 06aa36f..33c47cf 100644
--- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
@@ -147,7 +147,7 @@
TEST_F(VibratorHalWrapperHidlV1_0Test, TestSetAmplitude) {
{
InSequence seq;
- EXPECT_CALL(*mMockHal.get(), setAmplitude(static_cast<uint8_t>(1)))
+ EXPECT_CALL(*mMockHal.get(), setAmplitude(Eq(static_cast<uint8_t>(1))))
.Times(Exactly(1))
.WillRepeatedly(
[](uint8_t) { return hardware::Return<V1_0::Status>(V1_0::Status::OK); });
@@ -168,10 +168,11 @@
});
}
- ASSERT_TRUE(mWrapper->setAmplitude(1).isOk());
- ASSERT_TRUE(mWrapper->setAmplitude(2).isUnsupported());
- ASSERT_TRUE(mWrapper->setAmplitude(3).isFailed());
- ASSERT_TRUE(mWrapper->setAmplitude(4).isFailed());
+ auto maxAmplitude = std::numeric_limits<uint8_t>::max();
+ ASSERT_TRUE(mWrapper->setAmplitude(1.0f / maxAmplitude).isOk());
+ ASSERT_TRUE(mWrapper->setAmplitude(2.0f / maxAmplitude).isUnsupported());
+ ASSERT_TRUE(mWrapper->setAmplitude(3.0f / maxAmplitude).isFailed());
+ ASSERT_TRUE(mWrapper->setAmplitude(4.0f / maxAmplitude).isFailed());
}
TEST_F(VibratorHalWrapperHidlV1_0Test, TestSetExternalControlUnsupported) {
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index a513239..438e5dd 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -842,6 +842,8 @@
bool ret = true;
switch (device->properties.apiVersion ^
VK_VERSION_PATCH(device->properties.apiVersion)) {
+ case VK_API_VERSION_1_2:
+ FALLTHROUGH_INTENDED;
case VK_API_VERSION_1_1:
ret &=
visitor->Visit("subgroupProperties", &device->subgroup_properties) &&
@@ -896,6 +898,8 @@
inline bool Iterate(Visitor* visitor, VkJsonInstance* instance) {
bool ret = true;
switch (instance->api_version ^ VK_VERSION_PATCH(instance->api_version)) {
+ case VK_API_VERSION_1_2:
+ FALLTHROUGH_INTENDED;
case VK_API_VERSION_1_1:
ret &= visitor->Visit("deviceGroups", &instance->device_groups);
FALLTHROUGH_INTENDED;