Merge changes If3d6ea21,Iab8360f2
* changes:
WindowInfo: Remove unused field portalToDisplayId
InputDispatcher: Allow spy window to receive entire gesture after pilfer
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 77915d5..e42ee05 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -202,7 +202,6 @@
dprintf(fd, "base_name: %s\n", ds_->base_name_.c_str());
dprintf(fd, "name: %s\n", ds_->name_.c_str());
dprintf(fd, "now: %ld\n", ds_->now_);
- dprintf(fd, "is_zipping: %s\n", ds_->IsZipping() ? "true" : "false");
dprintf(fd, "notification title: %s\n", ds_->options_->notification_title.c_str());
dprintf(fd, "notification description: %s\n", ds_->options_->notification_description.c_str());
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index e97949e..a951c4f 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -371,14 +371,10 @@
/*
* Returns a vector of dump fds under |dir_path| with a given |file_prefix|.
* The returned vector is sorted by the mtimes of the dumps with descending
- * order. If |limit_by_mtime| is set, the vector only contains files that
- * were written in the last 30 minutes.
+ * order.
*/
static std::vector<DumpData> GetDumpFds(const std::string& dir_path,
- const std::string& file_prefix,
- bool limit_by_mtime) {
- const time_t thirty_minutes_ago = ds.now_ - 60 * 30;
-
+ const std::string& file_prefix) {
std::unique_ptr<DIR, decltype(&closedir)> dump_dir(opendir(dir_path.c_str()), closedir);
if (dump_dir == nullptr) {
@@ -412,11 +408,6 @@
continue;
}
- if (limit_by_mtime && st.st_mtime < thirty_minutes_ago) {
- MYLOGI("Excluding stale dump file: %s\n", abs_path.c_str());
- continue;
- }
-
dump_data.emplace_back(DumpData{abs_path, std::move(fd), st.st_mtime});
}
if (!dump_data.empty()) {
@@ -447,7 +438,7 @@
strerror(errno));
}
- if (ds.IsZipping() && add_to_zip) {
+ if (add_to_zip) {
if (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd, /* timeout = */ 0ms) != OK) {
MYLOGE("Unable to add %s to zip file, addZipEntryFromFd failed\n", name.c_str());
}
@@ -486,7 +477,6 @@
}
void add_mountinfo() {
- if (!ds.IsZipping()) return;
std::string title = "MOUNT INFO";
mount_points.clear();
DurationReporter duration_reporter(title, true);
@@ -823,11 +813,6 @@
status_t Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd,
std::chrono::milliseconds timeout = 0ms) {
- if (!IsZipping()) {
- MYLOGD("Not adding zip entry %s from fd because it's not a zipped bugreport\n",
- entry_name.c_str());
- return INVALID_OPERATION;
- }
std::string valid_name = entry_name;
// Rename extension if necessary.
@@ -928,21 +913,12 @@
}
void Dumpstate::AddDir(const std::string& dir, bool recursive) {
- if (!IsZipping()) {
- MYLOGD("Not adding dir %s because it's not a zipped bugreport\n", dir.c_str());
- return;
- }
MYLOGD("Adding dir %s (recursive: %d)\n", dir.c_str(), recursive);
DurationReporter duration_reporter(dir, true);
dump_files("", dir.c_str(), recursive ? skip_none : is_dir, _add_file_from_fd);
}
bool Dumpstate::AddTextZipEntry(const std::string& entry_name, const std::string& content) {
- if (!IsZipping()) {
- MYLOGD("Not adding text zip entry %s because it's not a zipped bugreport\n",
- entry_name.c_str());
- return false;
- }
MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
int32_t err = zip_writer_->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, ds.now_);
if (err != 0) {
@@ -1035,10 +1011,6 @@
}
static void DumpIncidentReport() {
- if (!ds.IsZipping()) {
- MYLOGD("Not dumping incident report because it's not a zipped bugreport\n");
- return;
- }
const std::string path = ds.bugreport_internal_dir_ + "/tmp_incident_report";
auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(),
O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
@@ -1064,10 +1036,6 @@
// This function copies into the .zip the system trace that was snapshotted
// by the early call to MaybeSnapshotSystemTrace(), if any background
// tracing was happening.
- if (!ds.IsZipping()) {
- MYLOGD("Not dumping system trace because it's not a zipped bugreport\n");
- return;
- }
if (!ds.has_system_trace_) {
// No background trace was happening at the time dumpstate was invoked.
return;
@@ -1079,10 +1047,6 @@
}
static void DumpVisibleWindowViews() {
- if (!ds.IsZipping()) {
- MYLOGD("Not dumping visible views because it's not a zipped bugreport\n");
- return;
- }
DurationReporter duration_reporter("VISIBLE WINDOW VIEWS");
const std::string path = ds.bugreport_internal_dir_ + "/tmp_visible_window_views";
auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(),
@@ -1163,7 +1127,7 @@
}
static void AddAnrTraceFiles() {
- const bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
+ const bool add_to_zip = ds.version_ == VERSION_SPLIT_ANR;
std::string anr_traces_dir = "/data/anr";
@@ -1303,10 +1267,6 @@
static Dumpstate::RunStatus RunDumpsysProto(const std::string& title, int priority,
std::chrono::milliseconds timeout,
std::chrono::milliseconds service_timeout) {
- if (!ds.IsZipping()) {
- MYLOGD("Not dumping %s because it's not a zipped bugreport\n", title.c_str());
- return Dumpstate::RunStatus::OK;
- }
sp<android::IServiceManager> sm = defaultServiceManager();
Dumpsys dumpsys(sm.get());
Vector<String16> args;
@@ -1386,12 +1346,6 @@
* if it's not running in the parallel task.
*/
static void DumpHals(int out_fd = STDOUT_FILENO) {
- if (!ds.IsZipping()) {
- RunCommand("HARDWARE HALS", {"lshal", "--all", "--types=all", "--debug"},
- CommandOptions::WithTimeout(60).AsRootIfAvailable().Build(),
- false, out_fd);
- return;
- }
RunCommand("HARDWARE HALS", {"lshal", "--all", "--types=all"},
CommandOptions::WithTimeout(10).AsRootIfAvailable().Build(),
false, out_fd);
@@ -1846,8 +1800,8 @@
/* Run some operations that require root. */
if (!PropertiesHelper::IsDryRun()) {
- ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
- ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
+ ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX);
+ ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX);
}
ds.AddDir(RECOVERY_DIR, true);
@@ -2394,11 +2348,6 @@
dprintf(out_fd, "== Board\n");
dprintf(out_fd, "========================================================\n");
- if (!IsZipping()) {
- MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
- return;
- }
-
/*
* mount debugfs for non-user builds with ro.product.debugfs_restrictions.enabled
* set to true and unmount it after invoking dumpstateBoard_* methods.
@@ -3567,10 +3516,6 @@
dprintf(fd, "%saverage_max: %d\n", pr, average_max_);
}
-bool Dumpstate::IsZipping() const {
- return zip_writer_ != nullptr;
-}
-
std::string Dumpstate::GetPath(const std::string& suffix) const {
return GetPath(bugreport_internal_dir_, suffix);
}
@@ -4216,10 +4161,6 @@
}
void dump_frozen_cgroupfs() {
- if (!ds.IsZipping()) {
- MYLOGD("Not adding cgroupfs because it's not a zipped bugreport\n");
- return;
- }
MYLOGD("Adding frozen processes from %s\n", CGROUPFS_DIR);
DurationReporter duration_reporter("FROZEN CGROUPFS");
if (PropertiesHelper::IsDryRun()) return;
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 852b9a8..d0acb31 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -214,9 +214,6 @@
static Dumpstate& GetInstance();
- /* Checkes whether dumpstate is generating a zipped bugreport. */
- bool IsZipping() const;
-
/* Initialize dumpstate fields before starting bugreport generation */
void Initialize();
diff --git a/data/etc/android.hardware.telephony.radio.xml b/data/etc/android.hardware.sensor.heading.xml
similarity index 71%
copy from data/etc/android.hardware.telephony.radio.xml
copy to data/etc/android.hardware.sensor.heading.xml
index 4377705..8b81823 100644
--- a/data/etc/android.hardware.telephony.radio.xml
+++ b/data/etc/android.hardware.sensor.heading.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 The Android Open Source Project
+<!-- Copyright (C) 2022 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.
@@ -14,8 +14,7 @@
limitations under the License.
-->
-<!-- This is the standard set of features for devices to support Telephony Radio Access API. -->
+<!-- Feature for devices with a heading sensor. -->
<permissions>
- <feature name="android.hardware.telephony" />
- <feature name="android.hardware.telephony.radio" />
+ <feature name="android.hardware.sensor.heading" />
</permissions>
diff --git a/data/etc/android.hardware.telephony.calling.xml b/data/etc/android.hardware.telephony.calling.xml
index 3e92a66..ab245fc 100644
--- a/data/etc/android.hardware.telephony.calling.xml
+++ b/data/etc/android.hardware.telephony.calling.xml
@@ -18,7 +18,7 @@
<permissions>
<feature name="android.hardware.telephony" />
<feature name="android.software.telecom" />
- <feature name="android.hardware.telephony.radio" />
+ <feature name="android.hardware.telephony.radio.access" />
<feature name="android.hardware.telephony.subscription" />
<feature name="android.hardware.telephony.calling" />
</permissions>
diff --git a/data/etc/android.hardware.telephony.cdma.xml b/data/etc/android.hardware.telephony.cdma.xml
index c81cf06..0a8cfc4 100644
--- a/data/etc/android.hardware.telephony.cdma.xml
+++ b/data/etc/android.hardware.telephony.cdma.xml
@@ -18,7 +18,7 @@
<permissions>
<feature name="android.hardware.telephony" />
<feature name="android.software.telecom" />
- <feature name="android.hardware.telephony.radio" />
+ <feature name="android.hardware.telephony.radio.access" />
<feature name="android.hardware.telephony.subscription" />
<feature name="android.hardware.telephony.cdma" />
<feature name="android.hardware.telephony.calling" />
diff --git a/data/etc/android.hardware.telephony.data.xml b/data/etc/android.hardware.telephony.data.xml
index 2716152..a9bb36e 100644
--- a/data/etc/android.hardware.telephony.data.xml
+++ b/data/etc/android.hardware.telephony.data.xml
@@ -17,7 +17,7 @@
<!-- This is the standard set of features for devices to support Telephony Data API. -->
<permissions>
<feature name="android.hardware.telephony" />
- <feature name="android.hardware.telephony.radio" />
+ <feature name="android.hardware.telephony.radio.access" />
<feature name="android.hardware.telephony.subscription" />
<feature name="android.hardware.telephony.data" />
</permissions>
diff --git a/data/etc/android.hardware.telephony.gsm.xml b/data/etc/android.hardware.telephony.gsm.xml
index e368a06..e3952bf 100644
--- a/data/etc/android.hardware.telephony.gsm.xml
+++ b/data/etc/android.hardware.telephony.gsm.xml
@@ -18,7 +18,7 @@
<permissions>
<feature name="android.hardware.telephony" />
<feature name="android.software.telecom" />
- <feature name="android.hardware.telephony.radio" />
+ <feature name="android.hardware.telephony.radio.access" />
<feature name="android.hardware.telephony.subscription" />
<feature name="android.hardware.telephony.gsm" />
<feature name="android.hardware.telephony.calling" />
diff --git a/data/etc/android.hardware.telephony.radio.xml b/data/etc/android.hardware.telephony.radio.access.xml
similarity index 92%
rename from data/etc/android.hardware.telephony.radio.xml
rename to data/etc/android.hardware.telephony.radio.access.xml
index 4377705..c98267c 100644
--- a/data/etc/android.hardware.telephony.radio.xml
+++ b/data/etc/android.hardware.telephony.radio.access.xml
@@ -17,5 +17,5 @@
<!-- This is the standard set of features for devices to support Telephony Radio Access API. -->
<permissions>
<feature name="android.hardware.telephony" />
- <feature name="android.hardware.telephony.radio" />
+ <feature name="android.hardware.telephony.radio.access" />
</permissions>
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 7e86d3f..cf1ca02 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -301,6 +301,14 @@
* supported and a value of 0 means not supported.
*/
ASENSOR_TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED = 41,
+ /**
+ * {@link ASENSOR_TYPE_HEADING}
+ * reporting-mode: continuous
+ *
+ * A heading sensor measures the direction in which the device is pointing
+ * relative to true north in degrees.
+ */
+ ASENSOR_TYPE_HEADING = 42,
};
/**
@@ -563,6 +571,23 @@
};
} ALimitedAxesImuUncalibratedEvent;
+typedef struct AHeadingEvent {
+ /**
+ * The direction in which the device is pointing relative to true north in
+ * degrees. The value must be between 0.0 (inclusive) and 360.0 (exclusive),
+ * with 0 indicating north, 90 east, 180 south, and 270 west.
+ */
+ float heading;
+ /**
+ * Accuracy is defined at 68% confidence. In the case where the underlying
+ * distribution is assumed Gaussian normal, this would be considered one
+ * standard deviation. For example, if the heading returns 60 degrees, and
+ * accuracy returns 10 degrees, then there is a 68 percent probability of
+ * the true heading being between 50 degrees and 70 degrees.
+ */
+ float accuracy;
+} AHeadingEvent;
+
/**
* Information that describes a sensor event, refer to
* <a href="/reference/android/hardware/SensorEvent">SensorEvent</a> for additional
@@ -602,6 +627,7 @@
AHeadTrackerEvent head_tracker;
ALimitedAxesImuEvent limited_axes_imu;
ALimitedAxesImuUncalibratedEvent limited_axes_imu_uncalibrated;
+ AHeadingEvent heading;
};
union {
uint64_t data[8];
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
index a44c578..83b97d0 100644
--- a/libs/binder/Status.cpp
+++ b/libs/binder/Status.cpp
@@ -211,6 +211,12 @@
return status;
}
+status_t Status::writeOverParcel(Parcel* parcel) const {
+ parcel->setDataSize(0);
+ parcel->setDataPosition(0);
+ return writeToParcel(parcel);
+}
+
void Status::setException(int32_t ex, const String8& message) {
mException = ex;
mErrorCode = ex == EX_TRANSACTION_FAILED ? FAILED_TRANSACTION : NO_ERROR;
diff --git a/libs/binder/include/binder/Status.h b/libs/binder/include/binder/Status.h
index aaafa36..af34695 100644
--- a/libs/binder/include/binder/Status.h
+++ b/libs/binder/include/binder/Status.h
@@ -117,6 +117,10 @@
status_t readFromParcel(const Parcel& parcel);
status_t writeToParcel(Parcel* parcel) const;
+ // Convenience API to replace a Parcel with a status value, w/o requiring
+ // calling multiple APIs (makes generated code smaller).
+ status_t writeOverParcel(Parcel* parcel) const;
+
// Set one of the pre-defined exception types defined above.
void setException(int32_t ex, const String8& message);
// Set a service specific exception with error code.
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 77493b3..79c8c8f 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -32,16 +32,6 @@
],
}
-// TODO(b/211908498): remove this
-cc_defaults {
- name: "libbinder_ndk_host_user",
- target: {
- darwin: {
- enabled: false,
- },
- },
-}
-
cc_library {
name: "libbinder_ndk",
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 86da588..ff55d6e 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -37,7 +37,11 @@
srcs: ["binderDriverInterfaceTest.cpp"],
header_libs: ["libbinder_headers"],
compile_multilib: "32",
- multilib: { lib32: { suffix: "" } },
+ multilib: {
+ lib32: {
+ suffix: "",
+ },
+ },
cflags: ["-DBINDER_IPC_32BIT=1"],
test_suites: ["vts"],
}
@@ -52,7 +56,10 @@
},
header_libs: ["libbinder_headers"],
srcs: ["binderDriverInterfaceTest.cpp"],
- test_suites: ["device-tests", "vts"],
+ test_suites: [
+ "device-tests",
+ "vts",
+ ],
}
cc_test {
@@ -69,7 +76,11 @@
"libgmock",
],
compile_multilib: "32",
- multilib: { lib32: { suffix: "" } },
+ multilib: {
+ lib32: {
+ suffix: "",
+ },
+ },
cflags: ["-DBINDER_IPC_32BIT=1"],
test_suites: ["vts"],
require_root: true,
@@ -84,7 +95,11 @@
enabled: false,
},
},
- srcs: ["binderParcelUnitTest.cpp", "binderBinderUnitTest.cpp"],
+ srcs: [
+ "binderParcelUnitTest.cpp",
+ "binderBinderUnitTest.cpp",
+ "binderStatusUnitTest.cpp",
+ ],
shared_libs: [
"libbinder",
"libcutils",
@@ -112,7 +127,10 @@
static_libs: [
"libgmock",
],
- test_suites: ["device-tests", "vts"],
+ test_suites: [
+ "device-tests",
+ "vts",
+ ],
require_root: true,
}
@@ -179,7 +197,6 @@
},
defaults: [
"binder_test_defaults",
- "libbinder_ndk_host_user",
"libbinder_tls_shared_deps",
],
@@ -232,7 +249,10 @@
"libbinder_tls_test_utils",
"libbinder_tls_static",
],
- test_suites: ["general-tests", "device-tests"],
+ test_suites: [
+ "general-tests",
+ "device-tests",
+ ],
}
cc_benchmark {
@@ -348,7 +368,10 @@
"liblog",
"libutils",
],
- test_suites: ["device-tests", "vts"],
+ test_suites: [
+ "device-tests",
+ "vts",
+ ],
require_root: true,
}
@@ -402,7 +425,10 @@
"binderStabilityTestIface-ndk",
],
- test_suites: ["device-tests", "vts"],
+ test_suites: [
+ "device-tests",
+ "vts",
+ ],
require_root: true,
}
diff --git a/libs/binder/tests/binderStatusUnitTest.cpp b/libs/binder/tests/binderStatusUnitTest.cpp
new file mode 100644
index 0000000..a32ec5c
--- /dev/null
+++ b/libs/binder/tests/binderStatusUnitTest.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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 <binder/Parcel.h>
+#include <binder/Status.h>
+#include <gtest/gtest.h>
+
+using android::Parcel;
+using android::binder::Status;
+
+TEST(Status, WriteOverParcel) {
+ Status status = Status::fromExceptionCode(Status::EX_NULL_POINTER);
+
+ Parcel indirect;
+ indirect.writeInt32(64);
+ status.writeOverParcel(&indirect);
+
+ Parcel direct;
+ status.writeToParcel(&direct);
+
+ EXPECT_EQ(0, indirect.compareData(direct));
+}
diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp
index 6afd172..bd21fba 100644
--- a/libs/gralloc/types/Android.bp
+++ b/libs/gralloc/types/Android.bp
@@ -23,7 +23,6 @@
cc_library {
name: "libgralloctypes",
- defaults: ["libbinder_ndk_host_user"],
cflags: [
"-Wall",
"-Werror",
diff --git a/libs/gralloc/types/fuzzer/Android.bp b/libs/gralloc/types/fuzzer/Android.bp
index 6689771..3c3b6af 100644
--- a/libs/gralloc/types/fuzzer/Android.bp
+++ b/libs/gralloc/types/fuzzer/Android.bp
@@ -9,12 +9,11 @@
cc_fuzz {
name: "libgralloctypes_fuzzer",
- defaults: ["libbinder_ndk_host_user"],
host_supported: true,
target: {
darwin: {
enabled: false,
- }
+ },
},
fuzz_config: {
diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp
index 0827bbe..ea5fb29 100644
--- a/libs/gui/LayerDebugInfo.cpp
+++ b/libs/gui/LayerDebugInfo.cpp
@@ -58,7 +58,6 @@
RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferStride));
RETURN_ON_ERROR(parcel->writeInt32(mActiveBufferFormat));
RETURN_ON_ERROR(parcel->writeInt32(mNumQueuedFrames));
- RETURN_ON_ERROR(parcel->writeBool(mRefreshPending));
RETURN_ON_ERROR(parcel->writeBool(mIsOpaque));
RETURN_ON_ERROR(parcel->writeBool(mContentDirty));
RETURN_ON_ERROR(parcel->write(mStretchEffect));
@@ -103,7 +102,6 @@
RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferStride));
RETURN_ON_ERROR(parcel->readInt32(&mActiveBufferFormat));
RETURN_ON_ERROR(parcel->readInt32(&mNumQueuedFrames));
- RETURN_ON_ERROR(parcel->readBool(&mRefreshPending));
RETURN_ON_ERROR(parcel->readBool(&mIsOpaque));
RETURN_ON_ERROR(parcel->readBool(&mContentDirty));
RETURN_ON_ERROR(parcel->read(mStretchEffect));
@@ -146,8 +144,7 @@
StringAppendF(&result, " activeBuffer=[%4ux%4u:%4u,%s],", info.mActiveBufferWidth,
info.mActiveBufferHeight, info.mActiveBufferStride,
decodePixelFormat(info.mActiveBufferFormat).c_str());
- StringAppendF(&result, " queued-frames=%d, mRefreshPending=%d", info.mNumQueuedFrames,
- info.mRefreshPending);
+ StringAppendF(&result, " queued-frames=%d", info.mNumQueuedFrames);
result.append("\n");
return result;
}
diff --git a/libs/gui/include/gui/LayerDebugInfo.h b/libs/gui/include/gui/LayerDebugInfo.h
index 8b7d32c..af834d7 100644
--- a/libs/gui/include/gui/LayerDebugInfo.h
+++ b/libs/gui/include/gui/LayerDebugInfo.h
@@ -64,7 +64,6 @@
int32_t mActiveBufferStride = 0;
PixelFormat mActiveBufferFormat = PIXEL_FORMAT_NONE;
int32_t mNumQueuedFrames = -1;
- bool mRefreshPending = false;
bool mIsOpaque = false;
bool mContentDirty = false;
StretchEffect mStretchEffect = {};
diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp
index 5b4631a..ec0ced8 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -296,6 +296,10 @@
mStringType = SENSOR_STRING_TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED;
mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
break;
+ case SENSOR_TYPE_HEADING:
+ mStringType = SENSOR_STRING_TYPE_HEADING;
+ mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
+ break;
default:
// Only pipe the stringType, requiredPermission and flags for custom sensors.
if (halVersion > SENSORS_DEVICE_API_VERSION_1_0 && hwSensor.stringType) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index dc46f30..6c321bc 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -137,7 +137,7 @@
// Number of recent events to keep for debugging purposes.
constexpr size_t RECENT_QUEUE_MAX_SIZE = 10;
-// Event log tags. See EventLogTags.logtags for reference
+// Event log tags. See EventLogTags.logtags for reference.
constexpr int LOGTAG_INPUT_INTERACTION = 62000;
constexpr int LOGTAG_INPUT_FOCUS = 62001;
constexpr int LOGTAG_INPUT_CANCEL = 62003;
@@ -4903,23 +4903,42 @@
mLooper->wake();
}
-void InputDispatcher::setInTouchMode(bool inTouchMode) {
+bool InputDispatcher::setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid,
+ bool hasPermission) {
bool needWake = false;
{
std::scoped_lock lock(mLock);
if (mInTouchMode == inTouchMode) {
- return;
+ return false;
}
if (DEBUG_TOUCH_MODE) {
- ALOGD("Request to change touch mode from %s to %s", toString(mInTouchMode),
- toString(inTouchMode));
- // TODO(b/198487159): Also print the current last interacted apps.
+ ALOGD("Request to change touch mode from %s to %s (calling pid=%d, uid=%d, "
+ "hasPermission=%s)",
+ toString(mInTouchMode), toString(inTouchMode), pid, uid, toString(hasPermission));
+ }
+ if (!hasPermission) {
+ const sp<IBinder> focusedToken =
+ mFocusResolver.getFocusedWindowToken(mFocusedDisplayId);
+
+ // TODO(b/198487159): if no window is currently focused, then we need to check the last
+ // interacted window (within 1 second timeout). We should allow touch mode change
+ // if the last interacted window owner's pid/uid match the calling ones.
+ if (focusedToken == nullptr) {
+ return false;
+ }
+ const sp<WindowInfoHandle> windowHandle = getWindowHandleLocked(focusedToken);
+ if (windowHandle == nullptr) {
+ return false;
+ }
+ const WindowInfo* windowInfo = windowHandle->getInfo();
+ if (pid != windowInfo->ownerPid || uid != windowInfo->ownerUid) {
+ return false;
+ }
}
// TODO(b/198499018): Store touch mode per display.
mInTouchMode = inTouchMode;
- // TODO(b/198487159): Enforce that only last interacted apps can change touch mode.
auto entry = std::make_unique<TouchModeEntry>(mIdGenerator.nextId(), now(), inTouchMode);
needWake = enqueueInboundEventLocked(std::move(entry));
} // release lock
@@ -4927,6 +4946,7 @@
if (needWake) {
mLooper->wake();
}
+ return true;
}
void InputDispatcher::setMaximumObscuringOpacityForTouch(float opacity) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 0a70385..e162c78 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -117,7 +117,7 @@
void setFocusedDisplay(int32_t displayId) override;
void setInputDispatchMode(bool enabled, bool frozen) override;
void setInputFilterEnabled(bool enabled) override;
- void setInTouchMode(bool inTouchMode) override;
+ bool setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) override;
void setMaximumObscuringOpacityForTouch(float opacity) override;
void setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode mode) override;
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 44ce8ec..67e1b6f 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -123,8 +123,10 @@
* Touch mode is a global state that apps may enter / exit based on specific
* user interactions with input devices.
* If true, the device is in touch mode.
+ *
+ * Returns true when changing touch mode state.
*/
- virtual void setInTouchMode(bool inTouchMode) = 0;
+ virtual bool setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) = 0;
/**
* Sets the maximum allowed obscuring opacity by UID to propagate touches.
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index ef1ee26..872882e 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -2997,6 +2997,7 @@
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+ const WindowInfo& windowInfo = *window->getInfo();
// Set focused application.
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -3013,7 +3014,8 @@
window->consumeFocusEvent(false /*hasFocus*/, true /*inTouchMode*/);
SCOPED_TRACE("Disable touch mode");
- mDispatcher->setInTouchMode(false);
+ mDispatcher->setInTouchMode(false, windowInfo.ownerPid, windowInfo.ownerUid,
+ /* hasPermission */ true);
window->consumeTouchModeEvent(false);
window->setFocusable(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -3026,7 +3028,8 @@
window->consumeFocusEvent(false /*hasFocus*/, false /*inTouchMode*/);
SCOPED_TRACE("Enable touch mode again");
- mDispatcher->setInTouchMode(true);
+ mDispatcher->setInTouchMode(true, windowInfo.ownerPid, windowInfo.ownerUid,
+ /* hasPermission */ true);
window->consumeTouchModeEvent(true);
window->setFocusable(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -6231,19 +6234,23 @@
mWindow->consumeFocusEvent(true);
}
- void changeAndVerifyTouchMode(bool inTouchMode) {
- mDispatcher->setInTouchMode(inTouchMode);
+ void changeAndVerifyTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) {
+ mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission);
mWindow->consumeTouchModeEvent(inTouchMode);
mSecondWindow->consumeTouchModeEvent(inTouchMode);
}
};
TEST_F(InputDispatcherTouchModeChangedTests, ChangeTouchModeOnFocusedWindow) {
- changeAndVerifyTouchMode(!InputDispatcher::kDefaultInTouchMode);
+ const WindowInfo& windowInfo = *mWindow->getInfo();
+ changeAndVerifyTouchMode(!InputDispatcher::kDefaultInTouchMode, windowInfo.ownerPid,
+ windowInfo.ownerUid, /* hasPermission */ false);
}
TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTouchMode) {
- mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode);
+ const WindowInfo& windowInfo = *mWindow->getInfo();
+ mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, windowInfo.ownerPid,
+ windowInfo.ownerUid, /* hasPermission */ true);
mWindow->assertNoEvents();
mSecondWindow->assertNoEvents();
}
@@ -6813,4 +6820,7 @@
window->assertNoEvents();
}
+// TODO(b/198487159): Add permission tests for touch mode switch once the validation is put in
+// place.
+
} // namespace android::inputdispatcher
diff --git a/services/sensorservice/AidlSensorHalWrapper.cpp b/services/sensorservice/AidlSensorHalWrapper.cpp
index 09aed46..86c8b0d 100644
--- a/services/sensorservice/AidlSensorHalWrapper.cpp
+++ b/services/sensorservice/AidlSensorHalWrapper.cpp
@@ -285,6 +285,11 @@
src.payload.get<Event::EventPayload::limitedAxesImuUncal>().zSupported;
break;
+ case SensorType::HEADING:
+ dst->heading.heading = src.payload.get<Event::EventPayload::heading>().heading;
+ dst->heading.accuracy = src.payload.get<Event::EventPayload::heading>().accuracy;
+ break;
+
default: {
CHECK_GE((int32_t)src.sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE);
@@ -473,6 +478,14 @@
break;
}
+ case SensorType::HEADING: {
+ Event::EventPayload::Heading heading;
+ heading.heading = src.heading.heading;
+ heading.accuracy = src.heading.accuracy;
+ dst->payload.set<Event::EventPayload::heading>(heading);
+ break;
+ }
+
default: {
CHECK_GE((int32_t)dst->sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE);
diff --git a/services/sensorservice/SensorServiceUtils.cpp b/services/sensorservice/SensorServiceUtils.cpp
index c304381..7dd2331 100644
--- a/services/sensorservice/SensorServiceUtils.cpp
+++ b/services/sensorservice/SensorServiceUtils.cpp
@@ -67,6 +67,9 @@
case SENSOR_TYPE_HEAD_TRACKER:
return 7;
+ case SENSOR_TYPE_HEADING:
+ return 2;
+
default:
return 3;
}
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index b7e2ff3..18a6bae 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -319,7 +319,6 @@
Mutex::Autolock lock(mFrameEventHistoryMutex);
mFrameEventHistory.addPreComposition(mCurrentFrameNumber, refreshStartTime);
}
- mRefreshPending = false;
return hasReadyFrame();
}
namespace {
@@ -474,19 +473,6 @@
return refreshRequired;
}
- if (!hasReadyFrame()) {
- return false;
- }
-
- // if we've already called updateTexImage() without going through
- // a composition step, we have to skip this layer at this point
- // because we cannot call updateTeximage() without a corresponding
- // compositionComplete() call.
- // we'll trigger an update in onPreComposition().
- if (mRefreshPending) {
- return false;
- }
-
// If the head buffer's acquire fence hasn't signaled yet, return and
// try again later
if (!fenceHasSignaled()) {
@@ -518,7 +504,6 @@
gatherBufferInfo();
- mRefreshPending = true;
if (oldBufferInfo.mBuffer == nullptr) {
// the first time we receive a buffer, we need to trigger a
// geometry invalidation.
@@ -689,7 +674,6 @@
}
void BufferLayer::latchAndReleaseBuffer() {
- mRefreshPending = false;
if (hasReadyFrame()) {
bool ignored = false;
latchBuffer(ignored, systemTime(), 0 /* expectedPresentTime */);
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 99267be..3e70493 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -88,9 +88,6 @@
// to figure out if the content or size of a surface has changed.
bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
nsecs_t expectedPresentTime) override;
-
- bool isBufferLatched() const override { return mRefreshPending; }
-
bool hasReadyFrame() const override;
// Returns the current scaling mode
@@ -158,9 +155,6 @@
// from graphics API
const uint32_t mTextureName;
-
- bool mRefreshPending{false};
-
ui::Dataspace translateDataspace(ui::Dataspace dataspace);
void setInitialValuesForClone(const sp<Layer>& clonedFrom);
void updateCloneBufferInfo() override;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 645d4d1..a039250 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1398,7 +1398,6 @@
}
}
info.mNumQueuedFrames = getQueuedFrameCount();
- info.mRefreshPending = isBufferLatched();
info.mIsOpaque = isOpaque(ds);
info.mContentDirty = contentDirty;
info.mStretchEffect = getStretchEffect();
@@ -2029,7 +2028,6 @@
layerInfo->set_is_protected(isProtected());
layerInfo->set_dataspace(dataspaceDetails(static_cast<android_dataspace>(getDataSpace())));
layerInfo->set_queued_frames(getQueuedFrameCount());
- layerInfo->set_refresh_pending(isBufferLatched());
layerInfo->set_curr_frame(mCurrentFrameNumber);
layerInfo->set_effective_scaling_mode(getEffectiveScalingMode());
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 605a27e..ddcd641 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -549,8 +549,6 @@
return false;
}
- virtual bool isBufferLatched() const { return false; }
-
virtual void latchAndReleaseBuffer() {}
/*
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 3459a8f..b3c3a41 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3563,11 +3563,9 @@
for (const auto& layer : mLayersWithQueuedFrames) {
if (layer->latchBuffer(visibleRegions, latchTime, expectedPresentTime)) {
mLayersPendingRefresh.push_back(layer);
- }
- layer->useSurfaceDamage();
- if (layer->isBufferLatched()) {
newDataLatched = true;
}
+ layer->useSurfaceDamage();
}
}
@@ -3915,7 +3913,8 @@
// been applied by SF
if (state.flags & eAnimation) {
while (itr != mPendingTransactionQueues.end()) {
- status_t err = mTransactionQueueCV.waitRelative(mQueueLock, s2ns(5));
+ status_t err =
+ mTransactionQueueCV.waitRelative(mQueueLock, mAnimationTransactionTimeout);
if (CC_UNLIKELY(err != NO_ERROR)) {
ALOGW_IF(err == TIMED_OUT,
"setTransactionState timed out "
@@ -3951,7 +3950,8 @@
// applyTransactionState is called on the main SF thread. While a given process may wish
// to wait on synchronous transactions, the main SF thread should apply the transaction and
// set the value to notify this after committed.
- if (!transactionCommittedSignal.wait_until(std::chrono::seconds(5))) {
+ if (!transactionCommittedSignal.wait_until(
+ std::chrono::nanoseconds(mAnimationTransactionTimeout))) {
ALOGE("setTransactionState timed out!");
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index c6a4d85..77193a6 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1372,6 +1372,8 @@
nsecs_t compositeStart;
nsecs_t presentEnd;
} mPowerHintSessionData GUARDED_BY(SF_MAIN_THREAD);
+
+ nsecs_t mAnimationTransactionTimeout = s2ns(5);
};
} // namespace android
diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h
index fe3f3fc..04ca347 100644
--- a/services/surfaceflinger/TransactionState.h
+++ b/services/surfaceflinger/TransactionState.h
@@ -93,7 +93,7 @@
}
// Return true if triggered.
- bool wait_until(const std::chrono::seconds& timeout) const {
+ bool wait_until(const std::chrono::nanoseconds& timeout) const {
std::unique_lock<std::mutex> lock(mMutex);
const auto untilTime = std::chrono::system_clock::now() + timeout;
while (mFlags != 0) {
diff --git a/services/surfaceflinger/fuzzer/Android.bp b/services/surfaceflinger/fuzzer/Android.bp
index 0ead163..b0d216e 100644
--- a/services/surfaceflinger/fuzzer/Android.bp
+++ b/services/surfaceflinger/fuzzer/Android.bp
@@ -92,3 +92,13 @@
"android.hardware.graphics.composer@2.4-hal",
],
}
+
+cc_fuzz {
+ name: "surfaceflinger_scheduler_fuzzer",
+ defaults: [
+ "surfaceflinger_fuzz_defaults",
+ ],
+ srcs: [
+ "surfaceflinger_scheduler_fuzzer.cpp",
+ ],
+}
diff --git a/services/surfaceflinger/fuzzer/README.md b/services/surfaceflinger/fuzzer/README.md
index 4ecf770..6231ca5 100644
--- a/services/surfaceflinger/fuzzer/README.md
+++ b/services/surfaceflinger/fuzzer/README.md
@@ -2,6 +2,7 @@
## Table of contents
+ [SurfaceFlinger](#SurfaceFlinger)
+ [DisplayHardware](#DisplayHardware)
++ [Scheduler](#Scheduler)
# <a name="SurfaceFlinger"></a> Fuzzer for SurfaceFlinger
@@ -51,3 +52,21 @@
$ adb sync data
$ adb shell /data/fuzz/arm64/surfaceflinger_displayhardware_fuzzer/surfaceflinger_displayhardware_fuzzer
```
+
+# <a name="Scheduler"></a> Fuzzer for Scheduler
+
+Scheduler supports the following parameters:
+1. VSync Periods (parameter name: `lowFpsPeriod`)
+
+You can find the possible values in the fuzzer's source code.
+
+#### Steps to run
+1. Build the fuzzer
+```
+ $ mm -j$(nproc) surfaceflinger_scheduler_fuzzer
+```
+2. To run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/surfaceflinger_scheduler_fuzzer/surfaceflinger_scheduler_fuzzer
+```
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
new file mode 100644
index 0000000..51a5081
--- /dev/null
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -0,0 +1,392 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "surfaceflinger_scheduler_fuzzer.h"
+#include <fuzzer/FuzzedDataProvider.h>
+#include <processgroup/sched_policy.h>
+#include "Scheduler/DispSyncSource.h"
+#include "Scheduler/OneShotTimer.h"
+#include "Scheduler/VSyncDispatchTimerQueue.h"
+#include "Scheduler/VSyncPredictor.h"
+#include "Scheduler/VSyncReactor.h"
+#include "surfaceflinger_fuzzers_utils.h"
+
+namespace android::fuzz {
+
+using hardware::graphics::composer::hal::PowerMode;
+
+static constexpr PowerMode kPowerModes[] = {PowerMode::ON, PowerMode::DOZE, PowerMode::OFF,
+ PowerMode::DOZE_SUSPEND, PowerMode::ON_SUSPEND};
+
+constexpr uint16_t kRandomStringLength = 256;
+constexpr std::chrono::duration kSyncPeriod(16ms);
+
+template <typename T>
+void dump(T* component, FuzzedDataProvider* fdp) {
+ std::string res = fdp->ConsumeRandomLengthString(kRandomStringLength);
+ component->dump(res);
+}
+
+class SchedulerFuzzer : private VSyncSource::Callback {
+public:
+ SchedulerFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+ void process();
+
+private:
+ void fuzzRefreshRateSelection();
+ void fuzzRefreshRateConfigs();
+ void fuzzVSyncModulator();
+ void fuzzVSyncPredictor();
+ void fuzzVSyncReactor();
+ void fuzzLayerHistory();
+ void fuzzDispSyncSource();
+ void fuzzCallbackToken(scheduler::VSyncDispatchTimerQueue* dispatch);
+ void fuzzVSyncDispatchTimerQueue();
+ void fuzzOneShotTimer();
+ void fuzzEventThread();
+ PhysicalDisplayId getPhysicalDisplayId();
+
+ FuzzedDataProvider mFdp;
+
+protected:
+ void onVSyncEvent(nsecs_t /* when */, nsecs_t /* expectedVSyncTimestamp */,
+ nsecs_t /* deadlineTimestamp */) {}
+};
+
+PhysicalDisplayId SchedulerFuzzer::getPhysicalDisplayId() {
+ PhysicalDisplayId internalDispId = PhysicalDisplayId::fromPort(111u);
+ PhysicalDisplayId externalDispId = PhysicalDisplayId::fromPort(222u);
+ PhysicalDisplayId randomDispId = PhysicalDisplayId::fromPort(mFdp.ConsumeIntegral<uint16_t>());
+ PhysicalDisplayId dispId64Bit = PhysicalDisplayId::fromEdid(0xffu, 0xffffu, 0xffff'ffffu);
+ PhysicalDisplayId displayId = mFdp.PickValueInArray<PhysicalDisplayId>(
+ {internalDispId, externalDispId, dispId64Bit, randomDispId});
+ return displayId;
+}
+
+void SchedulerFuzzer::fuzzEventThread() {
+ const auto getVsyncPeriod = [](uid_t /* uid */) { return kSyncPeriod.count(); };
+ std::unique_ptr<android::impl::EventThread> thread = std::make_unique<
+ android::impl::EventThread>(std::move(std::make_unique<FuzzImplVSyncSource>()), nullptr,
+ nullptr, nullptr, getVsyncPeriod);
+
+ thread->onHotplugReceived(getPhysicalDisplayId(), mFdp.ConsumeBool());
+ sp<EventThreadConnection> connection =
+ new EventThreadConnection(thread.get(), mFdp.ConsumeIntegral<uint16_t>(), nullptr,
+ {} /*eventRegistration*/);
+ thread->requestNextVsync(connection);
+ thread->setVsyncRate(mFdp.ConsumeIntegral<uint32_t>() /*rate*/, connection);
+
+ thread->setDuration((std::chrono::nanoseconds)mFdp.ConsumeIntegral<uint64_t>(),
+ (std::chrono::nanoseconds)mFdp.ConsumeIntegral<uint64_t>());
+ thread->registerDisplayEventConnection(connection);
+ thread->onScreenAcquired();
+ thread->onScreenReleased();
+ dump<android::impl::EventThread>(thread.get(), &mFdp);
+}
+
+void SchedulerFuzzer::fuzzDispSyncSource() {
+ std::unique_ptr<FuzzImplVSyncDispatch> vSyncDispatch =
+ std::make_unique<FuzzImplVSyncDispatch>();
+ std::unique_ptr<scheduler::DispSyncSource> dispSyncSource = std::make_unique<
+ scheduler::DispSyncSource>(*vSyncDispatch,
+ (std::chrono::nanoseconds)
+ mFdp.ConsumeIntegral<uint64_t>() /*workDuration*/,
+ (std::chrono::nanoseconds)mFdp.ConsumeIntegral<uint64_t>()
+ /*readyDuration*/,
+ mFdp.ConsumeBool(),
+ mFdp.ConsumeRandomLengthString(kRandomStringLength).c_str());
+ dispSyncSource->setVSyncEnabled(true);
+ dispSyncSource->setCallback(this);
+ dispSyncSource->setDuration((std::chrono::nanoseconds)mFdp.ConsumeIntegral<uint64_t>(), 0ns);
+ dump<scheduler::DispSyncSource>(dispSyncSource.get(), &mFdp);
+}
+
+void SchedulerFuzzer::fuzzCallbackToken(scheduler::VSyncDispatchTimerQueue* dispatch) {
+ scheduler::VSyncDispatch::CallbackToken tmp = dispatch->registerCallback(
+ [&](auto, auto, auto) {
+ dispatch->schedule(tmp,
+ {.workDuration = mFdp.ConsumeIntegral<nsecs_t>(),
+ .readyDuration = mFdp.ConsumeIntegral<nsecs_t>(),
+ .earliestVsync = mFdp.ConsumeIntegral<nsecs_t>()});
+ },
+ "o.o");
+ dispatch->schedule(tmp,
+ {.workDuration = mFdp.ConsumeIntegral<nsecs_t>(),
+ .readyDuration = mFdp.ConsumeIntegral<nsecs_t>(),
+ .earliestVsync = mFdp.ConsumeIntegral<nsecs_t>()});
+ dispatch->unregisterCallback(tmp);
+ dispatch->cancel(tmp);
+}
+
+void SchedulerFuzzer::fuzzVSyncDispatchTimerQueue() {
+ FuzzImplVSyncTracker stubTracker{mFdp.ConsumeIntegral<nsecs_t>()};
+ scheduler::VSyncDispatchTimerQueue
+ mDispatch{std::make_unique<scheduler::ControllableClock>(), stubTracker,
+ mFdp.ConsumeIntegral<nsecs_t>() /*dispatchGroupThreshold*/,
+ mFdp.ConsumeIntegral<nsecs_t>() /*vSyncMoveThreshold*/};
+
+ fuzzCallbackToken(&mDispatch);
+
+ dump<scheduler::VSyncDispatchTimerQueue>(&mDispatch, &mFdp);
+
+ scheduler::VSyncDispatchTimerQueueEntry entry(
+ "fuzz", [](auto, auto, auto) {},
+ mFdp.ConsumeIntegral<nsecs_t>() /*vSyncMoveThreshold*/);
+ entry.update(stubTracker, 0);
+ entry.schedule({.workDuration = mFdp.ConsumeIntegral<nsecs_t>(),
+ .readyDuration = mFdp.ConsumeIntegral<nsecs_t>(),
+ .earliestVsync = mFdp.ConsumeIntegral<nsecs_t>()},
+ stubTracker, 0);
+ entry.disarm();
+ entry.ensureNotRunning();
+ entry.schedule({.workDuration = mFdp.ConsumeIntegral<nsecs_t>(),
+ .readyDuration = mFdp.ConsumeIntegral<nsecs_t>(),
+ .earliestVsync = mFdp.ConsumeIntegral<nsecs_t>()},
+ stubTracker, 0);
+ auto const wakeup = entry.wakeupTime();
+ auto const ready = entry.readyTime();
+ entry.callback(entry.executing(), *wakeup, *ready);
+ entry.addPendingWorkloadUpdate({.workDuration = mFdp.ConsumeIntegral<nsecs_t>(),
+ .readyDuration = mFdp.ConsumeIntegral<nsecs_t>(),
+ .earliestVsync = mFdp.ConsumeIntegral<nsecs_t>()});
+ dump<scheduler::VSyncDispatchTimerQueueEntry>(&entry, &mFdp);
+}
+
+void SchedulerFuzzer::fuzzVSyncPredictor() {
+ uint16_t now = mFdp.ConsumeIntegral<uint16_t>();
+ uint16_t historySize = mFdp.ConsumeIntegralInRange<uint16_t>(1, UINT16_MAX);
+ uint16_t minimumSamplesForPrediction = mFdp.ConsumeIntegralInRange<uint16_t>(1, UINT16_MAX);
+ scheduler::VSyncPredictor tracker{mFdp.ConsumeIntegral<uint16_t>() /*period*/, historySize,
+ minimumSamplesForPrediction,
+ mFdp.ConsumeIntegral<uint32_t>() /*outlierTolerancePercent*/};
+ uint16_t period = mFdp.ConsumeIntegral<uint16_t>();
+ tracker.setPeriod(period);
+ for (uint16_t i = 0; i < minimumSamplesForPrediction; ++i) {
+ if (!tracker.needsMoreSamples()) {
+ break;
+ }
+ tracker.addVsyncTimestamp(now += period);
+ }
+ tracker.nextAnticipatedVSyncTimeFrom(now);
+ tracker.resetModel();
+}
+
+void SchedulerFuzzer::fuzzOneShotTimer() {
+ FakeClock* clock = new FakeClock();
+ std::unique_ptr<scheduler::OneShotTimer> idleTimer = std::make_unique<scheduler::OneShotTimer>(
+ mFdp.ConsumeRandomLengthString(kRandomStringLength) /*name*/,
+ (std::chrono::milliseconds)mFdp.ConsumeIntegral<uint8_t>() /*val*/,
+ [] {} /*resetCallback*/, [] {} /*timeoutCallback*/, std::unique_ptr<FakeClock>(clock));
+ idleTimer->start();
+ idleTimer->reset();
+ idleTimer->stop();
+}
+
+void SchedulerFuzzer::fuzzLayerHistory() {
+ TestableSurfaceFlinger flinger;
+ flinger.setupScheduler(std::make_unique<android::mock::VsyncController>(),
+ std::make_unique<android::mock::VSyncTracker>(),
+ std::make_unique<android::mock::EventThread>(),
+ std::make_unique<android::mock::EventThread>());
+ flinger.setupTimeStats(std::make_unique<android::mock::TimeStats>());
+ std::unique_ptr<android::renderengine::RenderEngine> renderEngine =
+ std::make_unique<android::renderengine::mock::RenderEngine>();
+ flinger.setupRenderEngine(std::move(renderEngine));
+ flinger.setupComposer(std::make_unique<android::Hwc2::mock::Composer>());
+
+ scheduler::TestableScheduler* scheduler = flinger.scheduler();
+
+ scheduler::LayerHistory& historyV1 = scheduler->mutableLayerHistory();
+ nsecs_t time1 = systemTime();
+ nsecs_t time2 = time1;
+ uint8_t historySize = mFdp.ConsumeIntegral<uint8_t>();
+
+ sp<FuzzImplLayer> layer1 = new FuzzImplLayer(flinger.flinger());
+ sp<FuzzImplLayer> layer2 = new FuzzImplLayer(flinger.flinger());
+
+ for (int i = 0; i < historySize; ++i) {
+ historyV1.record(layer1.get(), time1, time1,
+ scheduler::LayerHistory::LayerUpdateType::Buffer);
+ historyV1.record(layer2.get(), time2, time2,
+ scheduler::LayerHistory::LayerUpdateType::Buffer);
+ time1 += mFdp.PickValueInArray(kVsyncPeriods);
+ time2 += mFdp.PickValueInArray(kVsyncPeriods);
+ }
+ historyV1.summarize(*scheduler->refreshRateConfigs(), time1);
+ historyV1.summarize(*scheduler->refreshRateConfigs(), time2);
+
+ scheduler->createConnection(std::make_unique<android::mock::EventThread>());
+
+ scheduler::ConnectionHandle handle;
+ scheduler->createDisplayEventConnection(handle);
+ scheduler->setDuration(handle, (std::chrono::nanoseconds)mFdp.ConsumeIntegral<uint64_t>(),
+ (std::chrono::nanoseconds)mFdp.ConsumeIntegral<uint64_t>());
+
+ dump<scheduler::TestableScheduler>(scheduler, &mFdp);
+}
+
+void SchedulerFuzzer::fuzzVSyncReactor() {
+ std::shared_ptr<FuzzImplVSyncTracker> vSyncTracker = std::make_shared<FuzzImplVSyncTracker>();
+ scheduler::VSyncReactor reactor(std::make_unique<ClockWrapper>(
+ std::make_shared<FuzzImplClock>()),
+ *vSyncTracker, mFdp.ConsumeIntegral<uint8_t>() /*pendingLimit*/,
+ false);
+
+ reactor.startPeriodTransition(mFdp.ConsumeIntegral<nsecs_t>());
+ bool periodFlushed = mFdp.ConsumeBool();
+ reactor.addHwVsyncTimestamp(0, std::nullopt, &periodFlushed);
+ reactor.addHwVsyncTimestamp(mFdp.ConsumeIntegral<nsecs_t>() /*newPeriod*/, std::nullopt,
+ &periodFlushed);
+ sp<Fence> fence = new Fence(memfd_create("fd", MFD_ALLOW_SEALING));
+ std::shared_ptr<FenceTime> ft = std::make_shared<FenceTime>(fence);
+ vSyncTracker->addVsyncTimestamp(mFdp.ConsumeIntegral<nsecs_t>());
+ FenceTime::Snapshot snap(mFdp.ConsumeIntegral<nsecs_t>());
+ ft->applyTrustedSnapshot(snap);
+ reactor.setIgnorePresentFences(mFdp.ConsumeBool());
+ reactor.addPresentFence(ft);
+ dump<scheduler::VSyncReactor>(&reactor, &mFdp);
+}
+
+void SchedulerFuzzer::fuzzVSyncModulator() {
+ enum {
+ SF_OFFSET_LATE,
+ APP_OFFSET_LATE,
+ SF_DURATION_LATE,
+ APP_DURATION_LATE,
+ SF_OFFSET_EARLY,
+ APP_OFFSET_EARLY,
+ SF_DURATION_EARLY,
+ APP_DURATION_EARLY,
+ SF_OFFSET_EARLY_GPU,
+ APP_OFFSET_EARLY_GPU,
+ SF_DURATION_EARLY_GPU,
+ APP_DURATION_EARLY_GPU,
+ HWC_MIN_WORK_DURATION,
+ };
+ using Schedule = scheduler::TransactionSchedule;
+ using nanos = std::chrono::nanoseconds;
+ using VsyncModulator = scheduler::VsyncModulator;
+ using FuzzImplVsyncModulator = scheduler::FuzzImplVsyncModulator;
+ const VsyncModulator::VsyncConfig early{SF_OFFSET_EARLY, APP_OFFSET_EARLY,
+ nanos(SF_DURATION_LATE), nanos(APP_DURATION_LATE)};
+ const VsyncModulator::VsyncConfig earlyGpu{SF_OFFSET_EARLY_GPU, APP_OFFSET_EARLY_GPU,
+ nanos(SF_DURATION_EARLY), nanos(APP_DURATION_EARLY)};
+ const VsyncModulator::VsyncConfig late{SF_OFFSET_LATE, APP_OFFSET_LATE,
+ nanos(SF_DURATION_EARLY_GPU),
+ nanos(APP_DURATION_EARLY_GPU)};
+ const VsyncModulator::VsyncConfigSet offsets = {early, earlyGpu, late,
+ nanos(HWC_MIN_WORK_DURATION)};
+ sp<FuzzImplVsyncModulator> vSyncModulator =
+ sp<FuzzImplVsyncModulator>::make(offsets, scheduler::Now);
+ (void)vSyncModulator->setVsyncConfigSet(offsets);
+ (void)vSyncModulator->setTransactionSchedule(Schedule::Late);
+ const auto token = sp<BBinder>::make();
+ (void)vSyncModulator->setTransactionSchedule(Schedule::EarlyStart, token);
+ vSyncModulator->binderDied(token);
+}
+
+void SchedulerFuzzer::fuzzRefreshRateSelection() {
+ TestableSurfaceFlinger flinger;
+ flinger.setupScheduler(std::make_unique<android::mock::VsyncController>(),
+ std::make_unique<android::mock::VSyncTracker>(),
+ std::make_unique<android::mock::EventThread>(),
+ std::make_unique<android::mock::EventThread>());
+
+ sp<Client> client;
+ LayerCreationArgs args(flinger.flinger(), client,
+ mFdp.ConsumeRandomLengthString(kRandomStringLength) /*name*/,
+ mFdp.ConsumeIntegral<uint16_t>() /*layerFlags*/, LayerMetadata());
+ sp<Layer> layer = new BufferQueueLayer(args);
+
+ layer->setFrameRateSelectionPriority(mFdp.ConsumeIntegral<int16_t>());
+}
+
+void SchedulerFuzzer::fuzzRefreshRateConfigs() {
+ using RefreshRateConfigs = scheduler::RefreshRateConfigs;
+ using LayerRequirement = RefreshRateConfigs::LayerRequirement;
+ using RefreshRateStats = scheduler::RefreshRateStats;
+ uint16_t minRefreshRate = mFdp.ConsumeIntegralInRange<uint16_t>(1, UINT16_MAX >> 1);
+ uint16_t maxRefreshRate = mFdp.ConsumeIntegralInRange<uint16_t>(minRefreshRate + 1, UINT16_MAX);
+
+ DisplayModeId hwcConfigIndexType = DisplayModeId(mFdp.ConsumeIntegralInRange<uint8_t>(0, 10));
+
+ DisplayModes displayModes;
+ for (uint16_t fps = minRefreshRate; fps < maxRefreshRate; ++fps) {
+ constexpr int32_t kGroup = 0;
+ const auto refreshRate = Fps::fromValue(static_cast<float>(fps));
+ displayModes.push_back(scheduler::createDisplayMode(hwcConfigIndexType, kGroup,
+ refreshRate.getPeriodNsecs()));
+ }
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(displayModes, hwcConfigIndexType);
+ const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false};
+ auto layers = std::vector<LayerRequirement>{
+ LayerRequirement{.weight = mFdp.ConsumeFloatingPoint<float>()}};
+ refreshRateConfigs->getBestRefreshRate(layers, globalSignals);
+ layers[0].name = mFdp.ConsumeRandomLengthString(kRandomStringLength);
+ layers[0].ownerUid = mFdp.ConsumeIntegral<uint16_t>();
+ layers[0].desiredRefreshRate = Fps::fromValue(mFdp.ConsumeFloatingPoint<float>());
+ layers[0].vote = mFdp.PickValueInArray(kLayerVoteTypes);
+ auto frameRateOverrides =
+ refreshRateConfigs->getFrameRateOverrides(layers,
+ Fps::fromValue(
+ mFdp.ConsumeFloatingPoint<float>()),
+ globalSignals);
+
+ refreshRateConfigs->setDisplayManagerPolicy(
+ {hwcConfigIndexType,
+ {Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()),
+ Fps::fromValue(mFdp.ConsumeFloatingPoint<float>())}});
+ refreshRateConfigs->setCurrentModeId(hwcConfigIndexType);
+
+ RefreshRateConfigs::isFractionalPairOrMultiple(Fps::fromValue(
+ mFdp.ConsumeFloatingPoint<float>()),
+ Fps::fromValue(
+ mFdp.ConsumeFloatingPoint<float>()));
+ RefreshRateConfigs::getFrameRateDivider(Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()),
+ Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()));
+
+ android::mock::TimeStats timeStats;
+ std::unique_ptr<RefreshRateStats> refreshRateStats =
+ std::make_unique<RefreshRateStats>(timeStats,
+ Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()),
+ PowerMode::OFF);
+ refreshRateStats->setRefreshRate(
+ refreshRateConfigs->getRefreshRateFromModeId(hwcConfigIndexType).getFps());
+ refreshRateStats->setPowerMode(mFdp.PickValueInArray(kPowerModes));
+}
+
+void SchedulerFuzzer::process() {
+ fuzzRefreshRateSelection();
+ fuzzRefreshRateConfigs();
+ fuzzVSyncModulator();
+ fuzzVSyncPredictor();
+ fuzzVSyncReactor();
+ fuzzLayerHistory();
+ fuzzDispSyncSource();
+ fuzzEventThread();
+ fuzzVSyncDispatchTimerQueue();
+ fuzzOneShotTimer();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ SchedulerFuzzer schedulerFuzzer(data, size);
+ schedulerFuzzer.process();
+ return 0;
+}
+
+} // namespace android::fuzz
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
new file mode 100644
index 0000000..89cf819
--- /dev/null
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/*
+ Reference for some of the classes and functions has been taken from unittests
+ present in frameworks/native/services/surfaceflinger/tests/unittests
+*/
+
+#pragma once
+
+#include "Clock.h"
+#include "Layer.h"
+#include "Scheduler/EventThread.h"
+#include "Scheduler/RefreshRateConfigs.h"
+#include "Scheduler/Scheduler.h"
+#include "Scheduler/VSyncTracker.h"
+#include "Scheduler/VsyncModulator.h"
+#include "scheduler/TimeKeeper.h"
+
+namespace android::fuzz {
+
+constexpr int64_t kVsyncPeriods[] = {static_cast<int64_t>(1e9f / 30),
+ static_cast<int64_t>(1e9f / 60),
+ static_cast<int64_t>(1e9f / 72),
+ static_cast<int64_t>(1e9f / 90),
+ static_cast<int64_t>(1e9f / 120)};
+
+android::scheduler::RefreshRateConfigs::LayerVoteType kLayerVoteTypes[] =
+ {android::scheduler::RefreshRateConfigs::LayerVoteType::NoVote,
+ android::scheduler::RefreshRateConfigs::LayerVoteType::Min,
+ android::scheduler::RefreshRateConfigs::LayerVoteType::Max,
+ android::scheduler::RefreshRateConfigs::LayerVoteType::Heuristic,
+ android::scheduler::RefreshRateConfigs::LayerVoteType::ExplicitDefault,
+ android::scheduler::RefreshRateConfigs::LayerVoteType::ExplicitExactOrMultiple};
+
+class FuzzImplClock : public android::scheduler::Clock {
+public:
+ nsecs_t now() const { return 1; }
+};
+
+class ClockWrapper : public android::scheduler::Clock {
+public:
+ ClockWrapper(std::shared_ptr<android::scheduler::Clock> const& clock) : mClock(clock) {}
+
+ nsecs_t now() const { return mClock->now(); }
+
+private:
+ std::shared_ptr<android::scheduler::Clock> const mClock;
+};
+
+} // namespace android::fuzz
+
+namespace android {
+
+using namespace std::chrono_literals;
+
+class FakeClock : public Clock {
+public:
+ virtual ~FakeClock() = default;
+ std::chrono::steady_clock::time_point now() const override { return mNow; }
+
+ void advanceTime(std::chrono::nanoseconds delta) { mNow += delta; }
+
+private:
+ std::chrono::steady_clock::time_point mNow;
+};
+
+class FuzzImplLayer : public Layer {
+public:
+ FuzzImplLayer(SurfaceFlinger* flinger, std::string name)
+ : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {})) {}
+ explicit FuzzImplLayer(SurfaceFlinger* flinger) : FuzzImplLayer(flinger, "FuzzLayer") {}
+
+ const char* getType() const override { return ""; }
+
+ bool isVisible() const override { return true; }
+
+ sp<Layer> createClone() override { return nullptr; }
+};
+
+class FuzzImplVSyncSource : public VSyncSource {
+public:
+ const char* getName() const override { return "fuzz"; }
+
+ void setVSyncEnabled(bool /* enable */) override {}
+
+ void setCallback(Callback* /* callback */) override {}
+
+ void setDuration(std::chrono::nanoseconds /* workDuration */,
+ std::chrono::nanoseconds /* readyDuration */) override {}
+
+ void dump(std::string& /* result */) const override {}
+};
+
+class FuzzImplVSyncTracker : public scheduler::VSyncTracker {
+public:
+ FuzzImplVSyncTracker(nsecs_t period) { mPeriod = period; }
+
+ FuzzImplVSyncTracker() = default;
+
+ bool addVsyncTimestamp(nsecs_t /* timestamp */) override { return true; }
+
+ nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t /* timePoint */) const override { return 1; }
+
+ nsecs_t currentPeriod() const override { return 1; }
+
+ void setPeriod(nsecs_t /* period */) override {}
+
+ void resetModel() override {}
+
+ bool needsMoreSamples() const override { return true; }
+
+ bool isVSyncInPhase(nsecs_t /* timePoint */, Fps /* frameRate */) const override {
+ return true;
+ }
+
+ nsecs_t nextVSyncTime(nsecs_t timePoint) const {
+ if (timePoint % mPeriod == 0) {
+ return timePoint;
+ }
+ return (timePoint - (timePoint % mPeriod) + mPeriod);
+ }
+
+ void dump(std::string& /* result */) const override {}
+
+protected:
+ nsecs_t mPeriod;
+};
+
+class FuzzImplVSyncDispatch : public scheduler::VSyncDispatch {
+public:
+ CallbackToken registerCallback(Callback /* callbackFn */,
+ std::string /* callbackName */) override {
+ return CallbackToken{};
+ }
+
+ void unregisterCallback(CallbackToken /* token */) override {}
+
+ scheduler::ScheduleResult schedule(CallbackToken /* token */,
+ ScheduleTiming /* scheduleTiming */) override {
+ return (scheduler::ScheduleResult)0;
+ }
+
+ scheduler::CancelResult cancel(CallbackToken /* token */) override {
+ return (scheduler::CancelResult)0;
+ }
+
+ void dump(std::string& /* result */) const override {}
+};
+
+} // namespace android
+
+namespace android::scheduler {
+
+DisplayModePtr createDisplayMode(DisplayModeId modeId, int32_t group, int64_t vsyncPeriod,
+ ui::Size resolution = ui::Size()) {
+ return DisplayMode::Builder(hal::HWConfigId(modeId.value()))
+ .setId(modeId)
+ .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
+ .setVsyncPeriod(int32_t(vsyncPeriod))
+ .setGroup(group)
+ .setHeight(resolution.height)
+ .setWidth(resolution.width)
+ .build();
+}
+
+class ControllableClock : public TimeKeeper {
+public:
+ nsecs_t now() const { return 1; };
+ void alarmAt(std::function<void()> /* callback */, nsecs_t /* time */) override {}
+ void alarmCancel() override {}
+ void dump(std::string& /* result */) const override {}
+
+ void alarmAtDefaultBehavior(std::function<void()> const& callback, nsecs_t time) {
+ mCallback = callback;
+ mNextCallbackTime = time;
+ }
+
+ nsecs_t fakeTime() const { return mCurrentTime; }
+
+ void advanceToNextCallback() {
+ mCurrentTime = mNextCallbackTime;
+ if (mCallback) {
+ mCallback();
+ }
+ }
+
+ void advanceBy(nsecs_t advancement) {
+ mCurrentTime += advancement;
+ if (mCurrentTime >= (mNextCallbackTime + mLag) && mCallback) {
+ mCallback();
+ }
+ };
+
+ void setLag(nsecs_t lag) { mLag = lag; }
+
+private:
+ std::function<void()> mCallback;
+ nsecs_t mNextCallbackTime = 0;
+ nsecs_t mCurrentTime = 0;
+ nsecs_t mLag = 0;
+};
+
+static VsyncModulator::TimePoint Now() {
+ static VsyncModulator::TimePoint now;
+ return now += VsyncModulator::MIN_EARLY_TRANSACTION_TIME;
+}
+
+class FuzzImplVsyncModulator : public VsyncModulator {
+public:
+ FuzzImplVsyncModulator(const VsyncConfigSet& config, Now now) : VsyncModulator(config, now) {}
+
+ void binderDied(const wp<IBinder>& token) { VsyncModulator::binderDied(token); }
+};
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index 2841f7c..854084e 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -305,7 +305,7 @@
zOrderRelativeOf == nullptr ? "none" : zOrderRelativeOf->name.c_str());
StringAppendF(&result, " activeBuffer=%s,", activeBuffer.to_string().c_str());
StringAppendF(&result, " tr=%s", bufferTransform.to_string().c_str());
- StringAppendF(&result, " queued-frames=%d, mRefreshPending=%d,", queuedFrames, refreshPending);
+ StringAppendF(&result, " queued-frames=%d", queuedFrames);
StringAppendF(&result, " metadata={");
bool first = true;
for (const auto& entry : metadata.mMap) {
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index d292e08..4fe1e98 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -177,6 +177,11 @@
public:
using HotplugEvent = SurfaceFlinger::HotplugEvent;
+ TestableSurfaceFlinger()
+ : mFlinger(sp<SurfaceFlinger>::make(mFactory, SurfaceFlinger::SkipInitialization)) {
+ mFlinger->mAnimationTransactionTimeout = ms2ns(10);
+ }
+
SurfaceFlinger* flinger() { return mFlinger.get(); }
scheduler::TestableScheduler* scheduler() { return mScheduler; }
@@ -466,6 +471,10 @@
return static_cast<mock::FrameTracer*>(mFlinger->mFrameTracer.get());
}
+ nsecs_t getAnimationTransactionTimeout() const {
+ return mFlinger->mAnimationTransactionTimeout;
+ }
+
/* ------------------------------------------------------------------------
* Read-write access to private data to set up preconditions and assert
* post-conditions.
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 1ce0309..ed23176 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -89,10 +89,10 @@
mock::VsyncController* mVsyncController = new mock::VsyncController();
mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker();
- mock::MockFence* mFenceUnsignaled = new mock::MockFence();
- mock::MockFence* mFenceSignaled = new mock::MockFence();
- mock::MockFence* mFenceUnsignaled2 = new mock::MockFence();
- mock::MockFence* mFenceSignaled2 = new mock::MockFence();
+ sp<mock::MockFence> mFenceUnsignaled = sp<mock::MockFence>::make();
+ sp<mock::MockFence> mFenceSignaled = sp<mock::MockFence>::make();
+ sp<mock::MockFence> mFenceUnsignaled2 = sp<mock::MockFence>::make();
+ sp<mock::MockFence> mFenceSignaled2 = sp<mock::MockFence>::make();
struct TransactionInfo {
Vector<ComposerState> states;
@@ -159,9 +159,9 @@
// completed. If this is animation, it should not time out waiting.
nsecs_t returnedTime = systemTime();
if (flags & ISurfaceComposer::eSynchronous || syncInputWindows) {
- EXPECT_GE(returnedTime, applicationTime + s2ns(5));
+ EXPECT_GE(returnedTime, applicationTime + mFlinger.getAnimationTransactionTimeout());
} else {
- EXPECT_LE(returnedTime, applicationTime + s2ns(5));
+ EXPECT_LE(returnedTime, applicationTime + mFlinger.getAnimationTransactionTimeout());
}
// Each transaction should have been placed on the transaction queue
auto transactionQueue = mFlinger.getTransactionQueue();
@@ -188,9 +188,11 @@
nsecs_t returnedTime = systemTime();
if ((flags & ISurfaceComposer::eSynchronous) || syncInputWindows) {
- EXPECT_GE(systemTime(), applicationSentTime + s2ns(5));
+ EXPECT_GE(systemTime(),
+ applicationSentTime + mFlinger.getAnimationTransactionTimeout());
} else {
- EXPECT_LE(returnedTime, applicationSentTime + s2ns(5));
+ EXPECT_LE(returnedTime,
+ applicationSentTime + mFlinger.getAnimationTransactionTimeout());
}
// This transaction should have been placed on the transaction queue
auto transactionQueue = mFlinger.getTransactionQueue();
@@ -228,7 +230,7 @@
// This thread should not have been blocked by the above transaction
// (5s is the timeout period that applyTransactionState waits for SF to
// commit the transaction)
- EXPECT_LE(systemTime(), applicationSentTime + s2ns(5));
+ EXPECT_LE(systemTime(), applicationSentTime + mFlinger.getAnimationTransactionTimeout());
// transaction that would goes to pending transaciton queue.
mFlinger.flushTransactionQueues();
@@ -246,9 +248,11 @@
// the transaction should be placed on the pending queue
if (flags & (ISurfaceComposer::eAnimation | ISurfaceComposer::eSynchronous) ||
syncInputWindows) {
- EXPECT_GE(systemTime(), applicationSentTime + s2ns(5));
+ EXPECT_GE(systemTime(),
+ applicationSentTime + mFlinger.getAnimationTransactionTimeout());
} else {
- EXPECT_LE(systemTime(), applicationSentTime + s2ns(5));
+ EXPECT_LE(systemTime(),
+ applicationSentTime + mFlinger.getAnimationTransactionTimeout());
}
// transaction that would goes to pending transaciton queue.