Merge "GPU Memory: align the clock for perfetto tracing"
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 9017563..eb6870e 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -25,9 +25,6 @@
"view_compiler.cpp",
":installd_aidl",
],
- header_libs: [
- "dex2oat_headers",
- ],
shared_libs: [
"libbase",
"libbinder",
@@ -240,8 +237,6 @@
"view_compiler.cpp",
],
- header_libs: ["dex2oat_headers"],
-
static_libs: [
"libdiskusage",
"libotapreoptparameters",
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 2b36067..82ea746 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -39,7 +39,6 @@
#include <cutils/fs.h>
#include <cutils/properties.h>
#include <cutils/sched_policy.h>
-#include <dex2oat_return_codes.h>
#include <log/log.h> // TODO: Move everything to base/logging.
#include <openssl/sha.h>
#include <private/android_filesystem_config.h>
diff --git a/cmds/installd/dexopt_return_codes.h b/cmds/installd/dexopt_return_codes.h
index bbecfa4..e5198ad 100644
--- a/cmds/installd/dexopt_return_codes.h
+++ b/cmds/installd/dexopt_return_codes.h
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include <dex2oat_return_codes.h>
-
namespace android {
namespace installd {
@@ -70,48 +68,21 @@
return nullptr;
}
-inline const char* get_dex2oat_return_code_name(art::dex2oat::ReturnCode code) {
- switch (code) {
- case art::dex2oat::ReturnCode::kNoFailure:
- return "dex2oat success";
- case art::dex2oat::ReturnCode::kOther:
- return "unspecified dex2oat error";
- case art::dex2oat::ReturnCode::kCreateRuntime:
- return "dex2oat failed to create a runtime";
+inline const char* get_dex2oat_return_code_name(int code) {
+ if (code == 0) {
+ return "dex2oat success";
+ } else {
+ return "dex2oat error";
}
- return nullptr;
}
-// Get some slightly descriptive string for the return code. Handles both DexoptReturnCodes (local
-// exit codes) as well as art::dex2oat::ReturnCode.
+// Get some slightly descriptive string for the return code.
inline const char* get_return_code_name(int code) {
- // Try to enforce non-overlap (see comment on DexoptReturnCodes)
- // TODO: How could switch-case checks be used to enforce completeness?
- switch (code) {
- case kSetGid:
- case kSetUid:
- case kCapSet:
- case kFlock:
- case kProfmanExec:
- case kSetSchedPolicy:
- case kSetPriority:
- case kDex2oatExec:
- case kInstructionSetLength:
- case kHashValidatePath:
- case kHashOpenPath:
- case kHashReadDex:
- case kHashWrite:
- break;
- case static_cast<int>(art::dex2oat::ReturnCode::kNoFailure):
- case static_cast<int>(art::dex2oat::ReturnCode::kOther):
- case static_cast<int>(art::dex2oat::ReturnCode::kCreateRuntime):
- break;
- }
const char* value = get_installd_return_code_name(static_cast<DexoptReturnCodes>(code));
if (value != nullptr) {
return value;
}
- value = get_dex2oat_return_code_name(static_cast<art::dex2oat::ReturnCode>(code));
+ value = get_dex2oat_return_code_name(code);
return value;
}
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 5981014..443821c 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -33,7 +33,6 @@
#include <android-base/strings.h>
#include <cutils/fs.h>
#include <cutils/properties.h>
-#include <dex2oat_return_codes.h>
#include <log/log.h>
#include <private/android_filesystem_config.h>
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 96f5e44..fbf1e0c 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -663,7 +663,7 @@
&status);
EXPECT_STREQ(status.toString8().c_str(),
"Status(-8, EX_SERVICE_SPECIFIC): \'256: Dex2oat invocation for "
- "/data/app/com.installd.test.dexopt/base.jar failed: unspecified dex2oat error'");
+ "/data/app/com.installd.test.dexopt/base.jar failed: dex2oat error'");
}
TEST_F(DexoptTest, DexoptPrimaryProfileNonPublic) {
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
index 6d04f13..233f12a 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -133,7 +133,11 @@
OP_DEPRECATED_1 = 96,
OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED = 97,
OP_AUTO_REVOKE_MANAGED_BY_INSTALLER = 98,
- _NUM_OP = 99
+ OP_NO_ISOLATED_STORAGE = 99,
+ OP_PHONE_CALL_MICROPHONE = 100,
+ OP_PHONE_CALL_CAMERA = 101,
+ OP_RECORD_AUDIO_HOTWORD = 102,
+ _NUM_OP = 103
};
AppOpsManager();
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index b72c854..468cc16 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -234,6 +234,7 @@
"android.gui.IGraphicBufferConsumer",
"android.gui.IRegionSamplingListener",
"android.gui.ITransactionComposerListener",
+ "android.gui.IScreenCaptureListener",
"android.gui.SensorEventConnection",
"android.gui.SensorServer",
"android.hardware.ICamera",
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index 16811ee..0234820 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -3,12 +3,24 @@
crate_name: "binder",
srcs: ["src/lib.rs"],
shared_libs: [
- "libbinder_ndk",
"libutils",
],
rustlibs: [
"liblibc",
- "libbinder_ndk_bindgen",
+ "libbinder_ndk_sys",
+ ],
+ host_supported: true,
+}
+
+rust_library {
+ name: "libbinder_ndk_sys",
+ crate_name: "binder_ndk_sys",
+ srcs: [
+ "sys/lib.rs",
+ ":libbinder_ndk_bindgen",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
],
host_supported: true,
}
@@ -16,8 +28,8 @@
rust_bindgen {
name: "libbinder_ndk_bindgen",
crate_name: "binder_ndk_bindgen",
- wrapper_src: "BinderBindings.h",
- source_stem: "ndk_bindings",
+ wrapper_src: "sys/BinderBindings.h",
+ source_stem: "bindings",
cflags: [
"-x c++",
],
@@ -69,6 +81,6 @@
],
rustlibs: [
"liblibc",
- "libbinder_ndk_bindgen",
+ "libbinder_ndk_sys",
],
}
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index f5e7509..d55eafe 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -61,7 +61,7 @@
/// the AIDL backend, users need only implement the high-level AIDL-defined
/// interface. The AIDL compiler then generates a container struct that wraps
/// the user-defined service and implements `Remotable`.
-pub trait Remotable: Sync {
+pub trait Remotable: Send + Sync {
/// The Binder interface descriptor string.
///
/// This string is a unique identifier for a Binder interface, and should be
diff --git a/libs/binder/rust/src/error.rs b/libs/binder/rust/src/error.rs
index 289b157..4492cf7 100644
--- a/libs/binder/rust/src/error.rs
+++ b/libs/binder/rust/src/error.rs
@@ -43,14 +43,6 @@
}
}
-// impl Display for StatusCode {
-// fn fmt(&self, f: &mut Formatter) -> FmtResult {
-// write!(f, "StatusCode::{:?}", self)
-// }
-// }
-
-// impl error::Error for StatusCode {}
-
fn parse_status_code(code: i32) -> StatusCode {
match code {
e if e == StatusCode::OK as i32 => StatusCode::OK,
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 4b9cccf..8ee6a62 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -102,7 +102,7 @@
mod native;
mod state;
-use binder_ndk_bindgen as sys;
+use binder_ndk_sys as sys;
pub mod parcel;
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index 798fed8..185645e 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -36,6 +36,18 @@
rust_object: *mut T,
}
+/// # Safety
+///
+/// A `Binder<T>` is a pair of unique owning pointers to two values:
+/// * a C++ ABBinder which the C++ API guarantees can be passed between threads
+/// * a Rust object which implements `Remotable`; this trait requires `Send + Sync`
+///
+/// Both pointers are unique (never escape the `Binder<T>` object and are not copied)
+/// so we can essentially treat `Binder<T>` as a box-like containing the two objects;
+/// the box-like object inherits `Send` from the two inner values, similarly
+/// to how `Box<T>` is `Send` if `T` is `Send`.
+unsafe impl<T: Remotable> Send for Binder<T> {}
+
impl<T: Remotable> Binder<T> {
/// Create a new Binder remotable object.
///
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index 43850fe..a248f5c 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -21,6 +21,7 @@
use crate::proxy::SpIBinder;
use crate::sys;
+use std::cell::RefCell;
use std::convert::TryInto;
use std::mem::ManuallyDrop;
use std::ptr;
@@ -117,6 +118,55 @@
}
}
+ /// Perform a series of writes to the `Parcel`, prepended with the length
+ /// (in bytes) of the written data.
+ ///
+ /// The length `0i32` will be written to the parcel first, followed by the
+ /// writes performed by the callback. The initial length will then be
+ /// updated to the length of all data written by the callback, plus the
+ /// size of the length elemement itself (4 bytes).
+ ///
+ /// # Examples
+ ///
+ /// After the following call:
+ ///
+ /// ```
+ /// # use binder::{Binder, Interface, Parcel};
+ /// # let mut parcel = Parcel::Owned(std::ptr::null_mut());
+ /// parcel.sized_write(|subparcel| {
+ /// subparcel.write(&1u32)?;
+ /// subparcel.write(&2u32)?;
+ /// subparcel.write(&3u32)
+ /// });
+ /// ```
+ ///
+ /// `parcel` will contain the following:
+ ///
+ /// ```ignore
+ /// [16i32, 1u32, 2u32, 3u32]
+ /// ```
+ pub fn sized_write<F>(&mut self, f: F) -> Result<()>
+ where for<'a>
+ F: Fn(&'a WritableSubParcel<'a>) -> Result<()>
+ {
+ let start = self.get_data_position();
+ self.write(&0i32)?;
+ {
+ let subparcel = WritableSubParcel(RefCell::new(self));
+ f(&subparcel)?;
+ }
+ let end = self.get_data_position();
+ unsafe {
+ self.set_data_position(start)?;
+ }
+ assert!(end >= start);
+ self.write(&(end - start))?;
+ unsafe {
+ self.set_data_position(end)?;
+ }
+ Ok(())
+ }
+
/// Returns the current position in the parcel data.
pub fn get_data_position(&self) -> i32 {
unsafe {
@@ -143,6 +193,16 @@
}
}
+/// A segment of a writable parcel, used for [`Parcel::sized_write`].
+pub struct WritableSubParcel<'a>(RefCell<&'a mut Parcel>);
+
+impl<'a> WritableSubParcel<'a> {
+ /// Write a type that implements [`Serialize`] to the sub-parcel.
+ pub fn write<S: Serialize + ?Sized>(&self, parcelable: &S) -> Result<()> {
+ parcelable.serialize(&mut *self.0.borrow_mut())
+ }
+}
+
// Data deserialization methods
impl Parcel {
/// Attempt to read a type that implements [`Deserialize`] from this
@@ -445,3 +505,38 @@
);
assert_eq!(parcel.read::<Vec<String>>().unwrap(), [s1, s2, s3]);
}
+
+#[test]
+fn test_sized_write() {
+ use crate::binder::Interface;
+ use crate::native::Binder;
+
+ let mut service = Binder::new(()).as_binder();
+ let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+ let start = parcel.get_data_position();
+
+ let arr = [1i32, 2i32, 3i32];
+
+ parcel.sized_write(|subparcel| {
+ subparcel.write(&arr[..])
+ }).expect("Could not perform sized write");
+
+ // i32 sub-parcel length + i32 array length + 3 i32 elements
+ let expected_len = 20i32;
+
+ assert_eq!(parcel.get_data_position(), start + expected_len);
+
+ unsafe {
+ parcel.set_data_position(start).unwrap();
+ }
+
+ assert_eq!(
+ expected_len,
+ parcel.read().unwrap(),
+ );
+
+ assert_eq!(
+ parcel.read::<Vec<i32>>().unwrap(),
+ &arr,
+ );
+}
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index f9519b4..13e5619 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -122,6 +122,14 @@
}
}
+impl PartialEq for SpIBinder {
+ fn eq(&self, other: &Self) -> bool {
+ ptr::eq(self.0, other.0)
+ }
+}
+
+impl Eq for SpIBinder {}
+
impl Clone for SpIBinder {
fn clone(&self) -> Self {
unsafe {
@@ -363,6 +371,18 @@
assert!(!ptr.is_null());
Self(ptr)
}
+
+ /// Promote this weak reference to a strong reference to the binder object.
+ pub fn promote(&self) -> Option<SpIBinder> {
+ unsafe {
+ // Safety: `WpIBinder` always contains a valid weak reference, so we
+ // can pass this pointer to `AIBinder_Weak_promote`. Returns either
+ // null or an AIBinder owned by the caller, both of which are valid
+ // to pass to `SpIBinder::from_raw`.
+ let ptr = sys::AIBinder_Weak_promote(self.0);
+ SpIBinder::from_raw(ptr)
+ }
+ }
}
/// Rust wrapper around DeathRecipient objects.
diff --git a/libs/binder/rust/BinderBindings.h b/libs/binder/rust/sys/BinderBindings.h
similarity index 100%
rename from libs/binder/rust/BinderBindings.h
rename to libs/binder/rust/sys/BinderBindings.h
diff --git a/libs/binder/rust/sys/lib.rs b/libs/binder/rust/sys/lib.rs
new file mode 100644
index 0000000..9095af2
--- /dev/null
+++ b/libs/binder/rust/sys/lib.rs
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Generated Rust bindings to libbinder_ndk
+
+#![allow(
+ non_camel_case_types,
+ non_snake_case,
+ non_upper_case_globals,
+ unused,
+ improper_ctypes,
+ missing_docs
+)]
+use std::error::Error;
+use std::fmt;
+
+include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
+
+impl Error for android_c_interface_StatusCode {}
+
+impl fmt::Display for android_c_interface_StatusCode {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "StatusCode::{:?}", self)
+ }
+}
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 686e274..9285b23 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -62,6 +62,7 @@
"IGraphicBufferProducer.cpp",
"IProducerListener.cpp",
"IRegionSamplingListener.cpp",
+ "IScreenCaptureListener.cpp",
"ISurfaceComposer.cpp",
"ISurfaceComposerClient.cpp",
"ITransactionCompletedListener.cpp",
diff --git a/libs/gui/IScreenCaptureListener.cpp b/libs/gui/IScreenCaptureListener.cpp
new file mode 100644
index 0000000..0635e9c
--- /dev/null
+++ b/libs/gui/IScreenCaptureListener.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/IScreenCaptureListener.h>
+#include <gui/LayerState.h>
+
+namespace android {
+
+namespace { // Anonymous
+
+enum class Tag : uint32_t {
+ ON_SCREEN_CAPTURE_COMPLETE = IBinder::FIRST_CALL_TRANSACTION,
+ LAST = ON_SCREEN_CAPTURE_COMPLETE,
+};
+
+} // Anonymous namespace
+
+class BpScreenCaptureListener : public SafeBpInterface<IScreenCaptureListener> {
+public:
+ explicit BpScreenCaptureListener(const sp<IBinder>& impl)
+ : SafeBpInterface<IScreenCaptureListener>(impl, "BpScreenCaptureListener") {}
+
+ ~BpScreenCaptureListener() override;
+
+ status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override {
+ Parcel data, reply;
+ data.writeInterfaceToken(IScreenCaptureListener::getInterfaceDescriptor());
+
+ SAFE_PARCEL(captureResults.write, data);
+ return remote()->transact(static_cast<uint32_t>(Tag::ON_SCREEN_CAPTURE_COMPLETE), data,
+ &reply, IBinder::FLAG_ONEWAY);
+ }
+};
+
+// Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see
+// clang warning -Wweak-vtables)
+BpScreenCaptureListener::~BpScreenCaptureListener() = default;
+
+IMPLEMENT_META_INTERFACE(ScreenCaptureListener, "android.gui.IScreenCaptureListener");
+
+status_t BnScreenCaptureListener::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags) {
+ auto tag = static_cast<Tag>(code);
+ switch (tag) {
+ case Tag::ON_SCREEN_CAPTURE_COMPLETE: {
+ CHECK_INTERFACE(IScreenCaptureListener, data, reply);
+ ScreenCaptureResults captureResults;
+ SAFE_PARCEL(captureResults.read, data);
+ return onScreenCaptureComplete(captureResults);
+ }
+ default: {
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+ }
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 2c50acc..0ac493d 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -109,52 +109,33 @@
}
virtual status_t captureDisplay(const DisplayCaptureArgs& args,
- ScreenCaptureResults& captureResults) {
+ const sp<IScreenCaptureListener>& captureListener) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-
SAFE_PARCEL(args.write, data);
- status_t result = remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY, data, &reply);
- if (result != NO_ERROR) {
- ALOGE("captureDisplay failed to transact: %d", result);
- return result;
- }
+ SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(captureListener));
- SAFE_PARCEL(captureResults.read, reply);
- return NO_ERROR;
+ return remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY, data, &reply);
}
virtual status_t captureDisplay(uint64_t displayOrLayerStack,
- ScreenCaptureResults& captureResults) {
+ const sp<IScreenCaptureListener>& captureListener) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- SAFE_PARCEL(data.writeUint64, displayOrLayerStack)
- status_t result =
- remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY_BY_ID, data, &reply);
- if (result != NO_ERROR) {
- ALOGE("captureDisplay failed to transact: %d", result);
- return result;
- }
+ SAFE_PARCEL(data.writeUint64, displayOrLayerStack);
+ SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(captureListener));
- SAFE_PARCEL(captureResults.read, reply);
- return NO_ERROR;
+ return remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY_BY_ID, data, &reply);
}
virtual status_t captureLayers(const LayerCaptureArgs& args,
- ScreenCaptureResults& captureResults) {
+ const sp<IScreenCaptureListener>& captureListener) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-
SAFE_PARCEL(args.write, data);
+ SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(captureListener));
- status_t result = remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply);
- if (result != NO_ERROR) {
- ALOGE("captureLayers failed to transact: %d", result);
- return result;
- }
-
- SAFE_PARCEL(captureResults.read, reply);
- return NO_ERROR;
+ return remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply);
}
virtual bool authenticateSurfaceTexture(
@@ -1251,37 +1232,29 @@
case CAPTURE_DISPLAY: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
DisplayCaptureArgs args;
- ScreenCaptureResults captureResults;
-
+ sp<IScreenCaptureListener> captureListener;
SAFE_PARCEL(args.read, data);
- status_t res = captureDisplay(args, captureResults);
- if (res == NO_ERROR) {
- SAFE_PARCEL(captureResults.write, *reply);
- }
- return res;
+ SAFE_PARCEL(data.readStrongBinder, &captureListener);
+
+ return captureDisplay(args, captureListener);
}
case CAPTURE_DISPLAY_BY_ID: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
uint64_t displayOrLayerStack = 0;
+ sp<IScreenCaptureListener> captureListener;
SAFE_PARCEL(data.readUint64, &displayOrLayerStack);
- ScreenCaptureResults captureResults;
- status_t res = captureDisplay(displayOrLayerStack, captureResults);
- if (res == NO_ERROR) {
- SAFE_PARCEL(captureResults.write, *reply);
- }
- return res;
+ SAFE_PARCEL(data.readStrongBinder, &captureListener);
+
+ return captureDisplay(displayOrLayerStack, captureListener);
}
case CAPTURE_LAYERS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
LayerCaptureArgs args;
- ScreenCaptureResults captureResults;
-
+ sp<IScreenCaptureListener> captureListener;
SAFE_PARCEL(args.read, data);
- status_t res = captureLayers(args, captureResults);
- if (res == NO_ERROR) {
- SAFE_PARCEL(captureResults.write, *reply);
- }
- return res;
+ SAFE_PARCEL(data.readStrongBinder, &captureListener);
+
+ return captureLayers(args, captureListener);
}
case AUTHENTICATE_SURFACE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 62f7c23..3b0b392 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -607,19 +607,31 @@
}
status_t ScreenCaptureResults::write(Parcel& output) const {
- SAFE_PARCEL(output.write, *buffer);
+ if (buffer != nullptr) {
+ SAFE_PARCEL(output.writeBool, true);
+ SAFE_PARCEL(output.write, *buffer);
+ } else {
+ SAFE_PARCEL(output.writeBool, false);
+ }
SAFE_PARCEL(output.writeBool, capturedSecureLayers);
SAFE_PARCEL(output.writeUint32, static_cast<uint32_t>(capturedDataspace));
+ SAFE_PARCEL(output.writeInt32, result);
return NO_ERROR;
}
status_t ScreenCaptureResults::read(const Parcel& input) {
- buffer = new GraphicBuffer();
- SAFE_PARCEL(input.read, *buffer);
+ bool hasGraphicBuffer;
+ SAFE_PARCEL(input.readBool, &hasGraphicBuffer);
+ if (hasGraphicBuffer) {
+ buffer = new GraphicBuffer();
+ SAFE_PARCEL(input.read, *buffer);
+ }
+
SAFE_PARCEL(input.readBool, &capturedSecureLayers);
uint32_t dataspace = 0;
SAFE_PARCEL(input.readUint32, &dataspace);
capturedDataspace = static_cast<ui::Dataspace>(dataspace);
+ SAFE_PARCEL(input.readInt32, &result);
return NO_ERROR;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 62a3c45..65a1a01 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1921,26 +1921,57 @@
}
// ----------------------------------------------------------------------------
+status_t SyncScreenCaptureListener::onScreenCaptureComplete(
+ const ScreenCaptureResults& captureResults) {
+ resultsPromise.set_value(captureResults);
+ return NO_ERROR;
+}
+
+ScreenCaptureResults SyncScreenCaptureListener::waitForResults() {
+ std::future<ScreenCaptureResults> resultsFuture = resultsPromise.get_future();
+ return resultsFuture.get();
+}
status_t ScreenshotClient::captureDisplay(const DisplayCaptureArgs& captureArgs,
ScreenCaptureResults& captureResults) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == nullptr) return NO_INIT;
- return s->captureDisplay(captureArgs, captureResults);
+
+ sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
+ status_t status = s->captureDisplay(captureArgs, captureListener);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ captureResults = captureListener->waitForResults();
+ return captureResults.result;
}
status_t ScreenshotClient::captureDisplay(uint64_t displayOrLayerStack,
ScreenCaptureResults& captureResults) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == nullptr) return NO_INIT;
- return s->captureDisplay(displayOrLayerStack, captureResults);
+
+ sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
+ status_t status = s->captureDisplay(displayOrLayerStack, captureListener);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ captureResults = captureListener->waitForResults();
+ return captureResults.result;
}
status_t ScreenshotClient::captureLayers(const LayerCaptureArgs& captureArgs,
ScreenCaptureResults& captureResults) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == nullptr) return NO_INIT;
- return s->captureLayers(captureArgs, captureResults);
+
+ sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
+ status_t status = s->captureLayers(captureArgs, captureListener);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ captureResults = captureListener->waitForResults();
+ return captureResults.result;
}
} // namespace android
diff --git a/libs/gui/include/gui/IScreenCaptureListener.h b/libs/gui/include/gui/IScreenCaptureListener.h
new file mode 100644
index 0000000..a2ddc9f
--- /dev/null
+++ b/libs/gui/include/gui/IScreenCaptureListener.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/Binder.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <binder/SafeInterface.h>
+
+namespace android {
+
+struct ScreenCaptureResults;
+
+// TODO(b/166271443): Convert to AIDL
+class IScreenCaptureListener : public IInterface {
+public:
+ DECLARE_META_INTERFACE(ScreenCaptureListener)
+
+ virtual status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) = 0;
+};
+
+class BnScreenCaptureListener : public SafeBnInterface<IScreenCaptureListener> {
+public:
+ BnScreenCaptureListener()
+ : SafeBnInterface<IScreenCaptureListener>("BnScreenCaptureListener") {}
+
+ status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0) override;
+};
+
+} // namespace android
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index e955ea8..e057b68 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -22,6 +22,7 @@
#include <binder/IBinder.h>
#include <binder/IInterface.h>
+#include <gui/IScreenCaptureListener.h>
#include <gui/ITransactionCompletedListener.h>
#include <math/vec4.h>
@@ -255,10 +256,10 @@
* match the size of the output buffer.
*/
virtual status_t captureDisplay(const DisplayCaptureArgs& args,
- ScreenCaptureResults& captureResults) = 0;
+ const sp<IScreenCaptureListener>& captureListener) = 0;
virtual status_t captureDisplay(uint64_t displayOrLayerStack,
- ScreenCaptureResults& captureResults) = 0;
+ const sp<IScreenCaptureListener>& captureListener) = 0;
template <class AA>
struct SpHash {
@@ -271,7 +272,7 @@
* is a secure window on screen
*/
virtual status_t captureLayers(const LayerCaptureArgs& args,
- ScreenCaptureResults& captureResults) = 0;
+ const sp<IScreenCaptureListener>& captureListener) = 0;
/* Clears the frame statistics for animations.
*
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 653d849..47d62fe 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -369,6 +369,7 @@
sp<GraphicBuffer> buffer;
bool capturedSecureLayers{false};
ui::Dataspace capturedDataspace{ui::Dataspace::V0_SRGB};
+ status_t result = NO_ERROR;
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 1a9710a..05151ba 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -18,6 +18,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <future>
#include <set>
#include <unordered_map>
#include <unordered_set>
@@ -593,10 +594,17 @@
// ---------------------------------------------------------------------------
+class SyncScreenCaptureListener : public BnScreenCaptureListener {
+public:
+ status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override;
+ ScreenCaptureResults waitForResults();
+
+private:
+ std::promise<ScreenCaptureResults> resultsPromise;
+};
+
class ScreenshotClient {
public:
- // if cropping isn't required, callers may pass in a default Rect, e.g.:
- // capture(display, producer, Rect(), reqWidth, ...);
static status_t captureDisplay(const DisplayCaptureArgs& captureArgs,
ScreenCaptureResults& captureResults);
static status_t captureDisplay(uint64_t displayOrLayerStack,
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index d88c477..4a186b1 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -203,6 +203,20 @@
ASSERT_EQ(false, ::testing::Test::HasFailure());
}
+ static status_t captureDisplay(DisplayCaptureArgs& captureArgs,
+ ScreenCaptureResults& captureResults) {
+ const auto sf = ComposerService::getComposerService();
+ SurfaceComposerClient::Transaction().apply(true);
+
+ const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
+ status_t status = sf->captureDisplay(captureArgs, captureListener);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ captureResults = captureListener->waitForResults();
+ return captureResults.result;
+ }
+
sp<SurfaceComposerClient> mClient;
sp<ISurfaceComposer> mComposer;
@@ -306,7 +320,7 @@
adapter.waitForCallbacks();
// capture screen and verify that it is red
- ASSERT_EQ(NO_ERROR, mComposer->captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
ASSERT_NO_FATAL_FAILURE(
checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
}
@@ -383,7 +397,7 @@
adapter.waitForCallbacks();
// capture screen and verify that it is red
- ASSERT_EQ(NO_ERROR, mComposer->captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
ASSERT_NO_FATAL_FAILURE(
checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
@@ -440,7 +454,7 @@
adapter.waitForCallbacks();
// capture screen and verify that it is red
- ASSERT_EQ(NO_ERROR, mComposer->captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
ASSERT_NO_FATAL_FAILURE(
checkScreenCapture(r, g, b,
@@ -481,7 +495,7 @@
ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint);
adapter.waitForCallbacks();
- ASSERT_EQ(NO_ERROR, mComposer->captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
switch (tr) {
case ui::Transform::ROT_0:
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 9fd8c42..aedba2a 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -197,6 +197,20 @@
ASSERT_EQ(NO_ERROR, surface->disconnect(NATIVE_WINDOW_API_CPU));
}
+ static status_t captureDisplay(DisplayCaptureArgs& captureArgs,
+ ScreenCaptureResults& captureResults) {
+ const auto sf = ComposerService::getComposerService();
+ SurfaceComposerClient::Transaction().apply(true);
+
+ const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
+ status_t status = sf->captureDisplay(captureArgs, captureListener);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ captureResults = captureListener->waitForResults();
+ return captureResults.result;
+ }
+
sp<Surface> mSurface;
sp<SurfaceComposerClient> mComposerClient;
sp<SurfaceControl> mSurfaceControl;
@@ -250,7 +264,7 @@
captureArgs.height = 64;
ScreenCaptureResults captureResults;
- ASSERT_EQ(NO_ERROR, sf->captureDisplay(captureArgs, captureResults));
+ ASSERT_EQ(NO_ERROR, captureDisplay(captureArgs, captureResults));
ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(),
NATIVE_WINDOW_API_CPU));
@@ -280,7 +294,7 @@
&buf));
ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1));
}
- ASSERT_EQ(NO_ERROR, sf->captureDisplay(captureArgs, captureResults));
+ ASSERT_EQ(NO_ERROR, captureDisplay(captureArgs, captureResults));
}
TEST_F(SurfaceTest, ConcreteTypeIsSurface) {
@@ -743,7 +757,7 @@
status_t setActiveColorMode(const sp<IBinder>& /*display*/,
ColorMode /*colorMode*/) override { return NO_ERROR; }
status_t captureDisplay(const DisplayCaptureArgs& /* captureArgs */,
- ScreenCaptureResults& /* captureResults */) override {
+ const sp<IScreenCaptureListener>& /* captureListener */) override {
return NO_ERROR;
}
status_t getAutoLowLatencyModeSupport(const sp<IBinder>& /*display*/,
@@ -757,11 +771,12 @@
}
void setGameContentType(const sp<IBinder>& /*display*/, bool /*on*/) override {}
status_t captureDisplay(uint64_t /*displayOrLayerStack*/,
- ScreenCaptureResults& /* captureResults */) override {
+ const sp<IScreenCaptureListener>& /* captureListener */) override {
return NO_ERROR;
}
- virtual status_t captureLayers(const LayerCaptureArgs& /* captureArgs */,
- ScreenCaptureResults& /* captureResults */) override {
+ virtual status_t captureLayers(
+ const LayerCaptureArgs& /* captureArgs */,
+ const sp<IScreenCaptureListener>& /* captureListener */) override {
return NO_ERROR;
}
status_t clearAnimationFrameStats() override { return NO_ERROR; }
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 0157a7f..b24855d 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -61,7 +61,7 @@
constexpr auto timeForRegionSampling = 5000000ns;
constexpr auto maxRegionSamplingSkips = 10;
-constexpr auto defaultRegionSamplingOffset = -3ms;
+constexpr auto defaultRegionSamplingWorkDuration = 3ms;
constexpr auto defaultRegionSamplingPeriod = 100ms;
constexpr auto defaultRegionSamplingTimerTimeout = 100ms;
// TODO: (b/127403193) duration to string conversion could probably be constexpr
@@ -73,9 +73,9 @@
RegionSamplingThread::EnvironmentTimingTunables::EnvironmentTimingTunables() {
char value[PROPERTY_VALUE_MAX] = {};
- property_get("debug.sf.region_sampling_offset_ns", value,
- toNsString(defaultRegionSamplingOffset).c_str());
- int const samplingOffsetNsRaw = atoi(value);
+ property_get("debug.sf.region_sampling_duration_ns", value,
+ toNsString(defaultRegionSamplingWorkDuration).c_str());
+ int const samplingDurationNsRaw = atoi(value);
property_get("debug.sf.region_sampling_period_ns", value,
toNsString(defaultRegionSamplingPeriod).c_str());
@@ -87,22 +87,26 @@
if ((samplingPeriodNsRaw < 0) || (samplingTimerTimeoutNsRaw < 0)) {
ALOGW("User-specified sampling tuning options nonsensical. Using defaults");
- mSamplingOffset = defaultRegionSamplingOffset;
+ mSamplingDuration = defaultRegionSamplingWorkDuration;
mSamplingPeriod = defaultRegionSamplingPeriod;
mSamplingTimerTimeout = defaultRegionSamplingTimerTimeout;
} else {
- mSamplingOffset = std::chrono::nanoseconds(samplingOffsetNsRaw);
+ mSamplingDuration = std::chrono::nanoseconds(samplingDurationNsRaw);
mSamplingPeriod = std::chrono::nanoseconds(samplingPeriodNsRaw);
mSamplingTimerTimeout = std::chrono::nanoseconds(samplingTimerTimeoutNsRaw);
}
}
-struct SamplingOffsetCallback : DispSync::Callback {
+struct SamplingOffsetCallback : VSyncSource::Callback {
SamplingOffsetCallback(RegionSamplingThread& samplingThread, Scheduler& scheduler,
- std::chrono::nanoseconds targetSamplingOffset)
+ std::chrono::nanoseconds targetSamplingWorkDuration)
: mRegionSamplingThread(samplingThread),
- mScheduler(scheduler),
- mTargetSamplingOffset(targetSamplingOffset) {}
+ mTargetSamplingWorkDuration(targetSamplingWorkDuration),
+ mVSyncSource(scheduler.makePrimaryDispSyncSource("SamplingThreadDispSyncListener", 0ns,
+ 0ns,
+ /*traceVsync=*/false)) {
+ mVSyncSource->setCallback(this);
+ }
~SamplingOffsetCallback() { stopVsyncListener(); }
@@ -114,8 +118,7 @@
if (mVsyncListening) return;
mPhaseIntervalSetting = Phase::ZERO;
- mScheduler.getPrimaryDispSync().addEventListener("SamplingThreadDispSyncListener", 0, this,
- mLastCallbackTime);
+ mVSyncSource->setVSyncEnabled(true);
mVsyncListening = true;
}
@@ -128,23 +131,24 @@
void stopVsyncListenerLocked() /*REQUIRES(mMutex)*/ {
if (!mVsyncListening) return;
- mScheduler.getPrimaryDispSync().removeEventListener(this, &mLastCallbackTime);
+ mVSyncSource->setVSyncEnabled(false);
mVsyncListening = false;
}
- void onDispSyncEvent(nsecs_t /*when*/, nsecs_t /*expectedVSyncTimestamp*/) final {
+ void onVSyncEvent(nsecs_t /*when*/, nsecs_t /*expectedVSyncTimestamp*/,
+ nsecs_t /*deadlineTimestamp*/) final {
std::unique_lock<decltype(mMutex)> lock(mMutex);
if (mPhaseIntervalSetting == Phase::ZERO) {
ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForSamplePhase));
mPhaseIntervalSetting = Phase::SAMPLING;
- mScheduler.getPrimaryDispSync().changePhaseOffset(this, mTargetSamplingOffset.count());
+ mVSyncSource->setDuration(mTargetSamplingWorkDuration, 0ns);
return;
}
if (mPhaseIntervalSetting == Phase::SAMPLING) {
mPhaseIntervalSetting = Phase::ZERO;
- mScheduler.getPrimaryDispSync().changePhaseOffset(this, 0);
+ mVSyncSource->setDuration(0ns, 0ns);
stopVsyncListenerLocked();
lock.unlock();
mRegionSamplingThread.notifySamplingOffset();
@@ -153,16 +157,15 @@
}
RegionSamplingThread& mRegionSamplingThread;
- Scheduler& mScheduler;
- const std::chrono::nanoseconds mTargetSamplingOffset;
+ const std::chrono::nanoseconds mTargetSamplingWorkDuration;
mutable std::mutex mMutex;
- nsecs_t mLastCallbackTime = 0;
enum class Phase {
ZERO,
SAMPLING
} mPhaseIntervalSetting /*GUARDED_BY(mMutex) macro doesnt work with unique_lock?*/
= Phase::ZERO;
bool mVsyncListening /*GUARDED_BY(mMutex)*/ = false;
+ std::unique_ptr<VSyncSource> mVSyncSource;
};
RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler,
@@ -170,11 +173,12 @@
: mFlinger(flinger),
mScheduler(scheduler),
mTunables(tunables),
- mIdleTimer(std::chrono::duration_cast<std::chrono::milliseconds>(
- mTunables.mSamplingTimerTimeout),
- [] {}, [this] { checkForStaleLuma(); }),
+ mIdleTimer(
+ std::chrono::duration_cast<std::chrono::milliseconds>(
+ mTunables.mSamplingTimerTimeout),
+ [] {}, [this] { checkForStaleLuma(); }),
mPhaseCallback(std::make_unique<SamplingOffsetCallback>(*this, mScheduler,
- tunables.mSamplingOffset)),
+ tunables.mSamplingDuration)),
lastSampleTime(0ns) {
mThread = std::thread([this]() { threadMain(); });
pthread_setname_np(mThread.native_handle(), "RegionSamplingThread");
@@ -183,7 +187,7 @@
RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger, Scheduler& scheduler)
: RegionSamplingThread(flinger, scheduler,
- TimingTunables{defaultRegionSamplingOffset,
+ TimingTunables{defaultRegionSamplingWorkDuration,
defaultRegionSamplingPeriod,
defaultRegionSamplingTimerTimeout}) {}
diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h
index b9b7a3c..0defdb3 100644
--- a/services/surfaceflinger/RegionSamplingThread.h
+++ b/services/surfaceflinger/RegionSamplingThread.h
@@ -43,10 +43,10 @@
class RegionSamplingThread : public IBinder::DeathRecipient {
public:
struct TimingTunables {
- // debug.sf.sampling_offset_ns
- // When asynchronously collecting sample, the offset, from zero phase in the vsync timeline
- // at which the sampling should start.
- std::chrono::nanoseconds mSamplingOffset;
+ // debug.sf.sampling_duration_ns
+ // When asynchronously collecting sample, the duration, at which the sampling should start
+ // before a vsync
+ std::chrono::nanoseconds mSamplingDuration;
// debug.sf.sampling_period_ns
// This is the maximum amount of time the luma recieving client
// should have to wait for a new luma value after a frame is updated. The inverse of this is
diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h
index 7b2c9c3..f34aabc 100644
--- a/services/surfaceflinger/Scheduler/DispSync.h
+++ b/services/surfaceflinger/Scheduler/DispSync.h
@@ -32,32 +32,15 @@
class DispSync {
public:
- class Callback {
- public:
- Callback() = default;
- virtual ~Callback() = default;
- virtual void onDispSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) = 0;
-
- protected:
- Callback(Callback const&) = delete;
- Callback& operator=(Callback const&) = delete;
- };
-
DispSync() = default;
virtual ~DispSync() = default;
- virtual void reset() = 0;
virtual bool addPresentFence(const std::shared_ptr<FenceTime>&) = 0;
virtual void beginResync() = 0;
virtual bool addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod,
bool* periodFlushed) = 0;
- virtual void endResync() = 0;
virtual void setPeriod(nsecs_t period) = 0;
virtual nsecs_t getPeriod() = 0;
- virtual status_t addEventListener(const char* name, nsecs_t phase, Callback* callback,
- nsecs_t lastCallbackTime) = 0;
- virtual status_t removeEventListener(Callback* callback, nsecs_t* outLastCallback) = 0;
- virtual status_t changePhaseOffset(Callback* callback, nsecs_t phase) = 0;
virtual nsecs_t computeNextRefresh(int periodOffset, nsecs_t now) const = 0;
virtual void setIgnorePresentFences(bool ignore) = 0;
virtual nsecs_t expectedPresentTime(nsecs_t now) = 0;
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index 8752b66..75f072d 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.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"
-
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include "DispSyncSource.h"
@@ -29,34 +25,129 @@
#include "DispSync.h"
#include "EventThread.h"
-namespace android {
+namespace android::scheduler {
using base::StringAppendF;
+using namespace std::chrono_literals;
-DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
+// The DispSync interface has a 'repeat this callback at rate' semantic. This object adapts
+// VSyncDispatch's individually-scheduled callbacks so as to meet DispSync's existing semantic
+// for now.
+class CallbackRepeater {
+public:
+ CallbackRepeater(VSyncDispatch& dispatch, VSyncDispatch::Callback cb, const char* name,
+ std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration,
+ std::chrono::nanoseconds notBefore)
+ : mName(name),
+ mCallback(cb),
+ mRegistration(dispatch,
+ std::bind(&CallbackRepeater::callback, this, std::placeholders::_1,
+ std::placeholders::_2, std::placeholders::_3),
+ mName),
+ mStarted(false),
+ mWorkDuration(workDuration),
+ mReadyDuration(readyDuration),
+ mLastCallTime(notBefore) {}
+
+ ~CallbackRepeater() {
+ std::lock_guard lock(mMutex);
+ mRegistration.cancel();
+ }
+
+ void start(std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration) {
+ std::lock_guard lock(mMutex);
+ mStarted = true;
+ mWorkDuration = workDuration;
+ mReadyDuration = readyDuration;
+
+ auto const scheduleResult =
+ mRegistration.schedule({.workDuration = mWorkDuration.count(),
+ .readyDuration = mReadyDuration.count(),
+ .earliestVsync = mLastCallTime.count()});
+ LOG_ALWAYS_FATAL_IF((scheduleResult != scheduler::ScheduleResult::Scheduled),
+ "Error scheduling callback: rc %X", scheduleResult);
+ }
+
+ void stop() {
+ std::lock_guard lock(mMutex);
+ LOG_ALWAYS_FATAL_IF(!mStarted, "DispSyncInterface misuse: callback already stopped");
+ mStarted = false;
+ mRegistration.cancel();
+ }
+
+ void dump(std::string& result) const {
+ std::lock_guard lock(mMutex);
+ const auto relativeLastCallTime =
+ mLastCallTime - std::chrono::steady_clock::now().time_since_epoch();
+ StringAppendF(&result, "\t%s: ", mName.c_str());
+ StringAppendF(&result, "mWorkDuration=%.2f mReadyDuration=%.2f last vsync time ",
+ mWorkDuration.count() / 1e6f, mReadyDuration.count() / 1e6f);
+ StringAppendF(&result, "%.2fms relative to now (%s)\n", relativeLastCallTime.count() / 1e6f,
+ mStarted ? "running" : "stopped");
+ }
+
+private:
+ void callback(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) {
+ {
+ std::lock_guard lock(mMutex);
+ mLastCallTime = std::chrono::nanoseconds(vsyncTime);
+ }
+
+ mCallback(vsyncTime, wakeupTime, readyTime);
+
+ {
+ std::lock_guard lock(mMutex);
+ if (!mStarted) {
+ return;
+ }
+ auto const scheduleResult =
+ mRegistration.schedule({.workDuration = mWorkDuration.count(),
+ .readyDuration = mReadyDuration.count(),
+ .earliestVsync = vsyncTime});
+ LOG_ALWAYS_FATAL_IF((scheduleResult != ScheduleResult::Scheduled),
+ "Error rescheduling callback: rc %X", scheduleResult);
+ }
+ }
+
+ const std::string mName;
+ scheduler::VSyncDispatch::Callback mCallback;
+
+ mutable std::mutex mMutex;
+ VSyncCallbackRegistration mRegistration GUARDED_BY(mMutex);
+ bool mStarted GUARDED_BY(mMutex) = false;
+ std::chrono::nanoseconds mWorkDuration GUARDED_BY(mMutex) = 0ns;
+ std::chrono::nanoseconds mReadyDuration GUARDED_BY(mMutex) = 0ns;
+ std::chrono::nanoseconds mLastCallTime GUARDED_BY(mMutex) = 0ns;
+};
+
+DispSyncSource::DispSyncSource(scheduler::VSyncDispatch& vSyncDispatch,
+ std::chrono::nanoseconds workDuration,
+ std::chrono::nanoseconds readyDuration, bool traceVsync,
const char* name)
: mName(name),
mValue(base::StringPrintf("VSYNC-%s", name), 0),
mTraceVsync(traceVsync),
mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)),
- mDispSync(dispSync),
- mPhaseOffset(base::StringPrintf("VsyncOffset-%s", name), phaseOffset) {}
+ mWorkDuration(base::StringPrintf("VsyncWorkDuration-%s", name), workDuration),
+ mReadyDuration(readyDuration) {
+ mCallbackRepeater =
+ std::make_unique<CallbackRepeater>(vSyncDispatch,
+ std::bind(&DispSyncSource::onVsyncCallback, this,
+ std::placeholders::_1,
+ std::placeholders::_2,
+ std::placeholders::_3),
+ name, workDuration, readyDuration,
+ std::chrono::steady_clock::now().time_since_epoch());
+}
+
+DispSyncSource::~DispSyncSource() = default;
void DispSyncSource::setVSyncEnabled(bool enable) {
std::lock_guard lock(mVsyncMutex);
if (enable) {
- status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
- static_cast<DispSync::Callback*>(this),
- mLastCallbackTime);
- if (err != NO_ERROR) {
- ALOGE("error registering vsync callback: %s (%d)", strerror(-err), err);
- }
+ mCallbackRepeater->start(mWorkDuration, mReadyDuration);
// ATRACE_INT(mVsyncOnLabel.c_str(), 1);
} else {
- status_t err = mDispSync->removeEventListener(static_cast<DispSync::Callback*>(this),
- &mLastCallbackTime);
- if (err != NO_ERROR) {
- ALOGE("error unregistering vsync callback: %s (%d)", strerror(-err), err);
- }
+ mCallbackRepeater->stop();
// ATRACE_INT(mVsyncOnLabel.c_str(), 0);
}
mEnabled = enable;
@@ -67,32 +158,22 @@
mCallback = callback;
}
-void DispSyncSource::setPhaseOffset(nsecs_t phaseOffset) {
+void DispSyncSource::setDuration(std::chrono::nanoseconds workDuration,
+ std::chrono::nanoseconds readyDuration) {
std::lock_guard lock(mVsyncMutex);
- const nsecs_t period = mDispSync->getPeriod();
-
- // Normalize phaseOffset to [-period, period)
- const int numPeriods = phaseOffset / period;
- phaseOffset -= numPeriods * period;
- if (mPhaseOffset == phaseOffset) {
- return;
- }
-
- mPhaseOffset = phaseOffset;
+ mWorkDuration = workDuration;
+ mReadyDuration = readyDuration;
// If we're not enabled, we don't need to mess with the listeners
if (!mEnabled) {
return;
}
- status_t err =
- mDispSync->changePhaseOffset(static_cast<DispSync::Callback*>(this), mPhaseOffset);
- if (err != NO_ERROR) {
- ALOGE("error changing vsync offset: %s (%d)", strerror(-err), err);
- }
+ mCallbackRepeater->start(mWorkDuration, mReadyDuration);
}
-void DispSyncSource::onDispSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) {
+void DispSyncSource::onVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime,
+ nsecs_t readyTime) {
VSyncSource::Callback* callback;
{
std::lock_guard lock(mCallbackMutex);
@@ -104,17 +185,13 @@
}
if (callback != nullptr) {
- callback->onVSyncEvent(when, expectedVSyncTimestamp);
+ callback->onVSyncEvent(targetWakeupTime, vsyncTime, readyTime);
}
}
void DispSyncSource::dump(std::string& result) const {
std::lock_guard lock(mVsyncMutex);
StringAppendF(&result, "DispSyncSource: %s(%s)\n", mName, mEnabled ? "enabled" : "disabled");
- mDispSync->dump(result);
}
-} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h
index 2aee3f6..2fce235 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.h
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.h
@@ -18,45 +18,47 @@
#include <mutex>
#include <string>
-#include "DispSync.h"
#include "EventThread.h"
#include "TracedOrdinal.h"
+#include "VSyncDispatch.h"
-namespace android {
+namespace android::scheduler {
+class CallbackRepeater;
-class DispSyncSource final : public VSyncSource, private DispSync::Callback {
+class DispSyncSource final : public VSyncSource {
public:
- DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, const char* name);
+ DispSyncSource(VSyncDispatch& vSyncDispatch, std::chrono::nanoseconds workDuration,
+ std::chrono::nanoseconds readyDuration, bool traceVsync, const char* name);
- ~DispSyncSource() override = default;
+ ~DispSyncSource() override;
// The following methods are implementation of VSyncSource.
const char* getName() const override { return mName; }
void setVSyncEnabled(bool enable) override;
void setCallback(VSyncSource::Callback* callback) override;
- void setPhaseOffset(nsecs_t phaseOffset) override;
+ void setDuration(std::chrono::nanoseconds workDuration,
+ std::chrono::nanoseconds readyDuration) override;
void dump(std::string&) const override;
private:
- // The following method is the implementation of the DispSync::Callback.
- void onDispSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) override;
+ void onVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime);
const char* const mName;
TracedOrdinal<int> mValue;
const bool mTraceVsync;
const std::string mVsyncOnLabel;
- nsecs_t mLastCallbackTime GUARDED_BY(mVsyncMutex) = 0;
- DispSync* mDispSync;
+ std::unique_ptr<CallbackRepeater> mCallbackRepeater;
std::mutex mCallbackMutex;
VSyncSource::Callback* mCallback GUARDED_BY(mCallbackMutex) = nullptr;
mutable std::mutex mVsyncMutex;
- TracedOrdinal<nsecs_t> mPhaseOffset GUARDED_BY(mVsyncMutex);
+ TracedOrdinal<std::chrono::nanoseconds> mWorkDuration GUARDED_BY(mVsyncMutex);
+ std::chrono::nanoseconds mReadyDuration GUARDED_BY(mVsyncMutex);
bool mEnabled GUARDED_BY(mVsyncMutex) = false;
};
-} // namespace android
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 846190c..559626b 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -200,9 +200,10 @@
mThread.join();
}
-void EventThread::setPhaseOffset(nsecs_t phaseOffset) {
+void EventThread::setDuration(std::chrono::nanoseconds workDuration,
+ std::chrono::nanoseconds readyDuration) {
std::lock_guard<std::mutex> lock(mMutex);
- mVSyncSource->setPhaseOffset(phaseOffset);
+ mVSyncSource->setDuration(workDuration, readyDuration);
}
sp<EventThreadConnection> EventThread::createEventConnection(
@@ -283,7 +284,8 @@
mCondition.notify_all();
}
-void EventThread::onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp) {
+void EventThread::onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp,
+ nsecs_t /*deadlineTimestamp*/) {
std::lock_guard<std::mutex> lock(mMutex);
LOG_FATAL_IF(!mVSyncState);
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 49f624c..fa1ca64 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -57,7 +57,8 @@
class Callback {
public:
virtual ~Callback() {}
- virtual void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) = 0;
+ virtual void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp,
+ nsecs_t deadlineTimestamp) = 0;
};
virtual ~VSyncSource() {}
@@ -65,7 +66,8 @@
virtual const char* getName() const = 0;
virtual void setVSyncEnabled(bool enable) = 0;
virtual void setCallback(Callback* callback) = 0;
- virtual void setPhaseOffset(nsecs_t phaseOffset) = 0;
+ virtual void setDuration(std::chrono::nanoseconds workDuration,
+ std::chrono::nanoseconds readyDuration) = 0;
virtual void dump(std::string& result) const = 0;
};
@@ -116,7 +118,8 @@
virtual void dump(std::string& result) const = 0;
- virtual void setPhaseOffset(nsecs_t phaseOffset) = 0;
+ virtual void setDuration(std::chrono::nanoseconds workDuration,
+ std::chrono::nanoseconds readyDuration) = 0;
virtual status_t registerDisplayEventConnection(
const sp<EventThreadConnection>& connection) = 0;
@@ -157,7 +160,8 @@
void dump(std::string& result) const override;
- void setPhaseOffset(nsecs_t phaseOffset) override;
+ void setDuration(std::chrono::nanoseconds workDuration,
+ std::chrono::nanoseconds readyDuration) override;
size_t getEventThreadConnectionCount() override;
@@ -177,7 +181,8 @@
REQUIRES(mMutex);
// Implements VSyncSource::Callback
- void onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp) override;
+ void onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp,
+ nsecs_t deadlineTimestamp) override;
const std::unique_ptr<VSyncSource> mVSyncSource GUARDED_BY(mMutex);
diff --git a/services/surfaceflinger/Scheduler/InjectVSyncSource.h b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
index 975c9db..016b076 100644
--- a/services/surfaceflinger/Scheduler/InjectVSyncSource.h
+++ b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
@@ -35,16 +35,17 @@
mCallback = callback;
}
- void onInjectSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) {
+ void onInjectSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp,
+ nsecs_t deadlineTimestamp) {
std::lock_guard<std::mutex> lock(mCallbackMutex);
if (mCallback) {
- mCallback->onVSyncEvent(when, expectedVSyncTimestamp);
+ mCallback->onVSyncEvent(when, expectedVSyncTimestamp, deadlineTimestamp);
}
}
const char* getName() const override { return "inject"; }
void setVSyncEnabled(bool) override {}
- void setPhaseOffset(nsecs_t) override {}
+ void setDuration(std::chrono::nanoseconds, std::chrono::nanoseconds) override {}
void dump(std::string&) const override {}
private:
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 5f7b2c2..b0b5e2e 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -95,6 +95,26 @@
} // namespace
+class PredictedVsyncTracer {
+public:
+ PredictedVsyncTracer(scheduler::VSyncDispatch& dispatch)
+ : mRegistration(dispatch, std::bind(&PredictedVsyncTracer::callback, this),
+ "PredictedVsyncTracer") {
+ scheduleRegistration();
+ }
+
+private:
+ TracedOrdinal<bool> mParity = {"VSYNC-predicted", 0};
+ scheduler::VSyncCallbackRegistration mRegistration;
+
+ void scheduleRegistration() { mRegistration.schedule({0, 0, 0}); }
+
+ void callback() {
+ mParity = !mParity;
+ scheduleRegistration();
+ }
+};
+
Scheduler::Scheduler(const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& callback)
: Scheduler(configs, callback,
{.supportKernelTimer = sysprop::support_kernel_idle_timer(false),
@@ -145,7 +165,11 @@
mVsyncSchedule(std::move(schedule)),
mLayerHistory(std::move(layerHistory)),
mSchedulerCallback(schedulerCallback),
- mRefreshRateConfigs(configs) {
+ mRefreshRateConfigs(configs),
+ mPredictedVsyncTracer(
+ base::GetBoolProperty("debug.sf.show_predicted_vsync", false)
+ ? std::make_unique<PredictedVsyncTracer>(*mVsyncSchedule.dispatch)
+ : nullptr) {
mSchedulerCallback.setVsyncEnabled(false);
}
@@ -163,9 +187,9 @@
// TODO(b/144707443): Tune constants.
constexpr size_t pendingFenceLimit = 20;
- auto sync = std::make_unique<scheduler::VSyncReactor>(std::move(clock), *dispatch, *tracker,
- pendingFenceLimit,
- options.supportKernelTimer);
+ auto sync =
+ std::make_unique<scheduler::VSyncReactor>(std::move(clock), *tracker, pendingFenceLimit,
+ options.supportKernelTimer);
return {std::move(sync), std::move(tracker), std::move(dispatch)};
}
@@ -184,16 +208,18 @@
return *mVsyncSchedule.sync;
}
-std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource(const char* name,
- nsecs_t phaseOffsetNs) {
- return std::make_unique<DispSyncSource>(&getPrimaryDispSync(), phaseOffsetNs,
- true /* traceVsync */, name);
+std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource(
+ const char* name, std::chrono::nanoseconds workDuration,
+ std::chrono::nanoseconds readyDuration, bool traceVsync) {
+ return std::make_unique<scheduler::DispSyncSource>(*mVsyncSchedule.dispatch, workDuration,
+ readyDuration, traceVsync, name);
}
Scheduler::ConnectionHandle Scheduler::createConnection(
- const char* connectionName, nsecs_t phaseOffsetNs,
+ const char* connectionName, std::chrono::nanoseconds workDuration,
+ std::chrono::nanoseconds readyDuration,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
- auto vsyncSource = makePrimaryDispSyncSource(connectionName, phaseOffsetNs);
+ auto vsyncSource = makePrimaryDispSyncSource(connectionName, workDuration, readyDuration);
auto eventThread = std::make_unique<impl::EventThread>(std::move(vsyncSource),
std::move(interceptCallback));
return createConnection(std::move(eventThread));
@@ -286,9 +312,10 @@
mConnections.at(handle).thread->dump(result);
}
-void Scheduler::setPhaseOffset(ConnectionHandle handle, nsecs_t phaseOffset) {
+void Scheduler::setDuration(ConnectionHandle handle, std::chrono::nanoseconds workDuration,
+ std::chrono::nanoseconds readyDuration) {
RETURN_IF_INVALID_HANDLE(handle);
- mConnections[handle].thread->setPhaseOffset(phaseOffset);
+ mConnections[handle].thread->setDuration(workDuration, readyDuration);
}
void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats) {
@@ -318,12 +345,12 @@
return mInjectorConnectionHandle;
}
-bool Scheduler::injectVSync(nsecs_t when, nsecs_t expectedVSyncTime) {
+bool Scheduler::injectVSync(nsecs_t when, nsecs_t expectedVSyncTime, nsecs_t deadlineTimestamp) {
if (!mInjectVSyncs || !mVSyncInjector) {
return false;
}
- mVSyncInjector->onInjectSyncEvent(when, expectedVSyncTime);
+ mVSyncInjector->onInjectSyncEvent(when, expectedVSyncTime, deadlineTimestamp);
return true;
}
@@ -340,7 +367,6 @@
std::lock_guard<std::mutex> lock(mHWVsyncLock);
if (mPrimaryHWVsyncEnabled) {
mSchedulerCallback.setVsyncEnabled(false);
- getPrimaryDispSync().endResync();
mPrimaryHWVsyncEnabled = false;
}
if (makeUnavailable) {
@@ -598,6 +624,15 @@
mLayerHistory ? mLayerHistory->dump().c_str() : "(no layer history)");
}
+void Scheduler::dumpVSync(std::string& s) const {
+ using base::StringAppendF;
+
+ StringAppendF(&s, "VSyncReactor:\n");
+ mVsyncSchedule.sync->dump(s);
+ StringAppendF(&s, "VSyncDispatch:\n");
+ mVsyncSchedule.dispatch->dump(s);
+}
+
template <class T>
bool Scheduler::handleTimerStateChanged(T* currentState, T newState) {
HwcConfigIndexType newConfigId;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index ed68b86..9a4ac36 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -43,6 +43,7 @@
class DispSync;
class FenceTime;
class InjectVSyncSource;
+class PredictedVsyncTracer;
namespace scheduler {
class VSyncDispatch;
@@ -71,7 +72,9 @@
DispSync& getPrimaryDispSync();
using ConnectionHandle = scheduler::ConnectionHandle;
- ConnectionHandle createConnection(const char* connectionName, nsecs_t phaseOffsetNs,
+ ConnectionHandle createConnection(const char* connectionName,
+ std::chrono::nanoseconds workDuration,
+ std::chrono::nanoseconds readyDuration,
impl::EventThread::InterceptVSyncsCallback);
sp<IDisplayEventConnection> createDisplayEventConnection(ConnectionHandle,
@@ -88,17 +91,16 @@
void onScreenAcquired(ConnectionHandle);
void onScreenReleased(ConnectionHandle);
- // Modifies phase offset in the event thread.
- void setPhaseOffset(ConnectionHandle, nsecs_t phaseOffset);
+ // Modifies work duration in the event thread.
+ void setDuration(ConnectionHandle, std::chrono::nanoseconds workDuration,
+ std::chrono::nanoseconds readyDuration);
void getDisplayStatInfo(DisplayStatInfo* stats);
// Returns injector handle if injection has toggled, or an invalid handle otherwise.
ConnectionHandle enableVSyncInjection(bool enable);
-
// Returns false if injection is disabled.
- bool injectVSync(nsecs_t when, nsecs_t expectedVSyncTime);
-
+ bool injectVSync(nsecs_t when, nsecs_t expectedVSyncTime, nsecs_t deadlineTimestamp);
void enableHardwareVsync();
void disableHardwareVsync(bool makeUnavailable);
@@ -136,6 +138,7 @@
void dump(std::string&) const;
void dump(ConnectionHandle, std::string&) const;
+ void dumpVSync(std::string&) const;
// Get the appropriate refresh for current conditions.
std::optional<HwcConfigIndexType> getPreferredConfigId();
@@ -151,6 +154,11 @@
size_t getEventThreadConnectionCount(ConnectionHandle handle);
+ std::unique_ptr<VSyncSource> makePrimaryDispSyncSource(const char* name,
+ std::chrono::nanoseconds workDuration,
+ std::chrono::nanoseconds readyDuration,
+ bool traceVsync = true);
+
private:
friend class TestableScheduler;
@@ -186,8 +194,6 @@
static std::unique_ptr<LayerHistory> createLayerHistory(const scheduler::RefreshRateConfigs&,
bool useContentDetectionV2);
- std::unique_ptr<VSyncSource> makePrimaryDispSyncSource(const char* name, nsecs_t phaseOffsetNs);
-
// Create a connection on the given EventThread.
ConnectionHandle createConnection(std::unique_ptr<EventThread>);
sp<EventThreadConnection> createConnectionInternal(EventThread*,
@@ -280,6 +286,8 @@
std::optional<hal::VsyncPeriodChangeTimeline> mLastVsyncPeriodChangeTimeline
GUARDED_BY(mVsyncTimelineLock);
static constexpr std::chrono::nanoseconds MAX_VSYNC_APPLIED_TIME = 200ms;
+
+ const std::unique_ptr<PredictedVsyncTracer> mPredictedVsyncTracer;
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatch.h b/services/surfaceflinger/Scheduler/VSyncDispatch.h
index 2a2d7c5..0407900 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatch.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h
@@ -40,11 +40,13 @@
/*
* A callback that can be registered to be awoken at a given time relative to a vsync event.
- * \param [in] vsyncTime The timestamp of the vsync the callback is for.
- * \param [in] targetWakeupTime The timestamp of intended wakeup time of the cb.
- *
+ * \param [in] vsyncTime: The timestamp of the vsync the callback is for.
+ * \param [in] targetWakeupTime: The timestamp of intended wakeup time of the cb.
+ * \param [in] readyTime: The timestamp of intended time where client needs to finish
+ * its work by.
*/
- using Callback = std::function<void(nsecs_t vsyncTime, nsecs_t targetWakeupTime)>;
+ using Callback =
+ std::function<void(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime)>;
/*
* Registers a callback that will be called at designated points on the vsync timeline.
@@ -71,33 +73,54 @@
virtual void unregisterCallback(CallbackToken token) = 0;
/*
+ * Timing information about a scheduled callback
+ *
+ * @workDuration: The time needed for the client to perform its work
+ * @readyDuration: The time needed for the client to be ready before a vsync event.
+ * For external (non-SF) clients, not only do we need to account for their
+ * workDuration, but we also need to account for the time SF will take to
+ * process their buffer/transaction. In this case, readyDuration will be set
+ * to the SF duration in order to provide enough end-to-end time, and to be
+ * able to provide the ready-by time (deadline) on the callback.
+ * For internal clients, we don't need to add additional padding, so
+ * readyDuration will typically be 0.
+ * @earliestVsync: The targeted display time. This will be snapped to the closest
+ * predicted vsync time after earliestVsync.
+ *
+ * callback will be dispatched at 'workDuration + readyDuration' nanoseconds before a vsync
+ * event.
+ */
+ struct ScheduleTiming {
+ nsecs_t workDuration = 0;
+ nsecs_t readyDuration = 0;
+ nsecs_t earliestVsync = 0;
+ };
+
+ /*
* Schedules the registered callback to be dispatched.
*
- * The callback will be dispatched at 'workDuration' nanoseconds before a vsync event.
+ * The callback will be dispatched at 'workDuration + readyDuration' nanoseconds before a vsync
+ * event.
*
* The caller designates the earliest vsync event that should be targeted by the earliestVsync
* parameter.
- * The callback will be scheduled at (workDuration - predictedVsync), where predictedVsync
- * is the first vsync event time where ( predictedVsync >= earliestVsync ).
+ * The callback will be scheduled at (workDuration + readyDuration - predictedVsync), where
+ * predictedVsync is the first vsync event time where ( predictedVsync >= earliestVsync ).
*
- * If (workDuration - earliestVsync) is in the past, or if a callback has already been
- * dispatched for the predictedVsync, an error will be returned.
+ * If (workDuration + readyDuration - earliestVsync) is in the past, or if a callback has
+ * already been dispatched for the predictedVsync, an error will be returned.
*
* It is valid to reschedule a callback to a different time.
*
* \param [in] token The callback to schedule.
- * \param [in] workDuration The time before the actual vsync time to invoke the callback
- * associated with token.
- * \param [in] earliestVsync The targeted display time. This will be snapped to the closest
- * predicted vsync time after earliestVsync.
+ * \param [in] scheduleTiming The timing information for this schedule call
* \return A ScheduleResult::Scheduled if callback was scheduled.
* A ScheduleResult::CannotSchedule
- * if (workDuration - earliestVsync) is in the past, or
- * if a callback was dispatched for the predictedVsync already.
- * A ScheduleResult::Error if there was another error.
+ * if (workDuration + readyDuration - earliestVsync) is in the past,
+ * or if a callback was dispatched for the predictedVsync already. A ScheduleResult::Error if
+ * there was another error.
*/
- virtual ScheduleResult schedule(CallbackToken token, nsecs_t workDuration,
- nsecs_t earliestVsync) = 0;
+ virtual ScheduleResult schedule(CallbackToken token, ScheduleTiming scheduleTiming) = 0;
/* Cancels a scheduled callback, if possible.
*
@@ -129,7 +152,7 @@
~VSyncCallbackRegistration();
// See documentation for VSyncDispatch::schedule.
- ScheduleResult schedule(nsecs_t workDuration, nsecs_t earliestVsync);
+ ScheduleResult schedule(VSyncDispatch::ScheduleTiming scheduleTiming);
// See documentation for VSyncDispatch::cancel.
CancelResult cancel();
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index ef92680..2154a40 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -35,8 +35,6 @@
nsecs_t minVsyncDistance)
: mName(name),
mCallback(cb),
- mWorkDuration(0),
- mEarliestVsync(0),
mMinVsyncDistance(minVsyncDistance) {}
std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::lastExecutedVsyncTarget() const {
@@ -54,6 +52,13 @@
return {mArmedInfo->mActualWakeupTime};
}
+std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::readyTime() const {
+ if (!mArmedInfo) {
+ return {};
+ }
+ return {mArmedInfo->mActualReadyTime};
+}
+
std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::targetVsync() const {
if (!mArmedInfo) {
return {};
@@ -61,10 +66,10 @@
return {mArmedInfo->mActualVsyncTime};
}
-ScheduleResult VSyncDispatchTimerQueueEntry::schedule(nsecs_t workDuration, nsecs_t earliestVsync,
+ScheduleResult VSyncDispatchTimerQueueEntry::schedule(VSyncDispatch::ScheduleTiming timing,
VSyncTracker& tracker, nsecs_t now) {
- auto nextVsyncTime =
- tracker.nextAnticipatedVSyncTimeFrom(std::max(earliestVsync, now + workDuration));
+ auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(
+ std::max(timing.earliestVsync, now + timing.workDuration + timing.readyDuration));
bool const wouldSkipAVsyncTarget =
mArmedInfo && (nextVsyncTime > (mArmedInfo->mActualVsyncTime + mMinVsyncDistance));
@@ -80,16 +85,15 @@
tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance);
}
- auto const nextWakeupTime = nextVsyncTime - workDuration;
- mWorkDuration = workDuration;
- mEarliestVsync = earliestVsync;
- mArmedInfo = {nextWakeupTime, nextVsyncTime};
+ auto const nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
+ auto const nextReadyTime = nextVsyncTime - timing.readyDuration;
+ mScheduleTiming = timing;
+ mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
return ScheduleResult::Scheduled;
}
-void VSyncDispatchTimerQueueEntry::addPendingWorkloadUpdate(nsecs_t workDuration,
- nsecs_t earliestVsync) {
- mWorkloadUpdateInfo = {.earliestVsync = earliestVsync, .duration = workDuration};
+void VSyncDispatchTimerQueueEntry::addPendingWorkloadUpdate(VSyncDispatch::ScheduleTiming timing) {
+ mWorkloadUpdateInfo = timing;
}
bool VSyncDispatchTimerQueueEntry::hasPendingWorkloadUpdate() const {
@@ -102,14 +106,18 @@
}
if (mWorkloadUpdateInfo) {
- mEarliestVsync = mWorkloadUpdateInfo->earliestVsync;
- mWorkDuration = mWorkloadUpdateInfo->duration;
+ mScheduleTiming = *mWorkloadUpdateInfo;
mWorkloadUpdateInfo.reset();
}
- auto const nextVsyncTime =
- tracker.nextAnticipatedVSyncTimeFrom(std::max(mEarliestVsync, now + mWorkDuration));
- mArmedInfo = {nextVsyncTime - mWorkDuration, nextVsyncTime};
+ const auto earliestReadyBy = now + mScheduleTiming.workDuration + mScheduleTiming.readyDuration;
+ const auto earliestVsync = std::max(earliestReadyBy, mScheduleTiming.earliestVsync);
+
+ const auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(earliestVsync);
+ const auto nextReadyTime = nextVsyncTime - mScheduleTiming.readyDuration;
+ const auto nextWakeupTime = nextReadyTime - mScheduleTiming.workDuration;
+
+ mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
}
void VSyncDispatchTimerQueueEntry::disarm() {
@@ -122,13 +130,14 @@
return *mLastDispatchTime;
}
-void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp) {
+void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp,
+ nsecs_t deadlineTimestamp) {
{
std::lock_guard<std::mutex> lk(mRunningMutex);
mRunning = true;
}
- mCallback(vsyncTimestamp, wakeupTimestamp);
+ mCallback(vsyncTimestamp, wakeupTimestamp, deadlineTimestamp);
std::lock_guard<std::mutex> lk(mRunningMutex);
mRunning = false;
@@ -144,15 +153,20 @@
std::lock_guard<std::mutex> lk(mRunningMutex);
std::string armedInfo;
if (mArmedInfo) {
- StringAppendF(&armedInfo, "[wake up in %.2fms for vsync %.2fms from now]",
+ StringAppendF(&armedInfo,
+ "[wake up in %.2fms deadline in %.2fms for vsync %.2fms from now]",
(mArmedInfo->mActualWakeupTime - systemTime()) / 1e6f,
+ (mArmedInfo->mActualReadyTime - systemTime()) / 1e6f,
(mArmedInfo->mActualVsyncTime - systemTime()) / 1e6f);
}
StringAppendF(&result, "\t\t%s: %s %s\n", mName.c_str(),
mRunning ? "(in callback function)" : "", armedInfo.c_str());
- StringAppendF(&result, "\t\t\tmWorkDuration: %.2fms mEarliestVsync: %.2fms relative to now\n",
- mWorkDuration / 1e6f, (mEarliestVsync - systemTime()) / 1e6f);
+ StringAppendF(&result,
+ "\t\t\tworkDuration: %.2fms readyDuration: %.2fms earliestVsync: %.2fms relative "
+ "to now\n",
+ mScheduleTiming.workDuration / 1e6f, mScheduleTiming.readyDuration / 1e6f,
+ (mScheduleTiming.earliestVsync - systemTime()) / 1e6f);
if (mLastDispatchTime) {
StringAppendF(&result, "\t\t\tmLastDispatchTime: %.2fms ago\n",
@@ -239,6 +253,7 @@
std::shared_ptr<VSyncDispatchTimerQueueEntry> callback;
nsecs_t vsyncTimestamp;
nsecs_t wakeupTimestamp;
+ nsecs_t deadlineTimestamp;
};
std::vector<Invocation> invocations;
{
@@ -252,11 +267,13 @@
continue;
}
+ auto const readyTime = callback->readyTime();
+
auto const lagAllowance = std::max(now - mIntendedWakeupTime, static_cast<nsecs_t>(0));
if (*wakeupTime < mIntendedWakeupTime + mTimerSlack + lagAllowance) {
callback->executing();
- invocations.emplace_back(
- Invocation{callback, *callback->lastExecutedVsyncTarget(), *wakeupTime});
+ invocations.emplace_back(Invocation{callback, *callback->lastExecutedVsyncTarget(),
+ *wakeupTime, *readyTime});
}
}
@@ -265,7 +282,8 @@
}
for (auto const& invocation : invocations) {
- invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp);
+ invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp,
+ invocation.deadlineTimestamp);
}
}
@@ -297,8 +315,8 @@
}
}
-ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token, nsecs_t workDuration,
- nsecs_t earliestVsync) {
+ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token,
+ ScheduleTiming scheduleTiming) {
auto result = ScheduleResult::Error;
{
std::lock_guard<decltype(mMutex)> lk(mMutex);
@@ -314,11 +332,11 @@
* timer recalculation to avoid cancelling a callback that is about to fire. */
auto const rearmImminent = now > mIntendedWakeupTime;
if (CC_UNLIKELY(rearmImminent)) {
- callback->addPendingWorkloadUpdate(workDuration, earliestVsync);
+ callback->addPendingWorkloadUpdate(scheduleTiming);
return ScheduleResult::Scheduled;
}
- result = callback->schedule(workDuration, earliestVsync, mTracker, now);
+ result = callback->schedule(scheduleTiming, mTracker, now);
if (result == ScheduleResult::CannotSchedule) {
return result;
}
@@ -396,11 +414,11 @@
if (mValidToken) mDispatch.get().unregisterCallback(mToken);
}
-ScheduleResult VSyncCallbackRegistration::schedule(nsecs_t workDuration, nsecs_t earliestVsync) {
+ScheduleResult VSyncCallbackRegistration::schedule(VSyncDispatch::ScheduleTiming scheduleTiming) {
if (!mValidToken) {
return ScheduleResult::Error;
}
- return mDispatch.get().schedule(mToken, workDuration, earliestVsync);
+ return mDispatch.get().schedule(mToken, scheduleTiming);
}
CancelResult VSyncCallbackRegistration::cancel() {
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
index 957c0d1..26237b6 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
@@ -47,7 +47,7 @@
std::optional<nsecs_t> lastExecutedVsyncTarget() const;
// This moves the state from disarmed->armed and will calculate the wakeupTime.
- ScheduleResult schedule(nsecs_t workDuration, nsecs_t earliestVsync, VSyncTracker& tracker,
+ ScheduleResult schedule(VSyncDispatch::ScheduleTiming timing, VSyncTracker& tracker,
nsecs_t now);
// This will update armed entries with the latest vsync information. Entry remains armed.
void update(VSyncTracker& tracker, nsecs_t now);
@@ -56,6 +56,8 @@
// It will not update the wakeupTime.
std::optional<nsecs_t> wakeupTime() const;
+ std::optional<nsecs_t> readyTime() const;
+
std::optional<nsecs_t> targetVsync() const;
// This moves state from armed->disarmed.
@@ -67,14 +69,14 @@
// Adds a pending upload of the earliestVSync and workDuration that will be applied on the next
// call to update()
- void addPendingWorkloadUpdate(nsecs_t workDuration, nsecs_t earliestVsync);
+ void addPendingWorkloadUpdate(VSyncDispatch::ScheduleTiming);
// Checks if there is a pending update to the workload, returning true if so.
bool hasPendingWorkloadUpdate() const;
// End: functions that are not threadsafe.
// Invoke the callback with the two given timestamps, moving the state from running->disarmed.
- void callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp);
+ void callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp, nsecs_t deadlineTimestamp);
// Block calling thread while the callback is executing.
void ensureNotRunning();
@@ -84,22 +86,18 @@
std::string const mName;
VSyncDispatch::Callback const mCallback;
- nsecs_t mWorkDuration;
- nsecs_t mEarliestVsync;
+ VSyncDispatch::ScheduleTiming mScheduleTiming;
nsecs_t const mMinVsyncDistance;
struct ArmingInfo {
nsecs_t mActualWakeupTime;
nsecs_t mActualVsyncTime;
+ nsecs_t mActualReadyTime;
};
std::optional<ArmingInfo> mArmedInfo;
std::optional<nsecs_t> mLastDispatchTime;
- struct WorkloadUpdateInfo {
- nsecs_t duration;
- nsecs_t earliestVsync;
- };
- std::optional<WorkloadUpdateInfo> mWorkloadUpdateInfo;
+ std::optional<VSyncDispatch::ScheduleTiming> mWorkloadUpdateInfo;
mutable std::mutex mRunningMutex;
std::condition_variable mCv;
@@ -125,7 +123,7 @@
CallbackToken registerCallback(Callback const& callbackFn, std::string callbackName) final;
void unregisterCallback(CallbackToken token) final;
- ScheduleResult schedule(CallbackToken token, nsecs_t workDuration, nsecs_t earliestVsync) final;
+ ScheduleResult schedule(CallbackToken token, ScheduleTiming scheduleTiming) final;
CancelResult cancel(CallbackToken token) final;
void dump(std::string& result) const final;
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 61f3fbb..e90edf7 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.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"
-
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
//#define LOG_NDEBUG 0
#include "VSyncPredictor.h"
@@ -54,7 +50,7 @@
}
}
-inline size_t VSyncPredictor::next(int i) const {
+inline size_t VSyncPredictor::next(size_t i) const {
return (i + 1) % mTimestamps.size();
}
@@ -69,12 +65,12 @@
}
nsecs_t VSyncPredictor::currentPeriod() const {
- std::lock_guard<std::mutex> lk(mMutex);
+ std::lock_guard lock(mMutex);
return std::get<0>(mRateMap.find(mIdealPeriod)->second);
}
bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) {
- std::lock_guard<std::mutex> lk(mMutex);
+ std::lock_guard lock(mMutex);
if (!validate(timestamp)) {
// VSR could elect to ignore the incongruent timestamp or resetModel(). If ts is ignored,
@@ -138,14 +134,14 @@
auto meanTS = scheduler::calculate_mean(vsyncTS);
auto meanOrdinal = scheduler::calculate_mean(ordinals);
- for (auto i = 0; i < vsyncTS.size(); i++) {
+ for (size_t i = 0; i < vsyncTS.size(); i++) {
vsyncTS[i] -= meanTS;
ordinals[i] -= meanOrdinal;
}
auto top = 0ll;
auto bottom = 0ll;
- for (auto i = 0; i < vsyncTS.size(); i++) {
+ for (size_t i = 0; i < vsyncTS.size(); i++) {
top += vsyncTS[i] * ordinals[i];
bottom += ordinals[i] * ordinals[i];
}
@@ -177,9 +173,9 @@
}
nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const {
- std::lock_guard<std::mutex> lk(mMutex);
+ std::lock_guard lock(mMutex);
- auto const [slope, intercept] = getVSyncPredictionModel(lk);
+ auto const [slope, intercept] = getVSyncPredictionModel(lock);
if (mTimestamps.empty()) {
traceInt64If("VSP-mode", 1);
@@ -215,8 +211,8 @@
}
std::tuple<nsecs_t, nsecs_t> VSyncPredictor::getVSyncPredictionModel() const {
- std::lock_guard<std::mutex> lk(mMutex);
- return VSyncPredictor::getVSyncPredictionModel(lk);
+ std::lock_guard lock(mMutex);
+ return VSyncPredictor::getVSyncPredictionModel(lock);
}
std::tuple<nsecs_t, nsecs_t> VSyncPredictor::getVSyncPredictionModel(
@@ -227,7 +223,7 @@
void VSyncPredictor::setPeriod(nsecs_t period) {
ATRACE_CALL();
- std::lock_guard<std::mutex> lk(mMutex);
+ std::lock_guard lock(mMutex);
static constexpr size_t kSizeLimit = 30;
if (CC_UNLIKELY(mRateMap.size() == kSizeLimit)) {
mRateMap.erase(mRateMap.begin());
@@ -256,18 +252,18 @@
}
bool VSyncPredictor::needsMoreSamples() const {
- std::lock_guard<std::mutex> lk(mMutex);
+ std::lock_guard lock(mMutex);
return mTimestamps.size() < kMinimumSamplesForPrediction;
}
void VSyncPredictor::resetModel() {
- std::lock_guard<std::mutex> lk(mMutex);
+ std::lock_guard lock(mMutex);
mRateMap[mIdealPeriod] = {mIdealPeriod, 0};
clearTimestamps();
}
void VSyncPredictor::dump(std::string& result) const {
- std::lock_guard<std::mutex> lk(mMutex);
+ std::lock_guard lock(mMutex);
StringAppendF(&result, "\tmIdealPeriod=%.2f\n", mIdealPeriod / 1e6f);
StringAppendF(&result, "\tRefresh Rate Map:\n");
for (const auto& [idealPeriod, periodInterceptTuple] : mRateMap) {
@@ -280,5 +276,3 @@
} // namespace android::scheduler
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h
index 5f3c418..5f2ec49 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.h
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h
@@ -74,7 +74,7 @@
size_t const kOutlierTolerancePercent;
std::mutex mutable mMutex;
- size_t next(int i) const REQUIRES(mMutex);
+ size_t next(size_t i) const REQUIRES(mMutex);
bool validate(nsecs_t timestamp) const REQUIRES(mMutex);
std::tuple<nsecs_t, nsecs_t> getVSyncPredictionModel(std::lock_guard<std::mutex> const&) const
REQUIRES(mMutex);
@@ -84,7 +84,7 @@
std::unordered_map<nsecs_t, std::tuple<nsecs_t, nsecs_t>> mutable mRateMap GUARDED_BY(mMutex);
- int mLastTimestampIndex GUARDED_BY(mMutex) = 0;
+ size_t mLastTimestampIndex GUARDED_BY(mMutex) = 0;
std::vector<nsecs_t> mTimestamps GUARDED_BY(mMutex);
};
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index a2b279b..3c5b3f1 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -35,130 +35,15 @@
return systemTime(SYSTEM_TIME_MONOTONIC);
}
-class PredictedVsyncTracer {
-public:
- PredictedVsyncTracer(VSyncDispatch& dispatch)
- : mRegistration(dispatch,
- std::bind(&PredictedVsyncTracer::callback, this, std::placeholders::_1,
- std::placeholders::_2),
- "PredictedVsyncTracer") {
- mRegistration.schedule(0, 0);
- }
-
-private:
- TracedOrdinal<bool> mParity = {"VSYNC-predicted", 0};
- VSyncCallbackRegistration mRegistration;
-
- void callback(nsecs_t /*vsyncTime*/, nsecs_t /*targetWakeupTim*/) {
- mParity = !mParity;
- mRegistration.schedule(0, 0);
- }
-};
-
-VSyncReactor::VSyncReactor(std::unique_ptr<Clock> clock, VSyncDispatch& dispatch,
- VSyncTracker& tracker, size_t pendingFenceLimit,
- bool supportKernelIdleTimer)
+VSyncReactor::VSyncReactor(std::unique_ptr<Clock> clock, VSyncTracker& tracker,
+ size_t pendingFenceLimit, bool supportKernelIdleTimer)
: mClock(std::move(clock)),
mTracker(tracker),
- mDispatch(dispatch),
mPendingLimit(pendingFenceLimit),
- mPredictedVsyncTracer(property_get_bool("debug.sf.show_predicted_vsync", false)
- ? std::make_unique<PredictedVsyncTracer>(mDispatch)
- : nullptr),
mSupportKernelIdleTimer(supportKernelIdleTimer) {}
VSyncReactor::~VSyncReactor() = default;
-// The DispSync interface has a 'repeat this callback at rate' semantic. This object adapts
-// VSyncDispatch's individually-scheduled callbacks so as to meet DispSync's existing semantic
-// for now.
-class CallbackRepeater {
-public:
- CallbackRepeater(VSyncDispatch& dispatch, DispSync::Callback* cb, const char* name,
- nsecs_t period, nsecs_t offset, nsecs_t notBefore)
- : mName(name),
- mCallback(cb),
- mRegistration(dispatch,
- std::bind(&CallbackRepeater::callback, this, std::placeholders::_1,
- std::placeholders::_2),
- mName),
- mPeriod(period),
- mOffset(offset),
- mLastCallTime(notBefore) {}
-
- ~CallbackRepeater() {
- std::lock_guard<std::mutex> lk(mMutex);
- mRegistration.cancel();
- }
-
- void start(nsecs_t offset) {
- std::lock_guard<std::mutex> lk(mMutex);
- mStopped = false;
- mOffset = offset;
-
- auto const schedule_result = mRegistration.schedule(calculateWorkload(), mLastCallTime);
- LOG_ALWAYS_FATAL_IF((schedule_result != ScheduleResult::Scheduled),
- "Error scheduling callback: rc %X", schedule_result);
- }
-
- void setPeriod(nsecs_t period) {
- std::lock_guard<std::mutex> lk(mMutex);
- if (period == mPeriod) {
- return;
- }
- mPeriod = period;
- }
-
- void stop() {
- std::lock_guard<std::mutex> lk(mMutex);
- LOG_ALWAYS_FATAL_IF(mStopped, "DispSyncInterface misuse: callback already stopped");
- mStopped = true;
- mRegistration.cancel();
- }
-
- void dump(std::string& result) const {
- std::lock_guard<std::mutex> lk(mMutex);
- StringAppendF(&result, "\t%s: mPeriod=%.2f last vsync time %.2fms relative to now (%s)\n",
- mName.c_str(), mPeriod / 1e6f, (mLastCallTime - systemTime()) / 1e6f,
- mStopped ? "stopped" : "running");
- }
-
-private:
- void callback(nsecs_t vsynctime, nsecs_t wakeupTime) {
- {
- std::lock_guard<std::mutex> lk(mMutex);
- mLastCallTime = vsynctime;
- }
-
- mCallback->onDispSyncEvent(wakeupTime, vsynctime);
-
- {
- std::lock_guard<std::mutex> lk(mMutex);
- if (mStopped) {
- return;
- }
- auto const schedule_result = mRegistration.schedule(calculateWorkload(), vsynctime);
- LOG_ALWAYS_FATAL_IF((schedule_result != ScheduleResult::Scheduled),
- "Error rescheduling callback: rc %X", schedule_result);
- }
- }
-
- // DispSync offsets are defined as time after the vsync before presentation.
- // VSyncReactor workloads are defined as time before the intended presentation vsync.
- // Note change in sign between the two defnitions.
- nsecs_t calculateWorkload() REQUIRES(mMutex) { return mPeriod - mOffset; }
-
- const std::string mName;
- DispSync::Callback* const mCallback;
-
- std::mutex mutable mMutex;
- VSyncCallbackRegistration mRegistration GUARDED_BY(mMutex);
- bool mStopped GUARDED_BY(mMutex) = false;
- nsecs_t mPeriod GUARDED_BY(mMutex);
- nsecs_t mOffset GUARDED_BY(mMutex);
- nsecs_t mLastCallTime GUARDED_BY(mMutex);
-};
-
bool VSyncReactor::addPresentFence(const std::shared_ptr<FenceTime>& fence) {
if (!fence) {
return false;
@@ -169,7 +54,7 @@
return true;
}
- std::lock_guard<std::mutex> lk(mMutex);
+ std::lock_guard lock(mMutex);
if (mExternalIgnoreFences || mInternalIgnoreFences) {
return true;
}
@@ -207,7 +92,7 @@
}
void VSyncReactor::setIgnorePresentFences(bool ignoration) {
- std::lock_guard<std::mutex> lk(mMutex);
+ std::lock_guard lock(mMutex);
mExternalIgnoreFences = ignoration;
updateIgnorePresentFencesInternal();
}
@@ -269,8 +154,6 @@
mTracker.resetModel();
}
-void VSyncReactor::endResync() {}
-
bool VSyncReactor::periodConfirmed(nsecs_t vsync_timestamp, std::optional<nsecs_t> HwcVsyncPeriod) {
if (!mPeriodConfirmationInProgress) {
return false;
@@ -303,14 +186,11 @@
bool* periodFlushed) {
assert(periodFlushed);
- std::lock_guard<std::mutex> lk(mMutex);
+ std::lock_guard lock(mMutex);
if (periodConfirmed(timestamp, hwcVsyncPeriod)) {
ATRACE_NAME("VSR: period confirmed");
if (mPeriodTransitioningTo) {
mTracker.setPeriod(*mPeriodTransitioningTo);
- for (auto& entry : mCallbacks) {
- entry.second->setPeriod(*mPeriodTransitioningTo);
- }
*periodFlushed = true;
}
@@ -339,51 +219,8 @@
return mMoreSamplesNeeded;
}
-status_t VSyncReactor::addEventListener(const char* name, nsecs_t phase,
- DispSync::Callback* callback,
- nsecs_t /* lastCallbackTime */) {
- std::lock_guard<std::mutex> lk(mMutex);
- auto it = mCallbacks.find(callback);
- if (it == mCallbacks.end()) {
- // TODO (b/146557561): resolve lastCallbackTime semantics in DispSync i/f.
- static auto constexpr maxListeners = 4;
- if (mCallbacks.size() >= maxListeners) {
- ALOGE("callback %s not added, exceeded callback limit of %i (currently %zu)", name,
- maxListeners, mCallbacks.size());
- return NO_MEMORY;
- }
-
- auto const period = mTracker.currentPeriod();
- auto repeater = std::make_unique<CallbackRepeater>(mDispatch, callback, name, period, phase,
- mClock->now());
- it = mCallbacks.emplace(std::pair(callback, std::move(repeater))).first;
- }
-
- it->second->start(phase);
- return NO_ERROR;
-}
-
-status_t VSyncReactor::removeEventListener(DispSync::Callback* callback,
- nsecs_t* /* outLastCallback */) {
- std::lock_guard<std::mutex> lk(mMutex);
- auto const it = mCallbacks.find(callback);
- LOG_ALWAYS_FATAL_IF(it == mCallbacks.end(), "callback %p not registered", callback);
-
- it->second->stop();
- return NO_ERROR;
-}
-
-status_t VSyncReactor::changePhaseOffset(DispSync::Callback* callback, nsecs_t phase) {
- std::lock_guard<std::mutex> lk(mMutex);
- auto const it = mCallbacks.find(callback);
- LOG_ALWAYS_FATAL_IF(it == mCallbacks.end(), "callback was %p not registered", callback);
-
- it->second->start(phase);
- return NO_ERROR;
-}
-
void VSyncReactor::dump(std::string& result) const {
- std::lock_guard<std::mutex> lk(mMutex);
+ std::lock_guard lock(mMutex);
StringAppendF(&result, "VsyncReactor in use\n");
StringAppendF(&result, "Has %zu unfired fences\n", mUnfiredFences.size());
StringAppendF(&result, "mInternalIgnoreFences=%d mExternalIgnoreFences=%d\n",
@@ -403,17 +240,8 @@
StringAppendF(&result, "No Last HW vsync\n");
}
- StringAppendF(&result, "CallbackRepeaters:\n");
- for (const auto& [callback, repeater] : mCallbacks) {
- repeater->dump(result);
- }
-
StringAppendF(&result, "VSyncTracker:\n");
mTracker.dump(result);
- StringAppendF(&result, "VSyncDispatch:\n");
- mDispatch.dump(result);
}
-void VSyncReactor::reset() {}
-
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h
index 22ceb39..80b5232 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.h
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.h
@@ -29,14 +29,12 @@
class Clock;
class VSyncDispatch;
class VSyncTracker;
-class CallbackRepeater;
-class PredictedVsyncTracer;
// TODO (b/145217110): consider renaming.
class VSyncReactor : public android::DispSync {
public:
- VSyncReactor(std::unique_ptr<Clock> clock, VSyncDispatch& dispatch, VSyncTracker& tracker,
- size_t pendingFenceLimit, bool supportKernelIdleTimer);
+ VSyncReactor(std::unique_ptr<Clock> clock, VSyncTracker& tracker, size_t pendingFenceLimit,
+ bool supportKernelIdleTimer);
~VSyncReactor();
bool addPresentFence(const std::shared_ptr<FenceTime>& fence) final;
@@ -52,15 +50,8 @@
void beginResync() final;
bool addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod,
bool* periodFlushed) final;
- void endResync() final;
-
- status_t addEventListener(const char* name, nsecs_t phase, DispSync::Callback* callback,
- nsecs_t lastCallbackTime) final;
- status_t removeEventListener(DispSync::Callback* callback, nsecs_t* outLastCallback) final;
- status_t changePhaseOffset(DispSync::Callback* callback, nsecs_t phase) final;
void dump(std::string& result) const final;
- void reset() final;
private:
void setIgnorePresentFencesInternal(bool ignoration) REQUIRES(mMutex);
@@ -72,7 +63,6 @@
std::unique_ptr<Clock> const mClock;
VSyncTracker& mTracker;
- VSyncDispatch& mDispatch;
size_t const mPendingLimit;
mutable std::mutex mMutex;
@@ -85,10 +75,6 @@
std::optional<nsecs_t> mPeriodTransitioningTo GUARDED_BY(mMutex);
std::optional<nsecs_t> mLastHwVsync GUARDED_BY(mMutex);
- std::unordered_map<DispSync::Callback*, std::unique_ptr<CallbackRepeater>> mCallbacks
- GUARDED_BY(mMutex);
-
- const std::unique_ptr<PredictedVsyncTracer> mPredictedVsyncTracer;
const bool mSupportKernelIdleTimer = false;
};
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 2b642a2..7572be3 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1452,7 +1452,11 @@
status_t SurfaceFlinger::injectVSync(nsecs_t when) {
Mutex::Autolock lock(mStateLock);
- return mScheduler->injectVSync(when, calculateExpectedPresentTime(when)) ? NO_ERROR : BAD_VALUE;
+ const auto expectedPresent = calculateExpectedPresentTime(when);
+ return mScheduler->injectVSync(when, /*expectedVSyncTime=*/expectedPresent,
+ /*deadlineTimestamp=*/expectedPresent)
+ ? NO_ERROR
+ : BAD_VALUE;
}
status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) {
@@ -2984,14 +2988,16 @@
// start the EventThread
mScheduler = getFactory().createScheduler(*mRefreshRateConfigs, *this);
+ const auto configs = mVsyncConfiguration->getCurrentConfigs();
mAppConnectionHandle =
mScheduler->createConnection("app",
- mVsyncConfiguration->getCurrentConfigs().late.appOffset,
+ /*workDuration=*/configs.late.appWorkDuration,
+ /*readyDuration=*/configs.late.sfWorkDuration,
impl::EventThread::InterceptVSyncsCallback());
mSfConnectionHandle =
mScheduler->createConnection("sf",
- mVsyncConfiguration->getCurrentConfigs().late.sfOffset,
- [this](nsecs_t timestamp) {
+ /*workDuration=*/configs.late.sfWorkDuration,
+ /*readyDuration=*/0ns, [this](nsecs_t timestamp) {
mInterceptor->saveVSyncEvent(timestamp);
});
@@ -3024,8 +3030,12 @@
}
void SurfaceFlinger::setVsyncConfig(const VsyncModulator::VsyncConfig& config) {
- mScheduler->setPhaseOffset(mAppConnectionHandle, config.appOffset);
- mScheduler->setPhaseOffset(mSfConnectionHandle, config.sfOffset);
+ mScheduler->setDuration(mAppConnectionHandle,
+ /*workDuration=*/config.appWorkDuration,
+ /*readyDuration=*/config.sfWorkDuration);
+ mScheduler->setDuration(mSfConnectionHandle,
+ /*workDuration=*/config.sfWorkDuration,
+ /*readyDuration=*/0ns);
}
void SurfaceFlinger::commitTransaction() {
@@ -4342,8 +4352,7 @@
} else {
static const std::unordered_map<std::string, Dumper> dumpers = {
{"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)},
- {"--dispsync"s,
- dumper([this](std::string& s) { mScheduler->getPrimaryDispSync().dump(s); })},
+ {"--dispsync"s, dumper([this](std::string& s) { mScheduler->dumpVSync(s); })},
{"--edid"s, argsDumper(&SurfaceFlinger::dumpRawDisplayIdentificationData)},
{"--frame-events"s, dumper(&SurfaceFlinger::dumpFrameEventsLocked)},
{"--latency"s, argsDumper(&SurfaceFlinger::dumpStatsLocked)},
@@ -5170,14 +5179,14 @@
mForceFullDamage = n != 0;
return NO_ERROR;
}
- case 1018: { // Modify Choreographer's phase offset
+ case 1018: { // Modify Choreographer's duration
n = data.readInt32();
- mScheduler->setPhaseOffset(mAppConnectionHandle, static_cast<nsecs_t>(n));
+ mScheduler->setDuration(mAppConnectionHandle, std::chrono::nanoseconds(n), 0ns);
return NO_ERROR;
}
- case 1019: { // Modify SurfaceFlinger's phase offset
+ case 1019: { // Modify SurfaceFlinger's duration
n = data.readInt32();
- mScheduler->setPhaseOffset(mSfConnectionHandle, static_cast<nsecs_t>(n));
+ mScheduler->setDuration(mSfConnectionHandle, std::chrono::nanoseconds(n), 0ns);
return NO_ERROR;
}
case 1020: { // Layer updates interceptor
@@ -5484,7 +5493,7 @@
}
status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args,
- ScreenCaptureResults& captureResults) {
+ const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();
status_t validate = validateScreenshotPermissions(args);
@@ -5522,8 +5531,12 @@
auto traverseLayers = [this, args, layerStack](const LayerVector::Visitor& visitor) {
traverseLayersInLayerStack(layerStack, args.uid, visitor);
};
- return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
- args.pixelFormat, captureResults);
+ ScreenCaptureResults captureResults;
+ status_t status = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
+ args.pixelFormat, captureResults);
+ captureResults.result = status;
+ captureListener->onScreenCaptureComplete(captureResults);
+ return status;
}
status_t SurfaceFlinger::setSchedFifo(bool enabled) {
@@ -5566,7 +5579,7 @@
}
status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack,
- ScreenCaptureResults& captureResults) {
+ const sp<IScreenCaptureListener>& captureListener) {
ui::LayerStack layerStack;
wp<DisplayDevice> displayWeak;
ui::Size size;
@@ -5587,8 +5600,7 @@
}
RenderAreaFuture renderAreaFuture = promise::defer([=] {
- return DisplayRenderArea::create(displayWeak, Rect(), size,
- captureResults.capturedDataspace,
+ return DisplayRenderArea::create(displayWeak, Rect(), size, dataspace,
false /* useIdentityTransform */,
false /* captureSecureLayers */);
});
@@ -5597,12 +5609,16 @@
traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, visitor);
};
- return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
- ui::PixelFormat::RGBA_8888, captureResults);
+ ScreenCaptureResults captureResults;
+ status_t status = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
+ ui::PixelFormat::RGBA_8888, captureResults);
+ captureResults.result = status;
+ captureListener->onScreenCaptureComplete(captureResults);
+ return status;
}
status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
- ScreenCaptureResults& captureResults) {
+ const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();
status_t validate = validateScreenshotPermissions(args);
@@ -5711,8 +5727,12 @@
});
};
- return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
- args.pixelFormat, captureResults);
+ ScreenCaptureResults captureResults;
+ status_t status = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
+ args.pixelFormat, captureResults);
+ captureResults.result = status;
+ captureListener->onScreenCaptureComplete(captureResults);
+ return status;
}
status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index c53ae3e..fb79989 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -524,11 +524,11 @@
ISurfaceComposer::ConfigChanged configChanged =
ISurfaceComposer::eConfigChangedSuppress) override;
status_t captureDisplay(const DisplayCaptureArgs& args,
- ScreenCaptureResults& captureResults) override;
+ const sp<IScreenCaptureListener>& captureListener) override;
status_t captureDisplay(uint64_t displayOrLayerStack,
- ScreenCaptureResults& captureResults) override;
+ const sp<IScreenCaptureListener>& captureListener) override;
status_t captureLayers(const LayerCaptureArgs& args,
- ScreenCaptureResults& captureResults) override;
+ const sp<IScreenCaptureListener>& captureListener) override;
status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats) override;
status_t getDisplayState(const sp<IBinder>& displayToken, ui::DisplayState*) override;
diff --git a/services/surfaceflinger/TracedOrdinal.h b/services/surfaceflinger/TracedOrdinal.h
index 4e7f67d..49cf80c 100644
--- a/services/surfaceflinger/TracedOrdinal.h
+++ b/services/surfaceflinger/TracedOrdinal.h
@@ -21,12 +21,32 @@
#include <cmath>
#include <string>
+namespace std {
+template <class Rep, class Period>
+bool signbit(std::chrono::duration<Rep, Period> v) {
+ return signbit(std::chrono::duration_cast<std::chrono::nanoseconds>(v).count());
+}
+} // namespace std
+
namespace android {
+namespace {
+template <typename T>
+int64_t to_int64(T v) {
+ return int64_t(v);
+}
+
+template <class Rep, class Period>
+int64_t to_int64(std::chrono::duration<Rep, Period> v) {
+ return int64_t(v.count());
+}
+} // namespace
+
template <typename T>
class TracedOrdinal {
public:
- static_assert(std::is_same<bool, T>() || (std::is_signed<T>() && std::is_integral<T>()),
+ static_assert(std::is_same<bool, T>() || (std::is_signed<T>() && std::is_integral<T>()) ||
+ std::is_same<std::chrono::nanoseconds, T>(),
"Type is not supported. Please test it with systrace before adding "
"it to the list.");
@@ -57,12 +77,12 @@
}
if (!std::signbit(mData)) {
- ATRACE_INT64(mName.c_str(), int64_t(mData));
+ ATRACE_INT64(mName.c_str(), to_int64(mData));
if (mHasGoneNegative) {
ATRACE_INT64(mNameNegative.c_str(), 0);
}
} else {
- ATRACE_INT64(mNameNegative.c_str(), -int64_t(mData));
+ ATRACE_INT64(mNameNegative.c_str(), -to_int64(mData));
ATRACE_INT64(mName.c_str(), 0);
}
}
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index 10a517e..5128394 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -1,3 +1,23 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <gtest/gtest.h>
#include <gui/ISurfaceComposer.h>
#include <gui/LayerDebugInfo.h>
@@ -7,8 +27,8 @@
#include <private/gui/ComposerService.h>
#include <ui/DisplayConfig.h>
#include <utils/String8.h>
-
#include <functional>
+#include "utils/ScreenshotUtils.h"
namespace android {
@@ -262,7 +282,7 @@
DisplayCaptureArgs captureArgs;
captureArgs.displayToken = display;
ScreenCaptureResults captureResults;
- return ScreenshotClient::captureDisplay(captureArgs, captureResults);
+ return ScreenCapture::captureDisplay(captureArgs, captureResults);
};
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
}
@@ -276,7 +296,7 @@
captureArgs.sourceCrop = {0, 0, 1, 1};
ScreenCaptureResults captureResults;
- return ScreenshotClient::captureLayers(captureArgs, captureResults);
+ return ScreenCapture::captureLayers(captureArgs, captureResults);
};
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
}
diff --git a/services/surfaceflinger/tests/InvalidHandles_test.cpp b/services/surfaceflinger/tests/InvalidHandles_test.cpp
index 300e9c7..cfec0d2 100644
--- a/services/surfaceflinger/tests/InvalidHandles_test.cpp
+++ b/services/surfaceflinger/tests/InvalidHandles_test.cpp
@@ -14,6 +14,10 @@
* 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 <binder/Binder.h>
#include <gtest/gtest.h>
@@ -22,6 +26,7 @@
#include <gui/SurfaceComposerClient.h>
#include <private/gui/ComposerService.h>
#include <ui/Rect.h>
+#include "utils/ScreenshotUtils.h"
namespace android {
namespace {
@@ -56,13 +61,11 @@
}
TEST_F(InvalidHandleTest, captureLayersInvalidHandle) {
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-
LayerCaptureArgs args;
args.layerHandle = mNotSc->getHandle();
ScreenCaptureResults captureResults;
- ASSERT_EQ(NAME_NOT_FOUND, sf->captureLayers(args, captureResults));
+ ASSERT_EQ(NAME_NOT_FOUND, ScreenCapture::captureLayers(args, captureResults));
}
} // namespace
diff --git a/services/surfaceflinger/tests/LayerState_test.cpp b/services/surfaceflinger/tests/LayerState_test.cpp
index 785c2c3..e66df4a 100644
--- a/services/surfaceflinger/tests/LayerState_test.cpp
+++ b/services/surfaceflinger/tests/LayerState_test.cpp
@@ -83,6 +83,7 @@
results.buffer = new GraphicBuffer(100, 200, PIXEL_FORMAT_RGBA_8888, 1, 0);
results.capturedSecureLayers = true;
results.capturedDataspace = ui::Dataspace::DISPLAY_P3;
+ results.result = BAD_VALUE;
Parcel p;
results.write(p);
@@ -98,6 +99,7 @@
ASSERT_EQ(results.buffer->getPixelFormat(), results2.buffer->getPixelFormat());
ASSERT_EQ(results.capturedSecureLayers, results2.capturedSecureLayers);
ASSERT_EQ(results.capturedDataspace, results2.capturedDataspace);
+ ASSERT_EQ(results.result, results2.result);
}
} // namespace test
diff --git a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
index e3b9489..ab74c50 100644
--- a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
@@ -167,7 +167,6 @@
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
- sp<ISurfaceComposer> composer = ComposerService::getComposerService();
sp<GraphicBuffer> outBuffer;
Transaction()
.setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure)
@@ -177,11 +176,12 @@
args.displayToken = mDisplay;
ScreenCaptureResults captureResults;
- ASSERT_EQ(PERMISSION_DENIED, composer->captureDisplay(args, captureResults));
+ ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureDisplay(args, captureResults));
Transaction().setFlags(layer, 0, layer_state_t::eLayerSecure).apply(true);
- ASSERT_EQ(NO_ERROR, composer->captureDisplay(args, captureResults));
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureDisplay(args, captureResults));
}
+
TEST_P(LayerTypeTransactionTest, RefreshRateIsInitialized) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index 690f758..962a0cf 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -84,14 +84,13 @@
Transaction().show(layer).setLayer(layer, INT32_MAX).apply(true);
- sp<ISurfaceComposer> composer = ComposerService::getComposerService();
- ASSERT_EQ(PERMISSION_DENIED, composer->captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureDisplay(mCaptureArgs, mCaptureResults));
UIDFaker f(AID_SYSTEM);
// By default the system can capture screenshots with secure layers but they
// will be blacked out
- ASSERT_EQ(NO_ERROR, composer->captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureDisplay(mCaptureArgs, mCaptureResults));
{
SCOPED_TRACE("as system");
@@ -104,7 +103,7 @@
DisplayCaptureArgs args;
args.displayToken = mDisplay;
args.captureSecureLayers = true;
- ASSERT_EQ(NO_ERROR, composer->captureDisplay(args, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureDisplay(args, mCaptureResults));
ASSERT_TRUE(mCaptureResults.capturedSecureLayers);
ScreenCapture sc(mCaptureResults.buffer);
sc.expectColor(Rect(0, 0, 32, 32), Color::RED);
@@ -307,21 +306,17 @@
sp<SurfaceControl> child = createColorLayer("Child layer", Color::RED, mFGSurfaceControl.get());
SurfaceComposerClient::Transaction().show(child).apply(true);
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-
LayerCaptureArgs args;
args.layerHandle = child->getHandle();
ScreenCaptureResults captureResults;
- ASSERT_EQ(BAD_VALUE, sf->captureLayers(args, captureResults));
+ ASSERT_EQ(BAD_VALUE, ScreenCapture::captureLayers(args, captureResults));
}
TEST_F(ScreenCaptureTest, CaptureBufferLayerWithoutBufferFails) {
sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
SurfaceComposerClient::Transaction().show(child).apply(true);
-
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
sp<GraphicBuffer> outBuffer;
LayerCaptureArgs args;
@@ -329,11 +324,11 @@
args.childrenOnly = false;
ScreenCaptureResults captureResults;
- ASSERT_EQ(BAD_VALUE, sf->captureLayers(args, captureResults));
+ ASSERT_EQ(BAD_VALUE, ScreenCapture::captureLayers(args, captureResults));
TransactionUtils::fillSurfaceRGBA8(child, Color::RED);
SurfaceComposerClient::Transaction().apply(true);
- ASSERT_EQ(NO_ERROR, sf->captureLayers(args, captureResults));
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(args, captureResults));
ScreenCapture sc(captureResults.buffer);
sc.expectColor(Rect(0, 0, 9, 9), Color::RED);
}
@@ -482,9 +477,8 @@
args.layerHandle = redLayerHandle;
ScreenCaptureResults captureResults;
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
// Layer was deleted so captureLayers should fail with NAME_NOT_FOUND
- ASSERT_EQ(NAME_NOT_FOUND, sf->captureLayers(args, captureResults));
+ ASSERT_EQ(NAME_NOT_FOUND, ScreenCapture::captureLayers(args, captureResults));
}
TEST_F(ScreenCaptureTest, CaputureSecureLayer) {
@@ -505,15 +499,13 @@
.setLayer(redLayer, INT32_MAX)
.apply();
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-
LayerCaptureArgs args;
args.layerHandle = redLayerHandle;
args.childrenOnly = false;
ScreenCaptureResults captureResults;
// Call from outside system with secure layers will result in permission denied
- ASSERT_EQ(PERMISSION_DENIED, sf->captureLayers(args, captureResults));
+ ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureLayers(args, captureResults));
UIDFaker f(AID_SYSTEM);
@@ -551,8 +543,7 @@
// From non system uid, can't request screenshot without a specified uid.
UIDFaker f(fakeUid);
- sp<ISurfaceComposer> composer = ComposerService::getComposerService();
- ASSERT_EQ(PERMISSION_DENIED, composer->captureDisplay(captureArgs, mCaptureResults));
+ ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureDisplay(captureArgs, mCaptureResults));
// Make screenshot request with current uid set. No layers were created with the current
// uid so screenshot will be black.
@@ -604,8 +595,7 @@
// From non system uid, can't request screenshot without a specified uid.
std::unique_ptr<UIDFaker> uidFaker = std::make_unique<UIDFaker>(fakeUid);
- sp<ISurfaceComposer> composer = ComposerService::getComposerService();
- ASSERT_EQ(PERMISSION_DENIED, composer->captureLayers(captureArgs, mCaptureResults));
+ ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureLayers(captureArgs, mCaptureResults));
// Make screenshot request with current uid set. No layers were created with the current
// uid so screenshot will be black.
diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
index afebc40..54f4c7c 100644
--- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
@@ -27,13 +27,99 @@
#include "AsyncCallRecorder.h"
#include "Scheduler/DispSyncSource.h"
-#include "mock/MockDispSync.h"
+#include "Scheduler/VSyncDispatch.h"
namespace android {
namespace {
using namespace std::chrono_literals;
-using testing::Return;
+using namespace testing;
+
+class MockVSyncDispatch : public scheduler::VSyncDispatch {
+public:
+ MOCK_METHOD2(registerCallback,
+ CallbackToken(std::function<void(nsecs_t, nsecs_t, nsecs_t)> const&, std::string));
+ MOCK_METHOD1(unregisterCallback, void(CallbackToken));
+ MOCK_METHOD2(schedule, scheduler::ScheduleResult(CallbackToken, ScheduleTiming));
+ MOCK_METHOD1(cancel, scheduler::CancelResult(CallbackToken token));
+ MOCK_CONST_METHOD1(dump, void(std::string&));
+
+ MockVSyncDispatch() {
+ ON_CALL(*this, registerCallback)
+ .WillByDefault(
+ [this](std::function<void(nsecs_t, nsecs_t, nsecs_t)> const& callback,
+ std::string) {
+ CallbackToken token(mNextToken);
+ mNextToken++;
+
+ mCallbacks.emplace(token, CallbackData(callback));
+ ALOGD("registerCallback: %zu", token.value());
+ return token;
+ });
+
+ ON_CALL(*this, unregisterCallback).WillByDefault([this](CallbackToken token) {
+ ALOGD("unregisterCallback: %zu", token.value());
+ mCallbacks.erase(token);
+ });
+
+ ON_CALL(*this, schedule).WillByDefault([this](CallbackToken token, ScheduleTiming timing) {
+ ALOGD("schedule: %zu", token.value());
+ if (mCallbacks.count(token) == 0) {
+ ALOGD("schedule: callback %zu not registered", token.value());
+ return scheduler::ScheduleResult::Error;
+ }
+
+ auto& callback = mCallbacks.at(token);
+ callback.scheduled = true;
+ callback.vsyncTime = timing.earliestVsync;
+ callback.targetWakeupTime =
+ timing.earliestVsync - timing.workDuration - timing.readyDuration;
+ ALOGD("schedule: callback %zu scheduled", token.value());
+ return scheduler::ScheduleResult::Scheduled;
+ });
+
+ ON_CALL(*this, cancel).WillByDefault([this](CallbackToken token) {
+ ALOGD("cancel: %zu", token.value());
+ if (mCallbacks.count(token) == 0) {
+ ALOGD("cancel: callback %zu is not registered", token.value());
+ return scheduler::CancelResult::Error;
+ }
+
+ auto& callback = mCallbacks.at(token);
+ callback.scheduled = false;
+ ALOGD("cancel: callback %zu cancelled", token.value());
+ return scheduler::CancelResult::Cancelled;
+ });
+ }
+
+ void triggerCallbacks() {
+ ALOGD("triggerCallbacks");
+ for (auto& [token, callback] : mCallbacks) {
+ if (callback.scheduled) {
+ ALOGD("triggerCallbacks: callback %zu", token.value());
+ callback.scheduled = false;
+ callback.func(callback.vsyncTime, callback.targetWakeupTime, callback.readyTime);
+ } else {
+ ALOGD("triggerCallbacks: callback %zu is not scheduled", token.value());
+ }
+ }
+ }
+
+private:
+ struct CallbackData {
+ explicit CallbackData(std::function<void(nsecs_t, nsecs_t, nsecs_t)> func)
+ : func(std::move(func)) {}
+
+ std::function<void(nsecs_t, nsecs_t, nsecs_t)> func;
+ bool scheduled = false;
+ nsecs_t vsyncTime = 0;
+ nsecs_t targetWakeupTime = 0;
+ nsecs_t readyTime = 0;
+ };
+
+ std::unordered_map<CallbackToken, CallbackData> mCallbacks;
+ size_t mNextToken;
+};
class DispSyncSourceTest : public testing::Test, private VSyncSource::Callback {
protected:
@@ -43,15 +129,19 @@
void createDispSync();
void createDispSyncSource();
- void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) override;
+ void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp,
+ nsecs_t deadlineTimestamp) override;
- std::unique_ptr<mock::DispSync> mDispSync;
- std::unique_ptr<DispSyncSource> mDispSyncSource;
+ std::unique_ptr<MockVSyncDispatch> mVSyncDispatch;
+ std::unique_ptr<scheduler::DispSyncSource> mDispSyncSource;
- AsyncCallRecorder<void (*)(nsecs_t)> mVSyncEventCallRecorder;
+ AsyncCallRecorder<void (*)(nsecs_t, nsecs_t, nsecs_t)> mVSyncEventCallRecorder;
- static constexpr std::chrono::nanoseconds mPhaseOffset = 6ms;
+ static constexpr std::chrono::nanoseconds mWorkDuration = 20ms;
+ static constexpr std::chrono::nanoseconds mReadyDuration = 10ms;
static constexpr int mIterations = 100;
+ const scheduler::VSyncDispatch::CallbackToken mFakeToken{2398};
+ const std::string mName = "DispSyncSourceTest";
};
DispSyncSourceTest::DispSyncSourceTest() {
@@ -66,20 +156,21 @@
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
}
-void DispSyncSourceTest::onVSyncEvent(nsecs_t when, nsecs_t /*expectedVSyncTimestamp*/) {
+void DispSyncSourceTest::onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp,
+ nsecs_t deadlineTimestamp) {
ALOGD("onVSyncEvent: %" PRId64, when);
- mVSyncEventCallRecorder.recordCall(when);
+ mVSyncEventCallRecorder.recordCall(when, expectedVSyncTimestamp, deadlineTimestamp);
}
void DispSyncSourceTest::createDispSync() {
- mDispSync = std::make_unique<mock::DispSync>();
+ mVSyncDispatch = std::make_unique<MockVSyncDispatch>();
}
void DispSyncSourceTest::createDispSyncSource() {
- createDispSync();
- mDispSyncSource = std::make_unique<DispSyncSource>(mDispSync.get(), mPhaseOffset.count(), true,
- "DispSyncSourceTest");
+ mDispSyncSource =
+ std::make_unique<scheduler::DispSyncSource>(*mVSyncDispatch, mWorkDuration,
+ mReadyDuration, true, mName.c_str());
mDispSyncSource->setCallback(this);
}
@@ -89,57 +180,119 @@
TEST_F(DispSyncSourceTest, createDispSync) {
createDispSync();
- EXPECT_TRUE(mDispSync);
+ EXPECT_TRUE(mVSyncDispatch);
}
TEST_F(DispSyncSourceTest, createDispSyncSource) {
+ createDispSync();
+
+ InSequence seq;
+ EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).WillOnce(Return(mFakeToken));
+ EXPECT_CALL(*mVSyncDispatch, cancel(mFakeToken))
+ .WillOnce(Return(scheduler::CancelResult::Cancelled));
+ EXPECT_CALL(*mVSyncDispatch, unregisterCallback(mFakeToken)).WillOnce(Return());
createDispSyncSource();
+
EXPECT_TRUE(mDispSyncSource);
}
TEST_F(DispSyncSourceTest, noCallbackAfterInit) {
+ createDispSync();
+
+ InSequence seq;
+ EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
+ EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
+ EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
createDispSyncSource();
+
EXPECT_TRUE(mDispSyncSource);
// DispSyncSource starts with Vsync disabled
- mDispSync->triggerCallback();
+ mVSyncDispatch->triggerCallbacks();
EXPECT_FALSE(mVSyncEventCallRecorder.waitForUnexpectedCall().has_value());
}
TEST_F(DispSyncSourceTest, waitForCallbacks) {
+ createDispSync();
+
+ InSequence seq;
+ EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
+ EXPECT_CALL(*mVSyncDispatch,
+ schedule(_, Truly([&](auto timings) {
+ return timings.workDuration == mWorkDuration.count() &&
+ timings.readyDuration == mReadyDuration.count();
+ })))
+ .Times(mIterations + 1);
+ EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
+ EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
createDispSyncSource();
+
EXPECT_TRUE(mDispSyncSource);
mDispSyncSource->setVSyncEnabled(true);
- EXPECT_EQ(mDispSync->getCallbackPhase(), mPhaseOffset.count());
-
for (int i = 0; i < mIterations; i++) {
- mDispSync->triggerCallback();
- EXPECT_TRUE(mVSyncEventCallRecorder.waitForCall().has_value());
+ mVSyncDispatch->triggerCallbacks();
+ const auto callbackData = mVSyncEventCallRecorder.waitForCall();
+ ASSERT_TRUE(callbackData.has_value());
+ const auto [when, expectedVSyncTimestamp, deadlineTimestamp] = callbackData.value();
+ EXPECT_EQ(when, expectedVSyncTimestamp - mWorkDuration.count() - mReadyDuration.count());
}
}
-TEST_F(DispSyncSourceTest, waitForCallbacksWithPhaseChange) {
+TEST_F(DispSyncSourceTest, waitForCallbacksWithDurationChange) {
+ createDispSync();
+
+ InSequence seq;
+ EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
+ EXPECT_CALL(*mVSyncDispatch,
+ schedule(_, Truly([&](auto timings) {
+ return timings.workDuration == mWorkDuration.count() &&
+ timings.readyDuration == mReadyDuration.count();
+ })))
+ .Times(1);
+
createDispSyncSource();
+
EXPECT_TRUE(mDispSyncSource);
mDispSyncSource->setVSyncEnabled(true);
- EXPECT_EQ(mDispSync->getCallbackPhase(), mPhaseOffset.count());
-
+ EXPECT_CALL(*mVSyncDispatch,
+ schedule(_, Truly([&](auto timings) {
+ return timings.workDuration == mWorkDuration.count() &&
+ timings.readyDuration == mReadyDuration.count();
+ })))
+ .Times(mIterations);
for (int i = 0; i < mIterations; i++) {
- mDispSync->triggerCallback();
- EXPECT_TRUE(mVSyncEventCallRecorder.waitForCall().has_value());
+ mVSyncDispatch->triggerCallbacks();
+ const auto callbackData = mVSyncEventCallRecorder.waitForCall();
+ ASSERT_TRUE(callbackData.has_value());
+ const auto [when, expectedVSyncTimestamp, deadlineTimestamp] = callbackData.value();
+ EXPECT_EQ(when, expectedVSyncTimestamp - mWorkDuration.count() - mReadyDuration.count());
}
- EXPECT_CALL(*mDispSync, getPeriod()).Times(1).WillOnce(Return(16666666));
- mDispSyncSource->setPhaseOffset((mPhaseOffset / 2).count());
+ const auto newDuration = mWorkDuration / 2;
+ EXPECT_CALL(*mVSyncDispatch, schedule(_, Truly([&](auto timings) {
+ return timings.workDuration == newDuration.count() &&
+ timings.readyDuration == 0;
+ })))
+ .Times(1);
+ mDispSyncSource->setDuration(newDuration, 0ns);
- EXPECT_EQ(mDispSync->getCallbackPhase(), (mPhaseOffset / 2).count());
-
+ EXPECT_CALL(*mVSyncDispatch, schedule(_, Truly([&](auto timings) {
+ return timings.workDuration == newDuration.count() &&
+ timings.readyDuration == 0;
+ })))
+ .Times(mIterations);
for (int i = 0; i < mIterations; i++) {
- mDispSync->triggerCallback();
- EXPECT_TRUE(mVSyncEventCallRecorder.waitForCall().has_value());
+ mVSyncDispatch->triggerCallbacks();
+ const auto callbackData = mVSyncEventCallRecorder.waitForCall();
+ ASSERT_TRUE(callbackData.has_value());
+ const auto [when, expectedVSyncTimestamp, deadlineTimestamp] = callbackData.value();
+ EXPECT_EQ(when, expectedVSyncTimestamp - newDuration.count());
}
+
+ EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1);
+ EXPECT_CALL(*mVSyncDispatch, unregisterCallback(_)).Times(1);
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 7fade0d..b9c9fe7 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -1325,8 +1325,6 @@
// The call disable vsyncs
EXPECT_CALL(mSchedulerCallback, setVsyncEnabled(false)).Times(1);
- // The call ends any display resyncs
- EXPECT_CALL(*mPrimaryDispSync, endResync()).Times(1);
// --------------------------------------------------------------------
// Invocation
@@ -3265,16 +3263,11 @@
EXPECT_CALL(*test->mPrimaryDispSync, setPeriod(DEFAULT_REFRESH_RATE)).Times(1);
EXPECT_CALL(*test->mPrimaryDispSync, beginResync()).Times(1);
}
-
- static void setupEndResyncCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mPrimaryDispSync, endResync()).Times(1);
- }
};
struct DispSyncNotSupportedVariant {
static void setupBeginResyncCallExpectations(DisplayTransactionTest* /* test */) {}
- static void setupEndResyncCallExpectations(DisplayTransactionTest* /* test */) {}
};
// --------------------------------------------------------------------
@@ -3326,7 +3319,6 @@
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
- Case::DispSync::setupEndResyncCallExpectations(test);
Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::OFF);
}
@@ -3389,7 +3381,6 @@
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
- Case::DispSync::setupEndResyncCallExpectations(test);
Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND);
}
};
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index aab6d01..ae94f16 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -46,7 +46,9 @@
MOCK_METHOD1(setVSyncEnabled, void(bool));
MOCK_METHOD1(setCallback, void(VSyncSource::Callback*));
- MOCK_METHOD1(setPhaseOffset, void(nsecs_t));
+ MOCK_METHOD2(setDuration,
+ void(std::chrono::nanoseconds workDuration,
+ std::chrono::nanoseconds readyDuration));
MOCK_METHOD1(pauseVsyncCallback, void(bool));
MOCK_CONST_METHOD1(dump, void(std::string&));
};
@@ -74,7 +76,8 @@
ISurfaceComposer::ConfigChanged configChanged);
void expectVSyncSetEnabledCallReceived(bool expectedState);
- void expectVSyncSetPhaseOffsetCallReceived(nsecs_t expectedPhaseOffset);
+ void expectVSyncSetDurationCallReceived(std::chrono::nanoseconds expectedDuration,
+ std::chrono::nanoseconds expectedReadyDuration);
VSyncSource::Callback* expectVSyncSetCallbackCallReceived();
void expectInterceptCallReceived(nsecs_t expectedTimestamp);
void expectVsyncEventReceivedByConnection(const char* name,
@@ -89,7 +92,8 @@
AsyncCallRecorder<void (*)(bool)> mVSyncSetEnabledCallRecorder;
AsyncCallRecorder<void (*)(VSyncSource::Callback*)> mVSyncSetCallbackCallRecorder;
- AsyncCallRecorder<void (*)(nsecs_t)> mVSyncSetPhaseOffsetCallRecorder;
+ AsyncCallRecorder<void (*)(std::chrono::nanoseconds, std::chrono::nanoseconds)>
+ mVSyncSetDurationCallRecorder;
AsyncCallRecorder<void (*)()> mResyncCallRecorder;
AsyncCallRecorder<void (*)(nsecs_t)> mInterceptVSyncCallRecorder;
ConnectionEventRecorder mConnectionEventCallRecorder{0};
@@ -114,8 +118,8 @@
EXPECT_CALL(*mVSyncSource, setCallback(_))
.WillRepeatedly(Invoke(mVSyncSetCallbackCallRecorder.getInvocable()));
- EXPECT_CALL(*mVSyncSource, setPhaseOffset(_))
- .WillRepeatedly(Invoke(mVSyncSetPhaseOffsetCallRecorder.getInvocable()));
+ EXPECT_CALL(*mVSyncSource, setDuration(_, _))
+ .WillRepeatedly(Invoke(mVSyncSetDurationCallRecorder.getInvocable()));
createThread(std::move(vsyncSource));
mConnection = createConnection(mConnectionEventCallRecorder,
@@ -159,10 +163,12 @@
EXPECT_EQ(expectedState, std::get<0>(args.value()));
}
-void EventThreadTest::expectVSyncSetPhaseOffsetCallReceived(nsecs_t expectedPhaseOffset) {
- auto args = mVSyncSetPhaseOffsetCallRecorder.waitForCall();
+void EventThreadTest::expectVSyncSetDurationCallReceived(
+ std::chrono::nanoseconds expectedDuration, std::chrono::nanoseconds expectedReadyDuration) {
+ auto args = mVSyncSetDurationCallRecorder.waitForCall();
ASSERT_TRUE(args.has_value());
- EXPECT_EQ(expectedPhaseOffset, std::get<0>(args.value()));
+ EXPECT_EQ(expectedDuration, std::get<0>(args.value()));
+ EXPECT_EQ(expectedReadyDuration, std::get<1>(args.value()));
}
VSyncSource::Callback* EventThreadTest::expectVSyncSetCallbackCallReceived() {
@@ -229,7 +235,7 @@
TEST_F(EventThreadTest, canCreateAndDestroyThreadWithNoEventsSent) {
EXPECT_FALSE(mVSyncSetEnabledCallRecorder.waitForUnexpectedCall().has_value());
EXPECT_FALSE(mVSyncSetCallbackCallRecorder.waitForCall(0us).has_value());
- EXPECT_FALSE(mVSyncSetPhaseOffsetCallRecorder.waitForCall(0us).has_value());
+ EXPECT_FALSE(mVSyncSetDurationCallRecorder.waitForCall(0us).has_value());
EXPECT_FALSE(mResyncCallRecorder.waitForCall(0us).has_value());
EXPECT_FALSE(mInterceptVSyncCallRecorder.waitForCall(0us).has_value());
EXPECT_FALSE(mConnectionEventCallRecorder.waitForCall(0us).has_value());
@@ -258,14 +264,14 @@
// Use the received callback to signal a first vsync event.
// The interceptor should receive the event, as well as the connection.
- mCallback->onVSyncEvent(123, 456);
+ mCallback->onVSyncEvent(123, 456, 789);
expectInterceptCallReceived(123);
expectVsyncEventReceivedByConnection(123, 1u);
// Use the received callback to signal a second vsync event.
// The interceptor should receive the event, but the the connection should
// not as it was only interested in the first.
- mCallback->onVSyncEvent(456, 123);
+ mCallback->onVSyncEvent(456, 123, 0);
expectInterceptCallReceived(456);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
@@ -299,7 +305,7 @@
// Send a vsync event. EventThread should then make a call to the
// interceptor, and the second connection. The first connection should not
// get the event.
- mCallback->onVSyncEvent(123, 456);
+ mCallback->onVSyncEvent(123, 456, 0);
expectInterceptCallReceived(123);
EXPECT_FALSE(firstConnectionEventRecorder.waitForUnexpectedCall().has_value());
expectVsyncEventReceivedByConnection("secondConnection", secondConnectionEventRecorder, 123,
@@ -314,17 +320,17 @@
// Send a vsync event. EventThread should then make a call to the
// interceptor, and the connection.
- mCallback->onVSyncEvent(123, 456);
+ mCallback->onVSyncEvent(123, 456, 789);
expectInterceptCallReceived(123);
expectVsyncEventReceivedByConnection(123, 1u);
// A second event should go to the same places.
- mCallback->onVSyncEvent(456, 123);
+ mCallback->onVSyncEvent(456, 123, 0);
expectInterceptCallReceived(456);
expectVsyncEventReceivedByConnection(456, 2u);
// A third event should go to the same places.
- mCallback->onVSyncEvent(789, 777);
+ mCallback->onVSyncEvent(789, 777, 111);
expectInterceptCallReceived(789);
expectVsyncEventReceivedByConnection(789, 3u);
}
@@ -336,22 +342,22 @@
expectVSyncSetEnabledCallReceived(true);
// The first event will be seen by the interceptor, and not the connection.
- mCallback->onVSyncEvent(123, 456);
+ mCallback->onVSyncEvent(123, 456, 789);
expectInterceptCallReceived(123);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
// The second event will be seen by the interceptor and the connection.
- mCallback->onVSyncEvent(456, 123);
+ mCallback->onVSyncEvent(456, 123, 0);
expectInterceptCallReceived(456);
expectVsyncEventReceivedByConnection(456, 2u);
// The third event will be seen by the interceptor, and not the connection.
- mCallback->onVSyncEvent(789, 777);
+ mCallback->onVSyncEvent(789, 777, 744);
expectInterceptCallReceived(789);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
// The fourth event will be seen by the interceptor and the connection.
- mCallback->onVSyncEvent(101112, 7847);
+ mCallback->onVSyncEvent(101112, 7847, 86);
expectInterceptCallReceived(101112);
expectVsyncEventReceivedByConnection(101112, 4u);
}
@@ -366,7 +372,7 @@
mConnection = nullptr;
// The first event will be seen by the interceptor, and not the connection.
- mCallback->onVSyncEvent(123, 456);
+ mCallback->onVSyncEvent(123, 456, 789);
expectInterceptCallReceived(123);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
@@ -386,13 +392,13 @@
// The first event will be seen by the interceptor, and by the connection,
// which then returns an error.
- mCallback->onVSyncEvent(123, 456);
+ mCallback->onVSyncEvent(123, 456, 789);
expectInterceptCallReceived(123);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
// A subsequent event will be seen by the interceptor and not by the
// connection.
- mCallback->onVSyncEvent(456, 123);
+ mCallback->onVSyncEvent(456, 123, 0);
expectInterceptCallReceived(456);
EXPECT_FALSE(errorConnectionEventRecorder.waitForUnexpectedCall().has_value());
@@ -420,7 +426,7 @@
// The first event will be seen by the interceptor, and by the connection,
// which then returns an error.
- mCallback->onVSyncEvent(123, 456);
+ mCallback->onVSyncEvent(123, 456, 789);
expectInterceptCallReceived(123);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
expectVsyncEventReceivedByConnection("successConnection", secondConnectionEventRecorder, 123,
@@ -440,13 +446,13 @@
// The first event will be seen by the interceptor, and by the connection,
// which then returns an non-fatal error.
- mCallback->onVSyncEvent(123, 456);
+ mCallback->onVSyncEvent(123, 456, 789);
expectInterceptCallReceived(123);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
// A subsequent event will be seen by the interceptor, and by the connection,
// which still then returns an non-fatal error.
- mCallback->onVSyncEvent(456, 123);
+ mCallback->onVSyncEvent(456, 123, 0);
expectInterceptCallReceived(456);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 456, 2u);
@@ -455,8 +461,8 @@
}
TEST_F(EventThreadTest, setPhaseOffsetForwardsToVSyncSource) {
- mThread->setPhaseOffset(321);
- expectVSyncSetPhaseOffsetCallReceived(321);
+ mThread->setDuration(321ns, 456ns);
+ expectVSyncSetDurationCallReceived(321ns, 456ns);
}
TEST_F(EventThreadTest, postHotplugInternalDisconnect) {
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 39e793a..35619a3 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -120,8 +120,8 @@
mScheduler.dump(handle, output);
EXPECT_TRUE(output.empty());
- EXPECT_CALL(*mEventThread, setPhaseOffset(_)).Times(0);
- mScheduler.setPhaseOffset(handle, 10);
+ EXPECT_CALL(*mEventThread, setDuration(10ns, 20ns)).Times(0);
+ mScheduler.setDuration(handle, 10ns, 20ns);
}
TEST_F(SchedulerTest, validConnectionHandle) {
@@ -146,8 +146,8 @@
mScheduler.dump(mConnectionHandle, output);
EXPECT_FALSE(output.empty());
- EXPECT_CALL(*mEventThread, setPhaseOffset(10)).Times(1);
- mScheduler.setPhaseOffset(mConnectionHandle, 10);
+ EXPECT_CALL(*mEventThread, setDuration(10ns, 20ns)).Times(1);
+ mScheduler.setDuration(mConnectionHandle, 10ns, 20ns);
static constexpr size_t kEventConnections = 5;
EXPECT_CALL(*mEventThread, getEventThreadConnectionCount()).WillOnce(Return(kEventConnections));
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
index c2a7752..3408fed 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
@@ -104,14 +104,18 @@
class RepeatingCallbackReceiver {
public:
- RepeatingCallbackReceiver(VSyncDispatch& dispatch, nsecs_t wl)
- : mWorkload(wl),
+ RepeatingCallbackReceiver(VSyncDispatch& dispatch, nsecs_t workload, nsecs_t readyDuration)
+ : mWorkload(workload),
+ mReadyDuration(readyDuration),
mCallback(
- dispatch, [&](auto time, auto) { callback_called(time); }, "repeat0") {}
+ dispatch, [&](auto time, auto, auto) { callback_called(time); }, "repeat0") {}
void repeatedly_schedule(size_t iterations, std::function<void(nsecs_t)> const& onEachFrame) {
mCallbackTimes.reserve(iterations);
- mCallback.schedule(mWorkload, systemTime(SYSTEM_TIME_MONOTONIC) + mWorkload);
+ mCallback.schedule(
+ {.workDuration = mWorkload,
+ .readyDuration = mReadyDuration,
+ .earliestVsync = systemTime(SYSTEM_TIME_MONOTONIC) + mWorkload + mReadyDuration});
for (auto i = 0u; i < iterations - 1; i++) {
std::unique_lock<decltype(mMutex)> lk(mMutex);
@@ -122,7 +126,9 @@
onEachFrame(last);
- mCallback.schedule(mWorkload, last + mWorkload);
+ mCallback.schedule({.workDuration = mWorkload,
+ .readyDuration = mReadyDuration,
+ .earliestVsync = last + mWorkload + mReadyDuration});
}
// wait for the last callback.
@@ -144,6 +150,7 @@
}
nsecs_t const mWorkload;
+ nsecs_t const mReadyDuration;
VSyncCallbackRegistration mCallback;
std::mutex mMutex;
@@ -160,9 +167,9 @@
static size_t constexpr num_clients = 3;
std::array<RepeatingCallbackReceiver, num_clients>
- cb_receiver{RepeatingCallbackReceiver(dispatch, toNs(1500us)),
- RepeatingCallbackReceiver(dispatch, toNs(0h)),
- RepeatingCallbackReceiver(dispatch, toNs(1ms))};
+ cb_receiver{RepeatingCallbackReceiver(dispatch, toNs(1500us), toNs(2500us)),
+ RepeatingCallbackReceiver(dispatch, toNs(0h), toNs(0h)),
+ RepeatingCallbackReceiver(dispatch, toNs(1ms), toNs(3ms))};
auto const on_each_frame = [](nsecs_t) {};
std::array<std::thread, num_clients> threads{
@@ -187,7 +194,7 @@
VSyncDispatchTimerQueue dispatch(std::make_unique<Timer>(), tracker, mDispatchGroupThreshold,
mVsyncMoveThreshold);
- RepeatingCallbackReceiver cb_receiver(dispatch, toNs(1ms));
+ RepeatingCallbackReceiver cb_receiver(dispatch, toNs(1ms), toNs(5ms));
auto const on_each_frame = [&](nsecs_t last_known) {
tracker.set_interval(next_vsync_interval += toNs(1ms), last_known);
@@ -205,7 +212,7 @@
VSyncDispatchTimerQueue dispatch(std::make_unique<Timer>(), tracker, mDispatchGroupThreshold,
mVsyncMoveThreshold);
- RepeatingCallbackReceiver cb_receiver(dispatch, toNs(1ms));
+ RepeatingCallbackReceiver cb_receiver(dispatch, toNs(1ms), toNs(5ms));
auto jump_frame_counter = 0u;
auto constexpr jump_frame_at = 10u;
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index f630e3b..24e243f 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -109,22 +109,24 @@
CountingCallback(VSyncDispatch& dispatch)
: mDispatch(dispatch),
mToken(dispatch.registerCallback(std::bind(&CountingCallback::counter, this,
- std::placeholders::_1,
- std::placeholders::_2),
+ std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3),
"test")) {}
~CountingCallback() { mDispatch.unregisterCallback(mToken); }
operator VSyncDispatch::CallbackToken() const { return mToken; }
- void counter(nsecs_t time, nsecs_t wakeup_time) {
+ void counter(nsecs_t time, nsecs_t wakeup_time, nsecs_t readyTime) {
mCalls.push_back(time);
mWakeupTime.push_back(wakeup_time);
+ mReadyTime.push_back(readyTime);
}
VSyncDispatch& mDispatch;
VSyncDispatch::CallbackToken mToken;
std::vector<nsecs_t> mCalls;
std::vector<nsecs_t> mWakeupTime;
+ std::vector<nsecs_t> mReadyTime;
};
class PausingCallback {
@@ -228,7 +230,11 @@
VSyncDispatchTimerQueue mDispatch{createTimeKeeper(), mStubTracker, mDispatchGroupThreshold,
mVsyncMoveThreshold};
CountingCallback cb(mDispatch);
- EXPECT_EQ(mDispatch.schedule(cb, 100, 1000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb,
+ {.workDuration = 100,
+ .readyDuration = 0,
+ .earliestVsync = 1000}),
+ ScheduleResult::Scheduled);
}
}
@@ -237,7 +243,11 @@
EXPECT_CALL(mMockClock, alarmAt(_, 900));
CountingCallback cb(mDispatch);
- EXPECT_EQ(mDispatch.schedule(cb, 100, intended), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb,
+ {.workDuration = 100,
+ .readyDuration = 0,
+ .earliestVsync = intended}),
+ ScheduleResult::Scheduled);
advanceToNextCallback();
ASSERT_THAT(cb.mCalls.size(), Eq(1));
@@ -249,7 +259,7 @@
EXPECT_CALL(mMockClock, alarmAt(_, 1050));
CountingCallback cb(mDispatch);
- mDispatch.schedule(cb, 100, mPeriod);
+ mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = mPeriod});
advanceToNextCallback();
ASSERT_THAT(cb.mCalls.size(), Eq(1));
@@ -265,7 +275,11 @@
EXPECT_CALL(mMockClock, alarmAt(_, mPeriod));
CountingCallback cb(mDispatch);
- EXPECT_EQ(mDispatch.schedule(cb, workDuration, mPeriod), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb,
+ {.workDuration = workDuration,
+ .readyDuration = 0,
+ .earliestVsync = mPeriod}),
+ ScheduleResult::Scheduled);
}
TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancel) {
@@ -273,7 +287,11 @@
EXPECT_CALL(mMockClock, alarmCancel());
CountingCallback cb(mDispatch);
- EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb,
+ {.workDuration = 100,
+ .readyDuration = 0,
+ .earliestVsync = mPeriod}),
+ ScheduleResult::Scheduled);
EXPECT_EQ(mDispatch.cancel(cb), CancelResult::Cancelled);
}
@@ -282,7 +300,11 @@
EXPECT_CALL(mMockClock, alarmCancel());
CountingCallback cb(mDispatch);
- EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb,
+ {.workDuration = 100,
+ .readyDuration = 0,
+ .earliestVsync = mPeriod}),
+ ScheduleResult::Scheduled);
mMockClock.advanceBy(950);
EXPECT_EQ(mDispatch.cancel(cb), CancelResult::TooLate);
}
@@ -292,7 +314,11 @@
EXPECT_CALL(mMockClock, alarmCancel());
PausingCallback cb(mDispatch, std::chrono::duration_cast<std::chrono::milliseconds>(1s));
- EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb,
+ {.workDuration = 100,
+ .readyDuration = 0,
+ .earliestVsync = mPeriod}),
+ ScheduleResult::Scheduled);
std::thread pausingThread([&] { mMockClock.advanceToNextCallback(); });
EXPECT_TRUE(cb.waitForPause());
@@ -309,7 +335,11 @@
PausingCallback cb(mDispatch, 50ms);
cb.stashResource(resource);
- EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb,
+ {.workDuration = 100,
+ .readyDuration = 0,
+ .earliestVsync = mPeriod}),
+ ScheduleResult::Scheduled);
std::thread pausingThread([&] { mMockClock.advanceToNextCallback(); });
EXPECT_TRUE(cb.waitForPause());
@@ -339,8 +369,8 @@
CountingCallback cb0(mDispatch);
CountingCallback cb1(mDispatch);
- mDispatch.schedule(cb0, 100, mPeriod);
- mDispatch.schedule(cb1, 250, mPeriod);
+ mDispatch.schedule(cb0, {.workDuration = 100, .readyDuration = 0, .earliestVsync = mPeriod});
+ mDispatch.schedule(cb1, {.workDuration = 250, .readyDuration = 0, .earliestVsync = mPeriod});
advanceToNextCallback();
advanceToNextCallback();
@@ -367,8 +397,9 @@
CountingCallback cb0(mDispatch);
CountingCallback cb1(mDispatch);
- mDispatch.schedule(cb0, 100, mPeriod * 10);
- mDispatch.schedule(cb1, 250, mPeriod);
+ mDispatch.schedule(cb0,
+ {.workDuration = 100, .readyDuration = 0, .earliestVsync = mPeriod * 10});
+ mDispatch.schedule(cb1, {.workDuration = 250, .readyDuration = 0, .earliestVsync = mPeriod});
mDispatch.cancel(cb1);
}
@@ -380,9 +411,9 @@
CountingCallback cb0(mDispatch);
CountingCallback cb1(mDispatch);
- mDispatch.schedule(cb0, 400, 1000);
- mDispatch.schedule(cb1, 200, 1000);
- mDispatch.schedule(cb1, 300, 1000);
+ mDispatch.schedule(cb0, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000});
+ mDispatch.schedule(cb1, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 1000});
+ mDispatch.schedule(cb1, {.workDuration = 300, .readyDuration = 0, .earliestVsync = 1000});
advanceToNextCallback();
}
@@ -395,9 +426,9 @@
CountingCallback cb0(mDispatch);
CountingCallback cb1(mDispatch);
- mDispatch.schedule(cb0, 400, 1000);
- mDispatch.schedule(cb1, 200, 1000);
- mDispatch.schedule(cb1, 500, 1000);
+ mDispatch.schedule(cb0, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000});
+ mDispatch.schedule(cb1, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 1000});
+ mDispatch.schedule(cb1, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000});
advanceToNextCallback();
}
@@ -415,9 +446,10 @@
CountingCallback cb0(mDispatch);
CountingCallback cb1(mDispatch);
- mDispatch.schedule(cb0, 400, 1000);
- mDispatch.schedule(cb1, 200, 1000);
- mDispatch.schedule(cb1, closeOffset, 1000);
+ mDispatch.schedule(cb0, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000});
+ mDispatch.schedule(cb1, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 1000});
+ mDispatch.schedule(cb1,
+ {.workDuration = closeOffset, .readyDuration = 0, .earliestVsync = 1000});
advanceToNextCallback();
ASSERT_THAT(cb0.mCalls.size(), Eq(1));
@@ -425,8 +457,9 @@
ASSERT_THAT(cb1.mCalls.size(), Eq(1));
EXPECT_THAT(cb1.mCalls[0], Eq(mPeriod));
- mDispatch.schedule(cb0, 400, 2000);
- mDispatch.schedule(cb1, notCloseOffset, 2000);
+ mDispatch.schedule(cb0, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 2000});
+ mDispatch.schedule(cb1,
+ {.workDuration = notCloseOffset, .readyDuration = 0, .earliestVsync = 2000});
advanceToNextCallback();
ASSERT_THAT(cb1.mCalls.size(), Eq(2));
EXPECT_THAT(cb1.mCalls[1], Eq(2000));
@@ -446,8 +479,8 @@
CountingCallback cb0(mDispatch);
CountingCallback cb1(mDispatch);
- mDispatch.schedule(cb0, 100, 1000);
- mDispatch.schedule(cb1, 200, 1000);
+ mDispatch.schedule(cb0, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000});
+ mDispatch.schedule(cb1, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 1000});
advanceToNextCallback();
EXPECT_EQ(mDispatch.cancel(cb0), CancelResult::Cancelled);
}
@@ -460,18 +493,18 @@
.WillOnce(Return(2950));
CountingCallback cb(mDispatch);
- mDispatch.schedule(cb, 100, 920);
+ mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 920});
mMockClock.advanceBy(850);
EXPECT_THAT(cb.mCalls.size(), Eq(1));
- mDispatch.schedule(cb, 100, 1900);
+ mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1900});
mMockClock.advanceBy(900);
EXPECT_THAT(cb.mCalls.size(), Eq(1));
mMockClock.advanceBy(125);
EXPECT_THAT(cb.mCalls.size(), Eq(2));
- mDispatch.schedule(cb, 100, 2900);
+ mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2900});
mMockClock.advanceBy(975);
EXPECT_THAT(cb.mCalls.size(), Eq(3));
}
@@ -482,10 +515,16 @@
EXPECT_CALL(mMockClock, alarmAt(_, 1900)).InSequence(seq);
VSyncDispatch::CallbackToken tmp;
- tmp = mDispatch.registerCallback([&](auto, auto) { mDispatch.schedule(tmp, 100, 2000); },
- "o.o");
+ tmp = mDispatch.registerCallback(
+ [&](auto, auto, auto) {
+ mDispatch.schedule(tmp,
+ {.workDuration = 100,
+ .readyDuration = 0,
+ .earliestVsync = 2000});
+ },
+ "o.o");
- mDispatch.schedule(tmp, 100, 1000);
+ mDispatch.schedule(tmp, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000});
advanceToNextCallback();
}
@@ -493,17 +532,27 @@
VSyncDispatch::CallbackToken tmp;
std::optional<nsecs_t> lastTarget;
tmp = mDispatch.registerCallback(
- [&](auto timestamp, auto) {
- EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp - mVsyncMoveThreshold),
+ [&](auto timestamp, auto, auto) {
+ EXPECT_EQ(mDispatch.schedule(tmp,
+ {.workDuration = 400,
+ .readyDuration = 0,
+ .earliestVsync = timestamp - mVsyncMoveThreshold}),
ScheduleResult::Scheduled);
- EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp), ScheduleResult::Scheduled);
- EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp + mVsyncMoveThreshold),
+ EXPECT_EQ(mDispatch.schedule(tmp,
+ {.workDuration = 400,
+ .readyDuration = 0,
+ .earliestVsync = timestamp}),
+ ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(tmp,
+ {.workDuration = 400,
+ .readyDuration = 0,
+ .earliestVsync = timestamp + mVsyncMoveThreshold}),
ScheduleResult::Scheduled);
lastTarget = timestamp;
},
"oo");
- mDispatch.schedule(tmp, 999, 1000);
+ mDispatch.schedule(tmp, {.workDuration = 999, .readyDuration = 0, .earliestVsync = 1000});
advanceToNextCallback();
EXPECT_THAT(lastTarget, Eq(1000));
@@ -519,16 +568,16 @@
EXPECT_CALL(mMockClock, alarmAt(_, 1900)).InSequence(seq);
CountingCallback cb(mDispatch);
- mDispatch.schedule(cb, 0, 1000);
+ mDispatch.schedule(cb, {.workDuration = 0, .readyDuration = 0, .earliestVsync = 1000});
mMockClock.advanceBy(750);
- mDispatch.schedule(cb, 50, 1000);
+ mDispatch.schedule(cb, {.workDuration = 50, .readyDuration = 0, .earliestVsync = 1000});
advanceToNextCallback();
- mDispatch.schedule(cb, 50, 2000);
+ mDispatch.schedule(cb, {.workDuration = 50, .readyDuration = 0, .earliestVsync = 2000});
mMockClock.advanceBy(800);
- mDispatch.schedule(cb, 100, 2000);
+ mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2000});
}
TEST_F(VSyncDispatchTimerQueueTest, lateModifications) {
@@ -541,12 +590,12 @@
CountingCallback cb0(mDispatch);
CountingCallback cb1(mDispatch);
- mDispatch.schedule(cb0, 500, 1000);
- mDispatch.schedule(cb1, 100, 1000);
+ mDispatch.schedule(cb0, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000});
+ mDispatch.schedule(cb1, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000});
advanceToNextCallback();
- mDispatch.schedule(cb0, 200, 2000);
- mDispatch.schedule(cb1, 150, 1000);
+ mDispatch.schedule(cb0, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 2000});
+ mDispatch.schedule(cb1, {.workDuration = 150, .readyDuration = 0, .earliestVsync = 1000});
advanceToNextCallback();
advanceToNextCallback();
@@ -558,8 +607,8 @@
CountingCallback cb0(mDispatch);
CountingCallback cb1(mDispatch);
- mDispatch.schedule(cb0, 500, 1000);
- mDispatch.schedule(cb1, 500, 20000);
+ mDispatch.schedule(cb0, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000});
+ mDispatch.schedule(cb1, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 20000});
}
TEST_F(VSyncDispatchTimerQueueTest, setsTimerAfterCancellation) {
@@ -569,31 +618,43 @@
EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq);
CountingCallback cb0(mDispatch);
- mDispatch.schedule(cb0, 500, 1000);
+ mDispatch.schedule(cb0, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000});
mDispatch.cancel(cb0);
- mDispatch.schedule(cb0, 100, 1000);
+ mDispatch.schedule(cb0, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000});
}
TEST_F(VSyncDispatchTimerQueueTest, makingUpIdsError) {
VSyncDispatch::CallbackToken token(100);
- EXPECT_THAT(mDispatch.schedule(token, 100, 1000), Eq(ScheduleResult::Error));
+ EXPECT_THAT(mDispatch.schedule(token,
+ {.workDuration = 100,
+ .readyDuration = 0,
+ .earliestVsync = 1000}),
+ Eq(ScheduleResult::Error));
EXPECT_THAT(mDispatch.cancel(token), Eq(CancelResult::Error));
}
TEST_F(VSyncDispatchTimerQueueTest, canMoveCallbackBackwardsInTime) {
CountingCallback cb0(mDispatch);
- EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled);
- EXPECT_EQ(mDispatch.schedule(cb0, 100, 1000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb0,
+ {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}),
+ ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb0,
+ {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000}),
+ ScheduleResult::Scheduled);
}
// b/1450138150
TEST_F(VSyncDispatchTimerQueueTest, doesNotMoveCallbackBackwardsAndSkipAScheduledTargetVSync) {
EXPECT_CALL(mMockClock, alarmAt(_, 500));
CountingCallback cb(mDispatch);
- EXPECT_EQ(mDispatch.schedule(cb, 500, 1000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb,
+ {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}),
+ ScheduleResult::Scheduled);
mMockClock.advanceBy(400);
- EXPECT_EQ(mDispatch.schedule(cb, 800, 1000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb,
+ {.workDuration = 800, .readyDuration = 0, .earliestVsync = 1000}),
+ ScheduleResult::Scheduled);
advanceToNextCallback();
ASSERT_THAT(cb.mCalls.size(), Eq(1));
}
@@ -604,16 +665,24 @@
.WillOnce(Return(1000))
.WillOnce(Return(1002));
CountingCallback cb(mDispatch);
- EXPECT_EQ(mDispatch.schedule(cb, 500, 1000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb,
+ {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}),
+ ScheduleResult::Scheduled);
mMockClock.advanceBy(400);
- EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb,
+ {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}),
+ ScheduleResult::Scheduled);
}
TEST_F(VSyncDispatchTimerQueueTest, canScheduleNegativeOffsetAgainstDifferentPeriods) {
CountingCallback cb0(mDispatch);
- EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb0,
+ {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}),
+ ScheduleResult::Scheduled);
advanceToNextCallback();
- EXPECT_EQ(mDispatch.schedule(cb0, 1100, 2000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb0,
+ {.workDuration = 1100, .readyDuration = 0, .earliestVsync = 2000}),
+ ScheduleResult::Scheduled);
}
TEST_F(VSyncDispatchTimerQueueTest, canScheduleLargeNegativeOffset) {
@@ -621,18 +690,26 @@
EXPECT_CALL(mMockClock, alarmAt(_, 500)).InSequence(seq);
EXPECT_CALL(mMockClock, alarmAt(_, 1100)).InSequence(seq);
CountingCallback cb0(mDispatch);
- EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb0,
+ {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}),
+ ScheduleResult::Scheduled);
advanceToNextCallback();
- EXPECT_EQ(mDispatch.schedule(cb0, 1900, 2000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb0,
+ {.workDuration = 1900, .readyDuration = 0, .earliestVsync = 2000}),
+ ScheduleResult::Scheduled);
}
TEST_F(VSyncDispatchTimerQueueTest, scheduleUpdatesDoesNotAffectSchedulingState) {
EXPECT_CALL(mMockClock, alarmAt(_, 600));
CountingCallback cb(mDispatch);
- EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb,
+ {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}),
+ ScheduleResult::Scheduled);
- EXPECT_EQ(mDispatch.schedule(cb, 1400, 1000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb,
+ {.workDuration = 1400, .readyDuration = 0, .earliestVsync = 1000}),
+ ScheduleResult::Scheduled);
advanceToNextCallback();
}
@@ -642,12 +719,12 @@
EXPECT_CALL(mMockClock, alarmCancel()).Times(1);
VSyncCallbackRegistration cb(
- mDispatch, [](auto, auto) {}, "");
+ mDispatch, [](auto, auto, auto) {}, "");
VSyncCallbackRegistration cb1(std::move(cb));
- cb.schedule(100, 1000);
+ cb.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000});
cb.cancel();
- cb1.schedule(500, 1000);
+ cb1.schedule({.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000});
cb1.cancel();
}
@@ -656,14 +733,14 @@
EXPECT_CALL(mMockClock, alarmCancel()).Times(1);
VSyncCallbackRegistration cb(
- mDispatch, [](auto, auto) {}, "");
+ mDispatch, [](auto, auto, auto) {}, "");
VSyncCallbackRegistration cb1(
- mDispatch, [](auto, auto) {}, "");
+ mDispatch, [](auto, auto, auto) {}, "");
cb1 = std::move(cb);
- cb.schedule(100, 1000);
+ cb.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000});
cb.cancel();
- cb1.schedule(500, 1000);
+ cb1.schedule({.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000});
cb1.cancel();
}
@@ -675,12 +752,16 @@
CountingCallback cb1(mDispatch);
CountingCallback cb2(mDispatch);
- EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb1,
+ {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}),
+ ScheduleResult::Scheduled);
mMockClock.setLag(100);
mMockClock.advanceBy(620);
- EXPECT_EQ(mDispatch.schedule(cb2, 100, 2000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb2,
+ {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2000}),
+ ScheduleResult::Scheduled);
mMockClock.advanceBy(80);
EXPECT_THAT(cb1.mCalls.size(), Eq(1));
@@ -696,12 +777,16 @@
EXPECT_CALL(mMockClock, alarmAt(_, 1630)).InSequence(seq);
CountingCallback cb(mDispatch);
- EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb,
+ {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}),
+ ScheduleResult::Scheduled);
mMockClock.setLag(100);
mMockClock.advanceBy(620);
- EXPECT_EQ(mDispatch.schedule(cb, 370, 2000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb,
+ {.workDuration = 370, .readyDuration = 0, .earliestVsync = 2000}),
+ ScheduleResult::Scheduled);
mMockClock.advanceBy(80);
EXPECT_THAT(cb.mCalls.size(), Eq(1));
@@ -715,8 +800,12 @@
CountingCallback cb1(mDispatch);
CountingCallback cb2(mDispatch);
- EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled);
- EXPECT_EQ(mDispatch.schedule(cb2, 100, 2000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb1,
+ {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}),
+ ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb2,
+ {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2000}),
+ ScheduleResult::Scheduled);
mMockClock.setLag(100);
mMockClock.advanceBy(620);
@@ -737,8 +826,12 @@
CountingCallback cb1(mDispatch);
CountingCallback cb2(mDispatch);
- EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled);
- EXPECT_EQ(mDispatch.schedule(cb2, 100, 2000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb1,
+ {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}),
+ ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb2,
+ {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2000}),
+ ScheduleResult::Scheduled);
mMockClock.setLag(100);
mMockClock.advanceBy(620);
@@ -766,16 +859,44 @@
.InSequence(seq)
.WillOnce(Return(1000));
- EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled);
- EXPECT_EQ(mDispatch.schedule(cb2, 390, 1000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb1,
+ {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}),
+ ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb2,
+ {.workDuration = 390, .readyDuration = 0, .earliestVsync = 1000}),
+ ScheduleResult::Scheduled);
mMockClock.setLag(100);
mMockClock.advanceBy(700);
ASSERT_THAT(cb1.mWakeupTime.size(), Eq(1));
EXPECT_THAT(cb1.mWakeupTime[0], Eq(600));
+ ASSERT_THAT(cb1.mReadyTime.size(), Eq(1));
+ EXPECT_THAT(cb1.mReadyTime[0], Eq(1000));
ASSERT_THAT(cb2.mWakeupTime.size(), Eq(1));
EXPECT_THAT(cb2.mWakeupTime[0], Eq(610));
+ ASSERT_THAT(cb2.mReadyTime.size(), Eq(1));
+ EXPECT_THAT(cb2.mReadyTime[0], Eq(1000));
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFutureWithReadyDuration) {
+ auto intended = mPeriod - 230;
+ EXPECT_CALL(mMockClock, alarmAt(_, 900));
+
+ CountingCallback cb(mDispatch);
+ EXPECT_EQ(mDispatch.schedule(cb,
+ {.workDuration = 70,
+ .readyDuration = 30,
+ .earliestVsync = intended}),
+ ScheduleResult::Scheduled);
+ advanceToNextCallback();
+
+ ASSERT_THAT(cb.mCalls.size(), Eq(1));
+ EXPECT_THAT(cb.mCalls[0], Eq(mPeriod));
+ ASSERT_THAT(cb.mWakeupTime.size(), Eq(1));
+ EXPECT_THAT(cb.mWakeupTime[0], 900);
+ ASSERT_THAT(cb.mReadyTime.size(), Eq(1));
+ EXPECT_THAT(cb.mReadyTime[0], 970);
}
class VSyncDispatchTimerQueueEntryTest : public testing::Test {
@@ -788,7 +909,7 @@
TEST_F(VSyncDispatchTimerQueueEntryTest, stateAfterInitialization) {
std::string name("basicname");
VSyncDispatchTimerQueueEntry entry(
- name, [](auto, auto) {}, mVsyncMoveThreshold);
+ name, [](auto, auto, auto) {}, mVsyncMoveThreshold);
EXPECT_THAT(entry.name(), Eq(name));
EXPECT_FALSE(entry.lastExecutedVsyncTarget());
EXPECT_FALSE(entry.wakeupTime());
@@ -796,10 +917,12 @@
TEST_F(VSyncDispatchTimerQueueEntryTest, stateScheduling) {
VSyncDispatchTimerQueueEntry entry(
- "test", [](auto, auto) {}, mVsyncMoveThreshold);
+ "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
EXPECT_FALSE(entry.wakeupTime());
- EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ EXPECT_THAT(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500},
+ mStubTracker, 0),
+ Eq(ScheduleResult::Scheduled));
auto const wakeup = entry.wakeupTime();
ASSERT_TRUE(wakeup);
EXPECT_THAT(*wakeup, Eq(900));
@@ -816,10 +939,12 @@
.Times(1)
.WillOnce(Return(10000));
VSyncDispatchTimerQueueEntry entry(
- "test", [](auto, auto) {}, mVsyncMoveThreshold);
+ "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
EXPECT_FALSE(entry.wakeupTime());
- EXPECT_THAT(entry.schedule(500, 994, mStubTracker, now), Eq(ScheduleResult::Scheduled));
+ EXPECT_THAT(entry.schedule({.workDuration = 500, .readyDuration = 0, .earliestVsync = 994},
+ mStubTracker, now),
+ Eq(ScheduleResult::Scheduled));
auto const wakeup = entry.wakeupTime();
ASSERT_TRUE(wakeup);
EXPECT_THAT(*wakeup, Eq(9500));
@@ -829,21 +954,29 @@
auto callCount = 0;
auto vsyncCalledTime = 0;
auto wakeupCalledTime = 0;
+ auto readyCalledTime = 0;
VSyncDispatchTimerQueueEntry entry(
"test",
- [&](auto vsyncTime, auto wakeupTime) {
+ [&](auto vsyncTime, auto wakeupTime, auto readyTime) {
callCount++;
vsyncCalledTime = vsyncTime;
wakeupCalledTime = wakeupTime;
+ readyCalledTime = readyTime;
},
mVsyncMoveThreshold);
- EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ EXPECT_THAT(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500},
+ mStubTracker, 0),
+ Eq(ScheduleResult::Scheduled));
auto const wakeup = entry.wakeupTime();
ASSERT_TRUE(wakeup);
EXPECT_THAT(*wakeup, Eq(900));
- entry.callback(entry.executing(), *wakeup);
+ auto const ready = entry.readyTime();
+ ASSERT_TRUE(ready);
+ EXPECT_THAT(*ready, Eq(1000));
+
+ entry.callback(entry.executing(), *wakeup, *ready);
EXPECT_THAT(callCount, Eq(1));
EXPECT_THAT(vsyncCalledTime, Eq(mPeriod));
@@ -861,13 +994,15 @@
.WillOnce(Return(1020));
VSyncDispatchTimerQueueEntry entry(
- "test", [](auto, auto) {}, mVsyncMoveThreshold);
+ "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
EXPECT_FALSE(entry.wakeupTime());
entry.update(mStubTracker, 0);
EXPECT_FALSE(entry.wakeupTime());
- EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ EXPECT_THAT(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500},
+ mStubTracker, 0),
+ Eq(ScheduleResult::Scheduled));
auto wakeup = entry.wakeupTime();
ASSERT_TRUE(wakeup);
EXPECT_THAT(wakeup, Eq(900));
@@ -880,8 +1015,10 @@
TEST_F(VSyncDispatchTimerQueueEntryTest, skipsUpdateIfJustScheduled) {
VSyncDispatchTimerQueueEntry entry(
- "test", [](auto, auto) {}, mVsyncMoveThreshold);
- EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
+ EXPECT_THAT(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500},
+ mStubTracker, 0),
+ Eq(ScheduleResult::Scheduled));
entry.update(mStubTracker, 0);
auto const wakeup = entry.wakeupTime();
@@ -891,24 +1028,35 @@
TEST_F(VSyncDispatchTimerQueueEntryTest, willSnapToNextTargettableVSync) {
VSyncDispatchTimerQueueEntry entry(
- "test", [](auto, auto) {}, mVsyncMoveThreshold);
- EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
+ EXPECT_THAT(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500},
+ mStubTracker, 0),
+ Eq(ScheduleResult::Scheduled));
entry.executing(); // 1000 is executing
// had 1000 not been executing, this could have been scheduled for time 800.
- EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ EXPECT_THAT(entry.schedule({.workDuration = 200, .readyDuration = 0, .earliestVsync = 500},
+ mStubTracker, 0),
+ Eq(ScheduleResult::Scheduled));
EXPECT_THAT(*entry.wakeupTime(), Eq(1800));
+ EXPECT_THAT(*entry.readyTime(), Eq(2000));
- EXPECT_THAT(entry.schedule(50, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ EXPECT_THAT(entry.schedule({.workDuration = 50, .readyDuration = 0, .earliestVsync = 500},
+ mStubTracker, 0),
+ Eq(ScheduleResult::Scheduled));
EXPECT_THAT(*entry.wakeupTime(), Eq(1950));
+ EXPECT_THAT(*entry.readyTime(), Eq(2000));
- EXPECT_THAT(entry.schedule(200, 1001, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ EXPECT_THAT(entry.schedule({.workDuration = 200, .readyDuration = 0, .earliestVsync = 1001},
+ mStubTracker, 0),
+ Eq(ScheduleResult::Scheduled));
EXPECT_THAT(*entry.wakeupTime(), Eq(1800));
+ EXPECT_THAT(*entry.readyTime(), Eq(2000));
}
TEST_F(VSyncDispatchTimerQueueEntryTest,
willRequestNextEstimateWhenSnappingToNextTargettableVSync) {
VSyncDispatchTimerQueueEntry entry(
- "test", [](auto, auto) {}, mVsyncMoveThreshold);
+ "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
Sequence seq;
EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(500))
@@ -921,35 +1069,85 @@
.InSequence(seq)
.WillOnce(Return(2000));
- EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ EXPECT_THAT(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500},
+ mStubTracker, 0),
+ Eq(ScheduleResult::Scheduled));
entry.executing(); // 1000 is executing
- EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ EXPECT_THAT(entry.schedule({.workDuration = 200, .readyDuration = 0, .earliestVsync = 500},
+ mStubTracker, 0),
+ Eq(ScheduleResult::Scheduled));
}
TEST_F(VSyncDispatchTimerQueueEntryTest, reportsScheduledIfStillTime) {
VSyncDispatchTimerQueueEntry entry(
- "test", [](auto, auto) {}, mVsyncMoveThreshold);
- EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
- EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
- EXPECT_THAT(entry.schedule(50, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
- EXPECT_THAT(entry.schedule(1200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
+ EXPECT_THAT(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500},
+ mStubTracker, 0),
+ Eq(ScheduleResult::Scheduled));
+ EXPECT_THAT(entry.schedule({.workDuration = 200, .readyDuration = 0, .earliestVsync = 500},
+ mStubTracker, 0),
+ Eq(ScheduleResult::Scheduled));
+ EXPECT_THAT(entry.schedule({.workDuration = 50, .readyDuration = 0, .earliestVsync = 500},
+ mStubTracker, 0),
+ Eq(ScheduleResult::Scheduled));
+ EXPECT_THAT(entry.schedule({.workDuration = 1200, .readyDuration = 0, .earliestVsync = 500},
+ mStubTracker, 0),
+ Eq(ScheduleResult::Scheduled));
}
TEST_F(VSyncDispatchTimerQueueEntryTest, storesPendingUpdatesUntilUpdate) {
static constexpr auto effectualOffset = 200;
VSyncDispatchTimerQueueEntry entry(
- "test", [](auto, auto) {}, mVsyncMoveThreshold);
+ "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
EXPECT_FALSE(entry.hasPendingWorkloadUpdate());
- entry.addPendingWorkloadUpdate(100, 400);
- entry.addPendingWorkloadUpdate(effectualOffset, 700);
+ entry.addPendingWorkloadUpdate({.workDuration = 100, .readyDuration = 0, .earliestVsync = 400});
+ entry.addPendingWorkloadUpdate(
+ {.workDuration = effectualOffset, .readyDuration = 0, .earliestVsync = 400});
EXPECT_TRUE(entry.hasPendingWorkloadUpdate());
entry.update(mStubTracker, 0);
EXPECT_FALSE(entry.hasPendingWorkloadUpdate());
EXPECT_THAT(*entry.wakeupTime(), Eq(mPeriod - effectualOffset));
}
+TEST_F(VSyncDispatchTimerQueueEntryTest, runCallbackWithReadyDuration) {
+ auto callCount = 0;
+ auto vsyncCalledTime = 0;
+ auto wakeupCalledTime = 0;
+ auto readyCalledTime = 0;
+ VSyncDispatchTimerQueueEntry entry(
+ "test",
+ [&](auto vsyncTime, auto wakeupTime, auto readyTime) {
+ callCount++;
+ vsyncCalledTime = vsyncTime;
+ wakeupCalledTime = wakeupTime;
+ readyCalledTime = readyTime;
+ },
+ mVsyncMoveThreshold);
+
+ EXPECT_THAT(entry.schedule({.workDuration = 70, .readyDuration = 30, .earliestVsync = 500},
+ mStubTracker, 0),
+ Eq(ScheduleResult::Scheduled));
+ auto const wakeup = entry.wakeupTime();
+ ASSERT_TRUE(wakeup);
+ EXPECT_THAT(*wakeup, Eq(900));
+
+ auto const ready = entry.readyTime();
+ ASSERT_TRUE(ready);
+ EXPECT_THAT(*ready, Eq(970));
+
+ entry.callback(entry.executing(), *wakeup, *ready);
+
+ EXPECT_THAT(callCount, Eq(1));
+ EXPECT_THAT(vsyncCalledTime, Eq(mPeriod));
+ EXPECT_THAT(wakeupCalledTime, Eq(*wakeup));
+ EXPECT_FALSE(entry.wakeupTime());
+ auto lastCalledTarget = entry.lastExecutedVsyncTarget();
+ ASSERT_TRUE(lastCalledTarget);
+ EXPECT_THAT(*lastCalledTarget, Eq(mPeriod));
+}
+
} // namespace android::scheduler
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index c5cddf3..0eae01e 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -63,9 +63,9 @@
class MockVSyncDispatch : public VSyncDispatch {
public:
MOCK_METHOD2(registerCallback,
- CallbackToken(std::function<void(nsecs_t, nsecs_t)> const&, std::string));
+ CallbackToken(std::function<void(nsecs_t, nsecs_t, nsecs_t)> const&, std::string));
MOCK_METHOD1(unregisterCallback, void(CallbackToken));
- MOCK_METHOD3(schedule, ScheduleResult(CallbackToken, nsecs_t, nsecs_t));
+ MOCK_METHOD2(schedule, ScheduleResult(CallbackToken, ScheduleTiming));
MOCK_METHOD1(cancel, CancelResult(CallbackToken token));
MOCK_CONST_METHOD1(dump, void(std::string&));
};
@@ -92,35 +92,17 @@
return ft;
}
-class StubCallback : public DispSync::Callback {
-public:
- void onDispSyncEvent(nsecs_t when, nsecs_t /*expectedVSyncTimestamp*/) final {
- std::lock_guard<std::mutex> lk(mMutex);
- mLastCallTime = when;
- }
- std::optional<nsecs_t> lastCallTime() const {
- std::lock_guard<std::mutex> lk(mMutex);
- return mLastCallTime;
- }
-
-private:
- std::mutex mutable mMutex;
- std::optional<nsecs_t> mLastCallTime GUARDED_BY(mMutex);
-};
-
class VSyncReactorTest : public testing::Test {
protected:
VSyncReactorTest()
- : mMockDispatch(std::make_shared<NiceMock<MockVSyncDispatch>>()),
- mMockTracker(std::make_shared<NiceMock<MockVSyncTracker>>()),
+ : mMockTracker(std::make_shared<NiceMock<MockVSyncTracker>>()),
mMockClock(std::make_shared<NiceMock<MockClock>>()),
- mReactor(std::make_unique<ClockWrapper>(mMockClock), *mMockDispatch, *mMockTracker,
- kPendingLimit, false /* supportKernelIdleTimer */) {
+ mReactor(std::make_unique<ClockWrapper>(mMockClock), *mMockTracker, kPendingLimit,
+ false /* supportKernelIdleTimer */) {
ON_CALL(*mMockClock, now()).WillByDefault(Return(mFakeNow));
ON_CALL(*mMockTracker, currentPeriod()).WillByDefault(Return(period));
}
- std::shared_ptr<MockVSyncDispatch> mMockDispatch;
std::shared_ptr<MockVSyncTracker> mMockTracker;
std::shared_ptr<MockClock> mMockClock;
static constexpr size_t kPendingLimit = 3;
@@ -135,7 +117,7 @@
VSyncDispatch::CallbackToken const mFakeToken{2398};
nsecs_t lastCallbackTime = 0;
- StubCallback outerCb;
+ // StubCallback outerCb;
std::function<void(nsecs_t, nsecs_t)> innerCb;
VSyncReactor mReactor;
@@ -489,192 +471,6 @@
EXPECT_FALSE(mReactor.addResyncSample(time += newPeriod2, std::nullopt, &periodFlushed));
}
-static nsecs_t computeWorkload(nsecs_t period, nsecs_t phase) {
- return period - phase;
-}
-
-TEST_F(VSyncReactorTest, addEventListener) {
- Sequence seq;
- EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
- .InSequence(seq)
- .WillOnce(Return(mFakeToken));
- EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
- .InSequence(seq);
- EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).Times(2).InSequence(seq);
- EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
-
- mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
- mReactor.removeEventListener(&outerCb, &lastCallbackTime);
-}
-
-TEST_F(VSyncReactorTest, addEventListenerTwiceChangesPhase) {
- Sequence seq;
- EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
- .InSequence(seq)
- .WillOnce(Return(mFakeToken));
- EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
- .InSequence(seq);
- EXPECT_CALL(*mMockDispatch,
- schedule(mFakeToken, computeWorkload(period, mAnotherPhase), _)) // mFakeNow))
- .InSequence(seq);
- EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq);
- EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
-
- mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
- mReactor.addEventListener(mName, mAnotherPhase, &outerCb, lastCallbackTime);
-}
-
-TEST_F(VSyncReactorTest, eventListenerGetsACallbackAndReschedules) {
- Sequence seq;
- EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
- .InSequence(seq)
- .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
- EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
- .InSequence(seq);
- EXPECT_CALL(*mMockDispatch,
- schedule(mFakeToken, computeWorkload(period, mPhase), mFakeVSyncTime))
- .Times(2)
- .InSequence(seq);
- EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq);
- EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
-
- mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
- ASSERT_TRUE(innerCb);
- innerCb(mFakeVSyncTime, mFakeWakeupTime);
- innerCb(mFakeVSyncTime, mFakeWakeupTime);
-}
-
-TEST_F(VSyncReactorTest, callbackTimestampDistributedIsWakeupTime) {
- Sequence seq;
- EXPECT_CALL(*mMockDispatch, registerCallback(_, _))
- .InSequence(seq)
- .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
- EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
- .InSequence(seq);
- EXPECT_CALL(*mMockDispatch,
- schedule(mFakeToken, computeWorkload(period, mPhase), mFakeVSyncTime))
- .InSequence(seq);
-
- mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
- ASSERT_TRUE(innerCb);
- innerCb(mFakeVSyncTime, mFakeWakeupTime);
- EXPECT_THAT(outerCb.lastCallTime(), Optional(mFakeWakeupTime));
-}
-
-TEST_F(VSyncReactorTest, eventListenersRemovedOnDestruction) {
- Sequence seq;
- EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
- .InSequence(seq)
- .WillOnce(Return(mFakeToken));
- EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
- .InSequence(seq);
- EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq);
- EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
-
- mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
-}
-
-// b/149221293
-TEST_F(VSyncReactorTest, selfRemovingEventListenerStopsCallbacks) {
- class SelfRemovingCallback : public DispSync::Callback {
- public:
- SelfRemovingCallback(VSyncReactor& vsr) : mVsr(vsr) {}
- void onDispSyncEvent(nsecs_t when, nsecs_t /*expectedVSyncTimestamp*/) final {
- mVsr.removeEventListener(this, &when);
- }
-
- private:
- VSyncReactor& mVsr;
- } selfRemover(mReactor);
-
- Sequence seq;
- EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
- .InSequence(seq)
- .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
- EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
- .InSequence(seq);
- EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).Times(2).InSequence(seq);
- EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
-
- mReactor.addEventListener(mName, mPhase, &selfRemover, lastCallbackTime);
- innerCb(0, 0);
-}
-
-TEST_F(VSyncReactorTest, addEventListenerChangePeriod) {
- Sequence seq;
- EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
- .InSequence(seq)
- .WillOnce(Return(mFakeToken));
- EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
- .InSequence(seq);
- EXPECT_CALL(*mMockDispatch,
- schedule(mFakeToken, computeWorkload(period, mAnotherPhase), mFakeNow))
- .InSequence(seq);
- EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq);
- EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
-
- mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
- mReactor.addEventListener(mName, mAnotherPhase, &outerCb, lastCallbackTime);
-}
-
-TEST_F(VSyncReactorTest, changingPeriodChangesOffsetsOnNextCb) {
- static constexpr nsecs_t anotherPeriod = 23333;
- Sequence seq;
- EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
- .InSequence(seq)
- .WillOnce(Return(mFakeToken));
- EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
- .InSequence(seq);
- EXPECT_CALL(*mMockTracker, setPeriod(anotherPeriod));
- EXPECT_CALL(*mMockDispatch,
- schedule(mFakeToken, computeWorkload(anotherPeriod, mPhase), mFakeNow))
- .InSequence(seq);
-
- mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
-
- bool periodFlushed = false;
- mReactor.setPeriod(anotherPeriod);
- EXPECT_TRUE(mReactor.addResyncSample(anotherPeriod, std::nullopt, &periodFlushed));
- EXPECT_FALSE(mReactor.addResyncSample(anotherPeriod * 2, std::nullopt, &periodFlushed));
-
- mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
-}
-
-TEST_F(VSyncReactorTest, offsetsAppliedOnNextOpportunity) {
- Sequence seq;
- EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
- .InSequence(seq)
- .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
- EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), _))
- .InSequence(seq)
- .WillOnce(Return(ScheduleResult::Scheduled));
-
- EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mAnotherPhase), _))
- .InSequence(seq)
- .WillOnce(Return(ScheduleResult::Scheduled));
-
- EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mAnotherPhase), _))
- .InSequence(seq)
- .WillOnce(Return(ScheduleResult::Scheduled));
-
- mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
- mReactor.changePhaseOffset(&outerCb, mAnotherPhase);
- ASSERT_TRUE(innerCb);
- innerCb(mFakeVSyncTime, mFakeWakeupTime);
-}
-
-TEST_F(VSyncReactorTest, negativeOffsetsApplied) {
- nsecs_t const negativePhase = -4000;
- Sequence seq;
- EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
- .InSequence(seq)
- .WillOnce(Return(mFakeToken));
- EXPECT_CALL(*mMockDispatch,
- schedule(mFakeToken, computeWorkload(period, negativePhase), mFakeNow))
- .InSequence(seq);
- mReactor.addEventListener(mName, negativePhase, &outerCb, lastCallbackTime);
-}
-
TEST_F(VSyncReactorTest, beginResyncResetsModel) {
EXPECT_CALL(*mMockTracker, resetModel());
mReactor.beginResync();
@@ -700,9 +496,8 @@
TEST_F(VSyncReactorTest, periodIsMeasuredIfIgnoringComposer) {
// Create a reactor which supports the kernel idle timer
- auto idleReactor =
- VSyncReactor(std::make_unique<ClockWrapper>(mMockClock), *mMockDispatch, *mMockTracker,
- kPendingLimit, true /* supportKernelIdleTimer */);
+ auto idleReactor = VSyncReactor(std::make_unique<ClockWrapper>(mMockClock), *mMockTracker,
+ kPendingLimit, true /* supportKernelIdleTimer */);
bool periodFlushed = true;
EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(4);
@@ -734,42 +529,4 @@
EXPECT_TRUE(idleReactor.addPresentFence(generateSignalledFenceWithTime(0)));
}
-using VSyncReactorDeathTest = VSyncReactorTest;
-TEST_F(VSyncReactorDeathTest, invalidRemoval) {
- mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
- mReactor.removeEventListener(&outerCb, &lastCallbackTime);
- EXPECT_DEATH(mReactor.removeEventListener(&outerCb, &lastCallbackTime), ".*");
-}
-
-TEST_F(VSyncReactorDeathTest, invalidChange) {
- EXPECT_DEATH(mReactor.changePhaseOffset(&outerCb, mPhase), ".*");
-
- // the current DispSync-interface usage pattern has evolved around an implementation quirk,
- // which is a callback is assumed to always exist, and it is valid api usage to change the
- // offset of an object that is in the removed state.
- mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
- mReactor.removeEventListener(&outerCb, &lastCallbackTime);
- mReactor.changePhaseOffset(&outerCb, mPhase);
-}
-
-TEST_F(VSyncReactorDeathTest, cannotScheduleOnRegistration) {
- ON_CALL(*mMockDispatch, schedule(_, _, _))
- .WillByDefault(Return(ScheduleResult::CannotSchedule));
- EXPECT_DEATH(mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime), ".*");
-}
-
-TEST_F(VSyncReactorDeathTest, cannotScheduleOnCallback) {
- EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
- .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
- EXPECT_CALL(*mMockDispatch, schedule(_, _, _)).WillOnce(Return(ScheduleResult::Scheduled));
-
- mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
- ASSERT_TRUE(innerCb);
- Mock::VerifyAndClearExpectations(mMockDispatch.get());
-
- ON_CALL(*mMockDispatch, schedule(_, _, _))
- .WillByDefault(Return(ScheduleResult::CannotSchedule));
- EXPECT_DEATH(innerCb(mFakeVSyncTime, mFakeWakeupTime), ".*");
-}
-
} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp b/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp
index 1c8c44d..bbd9f77 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp
@@ -25,40 +25,5 @@
DispSync::DispSync() = default;
DispSync::~DispSync() = default;
-status_t DispSync::addEventListener(const char* /*name*/, nsecs_t phase, Callback* callback,
- nsecs_t /*lastCallbackTime*/) {
- if (mCallback.callback != nullptr) {
- return BAD_VALUE;
- }
-
- mCallback = {callback, phase};
- return NO_ERROR;
-}
-status_t DispSync::removeEventListener(Callback* callback, nsecs_t* /*outLastCallback*/) {
- if (mCallback.callback != callback) {
- return BAD_VALUE;
- }
-
- mCallback = {nullptr, 0};
- return NO_ERROR;
-}
-
-status_t DispSync::changePhaseOffset(Callback* callback, nsecs_t phase) {
- if (mCallback.callback != callback) {
- return BAD_VALUE;
- }
-
- mCallback.phase = phase;
- return NO_ERROR;
-}
-
-void DispSync::triggerCallback() {
- if (mCallback.callback == nullptr) return;
-
- const std::chrono::nanoseconds now = std::chrono::steady_clock::now().time_since_epoch();
- const auto expectedVSyncTime = now + 16ms;
- mCallback.callback->onDispSyncEvent(now.count(), expectedVSyncTime.count());
-}
-
} // namespace mock
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
index b39487c..41445c8 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
@@ -28,11 +28,9 @@
DispSync();
~DispSync() override;
- MOCK_METHOD0(reset, void());
MOCK_METHOD1(addPresentFence, bool(const std::shared_ptr<FenceTime>&));
MOCK_METHOD0(beginResync, void());
MOCK_METHOD3(addResyncSample, bool(nsecs_t, std::optional<nsecs_t>, bool*));
- MOCK_METHOD0(endResync, void());
MOCK_METHOD1(setPeriod, void(nsecs_t));
MOCK_METHOD0(getPeriod, nsecs_t());
MOCK_METHOD0(getIntendedPeriod, nsecs_t());
@@ -42,22 +40,6 @@
MOCK_METHOD1(expectedPresentTime, nsecs_t(nsecs_t));
MOCK_CONST_METHOD1(dump, void(std::string&));
-
- status_t addEventListener(const char* name, nsecs_t phase, Callback* callback,
- nsecs_t lastCallbackTime) override;
- status_t removeEventListener(Callback* callback, nsecs_t* outLastCallback) override;
- status_t changePhaseOffset(Callback* callback, nsecs_t phase) override;
-
- nsecs_t getCallbackPhase() { return mCallback.phase; }
-
- void triggerCallback();
-
-private:
- struct CallbackType {
- Callback* callback = nullptr;
- nsecs_t phase;
- };
- CallbackType mCallback;
};
} // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index 054aaf8..eefdec1 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -35,7 +35,9 @@
MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool));
MOCK_METHOD3(onConfigChanged, void(PhysicalDisplayId, HwcConfigIndexType, nsecs_t));
MOCK_CONST_METHOD1(dump, void(std::string&));
- MOCK_METHOD1(setPhaseOffset, void(nsecs_t phaseOffset));
+ MOCK_METHOD2(setDuration,
+ void(std::chrono::nanoseconds workDuration,
+ std::chrono::nanoseconds readyDuration));
MOCK_METHOD1(registerDisplayEventConnection,
status_t(const sp<android::EventThreadConnection> &));
MOCK_METHOD2(setVsyncRate, void(uint32_t, const sp<android::EventThreadConnection> &));
diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
index 081d18b..fbf5ecf 100644
--- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h
+++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
@@ -17,28 +17,50 @@
#include <ui/Rect.h>
#include <utils/String8.h>
+#include <functional>
+#include <future>
#include "TransactionUtils.h"
namespace android {
namespace {
+class SyncScreenCaptureListener : public BnScreenCaptureListener {
+public:
+ status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override {
+ resultsPromise.set_value(captureResults);
+ return NO_ERROR;
+ }
+
+ ScreenCaptureResults waitForResults() {
+ std::future<ScreenCaptureResults> resultsFuture = resultsPromise.get_future();
+ return resultsFuture.get();
+ }
+
+private:
+ std::promise<ScreenCaptureResults> resultsPromise;
+};
+
// A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check
// individual pixel values for testing purposes.
class ScreenCapture : public RefBase {
public:
- static void captureScreen(std::unique_ptr<ScreenCapture>* sc) {
- captureScreen(sc, SurfaceComposerClient::getInternalDisplayToken());
- }
-
- static void captureDisplay(std::unique_ptr<ScreenCapture>* sc,
- const DisplayCaptureArgs& captureArgs) {
+ static status_t captureDisplay(DisplayCaptureArgs& captureArgs,
+ ScreenCaptureResults& captureResults) {
const auto sf = ComposerService::getComposerService();
SurfaceComposerClient::Transaction().apply(true);
- ScreenCaptureResults captureResults;
- ASSERT_EQ(NO_ERROR, sf->captureDisplay(captureArgs, captureResults));
- *sc = std::make_unique<ScreenCapture>(captureResults.buffer);
+ const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
+ status_t status = sf->captureDisplay(captureArgs, captureListener);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ captureResults = captureListener->waitForResults();
+ return captureResults.result;
+ }
+
+ static void captureScreen(std::unique_ptr<ScreenCapture>* sc) {
+ captureScreen(sc, SurfaceComposerClient::getInternalDisplayToken());
}
static void captureScreen(std::unique_ptr<ScreenCapture>* sc, sp<IBinder> displayToken) {
@@ -47,13 +69,30 @@
captureDisplay(sc, args);
}
- static void captureLayers(std::unique_ptr<ScreenCapture>* sc,
- const LayerCaptureArgs& captureArgs) {
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ static void captureDisplay(std::unique_ptr<ScreenCapture>* sc,
+ DisplayCaptureArgs& captureArgs) {
+ ScreenCaptureResults captureResults;
+ ASSERT_EQ(NO_ERROR, captureDisplay(captureArgs, captureResults));
+ *sc = std::make_unique<ScreenCapture>(captureResults.buffer);
+ }
+
+ static status_t captureLayers(LayerCaptureArgs& captureArgs,
+ ScreenCaptureResults& captureResults) {
+ const auto sf = ComposerService::getComposerService();
SurfaceComposerClient::Transaction().apply(true);
+ const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
+ status_t status = sf->captureLayers(captureArgs, captureListener);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ captureResults = captureListener->waitForResults();
+ return captureResults.result;
+ }
+
+ static void captureLayers(std::unique_ptr<ScreenCapture>* sc, LayerCaptureArgs& captureArgs) {
ScreenCaptureResults captureResults;
- ASSERT_EQ(NO_ERROR, sf->captureLayers(captureArgs, captureResults));
+ ASSERT_EQ(NO_ERROR, captureLayers(captureArgs, captureResults));
*sc = std::make_unique<ScreenCapture>(captureResults.buffer);
}