Merge "Add more info in BBQ Tracing"
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/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 677d6c7..49c1318 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -61,6 +61,10 @@
MOCK_METHOD1(getDeclaredInstances, Vector<String16>(const String16&));
MOCK_METHOD1(updatableViaApex, std::optional<String16>(const String16&));
MOCK_METHOD1(getConnectionInfo, std::optional<ConnectionInfo>(const String16&));
+ MOCK_METHOD2(registerForNotifications, status_t(const String16&,
+ const sp<LocalRegistrationCallback>&));
+ MOCK_METHOD2(unregisterForNotifications, status_t(const String16&,
+ const sp<LocalRegistrationCallback>&));
protected:
MOCK_METHOD0(onAsBinder, IBinder*());
};
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 31dee23..5003151 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -119,6 +119,12 @@
}
prebuilt_etc {
+ name: "android.hardware.sensor.dynamic.head_tracker.prebuilt.xml",
+ src: "android.hardware.sensor.dynamic.head_tracker.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "android.hardware.sensor.gyroscope.prebuilt.xml",
src: "android.hardware.sensor.gyroscope.xml",
defaults: ["frameworks_native_data_etc_defaults"],
diff --git a/data/etc/android.hardware.telephony.radio.xml b/data/etc/android.hardware.sensor.accelerometer_limited_axes.xml
similarity index 71%
copy from data/etc/android.hardware.telephony.radio.xml
copy to data/etc/android.hardware.sensor.accelerometer_limited_axes.xml
index 4377705..6a43d5d 100644
--- a/data/etc/android.hardware.telephony.radio.xml
+++ b/data/etc/android.hardware.sensor.accelerometer_limited_axes.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 limited axes accelerometer sensor. -->
<permissions>
- <feature name="android.hardware.telephony" />
- <feature name="android.hardware.telephony.radio" />
+ <feature name="android.hardware.sensor.accelerometer_limited_axes" />
</permissions>
diff --git a/data/etc/android.hardware.telephony.radio.xml b/data/etc/android.hardware.sensor.accelerometer_limited_axes_uncalibrated.xml
similarity index 71%
copy from data/etc/android.hardware.telephony.radio.xml
copy to data/etc/android.hardware.sensor.accelerometer_limited_axes_uncalibrated.xml
index 4377705..4c6755c 100644
--- a/data/etc/android.hardware.telephony.radio.xml
+++ b/data/etc/android.hardware.sensor.accelerometer_limited_axes_uncalibrated.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 an uncalibrated limited axes accelerometer sensor. -->
<permissions>
- <feature name="android.hardware.telephony" />
- <feature name="android.hardware.telephony.radio" />
+ <feature name="android.hardware.sensor.accelerometer_limited_axes_uncalibrated" />
</permissions>
diff --git a/data/etc/android.hardware.telephony.radio.xml b/data/etc/android.hardware.sensor.dynamic.head_tracker.xml
similarity index 71%
copy from data/etc/android.hardware.telephony.radio.xml
copy to data/etc/android.hardware.sensor.dynamic.head_tracker.xml
index 4377705..ece58c9 100644
--- a/data/etc/android.hardware.telephony.radio.xml
+++ b/data/etc/android.hardware.sensor.dynamic.head_tracker.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 head tracker sensor. -->
<permissions>
- <feature name="android.hardware.telephony" />
- <feature name="android.hardware.telephony.radio" />
-</permissions>
+ <feature name="android.hardware.sensor.dynamic.head_tracker" />
+</permissions>
\ No newline at end of file
diff --git a/data/etc/android.hardware.telephony.radio.xml b/data/etc/android.hardware.sensor.gyroscope_limited_axes.xml
similarity index 71%
copy from data/etc/android.hardware.telephony.radio.xml
copy to data/etc/android.hardware.sensor.gyroscope_limited_axes.xml
index 4377705..45c6547 100644
--- a/data/etc/android.hardware.telephony.radio.xml
+++ b/data/etc/android.hardware.sensor.gyroscope_limited_axes.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 limited axes gyroscope. -->
<permissions>
- <feature name="android.hardware.telephony" />
- <feature name="android.hardware.telephony.radio" />
+ <feature name="android.hardware.sensor.gyroscope_limited_axes" />
</permissions>
diff --git a/data/etc/android.hardware.telephony.radio.xml b/data/etc/android.hardware.sensor.gyroscope_limited_axes_uncalibrated.xml
similarity index 71%
copy from data/etc/android.hardware.telephony.radio.xml
copy to data/etc/android.hardware.sensor.gyroscope_limited_axes_uncalibrated.xml
index 4377705..2ca8364 100644
--- a/data/etc/android.hardware.telephony.radio.xml
+++ b/data/etc/android.hardware.sensor.gyroscope_limited_axes_uncalibrated.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 an uncalibrated limited axes gyroscope. -->
<permissions>
- <feature name="android.hardware.telephony" />
- <feature name="android.hardware.telephony.radio" />
+ <feature name="android.hardware.sensor.gyroscope_limited_axes_uncalibrated" />
</permissions>
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 45e8afc..cf1ca02 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -263,6 +263,52 @@
* Measures the orientation and rotational velocity of a user's head.
*/
ASENSOR_TYPE_HEAD_TRACKER = 37,
+ /**
+ * {@link ASENSOR_TYPE_ACCELEROMETER_LIMITED_AXES}
+ * reporting-mode: continuous
+ *
+ * The first three values are in SI units (m/s^2) and measure the acceleration of the device
+ * minus the force of gravity. The last three values indicate which acceleration axes are
+ * supported. A value of 1.0 means supported and a value of 0 means not supported.
+ */
+ ASENSOR_TYPE_ACCELEROMETER_LIMITED_AXES = 38,
+ /**
+ * {@link ASENSOR_TYPE_GYROSCOPE_LIMITED_AXES}
+ * reporting-mode: continuous
+ *
+ * The first three values are in radians/second and measure the rate of rotation around the X,
+ * Y and Z axis. The last three values indicate which rotation axes are supported. A value of
+ * 1.0 means supported and a value of 0 means not supported.
+ */
+ ASENSOR_TYPE_GYROSCOPE_LIMITED_AXES = 39,
+ /**
+ * {@link ASENSOR_TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED}
+ * reporting-mode: continuous
+ *
+ * The first three values are in SI units (m/s^2) and measure the acceleration of the device
+ * minus the force of gravity. The middle three values represent the estimated bias for each
+ * axis. The last three values indicate which acceleration axes are supported. A value of 1.0
+ * means supported and a value of 0 means not supported.
+ */
+ ASENSOR_TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED = 40,
+ /**
+ * {@link ASENSOR_TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED}
+ * reporting-mode: continuous
+ *
+ * The first three values are in radians/second and measure the rate of rotation around the X,
+ * Y and Z axis. The middle three values represent the estimated drift around each axis in
+ * rad/s. The last three values indicate which rotation axes are supported. A value of 1.0 means
+ * 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,
};
/**
@@ -479,6 +525,69 @@
int32_t discontinuity_count;
} AHeadTrackerEvent;
+typedef struct ALimitedAxesImuEvent {
+ union {
+ float calib[3];
+ struct {
+ float x;
+ float y;
+ float z;
+ };
+ };
+ union {
+ float supported[3];
+ struct {
+ float x_supported;
+ float y_supported;
+ float z_supported;
+ };
+ };
+} ALimitedAxesImuEvent;
+
+typedef struct ALimitedAxesImuUncalibratedEvent {
+ union {
+ float uncalib[3];
+ struct {
+ float x_uncalib;
+ float y_uncalib;
+ float z_uncalib;
+ };
+ };
+ union {
+ float bias[3];
+ struct {
+ float x_bias;
+ float y_bias;
+ float z_bias;
+ };
+ };
+ union {
+ float supported[3];
+ struct {
+ float x_supported;
+ float y_supported;
+ float z_supported;
+ };
+ };
+} 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
@@ -516,6 +625,9 @@
ADynamicSensorEvent dynamic_sensor_meta;
AAdditionalInfoEvent additional_info;
AHeadTrackerEvent head_tracker;
+ ALimitedAxesImuEvent limited_axes_imu;
+ ALimitedAxesImuUncalibratedEvent limited_axes_imu_uncalibrated;
+ AHeadingEvent heading;
};
union {
uint64_t data[8];
diff --git a/include/input/Input.h b/include/input/Input.h
index 55ebb90..e421dee 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -534,7 +534,7 @@
inline int32_t getActionMasked() const { return getActionMasked(mAction); }
- static int32_t getActionIndex(int32_t action) {
+ static uint8_t getActionIndex(int32_t action) {
return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >>
AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
}
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index ec9d554..0970ca5 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -54,6 +54,8 @@
constexpr const bool kEnableRpcDevServers = false;
#endif
+// Log any reply transactions for which the data exceeds this size
+#define LOG_REPLIES_OVER_SIZE (300 * 1024)
// ---------------------------------------------------------------------------
IBinder::IBinder()
@@ -296,6 +298,10 @@
// In case this is being transacted on in the same process.
if (reply != nullptr) {
reply->setDataPosition(0);
+ if (reply->dataSize() > LOG_REPLIES_OVER_SIZE) {
+ ALOGW("Large reply transaction of %zu bytes, interface descriptor %s, code %d",
+ reply->dataSize(), String8(getInterfaceDescriptor()).c_str(), code);
+ }
}
return err;
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 06542f0..056ef0a 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -48,6 +48,9 @@
// Another arbitrary value a binder count needs to drop below before another callback will be called
uint32_t BpBinder::sBinderProxyCountLowWatermark = 2000;
+// Log any transactions for which the data exceeds this size
+#define LOG_TRANSACTIONS_OVER_SIZE (300 * 1024)
+
enum {
LIMIT_REACHED_MASK = 0x80000000, // A flag denoting that the limit has been reached
COUNTING_VALUE_MASK = 0x7FFFFFFF, // A mask of the remaining bits for the count value
@@ -302,6 +305,14 @@
} else {
status = IPCThreadState::self()->transact(binderHandle(), code, data, reply, flags);
}
+ if (data.dataSize() > LOG_TRANSACTIONS_OVER_SIZE) {
+ Mutex::Autolock _l(mLock);
+ ALOGW("Large outgoing transaction of %zu bytes, interface descriptor %s, code %d",
+ data.dataSize(),
+ mDescriptorCache.size() ? String8(mDescriptorCache).c_str()
+ : "<uncached descriptor>",
+ code);
+ }
if (status == DEAD_OBJECT) mAlive = 0;
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 81e61da..ea2f8d2 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -43,6 +43,8 @@
namespace android {
+using AidlRegistrationCallback = IServiceManager::LocalRegistrationCallback;
+
using AidlServiceManager = android::os::IServiceManager;
using android::binder::Status;
@@ -79,7 +81,24 @@
Vector<String16> getDeclaredInstances(const String16& interface) override;
std::optional<String16> updatableViaApex(const String16& name) override;
std::optional<IServiceManager::ConnectionInfo> getConnectionInfo(const String16& name) override;
+ class RegistrationWaiter : public android::os::BnServiceCallback {
+ public:
+ explicit RegistrationWaiter(const sp<AidlRegistrationCallback>& callback)
+ : mImpl(callback) {}
+ Status onRegistration(const std::string& name, const sp<IBinder>& binder) override {
+ mImpl->onServiceRegistration(String16(name.c_str()), binder);
+ return Status::ok();
+ }
+ private:
+ sp<AidlRegistrationCallback> mImpl;
+ };
+
+ status_t registerForNotifications(const String16& service,
+ const sp<AidlRegistrationCallback>& cb) override;
+
+ status_t unregisterForNotifications(const String16& service,
+ const sp<AidlRegistrationCallback>& cb) override;
// for legacy ABI
const String16& getInterfaceDescriptor() const override {
return mTheRealServiceManager->getInterfaceDescriptor();
@@ -90,6 +109,17 @@
protected:
sp<AidlServiceManager> mTheRealServiceManager;
+ // AidlRegistrationCallback -> services that its been registered for
+ // notifications.
+ using LocalRegistrationAndWaiter =
+ std::pair<sp<LocalRegistrationCallback>, sp<RegistrationWaiter>>;
+ using ServiceCallbackMap = std::map<std::string, std::vector<LocalRegistrationAndWaiter>>;
+ ServiceCallbackMap mNameToRegistrationCallback;
+ std::mutex mNameToRegistrationLock;
+
+ void removeRegistrationCallbackLocked(const sp<AidlRegistrationCallback>& cb,
+ ServiceCallbackMap::iterator* it,
+ sp<RegistrationWaiter>* waiter);
// Directly get the service in a way that, for lazy services, requests the service to be started
// if it is not currently started. This way, calls directly to ServiceManagerShim::getService
@@ -442,6 +472,77 @@
: std::nullopt;
}
+status_t ServiceManagerShim::registerForNotifications(const String16& name,
+ const sp<AidlRegistrationCallback>& cb) {
+ if (cb == nullptr) {
+ ALOGE("%s: null cb passed", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ std::string nameStr = String8(name).c_str();
+ sp<RegistrationWaiter> registrationWaiter = sp<RegistrationWaiter>::make(cb);
+ std::lock_guard<std::mutex> lock(mNameToRegistrationLock);
+ if (Status status =
+ mTheRealServiceManager->registerForNotifications(nameStr, registrationWaiter);
+ !status.isOk()) {
+ ALOGW("Failed to registerForNotifications for %s: %s", nameStr.c_str(),
+ status.toString8().c_str());
+ return UNKNOWN_ERROR;
+ }
+ mNameToRegistrationCallback[nameStr].push_back(std::make_pair(cb, registrationWaiter));
+ return OK;
+}
+
+void ServiceManagerShim::removeRegistrationCallbackLocked(const sp<AidlRegistrationCallback>& cb,
+ ServiceCallbackMap::iterator* it,
+ sp<RegistrationWaiter>* waiter) {
+ std::vector<LocalRegistrationAndWaiter>& localRegistrationAndWaiters = (*it)->second;
+ for (auto lit = localRegistrationAndWaiters.begin();
+ lit != localRegistrationAndWaiters.end();) {
+ if (lit->first == cb) {
+ if (waiter) {
+ *waiter = lit->second;
+ }
+ lit = localRegistrationAndWaiters.erase(lit);
+ } else {
+ ++lit;
+ }
+ }
+
+ if (localRegistrationAndWaiters.empty()) {
+ mNameToRegistrationCallback.erase(*it);
+ }
+}
+
+status_t ServiceManagerShim::unregisterForNotifications(const String16& name,
+ const sp<AidlRegistrationCallback>& cb) {
+ if (cb == nullptr) {
+ ALOGE("%s: null cb passed", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ std::string nameStr = String8(name).c_str();
+ std::lock_guard<std::mutex> lock(mNameToRegistrationLock);
+ auto it = mNameToRegistrationCallback.find(nameStr);
+ sp<RegistrationWaiter> registrationWaiter;
+ if (it != mNameToRegistrationCallback.end()) {
+ removeRegistrationCallbackLocked(cb, &it, ®istrationWaiter);
+ } else {
+ ALOGE("%s no callback registered for notifications on %s", __FUNCTION__, nameStr.c_str());
+ return BAD_VALUE;
+ }
+ if (registrationWaiter == nullptr) {
+ ALOGE("%s Callback passed wasn't used to register for notifications", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ if (Status status = mTheRealServiceManager->unregisterForNotifications(String8(name).c_str(),
+ registrationWaiter);
+ !status.isOk()) {
+ ALOGW("Failed to get service manager to unregisterForNotifications for %s: %s",
+ String8(name).c_str(), status.toString8().c_str());
+ return UNKNOWN_ERROR;
+ }
+ return OK;
+}
+
#ifndef __ANDROID__
// ServiceManagerShim for host. Implements the old libbinder android::IServiceManager API.
// The internal implementation of the AIDL interface android::os::IServiceManager calls into
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/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 240e3c2..ea40db8 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -115,6 +115,17 @@
unsigned int port;
};
virtual std::optional<ConnectionInfo> getConnectionInfo(const String16& name) = 0;
+
+ struct LocalRegistrationCallback : public virtual RefBase {
+ virtual void onServiceRegistration(const String16& instance, const sp<IBinder>& binder) = 0;
+ virtual ~LocalRegistrationCallback() {}
+ };
+
+ virtual status_t registerForNotifications(const String16& name,
+ const sp<LocalRegistrationCallback>& callback) = 0;
+
+ virtual status_t unregisterForNotifications(const String16& name,
+ const sp<LocalRegistrationCallback>& callback) = 0;
};
sp<IServiceManager> defaultServiceManager();
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/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 63a4b2c..700940a 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -1220,6 +1220,19 @@
EXPECT_THAT(server->transact(BINDER_LIB_TEST_CAN_GET_SID, data, nullptr), StatusEq(OK));
}
+TEST(ServiceNotifications, Unregister) {
+ auto sm = defaultServiceManager();
+ using LocalRegistrationCallback = IServiceManager::LocalRegistrationCallback;
+ class LocalRegistrationCallbackImpl : public virtual LocalRegistrationCallback {
+ void onServiceRegistration(const String16 &, const sp<IBinder> &) override {}
+ virtual ~LocalRegistrationCallbackImpl() {}
+ };
+ sp<LocalRegistrationCallback> cb = sp<LocalRegistrationCallbackImpl>::make();
+
+ EXPECT_EQ(sm->registerForNotifications(String16("RogerRafa"), cb), OK);
+ EXPECT_EQ(sm->unregisterForNotifications(String16("RogerRafa"), cb), OK);
+}
+
class BinderLibRpcTestBase : public BinderLibTest {
public:
void SetUp() override {
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/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp
index 73f9d4d..4f63194 100644
--- a/libs/cputimeinstate/Android.bp
+++ b/libs/cputimeinstate/Android.bp
@@ -45,4 +45,5 @@
"-Wextra",
],
require_root: true,
+ test_suites: ["general-tests"],
}
diff --git a/libs/cputimeinstate/TEST_MAPPING b/libs/cputimeinstate/TEST_MAPPING
new file mode 100644
index 0000000..4781520
--- /dev/null
+++ b/libs/cputimeinstate/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "libtimeinstate_test"
+ }
+ ]
+}
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index 2112b10..1513eca 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -27,6 +27,7 @@
#include <gtest/gtest.h>
+#include <android-base/properties.h>
#include <android-base/unique_fd.h>
#include <bpf/BpfMap.h>
#include <cputimeinstate.h>
@@ -40,24 +41,31 @@
using std::vector;
-TEST(TimeInStateTest, IsTrackingSupported) {
- isTrackingUidTimesSupported();
- SUCCEED();
-}
+class TimeInStateTest : public testing::Test {
+ protected:
+ TimeInStateTest() {};
-TEST(TimeInStateTest, TotalTimeInState) {
+ void SetUp() {
+ if (!isTrackingUidTimesSupported() ||
+ !android::base::GetBoolProperty("sys.init.perf_lsm_hooks", false)) {
+ GTEST_SKIP();
+ }
+ }
+};
+
+TEST_F(TimeInStateTest, TotalTimeInState) {
auto times = getTotalCpuFreqTimes();
ASSERT_TRUE(times.has_value());
EXPECT_FALSE(times->empty());
}
-TEST(TimeInStateTest, SingleUidTimeInState) {
+TEST_F(TimeInStateTest, SingleUidTimeInState) {
auto times = getUidCpuFreqTimes(0);
ASSERT_TRUE(times.has_value());
EXPECT_FALSE(times->empty());
}
-TEST(TimeInStateTest, SingleUidConcurrentTimes) {
+TEST_F(TimeInStateTest, SingleUidConcurrentTimes) {
auto concurrentTimes = getUidConcurrentTimes(0);
ASSERT_TRUE(concurrentTimes.has_value());
ASSERT_FALSE(concurrentTimes->active.empty());
@@ -117,7 +125,7 @@
EXPECT_EQ(activeSum, policySum);
}
-TEST(TimeInStateTest, SingleUidTimesConsistent) {
+TEST_F(TimeInStateTest, SingleUidTimesConsistent) {
auto times = getUidCpuFreqTimes(0);
ASSERT_TRUE(times.has_value());
@@ -127,7 +135,7 @@
ASSERT_NO_FATAL_FAILURE(TestUidTimesConsistent(*times, *concurrentTimes));
}
-TEST(TimeInStateTest, AllUidTimeInState) {
+TEST_F(TimeInStateTest, AllUidTimeInState) {
uint64_t zero = 0;
auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)};
for (const auto &map : maps) {
@@ -163,7 +171,7 @@
ASSERT_LE(sumAfter - sumBefore, NSEC_PER_SEC);
}
-TEST(TimeInStateTest, AllUidUpdatedTimeInState) {
+TEST_F(TimeInStateTest, AllUidUpdatedTimeInState) {
uint64_t lastUpdate = 0;
auto map1 = getUidsUpdatedCpuFreqTimes(&lastUpdate);
ASSERT_TRUE(map1.has_value());
@@ -197,7 +205,7 @@
}
}
-TEST(TimeInStateTest, TotalAndAllUidTimeInStateConsistent) {
+TEST_F(TimeInStateTest, TotalAndAllUidTimeInStateConsistent) {
auto allUid = getUidsCpuFreqTimes();
auto total = getTotalCpuFreqTimes();
@@ -222,7 +230,7 @@
}
}
-TEST(TimeInStateTest, SingleAndAllUidTimeInStateConsistent) {
+TEST_F(TimeInStateTest, SingleAndAllUidTimeInStateConsistent) {
uint64_t zero = 0;
auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)};
for (const auto &map : maps) {
@@ -246,7 +254,7 @@
}
}
-TEST(TimeInStateTest, AllUidConcurrentTimes) {
+TEST_F(TimeInStateTest, AllUidConcurrentTimes) {
uint64_t zero = 0;
auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)};
for (const auto &map : maps) {
@@ -264,7 +272,7 @@
}
}
-TEST(TimeInStateTest, AllUidUpdatedConcurrentTimes) {
+TEST_F(TimeInStateTest, AllUidUpdatedConcurrentTimes) {
uint64_t lastUpdate = 0;
auto map1 = getUidsUpdatedConcurrentTimes(&lastUpdate);
ASSERT_TRUE(map1.has_value());
@@ -299,7 +307,7 @@
}
}
-TEST(TimeInStateTest, SingleAndAllUidConcurrentTimesConsistent) {
+TEST_F(TimeInStateTest, SingleAndAllUidConcurrentTimesConsistent) {
uint64_t zero = 0;
auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)};
for (const auto &map : maps) {
@@ -328,7 +336,7 @@
ASSERT_LE(after - before, NSEC_PER_SEC * 2 * get_nprocs_conf());
}
-TEST(TimeInStateTest, TotalTimeInStateMonotonic) {
+TEST_F(TimeInStateTest, TotalTimeInStateMonotonic) {
auto before = getTotalCpuFreqTimes();
ASSERT_TRUE(before.has_value());
sleep(1);
@@ -344,7 +352,7 @@
}
}
-TEST(TimeInStateTest, AllUidTimeInStateMonotonic) {
+TEST_F(TimeInStateTest, AllUidTimeInStateMonotonic) {
auto map1 = getUidsCpuFreqTimes();
ASSERT_TRUE(map1.has_value());
sleep(1);
@@ -365,7 +373,7 @@
}
}
-TEST(TimeInStateTest, AllUidConcurrentTimesMonotonic) {
+TEST_F(TimeInStateTest, AllUidConcurrentTimesMonotonic) {
auto map1 = getUidsConcurrentTimes();
ASSERT_TRUE(map1.has_value());
ASSERT_FALSE(map1->empty());
@@ -393,7 +401,7 @@
}
}
-TEST(TimeInStateTest, AllUidTimeInStateSanityCheck) {
+TEST_F(TimeInStateTest, AllUidTimeInStateSanityCheck) {
uint64_t zero = 0;
auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)};
for (const auto &map : maps) {
@@ -414,7 +422,7 @@
}
}
-TEST(TimeInStateTest, AllUidConcurrentTimesSanityCheck) {
+TEST_F(TimeInStateTest, AllUidConcurrentTimesSanityCheck) {
uint64_t zero = 0;
auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)};
for (const auto &concurrentMap : maps) {
@@ -441,7 +449,7 @@
}
}
-TEST(TimeInStateTest, AllUidConcurrentTimesFailsOnInvalidBucket) {
+TEST_F(TimeInStateTest, AllUidConcurrentTimesFailsOnInvalidBucket) {
uint32_t uid = 0;
{
// Find an unused UID
@@ -463,7 +471,7 @@
ASSERT_FALSE(deleteMapEntry(fd, &key));
}
-TEST(TimeInStateTest, AllUidTimesConsistent) {
+TEST_F(TimeInStateTest, AllUidTimesConsistent) {
auto tisMap = getUidsCpuFreqTimes();
ASSERT_TRUE(tisMap.has_value());
@@ -481,7 +489,7 @@
}
}
-TEST(TimeInStateTest, RemoveUid) {
+TEST_F(TimeInStateTest, RemoveUid) {
uint32_t uid = 0;
{
// Find an unused UID
@@ -547,7 +555,7 @@
ASSERT_EQ(allConcurrentTimes->find(uid), allConcurrentTimes->end());
}
-TEST(TimeInStateTest, GetCpuFreqs) {
+TEST_F(TimeInStateTest, GetCpuFreqs) {
auto freqs = getCpuFreqs();
ASSERT_TRUE(freqs.has_value());
@@ -583,7 +591,7 @@
return nullptr;
}
-TEST(TimeInStateTest, GetAggregatedTaskCpuFreqTimes) {
+TEST_F(TimeInStateTest, GetAggregatedTaskCpuFreqTimes) {
uint64_t startTimeNs = timeNanos();
sem_init(&pingsem, 0, 1);
diff --git a/libs/fakeservicemanager/ServiceManager.cpp b/libs/fakeservicemanager/ServiceManager.cpp
index 9f0754b..61e4a98 100644
--- a/libs/fakeservicemanager/ServiceManager.cpp
+++ b/libs/fakeservicemanager/ServiceManager.cpp
@@ -84,4 +84,14 @@
return std::nullopt;
}
+status_t ServiceManager::registerForNotifications(const String16&,
+ const sp<LocalRegistrationCallback>&) {
+ return INVALID_OPERATION;
+}
+
+status_t ServiceManager::unregisterForNotifications(const String16&,
+ const sp<LocalRegistrationCallback>&) {
+ return INVALID_OPERATION;
+}
+
} // namespace android
diff --git a/libs/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/ServiceManager.h
index b1496ba..6d6e008 100644
--- a/libs/fakeservicemanager/ServiceManager.h
+++ b/libs/fakeservicemanager/ServiceManager.h
@@ -53,6 +53,11 @@
std::optional<IServiceManager::ConnectionInfo> getConnectionInfo(const String16& name) override;
+ status_t registerForNotifications(const String16& name,
+ const sp<LocalRegistrationCallback>& callback) override;
+
+ status_t unregisterForNotifications(const String16& name,
+ const sp<LocalRegistrationCallback>& callback) override;
private:
std::map<String16, sp<IBinder>> mNameToService;
};
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/WindowInfo.cpp b/libs/gui/WindowInfo.cpp
index 1c7b270..a866786 100644
--- a/libs/gui/WindowInfo.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -69,7 +69,7 @@
info.hasWallpaper == hasWallpaper && info.paused == paused &&
info.ownerPid == ownerPid && info.ownerUid == ownerUid &&
info.packageName == packageName && info.inputFeatures == inputFeatures &&
- info.displayId == displayId && info.portalToDisplayId == portalToDisplayId &&
+ info.displayId == displayId &&
info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop &&
info.applicationInfo == applicationInfo;
}
@@ -116,7 +116,6 @@
parcel->writeUtf8AsUtf16(packageName) ?:
parcel->writeInt32(inputFeatures.get()) ?:
parcel->writeInt32(displayId) ?:
- parcel->writeInt32(portalToDisplayId) ?:
applicationInfo.writeToParcel(parcel) ?:
parcel->write(touchableRegion) ?:
parcel->writeBool(replaceTouchableRegionWithCrop) ?:
@@ -180,7 +179,6 @@
inputFeatures = Flags<Feature>(parcel->readInt32());
// clang-format off
status = parcel->readInt32(&displayId) ?:
- parcel->readInt32(&portalToDisplayId) ?:
applicationInfo.readFromParcel(parcel) ?:
parcel->read(touchableRegion) ?:
parcel->readBool(&replaceTouchableRegionWithCrop);
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/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index 2bfaec8..eb64ac9 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -214,7 +214,6 @@
std::string packageName;
Flags<Feature> inputFeatures;
int32_t displayId = ADISPLAY_ID_NONE;
- int32_t portalToDisplayId = ADISPLAY_ID_NONE;
InputApplicationInfo applicationInfo;
bool replaceTouchableRegionWithCrop = false;
wp<IBinder> touchableRegionCropHandle;
diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp
index dcdf76f..ff3ba2a 100644
--- a/libs/gui/tests/WindowInfo_test.cpp
+++ b/libs/gui/tests/WindowInfo_test.cpp
@@ -70,7 +70,6 @@
i.packageName = "com.example.package";
i.inputFeatures = WindowInfo::Feature::DISABLE_USER_ACTIVITY;
i.displayId = 34;
- i.portalToDisplayId = 2;
i.replaceTouchableRegionWithCrop = true;
i.touchableRegionCropHandle = touchableRegionCropHandle;
i.applicationInfo.name = "ApplicationFooBar";
@@ -107,7 +106,6 @@
ASSERT_EQ(i.packageName, i2.packageName);
ASSERT_EQ(i.inputFeatures, i2.inputFeatures);
ASSERT_EQ(i.displayId, i2.displayId);
- ASSERT_EQ(i.portalToDisplayId, i2.portalToDisplayId);
ASSERT_EQ(i.replaceTouchableRegionWithCrop, i2.replaceTouchableRegionWithCrop);
ASSERT_EQ(i.touchableRegionCropHandle, i2.touchableRegionCropHandle);
ASSERT_EQ(i.applicationInfo, i2.applicationInfo);
diff --git a/libs/nativedisplay/surfacetexture/EGLConsumer.cpp b/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
index 6882ea3..0128859 100644
--- a/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
+++ b/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
@@ -593,6 +593,10 @@
}
void EGLConsumer::onFreeBufferLocked(int slotIndex) {
+ if (mEglSlots[slotIndex].mEglImage != nullptr &&
+ mEglSlots[slotIndex].mEglImage == mCurrentTextureImage) {
+ mCurrentTextureImage.clear();
+ }
mEglSlots[slotIndex].mEglImage.clear();
}
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 612a0aa..e197150 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -49,6 +49,50 @@
namespace android {
namespace renderengine {
+namespace {
+
+double EOTF_PQ(double channel) {
+ float m1 = (2610.0 / 4096.0) / 4.0;
+ float m2 = (2523.0 / 4096.0) * 128.0;
+ float c1 = (3424.0 / 4096.0);
+ float c2 = (2413.0 / 4096.0) * 32.0;
+ float c3 = (2392.0 / 4096.0) * 32.0;
+
+ float tmp = std::pow(std::clamp(channel, 0.0, 1.0), 1.0 / m2);
+ tmp = std::fmax(tmp - c1, 0.0) / (c2 - c3 * tmp);
+ return std::pow(tmp, 1.0 / m1);
+}
+
+vec3 EOTF_PQ(vec3 color) {
+ return vec3(EOTF_PQ(color.r), EOTF_PQ(color.g), EOTF_PQ(color.b));
+}
+
+double EOTF_HLG(double channel) {
+ const float a = 0.17883277;
+ const float b = 0.28466892;
+ const float c = 0.55991073;
+ return channel <= 0.5 ? channel * channel / 3.0 : (exp((channel - c) / a) + b) / 12.0;
+}
+
+vec3 EOTF_HLG(vec3 color) {
+ return vec3(EOTF_HLG(color.r), EOTF_HLG(color.g), EOTF_HLG(color.b));
+}
+
+double OETF_sRGB(double channel) {
+ return channel <= 0.0031308 ? channel * 12.92 : (pow(channel, 1.0 / 2.4) * 1.055) - 0.055;
+}
+
+int sign(float in) {
+ return in >= 0.0 ? 1 : -1;
+}
+
+vec3 OETF_sRGB(vec3 linear) {
+ return vec3(sign(linear.r) * OETF_sRGB(linear.r), sign(linear.g) * OETF_sRGB(linear.g),
+ sign(linear.b) * OETF_sRGB(linear.b));
+}
+
+} // namespace
+
class RenderEngineFactory {
public:
virtual ~RenderEngineFactory() = default;
@@ -598,6 +642,12 @@
const renderengine::ShadowSettings& shadow,
const ubyte4& backgroundColor);
+ // Tonemaps grey values from sourceDataspace -> Display P3 and checks that GPU and CPU
+ // implementations are identical Also implicitly checks that the injected tonemap shader
+ // compiles
+ void tonemap(ui::Dataspace sourceDataspace, std::function<vec3(vec3)> eotf,
+ std::function<vec3(vec3, float)> scaleOotf);
+
void initializeRenderEngine();
std::unique_ptr<renderengine::RenderEngine> mRE;
@@ -1418,6 +1468,119 @@
invokeDraw(settings, layers);
}
+void RenderEngineTest::tonemap(ui::Dataspace sourceDataspace, std::function<vec3(vec3)> eotf,
+ std::function<vec3(vec3, float)> scaleOotf) {
+ constexpr int32_t kGreyLevels = 256;
+
+ const auto rect = Rect(0, 0, kGreyLevels, 1);
+
+ constexpr float kMaxLuminance = 750.f;
+ constexpr float kCurrentLuminanceNits = 500.f;
+ const renderengine::DisplaySettings display{
+ .physicalDisplay = rect,
+ .clip = rect,
+ .maxLuminance = kMaxLuminance,
+ .currentLuminanceNits = kCurrentLuminanceNits,
+ .outputDataspace = ui::Dataspace::DISPLAY_P3,
+ };
+
+ auto buf = std::make_shared<
+ renderengine::impl::
+ ExternalTexture>(new GraphicBuffer(kGreyLevels, 1, HAL_PIXEL_FORMAT_RGBA_8888,
+ 1,
+ GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_HW_RENDER |
+ GRALLOC_USAGE_HW_TEXTURE,
+ "input"),
+ *mRE,
+ renderengine::impl::ExternalTexture::Usage::READABLE |
+ renderengine::impl::ExternalTexture::Usage::WRITEABLE);
+ ASSERT_EQ(0, buf->getBuffer()->initCheck());
+ {
+ uint8_t* pixels;
+ buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ reinterpret_cast<void**>(&pixels));
+
+ uint8_t color = 0;
+ for (int32_t j = 0; j < buf->getBuffer()->getHeight(); j++) {
+ uint8_t* dest = pixels + (buf->getBuffer()->getStride() * j * 4);
+ for (int32_t i = 0; i < buf->getBuffer()->getWidth(); i++) {
+ dest[0] = color;
+ dest[1] = color;
+ dest[2] = color;
+ dest[3] = 255;
+ color++;
+ dest += 4;
+ }
+ }
+ buf->getBuffer()->unlock();
+ }
+
+ mBuffer = std::make_shared<
+ renderengine::impl::
+ ExternalTexture>(new GraphicBuffer(kGreyLevels, 1, HAL_PIXEL_FORMAT_RGBA_8888,
+ 1,
+ GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_HW_RENDER |
+ GRALLOC_USAGE_HW_TEXTURE,
+ "output"),
+ *mRE,
+ renderengine::impl::ExternalTexture::Usage::READABLE |
+ renderengine::impl::ExternalTexture::Usage::WRITEABLE);
+ ASSERT_EQ(0, mBuffer->getBuffer()->initCheck());
+
+ const renderengine::LayerSettings layer{.geometry.boundaries = rect.toFloatRect(),
+ .source =
+ renderengine::PixelSource{
+ .buffer =
+ renderengine::Buffer{
+ .buffer =
+ std::move(buf),
+ .usePremultipliedAlpha =
+ true,
+ },
+ },
+ .alpha = 1.0f,
+ .sourceDataspace = sourceDataspace};
+
+ std::vector<renderengine::LayerSettings> layers{layer};
+ invokeDraw(display, layers);
+
+ ColorSpace displayP3 = ColorSpace::DisplayP3();
+ ColorSpace bt2020 = ColorSpace::BT2020();
+
+ tonemap::Metadata metadata{.displayMaxLuminance = 750.0f};
+
+ auto generator = [=](Point location) {
+ const double normColor = static_cast<double>(location.x) / (kGreyLevels - 1);
+ const vec3 rgb = vec3(normColor, normColor, normColor);
+
+ const vec3 linearRGB = eotf(rgb);
+
+ const vec3 xyz = bt2020.getRGBtoXYZ() * linearRGB;
+
+ const vec3 scaledXYZ = scaleOotf(xyz, kCurrentLuminanceNits);
+ const double gain =
+ tonemap::getToneMapper()
+ ->lookupTonemapGain(static_cast<aidl::android::hardware::graphics::common::
+ Dataspace>(sourceDataspace),
+ static_cast<aidl::android::hardware::graphics::common::
+ Dataspace>(
+ ui::Dataspace::DISPLAY_P3),
+ scaleOotf(linearRGB, kCurrentLuminanceNits), scaledXYZ,
+ metadata);
+ const vec3 normalizedXYZ = scaledXYZ * gain / metadata.displayMaxLuminance;
+
+ const vec3 targetRGB = OETF_sRGB(displayP3.getXYZtoRGB() * normalizedXYZ) * 255;
+ return ubyte4(static_cast<uint8_t>(targetRGB.r), static_cast<uint8_t>(targetRGB.g),
+ static_cast<uint8_t>(targetRGB.b), 255);
+ };
+
+ expectBufferColor(Rect(kGreyLevels, 1), generator, 2);
+}
+
INSTANTIATE_TEST_SUITE_P(PerRenderEngineType, RenderEngineTest,
testing::Values(std::make_shared<GLESRenderEngineFactory>(),
std::make_shared<GLESCMRenderEngineFactory>(),
@@ -2412,155 +2575,47 @@
}
}
-double EOTF_PQ(double channel) {
- float m1 = (2610.0 / 4096.0) / 4.0;
- float m2 = (2523.0 / 4096.0) * 128.0;
- float c1 = (3424.0 / 4096.0);
- float c2 = (2413.0 / 4096.0) * 32.0;
- float c3 = (2392.0 / 4096.0) * 32.0;
-
- float tmp = std::pow(std::clamp(channel, 0.0, 1.0), 1.0 / m2);
- tmp = std::fmax(tmp - c1, 0.0) / (c2 - c3 * tmp);
- return std::pow(tmp, 1.0 / m1);
-}
-
-vec3 EOTF_PQ(vec3 color) {
- return vec3(EOTF_PQ(color.r), EOTF_PQ(color.g), EOTF_PQ(color.b));
-}
-
-double OETF_sRGB(double channel) {
- return channel <= 0.0031308 ? channel * 12.92 : (pow(channel, 1.0 / 2.4) * 1.055) - 0.055;
-}
-
-int sign(float in) {
- return in >= 0.0 ? 1 : -1;
-}
-
-vec3 OETF_sRGB(vec3 linear) {
- return vec3(sign(linear.r) * OETF_sRGB(linear.r), sign(linear.g) * OETF_sRGB(linear.g),
- sign(linear.b) * OETF_sRGB(linear.b));
-}
-
TEST_P(RenderEngineTest, test_tonemapPQMatches) {
if (!GetParam()->useColorManagement()) {
- return;
+ GTEST_SKIP();
}
if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
- return;
+ GTEST_SKIP();
}
initializeRenderEngine();
- constexpr int32_t kGreyLevels = 256;
+ tonemap(
+ static_cast<ui::Dataspace>(HAL_DATASPACE_STANDARD_BT2020 |
+ HAL_DATASPACE_TRANSFER_ST2084 | HAL_DATASPACE_RANGE_FULL),
+ [](vec3 color) { return EOTF_PQ(color); },
+ [](vec3 color, float) {
+ static constexpr float kMaxPQLuminance = 10000.f;
+ return color * kMaxPQLuminance;
+ });
+}
- const auto rect = Rect(0, 0, kGreyLevels, 1);
- const renderengine::DisplaySettings display{
- .physicalDisplay = rect,
- .clip = rect,
- .maxLuminance = 750.0f,
- .outputDataspace = ui::Dataspace::DISPLAY_P3,
- };
-
- auto buf = std::make_shared<
- renderengine::impl::
- ExternalTexture>(new GraphicBuffer(kGreyLevels, 1, HAL_PIXEL_FORMAT_RGBA_8888,
- 1,
- GRALLOC_USAGE_SW_READ_OFTEN |
- GRALLOC_USAGE_SW_WRITE_OFTEN |
- GRALLOC_USAGE_HW_RENDER |
- GRALLOC_USAGE_HW_TEXTURE,
- "input"),
- *mRE,
- renderengine::impl::ExternalTexture::Usage::READABLE |
- renderengine::impl::ExternalTexture::Usage::WRITEABLE);
- ASSERT_EQ(0, buf->getBuffer()->initCheck());
-
- {
- uint8_t* pixels;
- buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
- reinterpret_cast<void**>(&pixels));
-
- uint8_t color = 0;
- for (int32_t j = 0; j < buf->getBuffer()->getHeight(); j++) {
- uint8_t* dest = pixels + (buf->getBuffer()->getStride() * j * 4);
- for (int32_t i = 0; i < buf->getBuffer()->getWidth(); i++) {
- dest[0] = color;
- dest[1] = color;
- dest[2] = color;
- dest[3] = 255;
- color++;
- dest += 4;
- }
- }
- buf->getBuffer()->unlock();
+TEST_P(RenderEngineTest, test_tonemapHLGMatches) {
+ if (!GetParam()->useColorManagement()) {
+ GTEST_SKIP();
}
- mBuffer = std::make_shared<
- renderengine::impl::
- ExternalTexture>(new GraphicBuffer(kGreyLevels, 1, HAL_PIXEL_FORMAT_RGBA_8888,
- 1,
- GRALLOC_USAGE_SW_READ_OFTEN |
- GRALLOC_USAGE_SW_WRITE_OFTEN |
- GRALLOC_USAGE_HW_RENDER |
- GRALLOC_USAGE_HW_TEXTURE,
- "output"),
- *mRE,
- renderengine::impl::ExternalTexture::Usage::READABLE |
- renderengine::impl::ExternalTexture::Usage::WRITEABLE);
- ASSERT_EQ(0, mBuffer->getBuffer()->initCheck());
+ if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
+ GTEST_SKIP();
+ }
- const renderengine::LayerSettings layer{
- .geometry.boundaries = rect.toFloatRect(),
- .source =
- renderengine::PixelSource{
- .buffer =
- renderengine::Buffer{
- .buffer = std::move(buf),
- .usePremultipliedAlpha = true,
- },
- },
- .alpha = 1.0f,
- .sourceDataspace = static_cast<ui::Dataspace>(HAL_DATASPACE_STANDARD_BT2020 |
- HAL_DATASPACE_TRANSFER_ST2084 |
- HAL_DATASPACE_RANGE_FULL),
- };
+ initializeRenderEngine();
- std::vector<renderengine::LayerSettings> layers{layer};
- invokeDraw(display, layers);
-
- ColorSpace displayP3 = ColorSpace::DisplayP3();
- ColorSpace bt2020 = ColorSpace::BT2020();
-
- tonemap::Metadata metadata{.displayMaxLuminance = 750.0f};
-
- auto generator = [=](Point location) {
- const double normColor = static_cast<double>(location.x) / (kGreyLevels - 1);
- const vec3 rgb = vec3(normColor, normColor, normColor);
-
- const vec3 linearRGB = EOTF_PQ(rgb);
-
- static constexpr float kMaxPQLuminance = 10000.f;
- const vec3 xyz = bt2020.getRGBtoXYZ() * linearRGB * kMaxPQLuminance;
- const double gain =
- tonemap::getToneMapper()
- ->lookupTonemapGain(static_cast<aidl::android::hardware::graphics::common::
- Dataspace>(
- HAL_DATASPACE_STANDARD_BT2020 |
- HAL_DATASPACE_TRANSFER_ST2084 |
- HAL_DATASPACE_RANGE_FULL),
- static_cast<aidl::android::hardware::graphics::common::
- Dataspace>(
- ui::Dataspace::DISPLAY_P3),
- linearRGB * 10000.0, xyz, metadata);
- const vec3 scaledXYZ = xyz * gain / metadata.displayMaxLuminance;
-
- const vec3 targetRGB = OETF_sRGB(displayP3.getXYZtoRGB() * scaledXYZ) * 255;
- return ubyte4(static_cast<uint8_t>(targetRGB.r), static_cast<uint8_t>(targetRGB.g),
- static_cast<uint8_t>(targetRGB.b), 255);
- };
-
- expectBufferColor(Rect(kGreyLevels, 1), generator, 2);
+ tonemap(
+ static_cast<ui::Dataspace>(HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_HLG |
+ HAL_DATASPACE_RANGE_FULL),
+ [](vec3 color) { return EOTF_HLG(color); },
+ [](vec3 color, float currentLuminaceNits) {
+ static constexpr float kMaxHLGLuminance = 1000.f;
+ static const float kHLGGamma = 1.2 + 0.42 * std::log10(currentLuminaceNits / 1000);
+ return color * kMaxHLGLuminance * std::pow(color.y, kHLGGamma - 1);
+ });
}
TEST_P(RenderEngineTest, r8_behaves_as_mask) {
diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp
index da88e85..ec0ced8 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -280,6 +280,26 @@
mStringType = SENSOR_STRING_TYPE_HEAD_TRACKER;
mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
break;
+ case SENSOR_TYPE_ACCELEROMETER_LIMITED_AXES:
+ mStringType = SENSOR_STRING_TYPE_ACCELEROMETER_LIMITED_AXES;
+ mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
+ break;
+ case SENSOR_TYPE_GYROSCOPE_LIMITED_AXES:
+ mStringType = SENSOR_STRING_TYPE_GYROSCOPE_LIMITED_AXES;
+ mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
+ break;
+ case SENSOR_TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED:
+ mStringType = SENSOR_STRING_TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED;
+ mFlags |= SENSOR_FLAG_CONTINUOUS_MODE;
+ break;
+ case SENSOR_TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED:
+ 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/libs/shaders/shaders.cpp b/libs/shaders/shaders.cpp
index 4d88d5d..03da3ec 100644
--- a/libs/shaders/shaders.cpp
+++ b/libs/shaders/shaders.cpp
@@ -18,6 +18,7 @@
#include <tonemap/tonemap.h>
+#include <cmath>
#include <optional>
#include <math/mat4.h>
@@ -26,12 +27,13 @@
namespace android::shaders {
-static aidl::android::hardware::graphics::common::Dataspace toAidlDataspace(
- ui::Dataspace dataspace) {
+namespace {
+
+aidl::android::hardware::graphics::common::Dataspace toAidlDataspace(ui::Dataspace dataspace) {
return static_cast<aidl::android::hardware::graphics::common::Dataspace>(dataspace);
}
-static void generateEOTF(ui::Dataspace dataspace, std::string& shader) {
+void generateEOTF(ui::Dataspace dataspace, std::string& shader) {
switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) {
case HAL_DATASPACE_TRANSFER_ST2084:
shader.append(R"(
@@ -156,7 +158,7 @@
}
}
-static void generateXYZTransforms(std::string& shader) {
+void generateXYZTransforms(std::string& shader) {
shader.append(R"(
uniform float4x4 in_rgbToXyz;
uniform float4x4 in_xyzToRgb;
@@ -171,8 +173,8 @@
}
// Conversion from relative light to absolute light (maps from [0, 1] to [0, maxNits])
-static void generateLuminanceScalesForOOTF(ui::Dataspace inputDataspace,
- ui::Dataspace outputDataspace, std::string& shader) {
+void generateLuminanceScalesForOOTF(ui::Dataspace inputDataspace, ui::Dataspace outputDataspace,
+ std::string& shader) {
switch (inputDataspace & HAL_DATASPACE_TRANSFER_MASK) {
case HAL_DATASPACE_TRANSFER_ST2084:
shader.append(R"(
@@ -183,8 +185,9 @@
break;
case HAL_DATASPACE_TRANSFER_HLG:
shader.append(R"(
+ uniform float in_hlgGamma;
float3 ScaleLuminance(float3 xyz) {
- return xyz * 1000.0 * pow(xyz.y, 0.2);
+ return xyz * 1000.0 * pow(xyz.y, in_hlgGamma - 1);
}
)");
break;
@@ -225,8 +228,10 @@
break;
case HAL_DATASPACE_TRANSFER_HLG:
shader.append(R"(
+ uniform float in_hlgGamma;
float3 NormalizeLuminance(float3 xyz) {
- return xyz / 1000.0 * pow(xyz.y / 1000.0, -0.2 / 1.2);
+ return xyz / 1000.0 *
+ pow(xyz.y / 1000.0, (1 - in_hlgGamma) / (in_hlgGamma));
}
)");
break;
@@ -240,8 +245,8 @@
}
}
-static void generateOOTF(ui::Dataspace inputDataspace, ui::Dataspace outputDataspace,
- std::string& shader) {
+void generateOOTF(ui::Dataspace inputDataspace, ui::Dataspace outputDataspace,
+ std::string& shader) {
shader.append(tonemap::getToneMapper()
->generateTonemapGainShaderSkSL(toAidlDataspace(inputDataspace),
toAidlDataspace(outputDataspace))
@@ -262,7 +267,7 @@
)");
}
-static void generateOETF(ui::Dataspace dataspace, std::string& shader) {
+void generateOETF(ui::Dataspace dataspace, std::string& shader) {
switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) {
case HAL_DATASPACE_TRANSFER_ST2084:
shader.append(R"(
@@ -384,7 +389,7 @@
}
}
-static void generateEffectiveOOTF(bool undoPremultipliedAlpha, std::string& shader) {
+void generateEffectiveOOTF(bool undoPremultipliedAlpha, std::string& shader) {
shader.append(R"(
uniform shader child;
half4 main(float2 xy) {
@@ -412,7 +417,7 @@
}
// please keep in sync with toSkColorSpace function in renderengine/skia/ColorSpaces.cpp
-static ColorSpace toColorSpace(ui::Dataspace dataspace) {
+ColorSpace toColorSpace(ui::Dataspace dataspace) {
switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
case HAL_DATASPACE_STANDARD_BT709:
return ColorSpace::sRGB();
@@ -438,6 +443,21 @@
}
}
+template <typename T, std::enable_if_t<std::is_trivially_copyable<T>::value, bool> = true>
+std::vector<uint8_t> buildUniformValue(T value) {
+ std::vector<uint8_t> result;
+ result.resize(sizeof(value));
+ std::memcpy(result.data(), &value, sizeof(value));
+ return result;
+}
+
+// Refer to BT2100-2
+float computeHlgGamma(float currentDisplayBrightnessNits) {
+ return 1.2 + 0.42 * std::log10(currentDisplayBrightnessNits / 1000);
+}
+
+} // namespace
+
std::string buildLinearEffectSkSL(const LinearEffect& linearEffect) {
std::string shaderString;
generateEOTF(linearEffect.fakeInputDataspace == ui::Dataspace::UNKNOWN
@@ -451,14 +471,6 @@
return shaderString;
}
-template <typename T, std::enable_if_t<std::is_trivially_copyable<T>::value, bool> = true>
-std::vector<uint8_t> buildUniformValue(T value) {
- std::vector<uint8_t> result;
- result.resize(sizeof(value));
- std::memcpy(result.data(), &value, sizeof(value));
- return result;
-}
-
// Generates a list of uniforms to set on the LinearEffect shader above.
std::vector<tonemap::ShaderUniform> buildLinearEffectUniforms(const LinearEffect& linearEffect,
const mat4& colorTransform,
@@ -480,8 +492,13 @@
colorTransform * mat4(outputColorSpace.getXYZtoRGB()))});
}
+ if ((linearEffect.inputDataspace & HAL_DATASPACE_TRANSFER_MASK) == HAL_DATASPACE_TRANSFER_HLG) {
+ uniforms.push_back(
+ {.name = "in_hlgGamma",
+ .value = buildUniformValue<float>(computeHlgGamma(currentDisplayLuminanceNits))});
+ }
+
tonemap::Metadata metadata{.displayMaxLuminance = maxDisplayLuminance,
- .currentDisplayLuminanceNits = currentDisplayLuminanceNits,
// If the input luminance is unknown, use display luminance (aka,
// no-op any luminance changes)
// This will be the case for eg screenshots in addition to
diff --git a/libs/tonemap/include/tonemap/tonemap.h b/libs/tonemap/include/tonemap/tonemap.h
index 6233e6c..b9abf8c 100644
--- a/libs/tonemap/include/tonemap/tonemap.h
+++ b/libs/tonemap/include/tonemap/tonemap.h
@@ -44,8 +44,6 @@
struct Metadata {
// The maximum luminance of the display in nits
float displayMaxLuminance = 0.0;
- // The current luminance of the display in nits
- float currentDisplayLuminanceNits = 0.0;
// The maximum luminance of the content in nits
float contentMaxLuminance = 0.0;
};
diff --git a/libs/tonemap/tests/tonemap_test.cpp b/libs/tonemap/tests/tonemap_test.cpp
index 7a7958f..1d46482 100644
--- a/libs/tonemap/tests/tonemap_test.cpp
+++ b/libs/tonemap/tests/tonemap_test.cpp
@@ -61,7 +61,7 @@
EXPECT_GT(contentLumFloat, 0);
}
-TEST_F(TonemapTest, generateTonemapGainShaderSkSL_containsEntryPoint) {
+TEST_F(TonemapTest, generateTonemapGainShaderSkSL_containsEntryPointForPQ) {
const auto shader =
tonemap::getToneMapper()
->generateTonemapGainShaderSkSL(aidl::android::hardware::graphics::common::
@@ -73,4 +73,16 @@
EXPECT_THAT(shader, HasSubstr("float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz)"));
}
+TEST_F(TonemapTest, generateTonemapGainShaderSkSL_containsEntryPointForHLG) {
+ const auto shader =
+ tonemap::getToneMapper()
+ ->generateTonemapGainShaderSkSL(aidl::android::hardware::graphics::common::
+ Dataspace::BT2020_ITU_HLG,
+ aidl::android::hardware::graphics::common::
+ Dataspace::DISPLAY_P3);
+
+ // Other tests such as librenderengine_test will plug in the shader to check compilation.
+ EXPECT_THAT(shader, HasSubstr("float libtonemap_LookupTonemapGain(vec3 linearRGB, vec3 xyz)"));
+}
+
} // namespace android
diff --git a/libs/tonemap/tonemap.cpp b/libs/tonemap/tonemap.cpp
index c2372fe..bc0a884 100644
--- a/libs/tonemap/tonemap.cpp
+++ b/libs/tonemap/tonemap.cpp
@@ -407,7 +407,6 @@
)");
switch (sourceDataspaceInt & kTransferMask) {
case kTransferST2084:
- case kTransferHLG:
switch (destinationDataspaceInt & kTransferMask) {
case kTransferST2084:
program.append(R"(
@@ -428,39 +427,22 @@
break;
default:
- switch (sourceDataspaceInt & kTransferMask) {
- case kTransferST2084:
- program.append(R"(
- float libtonemap_OETFTone(float channel) {
- channel = channel / 10000.0;
- float m1 = (2610.0 / 4096.0) / 4.0;
- float m2 = (2523.0 / 4096.0) * 128.0;
- float c1 = (3424.0 / 4096.0);
- float c2 = (2413.0 / 4096.0) * 32.0;
- float c3 = (2392.0 / 4096.0) * 32.0;
-
- float tmp = pow(channel, float(m1));
- tmp = (c1 + c2 * tmp) / (1.0 + c3 * tmp);
- return pow(tmp, float(m2));
- }
- )");
- break;
- case kTransferHLG:
- program.append(R"(
- float libtonemap_OETFTone(float channel) {
- channel = channel / 1000.0;
- const float a = 0.17883277;
- const float b = 0.28466892;
- const float c = 0.55991073;
- return channel <= 1.0 / 12.0 ? sqrt(3.0 * channel) :
- a * log(12.0 * channel - b) + c;
- }
- )");
- break;
- }
// Here we're mapping from HDR to SDR content, so interpolate using a
// Hermitian polynomial onto the smaller luminance range.
program.append(R"(
+ float libtonemap_OETFTone(float channel) {
+ channel = channel / 10000.0;
+ float m1 = (2610.0 / 4096.0) / 4.0;
+ float m2 = (2523.0 / 4096.0) * 128.0;
+ float c1 = (3424.0 / 4096.0);
+ float c2 = (2413.0 / 4096.0) * 32.0;
+ float c3 = (2392.0 / 4096.0) * 32.0;
+
+ float tmp = pow(channel, float(m1));
+ tmp = (c1 + c2 * tmp) / (1.0 + c3 * tmp);
+ return pow(tmp, float(m2));
+ }
+
float libtonemap_ToneMapTargetNits(float maxRGB) {
float maxInLumi = in_libtonemap_inputMaxLuminance;
float maxOutLumi = in_libtonemap_displayMaxLuminance;
@@ -508,6 +490,30 @@
break;
}
break;
+ case kTransferHLG:
+ switch (destinationDataspaceInt & kTransferMask) {
+ // HLG -> HDR does not tone-map at all
+ case kTransferST2084:
+ case kTransferHLG:
+ program.append(R"(
+ float libtonemap_ToneMapTargetNits(float maxRGB) {
+ return maxRGB;
+ }
+ )");
+ break;
+ default:
+ // libshaders follows BT2100 OOTF, but with a nominal peak display luminance
+ // of 1000 nits. Renormalize to max display luminance if we're tone-mapping
+ // down to SDR, as libshaders normalizes all SDR output from [0,
+ // maxDisplayLumins] -> [0, 1]
+ program.append(R"(
+ float libtonemap_ToneMapTargetNits(float maxRGB) {
+ return maxRGB * in_libtonemap_displayMaxLuminance / 1000.0;
+ }
+ )");
+ break;
+ }
+ break;
default:
// Inverse tone-mapping and SDR-SDR mapping is not supported.
program.append(R"(
@@ -558,7 +564,6 @@
double targetNits = 0.0;
switch (sourceDataspaceInt & kTransferMask) {
case kTransferST2084:
- case kTransferHLG:
switch (destinationDataspaceInt & kTransferMask) {
case kTransferST2084:
targetNits = maxRGB;
@@ -587,19 +592,9 @@
double x2 = x1 + (x3 - x1) * 4.0 / 17.0;
double y2 = maxOutLumi * 0.9;
- double greyNorm1 = 0.0;
- double greyNorm2 = 0.0;
- double greyNorm3 = 0.0;
-
- if ((sourceDataspaceInt & kTransferMask) == kTransferST2084) {
- greyNorm1 = OETF_ST2084(x1);
- greyNorm2 = OETF_ST2084(x2);
- greyNorm3 = OETF_ST2084(x3);
- } else if ((sourceDataspaceInt & kTransferMask) == kTransferHLG) {
- greyNorm1 = OETF_HLG(x1);
- greyNorm2 = OETF_HLG(x2);
- greyNorm3 = OETF_HLG(x3);
- }
+ const double greyNorm1 = OETF_ST2084(x1);
+ const double greyNorm2 = OETF_ST2084(x2);
+ const double greyNorm3 = OETF_ST2084(x3);
double slope2 = (y2 - y1) / (greyNorm2 - greyNorm1);
double slope3 = (y3 - y2) / (greyNorm3 - greyNorm2);
@@ -613,12 +608,7 @@
break;
}
- double greyNits = 0.0;
- if ((sourceDataspaceInt & kTransferMask) == kTransferST2084) {
- greyNits = OETF_ST2084(targetNits);
- } else if ((sourceDataspaceInt & kTransferMask) == kTransferHLG) {
- greyNits = OETF_HLG(targetNits);
- }
+ const double greyNits = OETF_ST2084(targetNits);
if (greyNits <= greyNorm2) {
targetNits = (greyNits - greyNorm2) * slope2 + y2;
@@ -630,15 +620,20 @@
break;
}
break;
- default:
+ case kTransferHLG:
switch (destinationDataspaceInt & kTransferMask) {
case kTransferST2084:
case kTransferHLG:
- default:
targetNits = maxRGB;
break;
+ default:
+ targetNits = maxRGB * metadata.displayMaxLuminance / 1000.0;
+ break;
}
break;
+ default:
+ targetNits = maxRGB;
+ break;
}
return targetNits / maxRGB;
diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp
index 33ab7c4..cc96f83 100644
--- a/libs/ui/Fence.cpp
+++ b/libs/ui/Fence.cpp
@@ -132,9 +132,13 @@
ALOGE("sync_file_info returned NULL for fd %d", mFenceFd.get());
return SIGNAL_TIME_INVALID;
}
+
if (finfo->status != 1) {
+ const auto status = finfo->status;
+ ALOGE_IF(status < 0, "%s: sync_file_info contains an error: <%d> for fd: <%d>", __func__,
+ status, mFenceFd.get());
sync_file_info_free(finfo);
- return SIGNAL_TIME_PENDING;
+ return status < 0 ? SIGNAL_TIME_INVALID : SIGNAL_TIME_PENDING;
}
uint64_t timestamp = 0;
diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
index 9922d6a..1a42642 100644
--- a/libs/ui/Gralloc4.cpp
+++ b/libs/ui/Gralloc4.cpp
@@ -62,6 +62,9 @@
static constexpr Error kTransactionError = Error::NO_RESOURCES;
static const auto kAidlAllocatorServiceName = AidlIAllocator::descriptor + std::string("/default");
+// TODO(b/72323293, b/72703005): Remove these invalid bits from callers
+static constexpr uint64_t kRemovedUsageBits = static_cast<uint64_t>((1 << 10) | (1 << 13));
+
uint64_t getValidUsageBits() {
static const uint64_t validUsageBits = []() -> uint64_t {
uint64_t bits = 0;
@@ -71,7 +74,7 @@
}
return bits;
}();
- return validUsageBits;
+ return validUsageBits | kRemovedUsageBits;
}
uint64_t getValidUsageBits41() {
@@ -98,9 +101,6 @@
static bool hasIAllocatorAidl() {
// Avoid re-querying repeatedly for this information;
static bool sHasIAllocatorAidl = []() -> bool {
- // TODO: Enable after landing sepolicy changes
- if constexpr ((true)) return false;
-
if (__builtin_available(android 31, *)) {
return AServiceManager_isDeclared(kAidlAllocatorServiceName.c_str());
}
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index ec58325..22a69e5 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -49,6 +49,7 @@
srcs: [
"InputClassifier.cpp",
"InputClassifierConverter.cpp",
+ "UnwantedInteractionBlocker.cpp",
"InputManager.cpp",
],
}
@@ -60,6 +61,7 @@
"android.hardware.input.classifier@1.0",
"libbase",
"libbinder",
+ "libchrome",
"libcrypto",
"libcutils",
"libhidlbase",
@@ -76,6 +78,7 @@
],
static_libs: [
"libattestation",
+ "libpalmrejection",
],
}
diff --git a/services/inputflinger/InputClassifierConverter.cpp b/services/inputflinger/InputClassifierConverter.cpp
index fc8c7c3..b58a188 100644
--- a/services/inputflinger/InputClassifierConverter.cpp
+++ b/services/inputflinger/InputClassifierConverter.cpp
@@ -325,11 +325,6 @@
return out;
}
-static uint8_t getActionIndex(int32_t action) {
- return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >>
- AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
-}
-
static void getHidlPropertiesAndCoords(const NotifyMotionArgs& args,
std::vector<common::V1_0::PointerProperties>* outPointerProperties,
std::vector<common::V1_0::PointerCoords>* outPointerCoords) {
@@ -360,7 +355,7 @@
event.eventTime = args.eventTime;
event.deviceTimestamp = 0;
event.action = getAction(args.action & AMOTION_EVENT_ACTION_MASK);
- event.actionIndex = getActionIndex(args.action);
+ event.actionIndex = MotionEvent::getActionIndex(args.action);
event.actionButton = getActionButton(args.actionButton);
event.flags = getFlags(args.flags);
event.policyFlags = getPolicyFlags(args.policyFlags);
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 158d0eb..73b63e3 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -188,6 +188,25 @@
return true;
}
+std::string NotifyMotionArgs::dump() const {
+ std::string coords;
+ for (uint32_t i = 0; i < pointerCount; i++) {
+ if (!coords.empty()) {
+ coords += ", ";
+ }
+ coords += StringPrintf("{%" PRIu32 ": ", i);
+ coords +=
+ StringPrintf("id=%" PRIu32 " x=%.1f y=%.1f, pressure=%.1f", pointerProperties[i].id,
+ pointerCoords[i].getX(), pointerCoords[i].getY(),
+ pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
+ coords += "}";
+ }
+ return StringPrintf("NotifyMotionArgs(id=%" PRId32 ", eventTime=%" PRId64 ", deviceId=%" PRId32
+ ", source=%s, action=%s, pointerCount=%" PRIu32 " pointers=%s)",
+ id, eventTime, deviceId, inputEventSourceToString(source).c_str(),
+ MotionEvent::actionToString(action).c_str(), pointerCount, coords.c_str());
+}
+
void NotifyMotionArgs::notify(InputListenerInterface& listener) const {
listener.notifyMotion(this);
}
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 221e193..7a9862d 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -21,6 +21,7 @@
#include "InputManager.h"
#include "InputDispatcherFactory.h"
#include "InputReaderFactory.h"
+#include "UnwantedInteractionBlocker.h"
#include <binder/IPCThreadState.h>
@@ -54,12 +55,17 @@
}
}
+/**
+ * The event flow is via the "InputListener" interface, as follows:
+ * InputReader -> UnwantedInteractionBlocker -> InputClassifier -> InputDispatcher
+ */
InputManager::InputManager(
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = createInputDispatcher(dispatcherPolicy);
mClassifier = std::make_unique<InputClassifier>(*mDispatcher);
- mReader = createInputReader(readerPolicy, *mClassifier);
+ mUnwantedInteractionBlocker = std::make_unique<UnwantedInteractionBlocker>(*mClassifier);
+ mReader = createInputReader(readerPolicy, *mUnwantedInteractionBlocker);
}
InputManager::~InputManager() {
@@ -106,6 +112,10 @@
return *mReader;
}
+UnwantedInteractionBlockerInterface& InputManager::getUnwantedInteractionBlocker() {
+ return *mUnwantedInteractionBlocker;
+}
+
InputClassifierInterface& InputManager::getClassifier() {
return *mClassifier;
}
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index e000283..35d2b0f 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -23,6 +23,7 @@
#include "InputClassifier.h"
#include "InputReaderBase.h"
+#include "include/UnwantedInteractionBlockerInterface.h"
#include <InputDispatcherInterface.h>
#include <InputDispatcherPolicyInterface.h>
@@ -46,11 +47,16 @@
* The input manager has three components.
*
* 1. The InputReader class starts a thread that reads and preprocesses raw input events, applies
- * policy, and posts messages to a queue managed by the InputClassifier.
- * 2. The InputClassifier class starts a thread to communicate with the device-specific
- * classifiers. It then waits on the queue of events from InputReader, applies a classification
- * to them, and queues them for the InputDispatcher.
- * 3. The InputDispatcher class starts a thread that waits for new events on the
+ * policy, and posts messages to a queue managed by the UnwantedInteractionBlocker.
+ * 2. The UnwantedInteractionBlocker is responsible for removing unwanted interactions. For example,
+ * this could be a palm on the screen. This stage would alter the event stream to remove either
+ * partially (some of the pointers) or fully (all touches) the unwanted interaction. The events
+ * are processed on the InputReader thread, without any additional queue. The events are then
+ * posted to the queue managed by the InputClassifier.
+ * 3. The InputClassifier class starts a thread to communicate with the device-specific
+ * classifiers. It then waits on the queue of events from UnwantedInteractionBlocker, applies
+ * a classification to them, and queues them for the InputDispatcher.
+ * 4. The InputDispatcher class starts a thread that waits for new events on the
* previous queue and asynchronously dispatches them to applications.
*
* By design, none of these classes share any internal state. Moreover, all communication is
@@ -76,6 +82,9 @@
/* Gets the input reader. */
virtual InputReaderInterface& getReader() = 0;
+ /* Gets the unwanted interaction blocker. */
+ virtual UnwantedInteractionBlockerInterface& getUnwantedInteractionBlocker() = 0;
+
/* Gets the input classifier */
virtual InputClassifierInterface& getClassifier() = 0;
@@ -96,6 +105,7 @@
status_t stop() override;
InputReaderInterface& getReader() override;
+ UnwantedInteractionBlockerInterface& getUnwantedInteractionBlocker() override;
InputClassifierInterface& getClassifier() override;
InputDispatcherInterface& getDispatcher() override;
@@ -107,6 +117,8 @@
private:
std::unique_ptr<InputReaderInterface> mReader;
+ std::unique_ptr<UnwantedInteractionBlockerInterface> mUnwantedInteractionBlocker;
+
std::unique_ptr<InputClassifierInterface> mClassifier;
std::unique_ptr<InputDispatcherInterface> mDispatcher;
diff --git a/services/inputflinger/UnwantedInteractionBlocker.cpp b/services/inputflinger/UnwantedInteractionBlocker.cpp
new file mode 100644
index 0000000..64dbb8c
--- /dev/null
+++ b/services/inputflinger/UnwantedInteractionBlocker.cpp
@@ -0,0 +1,687 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "UnwantedInteractionBlocker"
+#include "UnwantedInteractionBlocker.h"
+
+#include <android-base/stringprintf.h>
+#include <inttypes.h>
+#include <linux/input-event-codes.h>
+#include <linux/input.h>
+#include <server_configurable_flags/get_flags.h>
+
+#include "ui/events/ozone/evdev/touch_filter/neural_stylus_palm_detection_filter.h"
+#include "ui/events/ozone/evdev/touch_filter/palm_model/onedevice_train_palm_detection_filter_model.h"
+
+using android::base::StringPrintf;
+
+namespace android {
+
+// Category (=namespace) name for the input settings that are applied at boot time
+static const char* INPUT_NATIVE_BOOT = "input_native_boot";
+/**
+ * Feature flag name. This flag determines whether palm rejection is enabled. To enable, specify
+ * 'true' (not case sensitive) or '1'. To disable, specify any other value.
+ */
+static const char* PALM_REJECTION_ENABLED = "palm_rejection_enabled";
+
+static std::string toLower(std::string s) {
+ std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::tolower(c); });
+ return s;
+}
+
+static bool isFromTouchscreen(int32_t source) {
+ return isFromSource(source, AINPUT_SOURCE_TOUCHSCREEN);
+}
+
+static ::base::TimeTicks toChromeTimestamp(nsecs_t eventTime) {
+ return ::base::TimeTicks::UnixEpoch() +
+ ::base::Milliseconds(static_cast<float>(ns2ms(eventTime)));
+}
+
+/**
+ * Return true if palm rejection is enabled via the server configurable flags. Return false
+ * otherwise.
+ */
+static bool isPalmRejectionEnabled() {
+ std::string value = toLower(
+ server_configurable_flags::GetServerConfigurableFlag(INPUT_NATIVE_BOOT,
+ PALM_REJECTION_ENABLED, "false"));
+ if (value == "true" || value == "1") {
+ return true;
+ }
+ return false;
+}
+
+static int getLinuxToolType(int32_t toolType) {
+ switch (toolType) {
+ case AMOTION_EVENT_TOOL_TYPE_FINGER:
+ return MT_TOOL_FINGER;
+ case AMOTION_EVENT_TOOL_TYPE_STYLUS:
+ return MT_TOOL_PEN;
+ case AMOTION_EVENT_TOOL_TYPE_PALM:
+ return MT_TOOL_PALM;
+ }
+ ALOGW("Got tool type %" PRId32 ", converting to MT_TOOL_FINGER", toolType);
+ return MT_TOOL_FINGER;
+}
+
+static std::string addPrefix(std::string str, const std::string& prefix) {
+ std::stringstream ss;
+ bool newLineStarted = true;
+ for (const auto& ch : str) {
+ if (newLineStarted) {
+ ss << prefix;
+ newLineStarted = false;
+ }
+ if (ch == '\n') {
+ newLineStarted = true;
+ }
+ ss << ch;
+ }
+ return ss.str();
+}
+
+template <typename T>
+static std::string dumpSet(const std::set<T>& v) {
+ static_assert(std::is_integral<T>::value, "Only integral types can be printed.");
+ std::string out;
+ for (const T& entry : v) {
+ out += out.empty() ? "{" : ", ";
+ out += android::base::StringPrintf("%i", entry);
+ }
+ return out.empty() ? "{}" : (out + "}");
+}
+
+template <typename K, typename V>
+static std::string dumpMap(const std::map<K, V>& map) {
+ static_assert(std::is_integral<K>::value, "Keys should have integral type to be printed.");
+ static_assert(std::is_integral<V>::value, "Values should have integral type to be printed.");
+ std::string out;
+ for (const auto& [k, v] : map) {
+ if (!out.empty()) {
+ out += "\n";
+ }
+ out += android::base::StringPrintf("%i : %i", static_cast<int>(k), static_cast<int>(v));
+ }
+ return out;
+}
+
+static std::string dumpDeviceInfo(const AndroidPalmFilterDeviceInfo& info) {
+ std::string out;
+ out += StringPrintf("max_x = %.2f\n", info.max_x);
+ out += StringPrintf("max_y = %.2f\n", info.max_y);
+ out += StringPrintf("x_res = %.2f\n", info.x_res);
+ out += StringPrintf("y_res = %.2f\n", info.y_res);
+ out += StringPrintf("major_radius_res = %.2f\n", info.major_radius_res);
+ out += StringPrintf("minor_radius_res = %.2f\n", info.minor_radius_res);
+ out += StringPrintf("minor_radius_supported = %s\n",
+ info.minor_radius_supported ? "true" : "false");
+ out += StringPrintf("touch_major_res = %" PRId32 "\n", info.touch_major_res);
+ out += StringPrintf("touch_minor_res = %" PRId32 "\n", info.touch_minor_res);
+ return out;
+}
+
+static int32_t getActionUpForPointerId(const NotifyMotionArgs& args, int32_t pointerId) {
+ for (size_t i = 0; i < args.pointerCount; i++) {
+ if (pointerId == args.pointerProperties[i].id) {
+ return AMOTION_EVENT_ACTION_POINTER_UP |
+ (i << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+ }
+ }
+ LOG_ALWAYS_FATAL("Can't find pointerId %" PRId32 " in %s", pointerId, args.dump().c_str());
+}
+
+/**
+ * Find the action for individual pointer at the given pointer index.
+ * This is always equal to MotionEvent::getActionMasked, except for
+ * POINTER_UP or POINTER_DOWN events. For example, in a POINTER_UP event, the action for
+ * the active pointer is ACTION_POINTER_UP, while the action for the other pointers is ACTION_MOVE.
+ */
+static int32_t resolveActionForPointer(uint8_t pointerIndex, int32_t action) {
+ const int32_t actionMasked = MotionEvent::getActionMasked(action);
+ if (actionMasked != AMOTION_EVENT_ACTION_POINTER_DOWN &&
+ actionMasked != AMOTION_EVENT_ACTION_POINTER_UP) {
+ return actionMasked;
+ }
+ // This is a POINTER_DOWN or POINTER_UP event
+ const uint8_t actionIndex = MotionEvent::getActionIndex(action);
+ if (pointerIndex == actionIndex) {
+ return actionMasked;
+ }
+ // When POINTER_DOWN or POINTER_UP happens, it's actually a MOVE for all of the other
+ // pointers
+ return AMOTION_EVENT_ACTION_MOVE;
+}
+
+static const char* toString(bool value) {
+ return value ? "true" : "false";
+}
+
+std::string toString(const ::ui::InProgressTouchEvdev& touch) {
+ return StringPrintf("x=%.1f, y=%.1f, tracking_id=%i, slot=%zu,"
+ " pressure=%.1f, major=%i, minor=%i, "
+ "tool_type=%i, altered=%s, was_touching=%s, touching=%s",
+ touch.x, touch.y, touch.tracking_id, touch.slot, touch.pressure,
+ touch.major, touch.minor, touch.tool_type, toString(touch.altered),
+ toString(touch.was_touching), toString(touch.touching));
+}
+
+/**
+ * Remove the data for the provided pointers from the args. The pointers are identified by their
+ * pointerId, not by the index inside the array.
+ * Return the new NotifyMotionArgs struct that has the remaining pointers.
+ * The only fields that may be different in the returned args from the provided args are:
+ * - action
+ * - pointerCount
+ * - pointerProperties
+ * - pointerCoords
+ * Action might change because it contains a pointer index. If another pointer is removed, the
+ * active pointer index would be shifted.
+ * Do not call this function for events with POINTER_UP or POINTER_DOWN events when removed pointer
+ * id is the acting pointer id.
+ *
+ * @param args the args from which the pointers should be removed
+ * @param pointerIds the pointer ids of the pointers that should be removed
+ */
+NotifyMotionArgs removePointerIds(const NotifyMotionArgs& args,
+ const std::set<int32_t>& pointerIds) {
+ const uint8_t actionIndex = MotionEvent::getActionIndex(args.action);
+ const int32_t actionMasked = MotionEvent::getActionMasked(args.action);
+ const bool isPointerUpOrDownAction = actionMasked == AMOTION_EVENT_ACTION_POINTER_DOWN ||
+ actionMasked == AMOTION_EVENT_ACTION_POINTER_UP;
+
+ NotifyMotionArgs newArgs{args};
+ newArgs.pointerCount = 0;
+ int32_t newActionIndex = 0;
+ for (uint32_t i = 0; i < args.pointerCount; i++) {
+ const int32_t pointerId = args.pointerProperties[i].id;
+ if (pointerIds.find(pointerId) != pointerIds.end()) {
+ // skip this pointer
+ if (isPointerUpOrDownAction && i == actionIndex) {
+ // The active pointer is being removed, so the action is no longer valid.
+ // Set the action to 'UNKNOWN' here. The caller is responsible for updating this
+ // action later to a proper value.
+ newArgs.action = ACTION_UNKNOWN;
+ }
+ continue;
+ }
+ newArgs.pointerProperties[newArgs.pointerCount].copyFrom(args.pointerProperties[i]);
+ newArgs.pointerCoords[newArgs.pointerCount].copyFrom(args.pointerCoords[i]);
+ if (i == actionIndex) {
+ newActionIndex = newArgs.pointerCount;
+ }
+ newArgs.pointerCount++;
+ }
+ // Update POINTER_DOWN or POINTER_UP actions
+ if (isPointerUpOrDownAction && newArgs.action != ACTION_UNKNOWN) {
+ newArgs.action =
+ actionMasked | (newActionIndex << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+ // Convert POINTER_DOWN and POINTER_UP to DOWN and UP if there's only 1 pointer remaining
+ if (newArgs.pointerCount == 1) {
+ if (actionMasked == AMOTION_EVENT_ACTION_POINTER_DOWN) {
+ newArgs.action = AMOTION_EVENT_ACTION_DOWN;
+ } else if (actionMasked == AMOTION_EVENT_ACTION_POINTER_UP) {
+ newArgs.action = AMOTION_EVENT_ACTION_UP;
+ }
+ }
+ }
+ return newArgs;
+}
+
+std::optional<AndroidPalmFilterDeviceInfo> createPalmFilterDeviceInfo(
+ const InputDeviceInfo& deviceInfo) {
+ if (!isFromTouchscreen(deviceInfo.getSources())) {
+ return std::nullopt;
+ }
+ AndroidPalmFilterDeviceInfo out;
+ const InputDeviceInfo::MotionRange* axisX =
+ deviceInfo.getMotionRange(AMOTION_EVENT_AXIS_X, AINPUT_SOURCE_TOUCHSCREEN);
+ if (axisX != nullptr) {
+ out.max_x = axisX->max;
+ out.x_res = axisX->resolution;
+ } else {
+ ALOGW("Palm rejection is disabled for %s because AXIS_X is not supported",
+ deviceInfo.getDisplayName().c_str());
+ return std::nullopt;
+ }
+ const InputDeviceInfo::MotionRange* axisY =
+ deviceInfo.getMotionRange(AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_TOUCHSCREEN);
+ if (axisY != nullptr) {
+ out.max_y = axisY->max;
+ out.y_res = axisY->resolution;
+ } else {
+ ALOGW("Palm rejection is disabled for %s because AXIS_Y is not supported",
+ deviceInfo.getDisplayName().c_str());
+ return std::nullopt;
+ }
+ const InputDeviceInfo::MotionRange* axisMajor =
+ deviceInfo.getMotionRange(AMOTION_EVENT_AXIS_TOUCH_MAJOR, AINPUT_SOURCE_TOUCHSCREEN);
+ if (axisMajor != nullptr) {
+ out.major_radius_res = axisMajor->resolution;
+ out.touch_major_res = axisMajor->resolution;
+ } else {
+ return std::nullopt;
+ }
+ const InputDeviceInfo::MotionRange* axisMinor =
+ deviceInfo.getMotionRange(AMOTION_EVENT_AXIS_TOUCH_MINOR, AINPUT_SOURCE_TOUCHSCREEN);
+ if (axisMinor != nullptr) {
+ out.minor_radius_res = axisMinor->resolution;
+ out.touch_minor_res = axisMinor->resolution;
+ out.minor_radius_supported = true;
+ } else {
+ out.minor_radius_supported = false;
+ }
+
+ return out;
+}
+
+/**
+ * Synthesize CANCEL events for any new pointers that should be canceled, while removing pointers
+ * that have already been canceled.
+ * The flow of the function is as follows:
+ * 1. Remove all already canceled pointers
+ * 2. Cancel all newly suppressed pointers
+ * 3. Decide what to do with the current event : keep it, or drop it
+ * The pointers can never be "unsuppressed": once a pointer is canceled, it will never become valid.
+ */
+std::vector<NotifyMotionArgs> cancelSuppressedPointers(
+ const NotifyMotionArgs& args, const std::set<int32_t>& oldSuppressedPointerIds,
+ const std::set<int32_t>& newSuppressedPointerIds) {
+ LOG_ALWAYS_FATAL_IF(args.pointerCount == 0, "0 pointers in %s", args.dump().c_str());
+
+ // First, let's remove the old suppressed pointers. They've already been canceled previously.
+ NotifyMotionArgs oldArgs = removePointerIds(args, oldSuppressedPointerIds);
+
+ // Cancel any newly suppressed pointers.
+ std::vector<NotifyMotionArgs> out;
+ const int32_t activePointerId =
+ args.pointerProperties[MotionEvent::getActionIndex(args.action)].id;
+ const int32_t actionMasked = MotionEvent::getActionMasked(args.action);
+ // We will iteratively remove pointers from 'removedArgs'.
+ NotifyMotionArgs removedArgs{oldArgs};
+ for (uint32_t i = 0; i < oldArgs.pointerCount; i++) {
+ const int32_t pointerId = oldArgs.pointerProperties[i].id;
+ if (newSuppressedPointerIds.find(pointerId) == newSuppressedPointerIds.end()) {
+ // This is a pointer that should not be canceled. Move on.
+ continue;
+ }
+ if (pointerId == activePointerId && actionMasked == AMOTION_EVENT_ACTION_POINTER_DOWN) {
+ // Remove this pointer, but don't cancel it. We'll just not send the POINTER_DOWN event
+ removedArgs = removePointerIds(removedArgs, {pointerId});
+ continue;
+ }
+
+ if (removedArgs.pointerCount == 1) {
+ // We are about to remove the last pointer, which means there will be no more gesture
+ // remaining. This is identical to canceling all pointers, so just send a single CANCEL
+ // event, without any of the preceding POINTER_UP with FLAG_CANCELED events.
+ oldArgs.flags |= AMOTION_EVENT_FLAG_CANCELED;
+ oldArgs.action = AMOTION_EVENT_ACTION_CANCEL;
+ return {oldArgs};
+ }
+ // Cancel the current pointer
+ out.push_back(removedArgs);
+ out.back().flags |= AMOTION_EVENT_FLAG_CANCELED;
+ out.back().action = getActionUpForPointerId(out.back(), pointerId);
+
+ // Remove the newly canceled pointer from the args
+ removedArgs = removePointerIds(removedArgs, {pointerId});
+ }
+
+ // Now 'removedArgs' contains only pointers that are valid.
+ if (removedArgs.pointerCount <= 0 || removedArgs.action == ACTION_UNKNOWN) {
+ return out;
+ }
+ out.push_back(removedArgs);
+ return out;
+}
+
+UnwantedInteractionBlocker::UnwantedInteractionBlocker(InputListenerInterface& listener)
+ : UnwantedInteractionBlocker(listener, isPalmRejectionEnabled()){};
+
+UnwantedInteractionBlocker::UnwantedInteractionBlocker(InputListenerInterface& listener,
+ bool enablePalmRejection)
+ : mListener(listener), mEnablePalmRejection(enablePalmRejection) {}
+
+void UnwantedInteractionBlocker::notifyConfigurationChanged(
+ const NotifyConfigurationChangedArgs* args) {
+ mListener.notifyConfigurationChanged(args);
+}
+
+void UnwantedInteractionBlocker::notifyKey(const NotifyKeyArgs* args) {
+ mListener.notifyKey(args);
+}
+
+void UnwantedInteractionBlocker::notifyMotion(const NotifyMotionArgs* args) {
+ auto it = mPalmRejectors.find(args->deviceId);
+ const bool sendToPalmRejector = it != mPalmRejectors.end() && isFromTouchscreen(args->source);
+ if (!sendToPalmRejector) {
+ mListener.notifyMotion(args);
+ return;
+ }
+
+ const std::vector<NotifyMotionArgs> newMotions = it->second.processMotion(*args);
+ for (const NotifyMotionArgs& newArgs : newMotions) {
+ mListener.notifyMotion(&newArgs);
+ }
+}
+
+void UnwantedInteractionBlocker::notifySwitch(const NotifySwitchArgs* args) {
+ mListener.notifySwitch(args);
+}
+
+void UnwantedInteractionBlocker::notifySensor(const NotifySensorArgs* args) {
+ mListener.notifySensor(args);
+}
+
+void UnwantedInteractionBlocker::notifyVibratorState(const NotifyVibratorStateArgs* args) {
+ mListener.notifyVibratorState(args);
+}
+void UnwantedInteractionBlocker::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
+ auto it = mPalmRejectors.find(args->deviceId);
+ if (it != mPalmRejectors.end()) {
+ AndroidPalmFilterDeviceInfo info = it->second.getPalmFilterDeviceInfo();
+ // Re-create the object instead of resetting it
+ mPalmRejectors.erase(it);
+ mPalmRejectors.emplace(args->deviceId, info);
+ }
+ mListener.notifyDeviceReset(args);
+}
+
+void UnwantedInteractionBlocker::notifyPointerCaptureChanged(
+ const NotifyPointerCaptureChangedArgs* args) {
+ mListener.notifyPointerCaptureChanged(args);
+}
+
+void UnwantedInteractionBlocker::notifyInputDevicesChanged(
+ const std::vector<InputDeviceInfo>& inputDevices) {
+ if (!mEnablePalmRejection) {
+ // Palm rejection is disabled. Don't create any palm rejector objects.
+ return;
+ }
+
+ // Let's see which of the existing devices didn't change, so that we can keep them
+ // and prevent event stream disruption
+ std::set<int32_t /*deviceId*/> devicesToKeep;
+ for (const InputDeviceInfo& device : inputDevices) {
+ std::optional<AndroidPalmFilterDeviceInfo> info = createPalmFilterDeviceInfo(device);
+ if (!info) {
+ continue;
+ }
+
+ auto [it, emplaced] = mPalmRejectors.try_emplace(device.getId(), *info);
+ if (!emplaced && *info != it->second.getPalmFilterDeviceInfo()) {
+ // Re-create the PalmRejector because the device info has changed.
+ mPalmRejectors.erase(it);
+ mPalmRejectors.emplace(device.getId(), *info);
+ }
+ devicesToKeep.insert(device.getId());
+ }
+ // Delete all devices that we don't need to keep
+ std::erase_if(mPalmRejectors, [&devicesToKeep](const auto& item) {
+ auto const& [deviceId, _] = item;
+ return devicesToKeep.find(deviceId) == devicesToKeep.end();
+ });
+}
+
+void UnwantedInteractionBlocker::dump(std::string& dump) {
+ dump += "UnwantedInteractionBlocker:\n";
+ dump += StringPrintf(" mEnablePalmRejection: %s\n", toString(mEnablePalmRejection));
+ dump += StringPrintf(" isPalmRejectionEnabled (flag value): %s\n",
+ toString(isPalmRejectionEnabled()));
+ dump += mPalmRejectors.empty() ? " mPalmRejectors: None\n" : " mPalmRejectors:\n";
+ for (const auto& [deviceId, palmRejector] : mPalmRejectors) {
+ dump += StringPrintf(" deviceId = %" PRId32 ":\n", deviceId);
+ dump += addPrefix(palmRejector.dump(), " ");
+ }
+}
+
+void UnwantedInteractionBlocker::monitor() {}
+
+UnwantedInteractionBlocker::~UnwantedInteractionBlocker() {}
+
+void SlotState::update(const NotifyMotionArgs& args) {
+ for (size_t i = 0; i < args.pointerCount; i++) {
+ const int32_t pointerId = args.pointerProperties[i].id;
+ const int32_t resolvedAction = resolveActionForPointer(i, args.action);
+ processPointerId(pointerId, resolvedAction);
+ }
+}
+
+size_t SlotState::findUnusedSlot() const {
+ size_t unusedSlot = 0;
+ // Since the collection is ordered, we can rely on the in-order traversal
+ for (const auto& [slot, trackingId] : mPointerIdsBySlot) {
+ if (unusedSlot != slot) {
+ break;
+ }
+ unusedSlot++;
+ }
+ return unusedSlot;
+}
+
+void SlotState::processPointerId(int pointerId, int32_t actionMasked) {
+ switch (MotionEvent::getActionMasked(actionMasked)) {
+ case AMOTION_EVENT_ACTION_DOWN:
+ case AMOTION_EVENT_ACTION_POINTER_DOWN:
+ case AMOTION_EVENT_ACTION_HOVER_ENTER: {
+ // New pointer going down
+ size_t newSlot = findUnusedSlot();
+ mPointerIdsBySlot[newSlot] = pointerId;
+ mSlotsByPointerId[pointerId] = newSlot;
+ return;
+ }
+ case AMOTION_EVENT_ACTION_MOVE:
+ case AMOTION_EVENT_ACTION_HOVER_MOVE: {
+ return;
+ }
+ case AMOTION_EVENT_ACTION_CANCEL:
+ case AMOTION_EVENT_ACTION_POINTER_UP:
+ case AMOTION_EVENT_ACTION_UP:
+ case AMOTION_EVENT_ACTION_HOVER_EXIT: {
+ auto it = mSlotsByPointerId.find(pointerId);
+ LOG_ALWAYS_FATAL_IF(it == mSlotsByPointerId.end());
+ size_t slot = it->second;
+ // Erase this pointer from both collections
+ mPointerIdsBySlot.erase(slot);
+ mSlotsByPointerId.erase(pointerId);
+ return;
+ }
+ }
+ LOG_ALWAYS_FATAL("Unhandled action : %s", MotionEvent::actionToString(actionMasked).c_str());
+ return;
+}
+
+std::optional<size_t> SlotState::getSlotForPointerId(int32_t pointerId) const {
+ auto it = mSlotsByPointerId.find(pointerId);
+ if (it == mSlotsByPointerId.end()) {
+ return std::nullopt;
+ }
+ return it->second;
+}
+
+std::string SlotState::dump() const {
+ std::string out = "mSlotsByPointerId:\n";
+ out += addPrefix(dumpMap(mSlotsByPointerId), " ") + "\n";
+ out += "mPointerIdsBySlot:\n";
+ out += addPrefix(dumpMap(mPointerIdsBySlot), " ") + "\n";
+ return out;
+}
+
+PalmRejector::PalmRejector(const AndroidPalmFilterDeviceInfo& info,
+ std::unique_ptr<::ui::PalmDetectionFilter> filter)
+ : mSharedPalmState(std::make_unique<::ui::SharedPalmDetectionFilterState>()),
+ mDeviceInfo(info),
+ mPalmDetectionFilter(std::move(filter)) {
+ if (mPalmDetectionFilter != nullptr) {
+ // This path is used for testing. Non-testing invocations should let this constructor
+ // create a real PalmDetectionFilter
+ return;
+ }
+ std::unique_ptr<::ui::NeuralStylusPalmDetectionFilterModel> model =
+ std::make_unique<::ui::OneDeviceTrainNeuralStylusPalmDetectionFilterModel>(
+ std::vector<float>());
+ mPalmDetectionFilter =
+ std::make_unique<::ui::NeuralStylusPalmDetectionFilter>(mDeviceInfo, std::move(model),
+ mSharedPalmState.get());
+}
+
+std::vector<::ui::InProgressTouchEvdev> getTouches(const NotifyMotionArgs& args,
+ const AndroidPalmFilterDeviceInfo& deviceInfo,
+ const SlotState& oldSlotState,
+ const SlotState& newSlotState) {
+ std::vector<::ui::InProgressTouchEvdev> touches;
+
+ for (size_t i = 0; i < args.pointerCount; i++) {
+ const int32_t pointerId = args.pointerProperties[i].id;
+ touches.emplace_back(::ui::InProgressTouchEvdev());
+ touches.back().major = args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR);
+ touches.back().minor = args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR);
+ touches.back().tool_type = getLinuxToolType(args.pointerProperties[i].toolType);
+
+ // Whether there is new information for the touch.
+ touches.back().altered = true;
+
+ // Whether the touch was cancelled. Touch events should be ignored till a
+ // new touch is initiated.
+ touches.back().was_cancelled = false;
+
+ // Whether the touch is going to be canceled.
+ touches.back().cancelled = false;
+
+ // Whether the touch is delayed at first appearance. Will not be reported yet.
+ touches.back().delayed = false;
+
+ // Whether the touch was delayed before.
+ touches.back().was_delayed = false;
+
+ // Whether the touch is held until end or no longer held.
+ touches.back().held = false;
+
+ // Whether this touch was held before being sent.
+ touches.back().was_held = false;
+
+ const int32_t resolvedAction = resolveActionForPointer(i, args.action);
+ const bool isDown = resolvedAction == AMOTION_EVENT_ACTION_POINTER_DOWN ||
+ resolvedAction == AMOTION_EVENT_ACTION_DOWN;
+ touches.back().was_touching = !isDown;
+
+ const bool isUpOrCancel = resolvedAction == AMOTION_EVENT_ACTION_CANCEL ||
+ resolvedAction == AMOTION_EVENT_ACTION_UP ||
+ resolvedAction == AMOTION_EVENT_ACTION_POINTER_UP;
+
+ touches.back().x = args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X);
+ touches.back().y = args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y);
+
+ std::optional<size_t> slot = newSlotState.getSlotForPointerId(pointerId);
+ if (!slot) {
+ slot = oldSlotState.getSlotForPointerId(pointerId);
+ }
+ LOG_ALWAYS_FATAL_IF(!slot, "Could not find slot for pointer %d", pointerId);
+ touches.back().slot = *slot;
+ touches.back().tracking_id = (!isUpOrCancel) ? pointerId : -1;
+ touches.back().touching = !isUpOrCancel;
+
+ // The fields 'radius_x' and 'radius_x' are not used for palm rejection
+ touches.back().pressure = args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE);
+ touches.back().tool_code = BTN_TOOL_FINGER;
+ // The field 'orientation' is not used for palm rejection
+ // The fields 'tilt_x' and 'tilt_y' are not used for palm rejection
+ touches.back().reported_tool_type = ::ui::EventPointerType::kTouch;
+ touches.back().stylus_button = false;
+ }
+ return touches;
+}
+
+std::vector<NotifyMotionArgs> PalmRejector::processMotion(const NotifyMotionArgs& args) {
+ if (mPalmDetectionFilter == nullptr) {
+ return {args};
+ }
+ const bool skipThisEvent = args.action == AMOTION_EVENT_ACTION_HOVER_ENTER ||
+ args.action == AMOTION_EVENT_ACTION_HOVER_MOVE ||
+ args.action == AMOTION_EVENT_ACTION_HOVER_EXIT ||
+ args.action == AMOTION_EVENT_ACTION_BUTTON_PRESS ||
+ args.action == AMOTION_EVENT_ACTION_BUTTON_RELEASE ||
+ args.action == AMOTION_EVENT_ACTION_SCROLL;
+ if (skipThisEvent) {
+ // Lets not process hover events, button events, or scroll for now.
+ return {args};
+ }
+ if (args.action == AMOTION_EVENT_ACTION_DOWN) {
+ mSuppressedPointerIds.clear();
+ }
+ std::bitset<::ui::kNumTouchEvdevSlots> slotsToHold;
+ std::bitset<::ui::kNumTouchEvdevSlots> slotsToSuppress;
+
+ // Store the slot state before we call getTouches and update it. This way, we can find
+ // the slots that have been removed due to the incoming event.
+ SlotState oldSlotState = mSlotState;
+ mSlotState.update(args);
+ std::vector<::ui::InProgressTouchEvdev> touches =
+ getTouches(args, mDeviceInfo, oldSlotState, mSlotState);
+ ::base::TimeTicks chromeTimestamp = toChromeTimestamp(args.eventTime);
+
+ mPalmDetectionFilter->Filter(touches, chromeTimestamp, &slotsToHold, &slotsToSuppress);
+
+ // Now that we know which slots should be suppressed, let's convert those to pointer id's.
+ std::set<int32_t> oldSuppressedIds;
+ std::swap(oldSuppressedIds, mSuppressedPointerIds);
+ for (size_t i = 0; i < args.pointerCount; i++) {
+ const int32_t pointerId = args.pointerProperties[i].id;
+ std::optional<size_t> slot = oldSlotState.getSlotForPointerId(pointerId);
+ if (!slot) {
+ slot = mSlotState.getSlotForPointerId(pointerId);
+ LOG_ALWAYS_FATAL_IF(!slot, "Could not find slot for pointer id %" PRId32, pointerId);
+ }
+ if (slotsToSuppress.test(*slot)) {
+ mSuppressedPointerIds.insert(pointerId);
+ }
+ }
+
+ std::vector<NotifyMotionArgs> argsWithoutUnwantedPointers =
+ cancelSuppressedPointers(args, oldSuppressedIds, mSuppressedPointerIds);
+ for (const NotifyMotionArgs& checkArgs : argsWithoutUnwantedPointers) {
+ LOG_ALWAYS_FATAL_IF(checkArgs.action == ACTION_UNKNOWN, "%s", checkArgs.dump().c_str());
+ }
+
+ if (mSuppressedPointerIds != oldSuppressedIds) {
+ if (argsWithoutUnwantedPointers.size() != 1 ||
+ argsWithoutUnwantedPointers[0].pointerCount != args.pointerCount) {
+ ALOGI("Palm detected, removing pointer ids %s from %s",
+ dumpSet(mSuppressedPointerIds).c_str(), args.dump().c_str());
+ }
+ }
+
+ return argsWithoutUnwantedPointers;
+}
+
+const AndroidPalmFilterDeviceInfo& PalmRejector::getPalmFilterDeviceInfo() {
+ return mDeviceInfo;
+}
+
+std::string PalmRejector::dump() const {
+ std::string out;
+ out += "mDeviceInfo:\n";
+ out += addPrefix(dumpDeviceInfo(mDeviceInfo), " ");
+ out += "mSlotState:\n";
+ out += addPrefix(mSlotState.dump(), " ");
+ out += "mSuppressedPointerIds: ";
+ out += dumpSet(mSuppressedPointerIds) + "\n";
+ return out;
+}
+
+} // namespace android
diff --git a/services/inputflinger/UnwantedInteractionBlocker.h b/services/inputflinger/UnwantedInteractionBlocker.h
new file mode 100644
index 0000000..14068fd
--- /dev/null
+++ b/services/inputflinger/UnwantedInteractionBlocker.h
@@ -0,0 +1,153 @@
+/*
+ * 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.
+ * 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 <map>
+#include <set>
+
+#include "include/UnwantedInteractionBlockerInterface.h"
+#include "ui/events/ozone/evdev/touch_filter/neural_stylus_palm_detection_filter_util.h"
+#include "ui/events/ozone/evdev/touch_filter/palm_detection_filter.h"
+
+namespace android {
+
+// --- Functions for manipulation of event streams
+
+struct AndroidPalmFilterDeviceInfo : ::ui::PalmFilterDeviceInfo {
+ // Additional fields from 'TouchEventConverterEvdev', added here for convenience
+ int32_t touch_major_res = 1; // info.GetAbsInfoByCode(ABS_MT_TOUCH_MAJOR).resolution;
+ int32_t touch_minor_res = 1; // info.GetAbsInfoByCode(ABS_MT_TOUCH_MINOR).resolution;
+
+ auto operator<=>(const AndroidPalmFilterDeviceInfo&) const = default;
+};
+
+std::optional<AndroidPalmFilterDeviceInfo> createPalmFilterDeviceInfo(
+ const InputDeviceInfo& deviceInfo);
+
+static constexpr int32_t ACTION_UNKNOWN = -1;
+
+NotifyMotionArgs removePointerIds(const NotifyMotionArgs& args,
+ const std::set<int32_t>& pointerIds);
+
+std::vector<NotifyMotionArgs> cancelSuppressedPointers(
+ const NotifyMotionArgs& args, const std::set<int32_t>& oldSuppressedPointerIds,
+ const std::set<int32_t>& newSuppressedPointerIds);
+
+std::string toString(const ::ui::InProgressTouchEvdev& touch);
+
+// --- Main classes and interfaces ---
+
+class PalmRejector;
+
+// --- Implementations ---
+
+/**
+ * Implementation of the UnwantedInteractionBlockerInterface.
+ * Represents a separate stage of input processing. All of the input events go through this stage.
+ * Acts as a passthrough for all input events except for motion events.
+ *
+ * The events of motion type are sent to PalmRejectors. PalmRejectors detect unwanted touches,
+ * and emit input streams with the bad pointers removed.
+ */
+class UnwantedInteractionBlocker : public UnwantedInteractionBlockerInterface {
+public:
+ explicit UnwantedInteractionBlocker(InputListenerInterface& listener);
+ explicit UnwantedInteractionBlocker(InputListenerInterface& listener, bool enablePalmRejection);
+
+ void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
+ void notifyKey(const NotifyKeyArgs* args) override;
+ void notifyMotion(const NotifyMotionArgs* args) override;
+ void notifySwitch(const NotifySwitchArgs* args) override;
+ void notifySensor(const NotifySensorArgs* args) override;
+ void notifyVibratorState(const NotifyVibratorStateArgs* args) override;
+ void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
+ void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
+
+ void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override;
+ void dump(std::string& dump) override;
+ void monitor() override;
+
+ ~UnwantedInteractionBlocker();
+
+private:
+ // The next stage to pass input events to
+ InputListenerInterface& mListener;
+ const bool mEnablePalmRejection;
+
+ // Detect and reject unwanted palms on screen
+ // Use a separate palm rejector for every touch device.
+ std::map<int32_t /*deviceId*/, PalmRejector> mPalmRejectors;
+};
+
+class SlotState {
+public:
+ /**
+ * Update the state using the new information provided in the NotifyMotionArgs
+ */
+ void update(const NotifyMotionArgs& args);
+ std::optional<size_t> getSlotForPointerId(int32_t pointerId) const;
+ std::string dump() const;
+
+private:
+ // Process a pointer with the provided action, and return the slot associated with it
+ void processPointerId(int32_t pointerId, int32_t action);
+ // The map from tracking id to slot state. Since the PalmRejectionFilter works close to the
+ // evdev level, the only way to tell it about UP or CANCEL events is by sending tracking id = -1
+ // to the appropriate touch slot. So we need to reconstruct the original slot.
+ // The two collections below must always be in-sync.
+ // Use std::map instead of std::unordered_map because we rely on these collections being
+ // ordered. It also has better space efficiency than unordered_map because we only have a few
+ // pointers most of the time.
+ std::map<int32_t /*pointerId*/, size_t /*slot*/> mSlotsByPointerId;
+ std::map<size_t /*slot*/, int32_t /*pointerId */> mPointerIdsBySlot;
+
+ size_t findUnusedSlot() const;
+};
+
+/**
+ * Convert an Android event to a linux-like 'InProgressTouchEvdev'. The provided SlotState's
+ * are used to figure out which slot does each pointer belong to.
+ */
+std::vector<::ui::InProgressTouchEvdev> getTouches(const NotifyMotionArgs& args,
+ const AndroidPalmFilterDeviceInfo& deviceInfo,
+ const SlotState& oldSlotState,
+ const SlotState& newSlotState);
+
+class PalmRejector {
+public:
+ explicit PalmRejector(const AndroidPalmFilterDeviceInfo& info,
+ std::unique_ptr<::ui::PalmDetectionFilter> filter = nullptr);
+ std::vector<NotifyMotionArgs> processMotion(const NotifyMotionArgs& args);
+
+ // Get the device info of this device, for comparison purposes
+ const AndroidPalmFilterDeviceInfo& getPalmFilterDeviceInfo();
+ std::string dump() const;
+
+private:
+ PalmRejector(const PalmRejector&) = delete;
+ PalmRejector& operator=(const PalmRejector&) = delete;
+
+ std::unique_ptr<::ui::SharedPalmDetectionFilterState> mSharedPalmState;
+ AndroidPalmFilterDeviceInfo mDeviceInfo;
+ std::unique_ptr<::ui::PalmDetectionFilter> mPalmDetectionFilter;
+ std::set<int32_t> mSuppressedPointerIds;
+
+ // Used to help convert an Android touch stream to Linux input stream.
+ SlotState mSlotState;
+};
+
+} // namespace android
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index d1982fc..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;
@@ -417,20 +417,6 @@
return event;
}
-std::optional<int32_t> findMonitorPidByToken(
- const std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay,
- const sp<IBinder>& token) {
- for (const auto& it : monitorsByDisplay) {
- const std::vector<Monitor>& monitors = it.second;
- for (const Monitor& monitor : monitors) {
- if (monitor.inputChannel->getConnectionToken() == token) {
- return monitor.pid;
- }
- }
- }
- return std::nullopt;
-}
-
bool shouldReportMetricsForConnection(const Connection& connection) {
// Do not keep track of gesture monitors. They receive every event and would disproportionately
// affect the statistics.
@@ -548,6 +534,7 @@
mAppSwitchSawKeyDown(false),
mAppSwitchDueTime(LONG_LONG_MAX),
mNextUnblockedEvent(nullptr),
+ mMonitorDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT),
mDispatchEnabled(false),
mDispatchFrozen(false),
mInputFilterEnabled(false),
@@ -707,8 +694,13 @@
return LONG_LONG_MIN;
}
-std::chrono::nanoseconds InputDispatcher::getDispatchingTimeoutLocked(const sp<IBinder>& token) {
- sp<WindowInfoHandle> window = getWindowHandleLocked(token);
+std::chrono::nanoseconds InputDispatcher::getDispatchingTimeoutLocked(
+ const sp<Connection>& connection) {
+ if (connection->monitor) {
+ return mMonitorDispatchingTimeout;
+ }
+ const sp<WindowInfoHandle> window =
+ getWindowHandleLocked(connection->inputChannel->getConnectionToken());
if (window != nullptr) {
return window->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
}
@@ -942,15 +934,16 @@
return true;
}
- // Alternatively, maybe there's a gesture monitor that could handle this event
- for (const auto& monitor : getValueByKey(mGestureMonitorsByDisplay, displayId)) {
- sp<Connection> connection =
- getConnectionLocked(monitor.inputChannel->getConnectionToken());
+ // Alternatively, maybe there's a spy window that could handle this event.
+ const std::vector<sp<WindowInfoHandle>> touchedSpies =
+ findTouchedSpyWindowsAtLocked(displayId, x, y, isStylus);
+ for (const auto& windowHandle : touchedSpies) {
+ const sp<Connection> connection = getConnectionLocked(windowHandle->getToken());
if (connection != nullptr && connection->responsive) {
- // This monitor could take more input. Drop all events preceding this
- // event, so that gesture monitor could get a chance to receive the stream
+ // This spy window could take more input. Drop all events preceding this
+ // event, so that the spy window can get a chance to receive the stream.
ALOGW("Pruning the input queue because %s is unresponsive, but we have a "
- "responsive gesture monitor that may handle the event",
+ "responsive spy window that may handle the event.",
mAwaitedFocusedApplication->getName().c_str());
return true;
}
@@ -1994,7 +1987,7 @@
TouchState tempTouchState;
if (const auto it = mTouchStatesByDisplay.find(displayId); it != mTouchStatesByDisplay.end()) {
oldState = &(it->second);
- tempTouchState.copyFrom(*oldState);
+ tempTouchState = *oldState;
}
bool isSplit = tempTouchState.split;
@@ -2098,6 +2091,13 @@
newTouchedWindows.insert(newTouchedWindows.begin(), newTouchedWindowHandle);
}
+ if (newTouchedWindows.empty()) {
+ ALOGI("Dropping event because there is no touchable window at (%d, %d) on display %d.",
+ x, y, displayId);
+ injectionResult = InputEventInjectionResult::FAILED;
+ goto Failed;
+ }
+
for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) {
const WindowInfo& info = *windowHandle->getInfo();
@@ -2166,23 +2166,6 @@
tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, pointerIds);
}
-
- const std::vector<Monitor> newGestureMonitors = isDown
- ? selectResponsiveMonitorsLocked(
- getValueByKey(mGestureMonitorsByDisplay, displayId))
- : std::vector<Monitor>{};
-
- if (newTouchedWindows.empty() && newGestureMonitors.empty() &&
- tempTouchState.gestureMonitors.empty()) {
- ALOGI("Dropping event because there is no touchable window or gesture monitor at "
- "(%d, %d) in display %" PRId32 ".",
- x, y, displayId);
- injectionResult = InputEventInjectionResult::FAILED;
- goto Failed;
- }
-
- tempTouchState.addGestureMonitors(newGestureMonitors);
-
} else {
/* Case 2: Pointer move, up, cancel or non-splittable pointer down. */
@@ -2284,40 +2267,34 @@
}
}
- // Check permission to inject into all touched foreground windows and ensure there
- // is at least one touched foreground window.
- {
- bool haveForegroundOrSpyWindow = false;
- for (const TouchedWindow& touchedWindow : tempTouchState.windows) {
- const bool isForeground =
- (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) != 0;
- if (touchedWindow.windowHandle->getInfo()->isSpy()) {
- haveForegroundOrSpyWindow = true;
- LOG_ALWAYS_FATAL_IF(isForeground,
- "Spy window cannot be dispatched as a foreground window.");
- }
- if (isForeground) {
- haveForegroundOrSpyWindow = true;
- if (!checkInjectionPermission(touchedWindow.windowHandle, entry.injectionState)) {
- injectionResult = InputEventInjectionResult::PERMISSION_DENIED;
- injectionPermission = INJECTION_PERMISSION_DENIED;
- goto Failed;
- }
- }
- }
- bool hasGestureMonitor = !tempTouchState.gestureMonitors.empty();
- if (!haveForegroundOrSpyWindow && !hasGestureMonitor) {
- ALOGI("Dropping event because there is no touched window in display "
- "%" PRId32 " or gesture monitor to receive it.",
- displayId);
- injectionResult = InputEventInjectionResult::FAILED;
- goto Failed;
- }
-
- // Permission granted to injection into all touched foreground windows.
- injectionPermission = INJECTION_PERMISSION_GRANTED;
+ // Ensure that we have at least one foreground or spy window. It's possible that we dropped some
+ // of the touched windows we previously found if they became paused or unresponsive or were
+ // removed.
+ if (std::none_of(tempTouchState.windows.begin(), tempTouchState.windows.end(),
+ [](const TouchedWindow& touchedWindow) {
+ return (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) != 0 ||
+ touchedWindow.windowHandle->getInfo()->isSpy();
+ })) {
+ ALOGI("Dropping event because there is no touched window on display %d to receive it.",
+ displayId);
+ injectionResult = InputEventInjectionResult::FAILED;
+ goto Failed;
}
+ // Check permission to inject into all touched foreground windows.
+ if (std::any_of(tempTouchState.windows.begin(), tempTouchState.windows.end(),
+ [this, &entry](const TouchedWindow& touchedWindow) {
+ return (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) != 0 &&
+ !checkInjectionPermission(touchedWindow.windowHandle,
+ entry.injectionState);
+ })) {
+ injectionResult = InputEventInjectionResult::PERMISSION_DENIED;
+ injectionPermission = INJECTION_PERMISSION_DENIED;
+ goto Failed;
+ }
+ // Permission granted to inject into all touched foreground windows.
+ injectionPermission = INJECTION_PERMISSION_GRANTED;
+
// Check whether windows listening for outside touches are owned by the same UID. If it is
// set the policy flag that we will not reveal coordinate information to this window.
if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
@@ -2374,10 +2351,6 @@
touchedWindow.pointerIds, inputTargets);
}
- for (const auto& monitor : tempTouchState.gestureMonitors) {
- addMonitoringTargetLocked(monitor, displayId, inputTargets);
- }
-
// Drop the outside or hover touch windows since we will not care about them
// in the next iteration.
tempTouchState.filterNonAsIsTouchWindows();
@@ -2578,32 +2551,21 @@
void InputDispatcher::addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets,
int32_t displayId) {
- std::unordered_map<int32_t, std::vector<Monitor>>::const_iterator it =
- mGlobalMonitorsByDisplay.find(displayId);
+ auto monitorsIt = mGlobalMonitorsByDisplay.find(displayId);
+ if (monitorsIt == mGlobalMonitorsByDisplay.end()) return;
- if (it != mGlobalMonitorsByDisplay.end()) {
- const std::vector<Monitor>& monitors = it->second;
- for (const Monitor& monitor : monitors) {
- addMonitoringTargetLocked(monitor, displayId, inputTargets);
+ for (const Monitor& monitor : selectResponsiveMonitorsLocked(monitorsIt->second)) {
+ InputTarget target;
+ target.inputChannel = monitor.inputChannel;
+ target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
+ if (const auto& it = mDisplayInfos.find(displayId); it != mDisplayInfos.end()) {
+ target.displayTransform = it->second.transform;
}
+ target.setDefaultPointerTransform(target.displayTransform);
+ inputTargets.push_back(target);
}
}
-void InputDispatcher::addMonitoringTargetLocked(const Monitor& monitor, int32_t displayId,
- std::vector<InputTarget>& inputTargets) {
- InputTarget target;
- target.inputChannel = monitor.inputChannel;
- target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
- ui::Transform t;
- if (const auto& it = mDisplayInfos.find(displayId); it != mDisplayInfos.end()) {
- const auto& displayTransform = it->second.transform;
- target.displayTransform = displayTransform;
- t = displayTransform;
- }
- target.setDefaultPointerTransform(t);
- inputTargets.push_back(target);
-}
-
bool InputDispatcher::checkInjectionPermission(const sp<WindowInfoHandle>& windowHandle,
const InjectionState* injectionState) {
if (injectionState &&
@@ -3205,8 +3167,7 @@
while (connection->status == Connection::Status::NORMAL && !connection->outboundQueue.empty()) {
DispatchEntry* dispatchEntry = connection->outboundQueue.front();
dispatchEntry->deliveryTime = currentTime;
- const std::chrono::nanoseconds timeout =
- getDispatchingTimeoutLocked(connection->inputChannel->getConnectionToken());
+ const std::chrono::nanoseconds timeout = getDispatchingTimeoutLocked(connection);
dispatchEntry->timeoutTime = currentTime + timeout.count();
// Publish the event.
@@ -3568,15 +3529,7 @@
void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked(
const CancelationOptions& options) {
- synthesizeCancelationEventsForMonitorsLocked(options, mGlobalMonitorsByDisplay);
- synthesizeCancelationEventsForMonitorsLocked(options, mGestureMonitorsByDisplay);
-}
-
-void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked(
- const CancelationOptions& options,
- std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) {
- for (const auto& it : monitorsByDisplay) {
- const std::vector<Monitor>& monitors = it.second;
+ for (const auto& [_, monitors] : mGlobalMonitorsByDisplay) {
for (const Monitor& monitor : monitors) {
synthesizeCancelationEventsForInputChannelLocked(monitor.inputChannel, options);
}
@@ -4950,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
@@ -4974,6 +4946,7 @@
if (needWake) {
mLooper->wake();
}
+ return true;
}
void InputDispatcher::setMaximumObscuringOpacityForTouch(float opacity) {
@@ -5261,22 +5234,16 @@
dump += INDENT "Displays: <none>\n";
}
- if (!mGlobalMonitorsByDisplay.empty() || !mGestureMonitorsByDisplay.empty()) {
- for (auto& it : mGlobalMonitorsByDisplay) {
- const std::vector<Monitor>& monitors = it.second;
- dump += StringPrintf(INDENT "Global monitors in display %" PRId32 ":\n", it.first);
- dumpMonitors(dump, monitors);
- }
- for (auto& it : mGestureMonitorsByDisplay) {
- const std::vector<Monitor>& monitors = it.second;
- dump += StringPrintf(INDENT "Gesture monitors in display %" PRId32 ":\n", it.first);
+ if (!mGlobalMonitorsByDisplay.empty()) {
+ for (const auto& [displayId, monitors] : mGlobalMonitorsByDisplay) {
+ dump += StringPrintf(INDENT "Global monitors on display %d:\n", displayId);
dumpMonitors(dump, monitors);
}
} else {
- dump += INDENT "Monitors: <none>\n";
+ dump += INDENT "Global Monitors: <none>\n";
}
- nsecs_t currentTime = now();
+ const nsecs_t currentTime = now();
// Dump recently dispatched or dropped events from oldest to newest.
if (!mRecentQueue.empty()) {
@@ -5434,7 +5401,6 @@
}
Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputMonitor(int32_t displayId,
- bool isGestureMonitor,
const std::string& name,
int32_t pid) {
std::shared_ptr<InputChannel> serverChannel;
@@ -5463,13 +5429,9 @@
std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback,
this, std::placeholders::_1, token);
- auto& monitorsByDisplay =
- isGestureMonitor ? mGestureMonitorsByDisplay : mGlobalMonitorsByDisplay;
- monitorsByDisplay[displayId].emplace_back(serverChannel, pid);
+ mGlobalMonitorsByDisplay[displayId].emplace_back(serverChannel, pid);
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, new LooperEventCallback(callback), nullptr);
- ALOGI("Created monitor %s for display %" PRId32 ", gesture=%s, pid=%" PRId32, name.c_str(),
- displayId, toString(isGestureMonitor), pid);
}
// Wake the looper because some connections have changed.
@@ -5517,26 +5479,14 @@
}
void InputDispatcher::removeMonitorChannelLocked(const sp<IBinder>& connectionToken) {
- removeMonitorChannelLocked(connectionToken, mGlobalMonitorsByDisplay);
- removeMonitorChannelLocked(connectionToken, mGestureMonitorsByDisplay);
-}
+ for (auto it = mGlobalMonitorsByDisplay.begin(); it != mGlobalMonitorsByDisplay.end();) {
+ auto& [displayId, monitors] = *it;
+ std::erase_if(monitors, [connectionToken](const Monitor& monitor) {
+ return monitor.inputChannel->getConnectionToken() == connectionToken;
+ });
-void InputDispatcher::removeMonitorChannelLocked(
- const sp<IBinder>& connectionToken,
- std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) {
- for (auto it = monitorsByDisplay.begin(); it != monitorsByDisplay.end();) {
- std::vector<Monitor>& monitors = it->second;
- const size_t numMonitors = monitors.size();
- for (size_t i = 0; i < numMonitors; i++) {
- if (monitors[i].inputChannel->getConnectionToken() == connectionToken) {
- ALOGI("Erasing monitor %s on display %" PRId32 ", pid=%" PRId32,
- monitors[i].inputChannel->getName().c_str(), it->first, monitors[i].pid);
- monitors.erase(monitors.begin() + i);
- break;
- }
- }
if (monitors.empty()) {
- it = monitorsByDisplay.erase(it);
+ it = mGlobalMonitorsByDisplay.erase(it);
} else {
++it;
}
@@ -5544,81 +5494,45 @@
}
status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) {
- { // acquire lock
- std::scoped_lock _l(mLock);
+ std::scoped_lock _l(mLock);
- TouchState* statePtr = nullptr;
- std::shared_ptr<InputChannel> requestingChannel;
- int32_t displayId;
- int32_t deviceId;
- const std::optional<int32_t> foundGestureMonitorDisplayId =
- findGestureMonitorDisplayByTokenLocked(token);
-
- // TODO: Optimize this function for pilfering from windows when removing gesture monitors.
- if (foundGestureMonitorDisplayId) {
- // A gesture monitor has requested to pilfer pointers.
- displayId = *foundGestureMonitorDisplayId;
- auto stateIt = mTouchStatesByDisplay.find(displayId);
- if (stateIt == mTouchStatesByDisplay.end()) {
- ALOGW("Failed to pilfer pointers: no pointers on display %" PRId32 ".", displayId);
- return BAD_VALUE;
- }
- statePtr = &stateIt->second;
-
- for (const auto& monitor : statePtr->gestureMonitors) {
- if (monitor.inputChannel->getConnectionToken() == token) {
- requestingChannel = monitor.inputChannel;
- deviceId = statePtr->deviceId;
- }
- }
- } else {
- // Check if a window has requested to pilfer pointers.
- for (auto& [curDisplayId, state] : mTouchStatesByDisplay) {
- const sp<WindowInfoHandle>& windowHandle = state.getWindow(token);
- if (windowHandle != nullptr) {
- displayId = curDisplayId;
- requestingChannel = getInputChannelLocked(token);
- deviceId = state.deviceId;
- statePtr = &state;
- break;
- }
- }
- }
-
- if (requestingChannel == nullptr) {
- ALOGW("Attempted to pilfer pointers from an un-registered channel or invalid token");
- return BAD_VALUE;
- }
- TouchState& state = *statePtr;
- if (!state.down) {
- ALOGW("Attempted to pilfer points from a channel without any on-going pointer streams."
- " Ignoring.");
- return BAD_VALUE;
- }
-
- // Send cancel events to all the input channels we're stealing from.
- CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
- "input channel stole pointer stream");
- options.deviceId = deviceId;
- options.displayId = displayId;
- std::string canceledWindows;
- for (const TouchedWindow& window : state.windows) {
- std::shared_ptr<InputChannel> channel =
- getInputChannelLocked(window.windowHandle->getToken());
- if (channel != nullptr && channel->getConnectionToken() != token) {
- synthesizeCancelationEventsForInputChannelLocked(channel, options);
- canceledWindows += canceledWindows.empty() ? "[" : ", ";
- canceledWindows += channel->getName();
- }
- }
- canceledWindows += canceledWindows.empty() ? "[]" : "]";
- ALOGI("Channel %s is stealing touch from %s", requestingChannel->getName().c_str(),
- canceledWindows.c_str());
-
- // Then clear the current touch state so we stop dispatching to them as well.
- state.split = false;
- state.filterWindowsExcept(token);
+ const std::shared_ptr<InputChannel> requestingChannel = getInputChannelLocked(token);
+ if (!requestingChannel) {
+ ALOGW("Attempted to pilfer pointers from an un-registered channel or invalid token");
+ return BAD_VALUE;
}
+
+ auto [statePtr, windowPtr] = findTouchStateAndWindowLocked(token);
+ if (statePtr == nullptr || windowPtr == nullptr || !statePtr->down) {
+ ALOGW("Attempted to pilfer points from a channel without any on-going pointer streams."
+ " Ignoring.");
+ return BAD_VALUE;
+ }
+
+ TouchState& state = *statePtr;
+
+ // Send cancel events to all the input channels we're stealing from.
+ CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
+ "input channel stole pointer stream");
+ options.deviceId = state.deviceId;
+ options.displayId = state.displayId;
+ std::string canceledWindows;
+ for (const TouchedWindow& window : state.windows) {
+ const std::shared_ptr<InputChannel> channel =
+ getInputChannelLocked(window.windowHandle->getToken());
+ if (channel != nullptr && channel->getConnectionToken() != token) {
+ synthesizeCancelationEventsForInputChannelLocked(channel, options);
+ canceledWindows += canceledWindows.empty() ? "[" : ", ";
+ canceledWindows += channel->getName();
+ }
+ }
+ canceledWindows += canceledWindows.empty() ? "[]" : "]";
+ ALOGI("Channel %s is stealing touch from %s", requestingChannel->getName().c_str(),
+ canceledWindows.c_str());
+
+ // Prevent the gesture from being sent to any other windows.
+ state.filterWindowsExcept(token);
+ state.preventNewTargets = true;
return OK;
}
@@ -5672,27 +5586,17 @@
} // release lock
}
-std::optional<int32_t> InputDispatcher::findGestureMonitorDisplayByTokenLocked(
- const sp<IBinder>& token) {
- for (const auto& it : mGestureMonitorsByDisplay) {
- const std::vector<Monitor>& monitors = it.second;
+std::optional<int32_t> InputDispatcher::findMonitorPidByTokenLocked(const sp<IBinder>& token) {
+ for (const auto& [_, monitors] : mGlobalMonitorsByDisplay) {
for (const Monitor& monitor : monitors) {
if (monitor.inputChannel->getConnectionToken() == token) {
- return it.first;
+ return monitor.pid;
}
}
}
return std::nullopt;
}
-std::optional<int32_t> InputDispatcher::findMonitorPidByTokenLocked(const sp<IBinder>& token) {
- std::optional<int32_t> gesturePid = findMonitorPidByToken(mGestureMonitorsByDisplay, token);
- if (gesturePid.has_value()) {
- return gesturePid;
- }
- return findMonitorPidByToken(mGlobalMonitorsByDisplay, token);
-}
-
sp<Connection> InputDispatcher::getConnectionLocked(const sp<IBinder>& inputConnectionToken) const {
if (inputConnectionToken == nullptr) {
return nullptr;
@@ -6400,4 +6304,9 @@
mLooper->wake();
}
+void InputDispatcher::setMonitorDispatchingTimeoutForTest(std::chrono::nanoseconds timeout) {
+ std::scoped_lock _l(mLock);
+ mMonitorDispatchingTimeout = timeout;
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 7564839..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;
@@ -129,7 +129,6 @@
const std::string& name) override;
void setFocusedWindow(const android::gui::FocusRequest&) override;
base::Result<std::unique_ptr<InputChannel>> createInputMonitor(int32_t displayId,
- bool isGestureMonitor,
const std::string& name,
int32_t pid) override;
status_t removeInputChannel(const sp<IBinder>& connectionToken) override;
@@ -148,6 +147,9 @@
void cancelCurrentTouch() override;
+ // Public to allow tests to verify that a Monitor can get ANR.
+ void setMonitorDispatchingTimeoutForTest(std::chrono::nanoseconds timeout);
+
private:
enum class DropReason {
NOT_DROPPED,
@@ -257,21 +259,12 @@
std::unordered_map<sp<IBinder>, sp<Connection>, StrongPointerHash<IBinder>> mConnectionsByToken
GUARDED_BY(mLock);
- // Finds the display ID of the gesture monitor identified by the provided token.
- std::optional<int32_t> findGestureMonitorDisplayByTokenLocked(const sp<IBinder>& token)
- REQUIRES(mLock);
// Find a monitor pid by the provided token.
std::optional<int32_t> findMonitorPidByTokenLocked(const sp<IBinder>& token) REQUIRES(mLock);
// Input channels that will receive a copy of all input events sent to the provided display.
std::unordered_map<int32_t, std::vector<Monitor>> mGlobalMonitorsByDisplay GUARDED_BY(mLock);
- // Input channels that will receive pointer events that start within the corresponding display.
- // These are a bit special when compared to global monitors since they'll cause gesture streams
- // to continue even when there isn't a touched window,and have the ability to steal the rest of
- // the pointer stream in order to claim it for a system gesture.
- std::unordered_map<int32_t, std::vector<Monitor>> mGestureMonitorsByDisplay GUARDED_BY(mLock);
-
const HmacKeyManager mHmacKeyManager;
const std::array<uint8_t, 32> getSignature(const MotionEntry& motionEntry,
const DispatchEntry& dispatchEntry) const;
@@ -324,8 +317,12 @@
bool runCommandsLockedInterruptable() REQUIRES(mLock);
void postCommandLocked(Command&& command) REQUIRES(mLock);
+ // The dispatching timeout to use for Monitors.
+ std::chrono::nanoseconds mMonitorDispatchingTimeout GUARDED_BY(mLock);
+
nsecs_t processAnrsLocked() REQUIRES(mLock);
- std::chrono::nanoseconds getDispatchingTimeoutLocked(const sp<IBinder>& token) REQUIRES(mLock);
+ std::chrono::nanoseconds getDispatchingTimeoutLocked(const sp<Connection>& connection)
+ REQUIRES(mLock);
// Input filter processing.
bool shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args) REQUIRES(mLock);
@@ -523,7 +520,6 @@
sp<android::gui::WindowInfoHandle> mLastHoverWindowHandle GUARDED_BY(mLock);
void cancelEventsForAnrLocked(const sp<Connection>& connection) REQUIRES(mLock);
- nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime) REQUIRES(mLock);
// If a focused application changes, we should stop counting down the "no focused window" time,
// because we will have no way of knowing when the previous application actually added a window.
// This also means that we will miss cases like pulling down notification shade when the
@@ -544,8 +540,6 @@
void addWindowTargetLocked(const sp<android::gui::WindowInfoHandle>& windowHandle,
int32_t targetFlags, BitSet32 pointerIds,
std::vector<InputTarget>& inputTargets) REQUIRES(mLock);
- void addMonitoringTargetLocked(const Monitor& monitor, int32_t displayId,
- std::vector<InputTarget>& inputTargets) REQUIRES(mLock);
void addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, int32_t displayId)
REQUIRES(mLock);
void pokeUserActivityLocked(const EventEntry& eventEntry) REQUIRES(mLock);
@@ -611,9 +605,6 @@
REQUIRES(mLock);
void synthesizeCancelationEventsForMonitorsLocked(const CancelationOptions& options)
REQUIRES(mLock);
- void synthesizeCancelationEventsForMonitorsLocked(
- const CancelationOptions& options,
- std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) REQUIRES(mLock);
void synthesizeCancelationEventsForInputChannelLocked(
const std::shared_ptr<InputChannel>& channel, const CancelationOptions& options)
REQUIRES(mLock);
@@ -639,9 +630,6 @@
// Registration.
void removeMonitorChannelLocked(const sp<IBinder>& connectionToken) REQUIRES(mLock);
- void removeMonitorChannelLocked(
- const sp<IBinder>& connectionToken,
- std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) REQUIRES(mLock);
status_t removeInputChannelLocked(const sp<IBinder>& connectionToken, bool notify)
REQUIRES(mLock);
diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp
index 08c7826..b63fe10 100644
--- a/services/inputflinger/dispatcher/TouchState.cpp
+++ b/services/inputflinger/dispatcher/TouchState.cpp
@@ -25,29 +25,8 @@
namespace android::inputdispatcher {
-TouchState::TouchState()
- : down(false), split(false), deviceId(-1), source(0), displayId(ADISPLAY_ID_NONE) {}
-
-TouchState::~TouchState() {}
-
void TouchState::reset() {
- down = false;
- split = false;
- deviceId = -1;
- source = 0;
- displayId = ADISPLAY_ID_NONE;
- windows.clear();
- gestureMonitors.clear();
-}
-
-void TouchState::copyFrom(const TouchState& other) {
- down = other.down;
- split = other.split;
- deviceId = other.deviceId;
- source = other.source;
- displayId = other.displayId;
- windows = other.windows;
- gestureMonitors = other.gestureMonitors;
+ *this = TouchState();
}
void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle, int32_t targetFlags,
@@ -68,6 +47,8 @@
}
}
+ if (preventNewTargets) return; // Don't add new TouchedWindows.
+
TouchedWindow touchedWindow;
touchedWindow.windowHandle = windowHandle;
touchedWindow.targetFlags = targetFlags;
@@ -75,13 +56,6 @@
windows.push_back(touchedWindow);
}
-void TouchState::addGestureMonitors(const std::vector<Monitor>& newMonitors) {
- const size_t newSize = gestureMonitors.size() + newMonitors.size();
- gestureMonitors.reserve(newSize);
- gestureMonitors.insert(std::end(gestureMonitors), std::begin(newMonitors),
- std::end(newMonitors));
-}
-
void TouchState::removeWindowByToken(const sp<IBinder>& token) {
for (size_t i = 0; i < windows.size(); i++) {
if (windows[i].windowHandle->getToken() == token) {
diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h
index 83ca901..9efb280 100644
--- a/services/inputflinger/dispatcher/TouchState.h
+++ b/services/inputflinger/dispatcher/TouchState.h
@@ -29,22 +29,26 @@
namespace inputdispatcher {
struct TouchState {
- bool down;
- bool split;
- int32_t deviceId; // id of the device that is currently down, others are rejected
- uint32_t source; // source of the device that is current down, others are rejected
- int32_t displayId; // id to the display that currently has a touch, others are rejected
+ bool down = false;
+ bool split = false;
+ bool preventNewTargets = false;
+
+ // id of the device that is currently down, others are rejected
+ int32_t deviceId = -1;
+ // source of the device that is current down, others are rejected
+ uint32_t source = 0;
+ // id to the display that currently has a touch, others are rejected
+ int32_t displayId = ADISPLAY_ID_NONE;
+
std::vector<TouchedWindow> windows;
- std::vector<Monitor> gestureMonitors;
+ TouchState() = default;
+ ~TouchState() = default;
+ TouchState& operator=(const TouchState&) = default;
- TouchState();
- ~TouchState();
void reset();
- void copyFrom(const TouchState& other);
void addOrUpdateWindow(const sp<android::gui::WindowInfoHandle>& windowHandle,
int32_t targetFlags, BitSet32 pointerIds);
- void addGestureMonitors(const std::vector<Monitor>& monitors);
void removeWindowByToken(const sp<IBinder>& token);
void filterNonAsIsTouchWindows();
void filterWindowsExcept(const sp<IBinder>& token);
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 16a6f16..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.
@@ -169,16 +171,14 @@
const std::string& name) = 0;
/**
- * Creates an input channel to be used to monitor input events.
+ * Creates an input channel to be used to monitor all input events on a display.
*
* Each monitor must target a specific display and will only receive input events sent to that
- * display. If the monitor is a gesture monitor, it will only receive pointer events on the
- * targeted display.
+ * display.
*
* This method may be called on any thread (usually by the input manager).
*/
virtual base::Result<std::unique_ptr<InputChannel>> createInputMonitor(int32_t displayId,
- bool gestureMonitor,
const std::string& name,
int32_t pid) = 0;
diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h
index db63104..dff5894 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -142,6 +142,8 @@
bool operator==(const NotifyMotionArgs& rhs) const;
void notify(InputListenerInterface& listener) const override;
+
+ std::string dump() const;
};
/* Describes a sensor event. */
diff --git a/services/inputflinger/include/UnwantedInteractionBlockerInterface.h b/services/inputflinger/include/UnwantedInteractionBlockerInterface.h
new file mode 100644
index 0000000..2327266
--- /dev/null
+++ b/services/inputflinger/include/UnwantedInteractionBlockerInterface.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ * 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 "InputListener.h"
+
+namespace android {
+
+/**
+ * Base interface for an InputListener stage.
+ * Blocks unintentional input events. Not thread safe. Must be called from the same
+ * thread. All work is performed on the calling threads.
+ */
+class UnwantedInteractionBlockerInterface : public InputListenerInterface {
+public:
+ /* Notifies the input reader policy that some input devices have changed
+ * and provides information about all current input devices.
+ * Important! This call should happen on the same thread as the calls to the
+ * InputListenerInterface methods.
+ * That is, same thread should call 'notifyMotion' and 'notifyInputDevicesChanged' and
+ * 'notifyDeviceReset'. If this architecture changes, we will need to make the implementation
+ * of this interface thread-safe.
+ */
+ virtual void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) = 0;
+
+ /**
+ * Dump the state of the interaction blocker.
+ * This method may be called on any thread (usually by the input manager).
+ */
+ virtual void dump(std::string& dump) = 0;
+
+ /* Called by the heatbeat to ensures that the dispatcher has not deadlocked. */
+ virtual void monitor() = 0;
+
+ UnwantedInteractionBlockerInterface() {}
+ ~UnwantedInteractionBlockerInterface() override {}
+};
+
+} // namespace android
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index d19dbaf..9d200bd 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -49,6 +49,7 @@
"LatencyTracker_test.cpp",
"TestInputListener.cpp",
"UinputDevice.cpp",
+ "UnwantedInteractionBlocker_test.cpp",
],
aidl: {
include_dirs: [
@@ -58,7 +59,6 @@
},
static_libs: [
"libc++fs",
- "libinput",
],
require_root: true,
test_suites: ["device-tests"],
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index aa2f832..872882e 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -17,6 +17,7 @@
#include "../dispatcher/InputDispatcher.h"
#include <android-base/properties.h>
+#include <android-base/silent_death_test.h>
#include <android-base/stringprintf.h>
#include <android-base/thread_annotations.h>
#include <binder/Binder.h>
@@ -1126,6 +1127,16 @@
expectedFlags);
}
+ void consumeMotionOutsideWithZeroedCoords(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
+ int32_t expectedFlags = 0) {
+ InputEvent* event = consume();
+ ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType());
+ const MotionEvent& motionEvent = static_cast<MotionEvent&>(*event);
+ EXPECT_EQ(AMOTION_EVENT_ACTION_OUTSIDE, motionEvent.getActionMasked());
+ EXPECT_EQ(0.f, motionEvent.getRawPointerCoords(0)->getX());
+ EXPECT_EQ(0.f, motionEvent.getRawPointerCoords(0)->getY());
+ }
+
void consumeFocusEvent(bool hasFocus, bool inTouchMode = true) {
ASSERT_NE(mInputReceiver, nullptr)
<< "Cannot consume events from a window with no receiver";
@@ -2766,9 +2777,9 @@
class FakeMonitorReceiver {
public:
FakeMonitorReceiver(const std::unique_ptr<InputDispatcher>& dispatcher, const std::string name,
- int32_t displayId, bool isGestureMonitor = false) {
+ int32_t displayId) {
base::Result<std::unique_ptr<InputChannel>> channel =
- dispatcher->createInputMonitor(displayId, isGestureMonitor, name, MONITOR_PID);
+ dispatcher->createInputMonitor(displayId, name, MONITOR_PID);
mInputReceiver = std::make_unique<FakeInputReceiver>(std::move(*channel), name);
}
@@ -2829,6 +2840,8 @@
std::unique_ptr<FakeInputReceiver> mInputReceiver;
};
+using InputDispatcherMonitorTest = InputDispatcherTest;
+
/**
* Two entities that receive touch: A window, and a global monitor.
* The touch goes to the window, and then the window disappears.
@@ -2837,14 +2850,12 @@
* 1. foregroundWindow
* 2. monitor <-- global monitor (doesn't observe z order, receives all events)
*/
-TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_GlobalMonitorTouchIsCanceled) {
+TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDisappears) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
- FakeMonitorReceiver monitor =
- FakeMonitorReceiver(mDispatcher, "GlobalMonitor", ADISPLAY_ID_DEFAULT,
- false /*isGestureMonitor*/);
+ FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -2880,15 +2891,13 @@
monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
}
-// Tests for gesture monitors
-TEST_F(InputDispatcherTest, GestureMonitor_ReceivesMotionEvents) {
+TEST_F(InputDispatcherMonitorTest, ReceivesMotionEvents) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
- FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
- true /*isGestureMonitor*/);
+ FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
@@ -2897,71 +2906,34 @@
monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
}
-TEST_F(InputDispatcherTest, GestureMonitor_DoesNotReceiveKeyEvents) {
- std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+TEST_F(InputDispatcherMonitorTest, MonitorCannotPilferPointers) {
+ FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
- mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
- window->setFocusable(true);
-
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
- setFocusedWindow(window);
-
- window->consumeFocusEvent(true);
-
- FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
- true /*isGestureMonitor*/);
-
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT))
- << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
- window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
- monitor.assertNoEvents();
-}
-
-TEST_F(InputDispatcherTest, GestureMonitor_CanPilferAfterWindowIsRemovedMidStream) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
- FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
- true /*isGestureMonitor*/);
-
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
<< "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
- window->releaseChannel();
-
- mDispatcher->pilferPointers(monitor.getToken());
+ // Pilfer pointers from the monitor.
+ // This should not do anything and the window should continue to receive events.
+ EXPECT_NE(OK, mDispatcher->pilferPointers(monitor.getToken()));
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
+ injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT))
<< "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
+
+ monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT);
+ window->consumeMotionMove(ADISPLAY_ID_DEFAULT);
}
-TEST_F(InputDispatcherTest, UnresponsiveGestureMonitor_GetsAnr) {
- FakeMonitorReceiver monitor =
- FakeMonitorReceiver(mDispatcher, "Gesture monitor", ADISPLAY_ID_DEFAULT,
- true /*isGestureMonitor*/);
-
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT));
- std::optional<uint32_t> consumeSeq = monitor.receiveEvent();
- ASSERT_TRUE(consumeSeq);
-
- mFakePolicy->assertNotifyMonitorUnresponsiveWasCalled(DISPATCHING_TIMEOUT);
- monitor.finishEvent(*consumeSeq);
- ASSERT_TRUE(mDispatcher->waitForIdle());
- mFakePolicy->assertNotifyMonitorResponsiveWasCalled();
-}
-
-// Tests for gesture monitors
-TEST_F(InputDispatcherTest, GestureMonitor_NoWindowTransform) {
+TEST_F(InputDispatcherMonitorTest, NoWindowTransform) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
@@ -2969,8 +2941,7 @@
window->setWindowOffset(20, 40);
window->setWindowTransform(0, 1, -1, 0);
- FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
- true /*isGestureMonitor*/);
+ FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
@@ -2981,15 +2952,14 @@
ASSERT_EQ(ui::Transform(), event->getTransform());
}
-TEST_F(InputDispatcherTest, GestureMonitor_NoWindow) {
+TEST_F(InputDispatcherMonitorTest, InjectionFailsWithNoWindow) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
- true /*isGestureMonitor*/);
+ FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ ASSERT_EQ(InputEventInjectionResult::FAILED,
injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
- << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ << "Injection should fail if there is a monitor, but no touchable window";
+ monitor.assertNoEvents();
}
TEST_F(InputDispatcherTest, TestMoveEvent) {
@@ -3018,91 +2988,6 @@
0 /*expectedFlags*/);
}
-TEST_F(InputDispatcherTest, GestureMonitor_SplitIfNoWindowTouched) {
- FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
- true /*isGestureMonitor*/);
-
- std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- // Create a non touch modal window that supports split touch
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
- window->setFrame(Rect(0, 0, 100, 100));
- window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
-
- // First finger down, no window touched.
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
- {100, 200}))
- << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
- window->assertNoEvents();
-
- // Second finger down on window, the window should receive touch down.
- const MotionEvent secondFingerDownEvent =
- MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
- (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- AINPUT_SOURCE_TOUCHSCREEN)
- .displayId(ADISPLAY_ID_DEFAULT)
- .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
- .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
- .x(100)
- .y(200))
- .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
- .build();
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
- InputEventInjectionSync::WAIT_FOR_RESULT))
- << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
-
- window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
- monitor.consumeMotionPointerDown(1 /* pointerIndex */);
-}
-
-TEST_F(InputDispatcherTest, GestureMonitor_NoSplitAfterPilfer) {
- FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
- true /*isGestureMonitor*/);
-
- std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- // Create a non touch modal window that supports split touch
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
- window->setFrame(Rect(0, 0, 100, 100));
- window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
-
- // First finger down, no window touched.
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
- {100, 200}))
- << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
- window->assertNoEvents();
-
- // Gesture monitor pilfer the pointers.
- mDispatcher->pilferPointers(monitor.getToken());
-
- // Second finger down on window, the window should not receive touch down.
- const MotionEvent secondFingerDownEvent =
- MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
- (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- AINPUT_SOURCE_TOUCHSCREEN)
- .displayId(ADISPLAY_ID_DEFAULT)
- .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
- .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
- .x(100)
- .y(200))
- .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
- .build();
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
- InputEventInjectionSync::WAIT_FOR_RESULT))
- << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
-
- window->assertNoEvents();
- monitor.consumeMotionPointerDown(1 /* pointerIndex */);
-}
-
/**
* Dispatcher has touch mode enabled by default. Typically, the policy overrides that value to
* the device default right away. In the test scenario, we check both the default value,
@@ -3112,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);
@@ -3128,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}}});
@@ -3141,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}}});
@@ -4442,6 +4330,17 @@
injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
WINDOW_LOCATION));
}
+
+ sp<FakeWindowHandle> addSpyWindow() {
+ sp<FakeWindowHandle> spy =
+ new FakeWindowHandle(mApplication, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
+ spy->setTrustedOverlay(true);
+ spy->setFocusable(false);
+ spy->setInputFeatures(WindowInfo::Feature::SPY);
+ spy->setDispatchingTimeout(30ms);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, mWindow}}});
+ return spy;
+ }
};
// Send a tap and respond, which should not cause an ANR.
@@ -4617,12 +4516,31 @@
mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
}
-// If an app is not responding to a key event, gesture monitors should continue to receive
+// A spy window can receive an ANR
+TEST_F(InputDispatcherSingleWindowAnr, SpyWindowAnr) {
+ sp<FakeWindowHandle> spy = addSpyWindow();
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ WINDOW_LOCATION));
+ mWindow->consumeMotionDown();
+
+ std::optional<uint32_t> sequenceNum = spy->receiveEvent(); // ACTION_DOWN
+ ASSERT_TRUE(sequenceNum);
+ const std::chrono::duration timeout = spy->getDispatchingTimeout(DISPATCHING_TIMEOUT);
+ mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, spy->getToken());
+
+ spy->finishEvent(*sequenceNum);
+ spy->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL, ADISPLAY_ID_DEFAULT,
+ 0 /*flags*/);
+ ASSERT_TRUE(mDispatcher->waitForIdle());
+ mFakePolicy->assertNotifyWindowResponsiveWasCalled(spy->getToken());
+}
+
+// If an app is not responding to a key event, spy windows should continue to receive
// new motion events
-TEST_F(InputDispatcherSingleWindowAnr, GestureMonitors_ReceiveEventsDuringAppAnrOnKey) {
- FakeMonitorReceiver monitor =
- FakeMonitorReceiver(mDispatcher, "Gesture monitor", ADISPLAY_ID_DEFAULT,
- true /*isGestureMonitor*/);
+TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnKey) {
+ sp<FakeWindowHandle> spy = addSpyWindow();
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT));
@@ -4633,44 +4551,64 @@
const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
- // New tap will go to the gesture monitor, but not to the window
+ // New tap will go to the spy window, but not to the window
tapOnWindow();
- monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
- monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
+ spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT); // still the previous motion
mDispatcher->waitForIdle();
mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken());
mWindow->assertNoEvents();
- monitor.assertNoEvents();
+ spy->assertNoEvents();
}
-// If an app is not responding to a motion event, gesture monitors should continue to receive
+// If an app is not responding to a motion event, spy windows should continue to receive
// new motion events
-TEST_F(InputDispatcherSingleWindowAnr, GestureMonitors_ReceiveEventsDuringAppAnrOnMotion) {
- FakeMonitorReceiver monitor =
- FakeMonitorReceiver(mDispatcher, "Gesture monitor", ADISPLAY_ID_DEFAULT,
- true /*isGestureMonitor*/);
+TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnMotion) {
+ sp<FakeWindowHandle> spy = addSpyWindow();
tapOnWindow();
- monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
- monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
+ spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
mWindow->consumeMotionDown();
// Stuck on the ACTION_UP
const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow->getToken());
- // New tap will go to the gesture monitor, but not to the window
+ // New tap will go to the spy window, but not to the window
tapOnWindow();
- monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
- monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT);
+ spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
mWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); // still the previous motion
mDispatcher->waitForIdle();
mFakePolicy->assertNotifyWindowResponsiveWasCalled(mWindow->getToken());
mWindow->assertNoEvents();
- monitor.assertNoEvents();
+ spy->assertNoEvents();
+}
+
+TEST_F(InputDispatcherSingleWindowAnr, UnresponsiveMonitorAnr) {
+ mDispatcher->setMonitorDispatchingTimeoutForTest(30ms);
+
+ FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ WINDOW_LOCATION));
+
+ mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ const std::optional<uint32_t> consumeSeq = monitor.receiveEvent();
+ ASSERT_TRUE(consumeSeq);
+
+ mFakePolicy->assertNotifyMonitorUnresponsiveWasCalled(30ms);
+
+ monitor.finishEvent(*consumeSeq);
+ monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT);
+
+ ASSERT_TRUE(mDispatcher->waitForIdle());
+ mFakePolicy->assertNotifyMonitorResponsiveWasCalled();
}
// If a window is unresponsive, then you get anr. if the window later catches up and starts to
@@ -5687,11 +5625,7 @@
touch();
- InputEvent* event = w->consume();
- ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType());
- MotionEvent& motionEvent = static_cast<MotionEvent&>(*event);
- EXPECT_EQ(0.0f, motionEvent.getRawPointerCoords(0)->getX());
- EXPECT_EQ(0.0f, motionEvent.getRawPointerCoords(0)->getY());
+ w->consumeMotionOutsideWithZeroedCoords();
}
TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityBelowThreshold_AllowsTouch) {
@@ -6300,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();
}
@@ -6338,6 +6276,7 @@
sp<FakeWindowHandle> window =
new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
window->addFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
+ window->setFocusable(true);
return window;
}
@@ -6345,10 +6284,13 @@
int mSpyCount{0};
};
+using InputDispatcherSpyWindowDeathTest = InputDispatcherSpyWindowTest;
/**
* Adding a spy window that is not a trusted overlay causes Dispatcher to abort.
*/
-TEST_F(InputDispatcherSpyWindowTest, UntrustedSpy_AbortsDispatcher) {
+TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) {
+ ScopedSilentDeath _silentDeath;
+
auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
spy->setTrustedOverlay(false);
ASSERT_DEATH(mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy}}}),
@@ -6498,20 +6440,23 @@
/**
* A spy window can listen for touches outside its touchable region using the WATCH_OUTSIDE_TOUCHES
- * flag.
+ * flag, but it will get zero-ed out coordinates if the foreground has a different owner.
*/
TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) {
auto window = createForeground();
+ window->setOwnerInfo(12, 34);
auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::WATCH_OUTSIDE_TOUCH);
+ spy->setOwnerInfo(56, 78);
spy->setFrame(Rect{0, 0, 20, 20});
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
// Inject an event outside the spy window's frame and touchable region.
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {100, 200}))
<< "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
window->consumeMotionDown();
- spy->consumeMotionOutside();
+ spy->consumeMotionOutsideWithZeroedCoords();
}
/**
@@ -6532,7 +6477,7 @@
spy2->consumeMotionDown();
// Pilfer pointers from the second spy window.
- mDispatcher->pilferPointers(spy2->getToken());
+ EXPECT_EQ(OK, mDispatcher->pilferPointers(spy2->getToken()));
spy2->assertNoEvents();
spy1->consumeMotionCancel();
window->consumeMotionCancel();
@@ -6548,6 +6493,95 @@
}
/**
+ * A spy window can pilfer pointers for a gesture even after the foreground window has been removed
+ * in the middle of the gesture.
+ */
+TEST_F(InputDispatcherSpyWindowTest, CanPilferAfterWindowIsRemovedMidStream) {
+ auto window = createForeground();
+ auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+
+ window->releaseChannel();
+
+ EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ spy->consumeMotionUp(ADISPLAY_ID_DEFAULT);
+}
+
+/**
+ * After a spy window pilfers pointers, new pointers that go down in its bounds should be sent to
+ * the spy, but not to any other windows.
+ */
+TEST_F(InputDispatcherSpyWindowTest, ContinuesToReceiveGestureAfterPilfer) {
+ auto spy = createSpy(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
+ auto window = createForeground();
+ window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
+
+ // First finger down on the window and the spy.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {100, 200}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ spy->consumeMotionDown();
+ window->consumeMotionDown();
+
+ // Spy window pilfers the pointers.
+ EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
+ window->consumeMotionCancel();
+
+ // Second finger down on the window and spy, but the window should not receive the pointer down.
+ const MotionEvent secondFingerDownEvent =
+ MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
+ (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ AINPUT_SOURCE_TOUCHSCREEN)
+ .displayId(ADISPLAY_ID_DEFAULT)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
+ .x(100)
+ .y(200))
+ .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ spy->consumeMotionPointerDown(1 /*pointerIndex*/);
+
+ // Third finger goes down outside all windows, so injection should fail.
+ const MotionEvent thirdFingerDownEvent =
+ MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
+ (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ AINPUT_SOURCE_TOUCHSCREEN)
+ .displayId(ADISPLAY_ID_DEFAULT)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
+ .x(100)
+ .y(200))
+ .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+ .pointer(PointerBuilder(/* id */ 2, AMOTION_EVENT_TOOL_TYPE_FINGER).x(-5).y(-5))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::FAILED,
+ injectMotionEvent(mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ spy->assertNoEvents();
+ window->assertNoEvents();
+}
+
+/**
* Even when a spy window spans over multiple foreground windows, the spy should receive all
* pointers that are down within its bounds.
*/
@@ -6619,6 +6653,76 @@
spyRight->consumeMotionDown();
}
+/**
+ * The spy window should not be able to affect whether or not touches are split. Only the foreground
+ * windows should be allowed to control split touch.
+ */
+TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) {
+ // Create a touch modal spy that spies on the entire display.
+ // This spy window does not set the SPLIT_TOUCH flag. However, we still expect to split touches
+ // because a foreground window has not disabled splitting.
+ auto spy = createSpy(static_cast<WindowInfo::Flag>(0));
+
+ // Create a non touch modal window that supports split touch.
+ auto window = createForeground();
+ window->setFrame(Rect(0, 0, 100, 100));
+ window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
+
+ // First finger down, no window touched.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {100, 200}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ spy->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ window->assertNoEvents();
+
+ // Second finger down on window, the window should receive touch down.
+ const MotionEvent secondFingerDownEvent =
+ MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
+ (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ AINPUT_SOURCE_TOUCHSCREEN)
+ .displayId(ADISPLAY_ID_DEFAULT)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
+ .x(100)
+ .y(200))
+ .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ spy->consumeMotionPointerDown(1 /* pointerIndex */);
+}
+
+/**
+ * A spy window will usually be implemented as an un-focusable window. Verify that these windows
+ * do not receive key events.
+ */
+TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) {
+ auto spy = createSpy(static_cast<WindowInfo::Flag>(0));
+ spy->setFocusable(false);
+
+ auto window = createForeground();
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
+ setFocusedWindow(window);
+ window->consumeFocusEvent(true);
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher))
+ << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
+ window->consumeKeyDown(ADISPLAY_ID_NONE);
+
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(mDispatcher))
+ << "Inject key event should return InputEventInjectionResult::SUCCEEDED";
+ window->consumeKeyUp(ADISPLAY_ID_NONE);
+
+ spy->assertNoEvents();
+}
+
class InputDispatcherStylusInterceptorTest : public InputDispatcherTest {
public:
std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupStylusOverlayScenario() {
@@ -6665,7 +6769,11 @@
}
};
-TEST_F(InputDispatcherStylusInterceptorTest, UntrustedOverlay_AbortsDispatcher) {
+using InputDispatcherStylusInterceptorDeathTest = InputDispatcherStylusInterceptorTest;
+
+TEST_F(InputDispatcherStylusInterceptorDeathTest, UntrustedOverlay_AbortsDispatcher) {
+ ScopedSilentDeath _silentDeath;
+
auto [overlay, window] = setupStylusOverlayScenario();
overlay->setTrustedOverlay(false);
// Configuring an untrusted overlay as a stylus interceptor should cause Dispatcher to abort.
@@ -6712,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/inputflinger/tests/UnwantedInteractionBlocker_test.cpp b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
new file mode 100644
index 0000000..a3220cc
--- /dev/null
+++ b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
@@ -0,0 +1,938 @@
+/*
+ * 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.
+ * 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 "../UnwantedInteractionBlocker.h"
+#include <android-base/silent_death_test.h>
+#include <gtest/gtest.h>
+#include <gui/constants.h>
+#include <linux/input.h>
+
+#include "TestInputListener.h"
+
+namespace android {
+
+constexpr int32_t DEVICE_ID = 3;
+constexpr int32_t X_RESOLUTION = 11;
+constexpr int32_t Y_RESOLUTION = 11;
+constexpr int32_t MAJOR_RESOLUTION = 1;
+
+constexpr int POINTER_0_DOWN =
+ AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+constexpr int POINTER_1_DOWN =
+ AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+constexpr int POINTER_2_DOWN =
+ AMOTION_EVENT_ACTION_POINTER_DOWN | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+constexpr int POINTER_0_UP =
+ AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+constexpr int POINTER_1_UP =
+ AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+constexpr int POINTER_2_UP =
+ AMOTION_EVENT_ACTION_POINTER_UP | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+constexpr int DOWN = AMOTION_EVENT_ACTION_DOWN;
+constexpr int MOVE = AMOTION_EVENT_ACTION_MOVE;
+constexpr int UP = AMOTION_EVENT_ACTION_UP;
+constexpr int CANCEL = AMOTION_EVENT_ACTION_CANCEL;
+
+struct PointerData {
+ float x;
+ float y;
+ float major;
+};
+
+static NotifyMotionArgs generateMotionArgs(nsecs_t downTime, nsecs_t eventTime, int32_t action,
+ const std::vector<PointerData>& points) {
+ size_t pointerCount = points.size();
+ if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_UP) {
+ EXPECT_EQ(1U, pointerCount) << "Actions DOWN and UP can only contain a single pointer";
+ }
+
+ PointerProperties pointerProperties[pointerCount];
+ PointerCoords pointerCoords[pointerCount];
+
+ for (size_t i = 0; i < pointerCount; i++) {
+ pointerProperties[i].clear();
+ pointerProperties[i].id = i;
+ pointerProperties[i].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+
+ pointerCoords[i].clear();
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, points[i].x);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, points[i].y);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, points[i].major);
+ }
+
+ // Define a valid motion event.
+ NotifyMotionArgs args(/* id */ 0, eventTime, 0 /*readTime*/, DEVICE_ID,
+ AINPUT_SOURCE_TOUCHSCREEN, 0 /*displayId*/, POLICY_FLAG_PASS_TO_USER,
+ action, /* actionButton */ 0,
+ /* flags */ 0, AMETA_NONE, /* buttonState */ 0,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount,
+ pointerProperties, pointerCoords, /* xPrecision */ 0, /* yPrecision */ 0,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, downTime, /* videoFrames */ {});
+
+ return args;
+}
+
+static InputDeviceInfo generateTestDeviceInfo() {
+ InputDeviceIdentifier identifier;
+
+ auto info = InputDeviceInfo();
+ info.initialize(DEVICE_ID, /*generation*/ 1, /*controllerNumber*/ 1, identifier, "alias",
+ /*isExternal*/ false, /*hasMic*/ false);
+ info.addSource(AINPUT_SOURCE_TOUCHSCREEN);
+ info.addMotionRange(AMOTION_EVENT_AXIS_X, AINPUT_SOURCE_TOUCHSCREEN, 0, 1599, /*flat*/ 0,
+ /*fuzz*/ 0, X_RESOLUTION);
+ info.addMotionRange(AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_TOUCHSCREEN, 0, 2559, /*flat*/ 0,
+ /*fuzz*/ 0, Y_RESOLUTION);
+ info.addMotionRange(AMOTION_EVENT_AXIS_TOUCH_MAJOR, AINPUT_SOURCE_TOUCHSCREEN, 0, 255,
+ /*flat*/ 0, /*fuzz*/ 0, MAJOR_RESOLUTION);
+
+ return info;
+}
+
+static AndroidPalmFilterDeviceInfo generatePalmFilterDeviceInfo() {
+ InputDeviceInfo androidInfo = generateTestDeviceInfo();
+ std::optional<AndroidPalmFilterDeviceInfo> info = createPalmFilterDeviceInfo(androidInfo);
+ if (!info) {
+ ADD_FAILURE() << "Could not convert android device info to ::ui version";
+ return {};
+ }
+ return *info;
+}
+
+TEST(DeviceInfoConversionTest, TabletDeviceTest) {
+ AndroidPalmFilterDeviceInfo info = generatePalmFilterDeviceInfo();
+ ASSERT_EQ(X_RESOLUTION, info.x_res);
+ ASSERT_EQ(Y_RESOLUTION, info.y_res);
+ ASSERT_EQ(MAJOR_RESOLUTION, info.touch_major_res);
+ ASSERT_EQ(1599, info.max_x);
+ ASSERT_EQ(2559, info.max_y);
+}
+
+static void assertArgs(const NotifyMotionArgs& args, int32_t action,
+ const std::vector<std::pair<int32_t /*pointerId*/, PointerData>>& pointers) {
+ ASSERT_EQ(action, args.action);
+ ASSERT_EQ(pointers.size(), args.pointerCount);
+ for (size_t i = 0; i < args.pointerCount; i++) {
+ const auto& [pointerId, pointerData] = pointers[i];
+ ASSERT_EQ(pointerId, args.pointerProperties[i].id);
+ ASSERT_EQ(pointerData.x, args.pointerCoords[i].getX());
+ ASSERT_EQ(pointerData.y, args.pointerCoords[i].getY());
+ ASSERT_EQ(pointerData.major,
+ args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR));
+ }
+}
+
+TEST(RemovePointerIdsTest, RemoveOnePointer) {
+ NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0,
+ AMOTION_EVENT_ACTION_MOVE, {{1, 2, 3}, {4, 5, 6}});
+
+ NotifyMotionArgs pointer1Only = removePointerIds(args, {0});
+ assertArgs(pointer1Only, AMOTION_EVENT_ACTION_MOVE, {{1, {4, 5, 6}}});
+
+ NotifyMotionArgs pointer0Only = removePointerIds(args, {1});
+ assertArgs(pointer0Only, AMOTION_EVENT_ACTION_MOVE, {{0, {1, 2, 3}}});
+}
+
+/**
+ * Remove 2 out of 3 pointers during a MOVE event.
+ */
+TEST(RemovePointerIdsTest, RemoveTwoPointers) {
+ NotifyMotionArgs args =
+ generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, AMOTION_EVENT_ACTION_MOVE,
+ {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
+
+ NotifyMotionArgs pointer1Only = removePointerIds(args, {0, 2});
+ assertArgs(pointer1Only, AMOTION_EVENT_ACTION_MOVE, {{1, {4, 5, 6}}});
+}
+
+/**
+ * Remove an active pointer during a POINTER_DOWN event, and also remove a non-active
+ * pointer during a POINTER_DOWN event.
+ */
+TEST(RemovePointerIdsTest, ActionPointerDown) {
+ NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, POINTER_1_DOWN,
+ {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
+
+ NotifyMotionArgs pointers0And2 = removePointerIds(args, {1});
+ assertArgs(pointers0And2, ACTION_UNKNOWN, {{0, {1, 2, 3}}, {2, {7, 8, 9}}});
+
+ NotifyMotionArgs pointers1And2 = removePointerIds(args, {0});
+ assertArgs(pointers1And2, POINTER_0_DOWN, {{1, {4, 5, 6}}, {2, {7, 8, 9}}});
+}
+
+/**
+ * Remove all pointers during a MOVE event.
+ */
+TEST(RemovePointerIdsTest, RemoveAllPointersDuringMove) {
+ NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0,
+ AMOTION_EVENT_ACTION_MOVE, {{1, 2, 3}, {4, 5, 6}});
+
+ NotifyMotionArgs noPointers = removePointerIds(args, {0, 1});
+ ASSERT_EQ(0u, noPointers.pointerCount);
+}
+
+/**
+ * If we have ACTION_POINTER_DOWN, and we remove all pointers except for the active pointer,
+ * then we should just have ACTION_DOWN. Likewise, a POINTER_UP event should become an UP event.
+ */
+TEST(RemovePointerIdsTest, PointerDownBecomesDown) {
+ NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, POINTER_1_DOWN,
+ {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
+
+ NotifyMotionArgs pointer1 = removePointerIds(args, {0, 2});
+ assertArgs(pointer1, DOWN, {{1, {4, 5, 6}}});
+
+ args.action = POINTER_1_UP;
+ pointer1 = removePointerIds(args, {0, 2});
+ assertArgs(pointer1, UP, {{1, {4, 5, 6}}});
+}
+
+/**
+ * If a pointer that is now going down is canceled, then we can just drop the POINTER_DOWN event.
+ */
+TEST(CancelSuppressedPointersTest, CanceledPointerDownIsDropped) {
+ NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, POINTER_1_DOWN,
+ {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
+ std::vector<NotifyMotionArgs> result =
+ cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {},
+ /*newSuppressedPointerIds*/ {1});
+ ASSERT_TRUE(result.empty());
+}
+
+/**
+ * If a pointer is already suppressed, the POINTER_UP event for this pointer should be dropped
+ */
+TEST(CancelSuppressedPointersTest, SuppressedPointerUpIsDropped) {
+ NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, POINTER_1_UP,
+ {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
+ std::vector<NotifyMotionArgs> result =
+ cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {1},
+ /*newSuppressedPointerIds*/ {1});
+ ASSERT_TRUE(result.empty());
+}
+
+/**
+ * If a pointer is already suppressed, it should be removed from a MOVE event.
+ */
+TEST(CancelSuppressedPointersTest, SuppressedPointerIsRemovedDuringMove) {
+ NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, MOVE,
+ {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
+ std::vector<NotifyMotionArgs> result =
+ cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {1},
+ /*newSuppressedPointerIds*/ {1});
+ ASSERT_EQ(1u, result.size());
+ assertArgs(result[0], MOVE, {{0, {1, 2, 3}}, {2, {7, 8, 9}}});
+}
+
+/**
+ * If a pointer just got canceled during a MOVE event, we should see two events:
+ * 1) ACTION_POINTER_UP with FLAG_CANCELED so that this pointer is lifted
+ * 2) A MOVE event without this pointer
+ */
+TEST(CancelSuppressedPointersTest, NewlySuppressedPointerIsCanceled) {
+ NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, MOVE,
+ {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
+ std::vector<NotifyMotionArgs> result =
+ cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {},
+ /*newSuppressedPointerIds*/ {1});
+ ASSERT_EQ(2u, result.size());
+ assertArgs(result[0], POINTER_1_UP, {{0, {1, 2, 3}}, {1, {4, 5, 6}}, {2, {7, 8, 9}}});
+ ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, result[0].flags);
+ assertArgs(result[1], MOVE, {{0, {1, 2, 3}}, {2, {7, 8, 9}}});
+}
+
+/**
+ * If we have a single pointer that gets canceled during a MOVE, the entire gesture
+ * should be canceled with ACTION_CANCEL.
+ */
+TEST(CancelSuppressedPointersTest, SingleSuppressedPointerIsCanceled) {
+ NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, MOVE, {{1, 2, 3}});
+ std::vector<NotifyMotionArgs> result =
+ cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {},
+ /*newSuppressedPointerIds*/ {0});
+ ASSERT_EQ(1u, result.size());
+ assertArgs(result[0], CANCEL, {{0, {1, 2, 3}}});
+ ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, result[0].flags);
+}
+
+/**
+ * If one of 3 pointers gets canceled during a POINTER_UP event, we should proceed with POINTER_UP,
+ * but this event should also have FLAG_CANCELED to indicate that this pointer was unintentional.
+ */
+TEST(CancelSuppressedPointersTest, SuppressedPointer1GoingUpIsCanceled) {
+ NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, POINTER_1_UP,
+ {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
+ std::vector<NotifyMotionArgs> result =
+ cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {},
+ /*newSuppressedPointerIds*/ {1});
+ ASSERT_EQ(1u, result.size());
+ assertArgs(result[0], POINTER_1_UP, {{0, {1, 2, 3}}, {1, {4, 5, 6}}, {2, {7, 8, 9}}});
+ ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, result[0].flags);
+}
+
+/**
+ * Same test as above, but we change the pointer's index to 0 instead of 1. This helps detect
+ * errors with handling pointer index inside the action.
+ */
+TEST(CancelSuppressedPointersTest, SuppressedPointer0GoingUpIsCanceled) {
+ NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, POINTER_0_UP,
+ {{1, 2, 3}, {4, 5, 6}});
+ std::vector<NotifyMotionArgs> result =
+ cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {},
+ /*newSuppressedPointerIds*/ {0});
+ ASSERT_EQ(1u, result.size());
+ assertArgs(result[0], POINTER_0_UP, {{0, {1, 2, 3}}, {1, {4, 5, 6}}});
+ ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, result[0].flags);
+}
+
+/**
+ * If two pointers are canceled simultaneously during MOVE, we should see a single ACTION_CANCEL
+ * event. This event would cancel the entire gesture.
+ */
+TEST(CancelSuppressedPointersTest, TwoNewlySuppressedPointersAreBothCanceled) {
+ NotifyMotionArgs args =
+ generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, MOVE, {{1, 2, 3}, {4, 5, 6}});
+ std::vector<NotifyMotionArgs> result =
+ cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {},
+ /*newSuppressedPointerIds*/ {0, 1});
+ ASSERT_EQ(1u, result.size());
+ assertArgs(result[0], CANCEL, {{0, {1, 2, 3}}, {1, {4, 5, 6}}});
+ ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, result[0].flags);
+}
+
+/**
+ * Similar test to above. During a POINTER_UP event, both pointers are detected as 'palm' and
+ * therefore should be removed. In this case, we should send a single ACTION_CANCEL that
+ * would undo the entire gesture.
+ */
+TEST(CancelSuppressedPointersTest, TwoPointersAreCanceledDuringPointerUp) {
+ NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, POINTER_1_UP,
+ {{1, 2, 3}, {4, 5, 6}});
+ std::vector<NotifyMotionArgs> result =
+ cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {1},
+ /*newSuppressedPointerIds*/ {0, 1});
+ ASSERT_EQ(1u, result.size());
+ assertArgs(result[0], CANCEL, {{0, {1, 2, 3}}});
+ ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, result[0].flags);
+}
+
+/**
+ * When all pointers have been removed from the touch stream, and we have a new POINTER_DOWN,
+ * this should become a regular DOWN event because it's the only pointer that will be valid now.
+ */
+TEST(CancelSuppressedPointersTest, NewPointerDownBecomesDown) {
+ NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, POINTER_2_DOWN,
+ {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}});
+ std::vector<NotifyMotionArgs> result =
+ cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {0, 1},
+ /*newSuppressedPointerIds*/ {0, 1});
+ ASSERT_EQ(1u, result.size());
+ assertArgs(result[0], DOWN, {{2, {7, 8, 9}}});
+ ASSERT_EQ(0, result[0].flags);
+}
+
+/**
+ * Call 'getTouches' for a DOWN event and check that the resulting 'InProgressTouchEvdev'
+ * struct is populated as expected.
+ */
+TEST(GetTouchesTest, ConvertDownEvent) {
+ NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, DOWN, {{1, 2, 3}});
+ AndroidPalmFilterDeviceInfo deviceInfo = generatePalmFilterDeviceInfo();
+ SlotState slotState;
+ SlotState oldSlotState = slotState;
+ slotState.update(args);
+ std::vector<::ui::InProgressTouchEvdev> touches =
+ getTouches(args, deviceInfo, oldSlotState, slotState);
+ ASSERT_EQ(1u, touches.size());
+ ::ui::InProgressTouchEvdev expected;
+
+ expected.major = 3;
+ expected.minor = 0;
+ expected.tool_type = MT_TOOL_FINGER;
+ expected.altered = true;
+ expected.was_cancelled = false;
+ expected.cancelled = false;
+ expected.delayed = false;
+ expected.was_delayed = false;
+ expected.held = false;
+ expected.was_held = false;
+ expected.was_touching = false;
+ expected.touching = true;
+ expected.x = 1;
+ expected.y = 2;
+ expected.tracking_id = 0;
+ std::optional<size_t> slot = slotState.getSlotForPointerId(0);
+ ASSERT_TRUE(slot);
+ expected.slot = *slot;
+ expected.pressure = 0;
+ expected.tool_code = BTN_TOOL_FINGER;
+ expected.reported_tool_type = ::ui::EventPointerType::kTouch;
+ expected.stylus_button = false;
+
+ ASSERT_EQ(expected, touches[0]) << toString(touches[0]);
+}
+
+// --- UnwantedInteractionBlockerTest ---
+
+class UnwantedInteractionBlockerTest : public testing::Test {
+protected:
+ TestInputListener mTestListener;
+ std::unique_ptr<UnwantedInteractionBlockerInterface> mBlocker;
+
+ void SetUp() override {
+ mBlocker = std::make_unique<UnwantedInteractionBlocker>(mTestListener,
+ /*enablePalmRejection*/ true);
+ }
+};
+
+/**
+ * Create a basic configuration change and send it to input classifier.
+ * Expect that the event is received by the next input stage, unmodified.
+ */
+TEST_F(UnwantedInteractionBlockerTest, ConfigurationChangedIsPassedToNextListener) {
+ // Create a basic configuration change and send to classifier
+ NotifyConfigurationChangedArgs args(1 /*sequenceNum*/, 2 /*eventTime*/);
+
+ mBlocker->notifyConfigurationChanged(&args);
+ NotifyConfigurationChangedArgs outArgs;
+ ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyConfigurationChangedWasCalled(&outArgs));
+ ASSERT_EQ(args, outArgs);
+}
+
+/**
+ * Keys are not handled in 'UnwantedInteractionBlocker' and should be passed
+ * to next stage unmodified.
+ */
+TEST_F(UnwantedInteractionBlockerTest, KeyIsPassedToNextListener) {
+ // Create a basic key event and send to classifier
+ NotifyKeyArgs args(1 /*sequenceNum*/, 2 /*eventTime*/, 21 /*readTime*/, 3 /*deviceId*/,
+ AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_DEFAULT, 0 /*policyFlags*/,
+ AKEY_EVENT_ACTION_DOWN, 4 /*flags*/, AKEYCODE_HOME, 5 /*scanCode*/,
+ AMETA_NONE, 6 /*downTime*/);
+
+ mBlocker->notifyKey(&args);
+ NotifyKeyArgs outArgs;
+ ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyKeyWasCalled(&outArgs));
+ ASSERT_EQ(args, outArgs);
+}
+
+/**
+ * Create a basic motion event. Since it's just a DOWN event, it should not
+ * be detected as palm and should be sent to the next listener stage
+ * unmodified.
+ */
+TEST_F(UnwantedInteractionBlockerTest, DownEventIsPassedToNextListener) {
+ NotifyMotionArgs motionArgs =
+ generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2, 3}});
+ mBlocker->notifyMotion(&motionArgs);
+ NotifyMotionArgs args;
+ ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(motionArgs, args);
+}
+
+/**
+ * Create a basic switch event and send it to the UnwantedInteractionBlocker.
+ * Expect that the event is received by the next input stage, unmodified.
+ */
+TEST_F(UnwantedInteractionBlockerTest, SwitchIsPassedToNextListener) {
+ NotifySwitchArgs args(1 /*sequenceNum*/, 2 /*eventTime*/, 3 /*policyFlags*/, 4 /*switchValues*/,
+ 5 /*switchMask*/);
+
+ mBlocker->notifySwitch(&args);
+ NotifySwitchArgs outArgs;
+ ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifySwitchWasCalled(&outArgs));
+ ASSERT_EQ(args, outArgs);
+}
+
+/**
+ * Create a basic device reset event and send it to UnwantedInteractionBlocker.
+ * Expect that the event is received by the next input stage, unmodified.
+ */
+TEST_F(UnwantedInteractionBlockerTest, DeviceResetIsPassedToNextListener) {
+ NotifyDeviceResetArgs args(1 /*sequenceNum*/, 2 /*eventTime*/, DEVICE_ID);
+
+ mBlocker->notifyDeviceReset(&args);
+ NotifyDeviceResetArgs outArgs;
+ ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyDeviceResetWasCalled(&outArgs));
+ ASSERT_EQ(args, outArgs);
+}
+
+/**
+ * The state should be reset when device reset happens. That means, we can reset in the middle of a
+ * gesture, and start a new stream. There should be no crash. If the state wasn't reset correctly,
+ * a crash due to inconsistent event stream could have occurred.
+ */
+TEST_F(UnwantedInteractionBlockerTest, NoCrashWhenResetHappens) {
+ NotifyMotionArgs args;
+ mBlocker->notifyInputDevicesChanged({generateTestDeviceInfo()});
+ mBlocker->notifyMotion(
+ &(args = generateMotionArgs(0 /*downTime*/, 1 /*eventTime*/, DOWN, {{1, 2, 3}})));
+ mBlocker->notifyMotion(
+ &(args = generateMotionArgs(0 /*downTime*/, 2 /*eventTime*/, MOVE, {{4, 5, 6}})));
+ NotifyDeviceResetArgs resetArgs(1 /*sequenceNum*/, 3 /*eventTime*/, DEVICE_ID);
+ mBlocker->notifyDeviceReset(&resetArgs);
+ // Start a new gesture with a DOWN event, even though the previous event stream was incomplete.
+ mBlocker->notifyMotion(
+ &(args = generateMotionArgs(0 /*downTime*/, 4 /*eventTime*/, DOWN, {{7, 8, 9}})));
+}
+
+/**
+ * If input devices have changed, but the important device info that's used by the
+ * UnwantedInteractionBlocker has not changed, there should not be a reset.
+ */
+TEST_F(UnwantedInteractionBlockerTest, NoResetIfDeviceInfoChanges) {
+ NotifyMotionArgs args;
+ mBlocker->notifyInputDevicesChanged({generateTestDeviceInfo()});
+ mBlocker->notifyMotion(
+ &(args = generateMotionArgs(0 /*downTime*/, 1 /*eventTime*/, DOWN, {{1, 2, 3}})));
+ mBlocker->notifyMotion(
+ &(args = generateMotionArgs(0 /*downTime*/, 2 /*eventTime*/, MOVE, {{4, 5, 6}})));
+
+ // Now pretend the device changed, even though nothing is different for DEVICE_ID in practice.
+ mBlocker->notifyInputDevicesChanged({generateTestDeviceInfo()});
+
+ // The MOVE event continues the gesture that started before 'devices changed', so it should not
+ // cause a crash.
+ mBlocker->notifyMotion(
+ &(args = generateMotionArgs(0 /*downTime*/, 4 /*eventTime*/, MOVE, {{7, 8, 9}})));
+}
+
+using UnwantedInteractionBlockerTestDeathTest = UnwantedInteractionBlockerTest;
+
+/**
+ * The state should be reset when device reset happens. If we receive an inconsistent event after
+ * the reset happens, crash should occur.
+ */
+TEST_F(UnwantedInteractionBlockerTestDeathTest, InconsistentEventAfterResetCausesACrash) {
+ ScopedSilentDeath _silentDeath;
+ NotifyMotionArgs args;
+ mBlocker->notifyInputDevicesChanged({generateTestDeviceInfo()});
+ mBlocker->notifyMotion(
+ &(args = generateMotionArgs(0 /*downTime*/, 1 /*eventTime*/, DOWN, {{1, 2, 3}})));
+ mBlocker->notifyMotion(
+ &(args = generateMotionArgs(0 /*downTime*/, 2 /*eventTime*/, MOVE, {{4, 5, 6}})));
+ NotifyDeviceResetArgs resetArgs(1 /*sequenceNum*/, 3 /*eventTime*/, DEVICE_ID);
+ mBlocker->notifyDeviceReset(&resetArgs);
+ // Sending MOVE without a DOWN -> should crash!
+ ASSERT_DEATH(
+ {
+ mBlocker->notifyMotion(&(args = generateMotionArgs(0 /*downTime*/, 4 /*eventTime*/,
+ MOVE, {{7, 8, 9}})));
+ },
+ "Could not find slot");
+}
+
+/**
+ * There should be a crash when an inconsistent event is received.
+ */
+TEST_F(UnwantedInteractionBlockerTestDeathTest, WhenMoveWithoutDownCausesACrash) {
+ ScopedSilentDeath _silentDeath;
+ NotifyMotionArgs args = generateMotionArgs(0 /*downTime*/, 1 /*eventTime*/, MOVE, {{1, 2, 3}});
+ mBlocker->notifyInputDevicesChanged({generateTestDeviceInfo()});
+ ASSERT_DEATH({ mBlocker->notifyMotion(&args); }, "Could not find slot");
+}
+
+class PalmRejectorTest : public testing::Test {
+protected:
+ std::unique_ptr<PalmRejector> mPalmRejector;
+
+ void SetUp() override {
+ AndroidPalmFilterDeviceInfo info = generatePalmFilterDeviceInfo();
+ mPalmRejector = std::make_unique<PalmRejector>(info);
+ }
+};
+
+using PalmRejectorTestDeathTest = PalmRejectorTest;
+
+TEST_F(PalmRejectorTestDeathTest, InconsistentEventCausesACrash) {
+ ScopedSilentDeath _silentDeath;
+ constexpr nsecs_t downTime = 0;
+ NotifyMotionArgs args =
+ generateMotionArgs(downTime, 2 /*eventTime*/, MOVE, {{1406.0, 650.0, 52.0}});
+ ASSERT_DEATH({ mPalmRejector->processMotion(args); }, "Could not find slot");
+}
+
+/**
+ * Use PalmRejector with actual touchscreen data and real model.
+ * Two pointers that should both be classified as palms.
+ */
+TEST_F(PalmRejectorTest, TwoPointersAreCanceled) {
+ std::vector<NotifyMotionArgs> argsList;
+ constexpr nsecs_t downTime = 255955749837000;
+
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, downTime, DOWN, {{1342.0, 613.0, 79.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955759313000, MOVE, {{1406.0, 650.0, 52.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955766361000, MOVE, {{1429.0, 672.0, 46.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955775989000, MOVE, {{1417.0, 685.0, 41.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955775989000, POINTER_1_DOWN,
+ {{1417.0, 685.0, 41.0}, {1062.0, 697.0, 10.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955783039000, MOVE,
+ {{1414.0, 702.0, 41.0}, {1059.0, 731.0, 12.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955792536000, MOVE,
+ {{1415.0, 719.0, 44.0}, {1060.0, 760.0, 11.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955799474000, MOVE,
+ {{1421.0, 733.0, 42.0}, {1065.0, 769.0, 13.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955809177000, MOVE,
+ {{1426.0, 742.0, 43.0}, {1068.0, 771.0, 13.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955816131000, MOVE,
+ {{1430.0, 748.0, 45.0}, {1069.0, 772.0, 13.0}}));
+ argsList = mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955825907000, MOVE,
+ {{1432.0, 750.0, 44.0}, {1069.0, 772.0, 13.0}}));
+ ASSERT_EQ(1u, argsList.size());
+ ASSERT_EQ(0 /* No FLAG_CANCELED */, argsList[0].flags);
+ argsList = mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955832736000, MOVE,
+ {{1433.0, 751.0, 44.0}, {1070.0, 771.0, 13.0}}));
+ ASSERT_EQ(2u, argsList.size());
+ ASSERT_EQ(POINTER_0_UP, argsList[0].action);
+ ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, argsList[0].flags);
+ ASSERT_EQ(MOVE, argsList[1].action);
+ ASSERT_EQ(1u, argsList[1].pointerCount);
+ ASSERT_EQ(0, argsList[1].flags);
+
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955842432000, MOVE,
+ {{1433.0, 751.0, 42.0}, {1071.0, 770.0, 13.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955849380000, MOVE,
+ {{1433.0, 751.0, 45.0}, {1072.0, 769.0, 13.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955859046000, MOVE,
+ {{1433.0, 751.0, 43.0}, {1072.0, 768.0, 13.0}}));
+ argsList = mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955869823000, MOVE,
+ {{1433.0, 751.0, 45.0}, {1072.0, 767.0, 13.0}}));
+ ASSERT_EQ(1u, argsList.size());
+ ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, argsList[0].action);
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955875641000, MOVE,
+ {{1433.0, 751.0, 43.0}, {1072.0, 766.0, 13.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955882693000, MOVE,
+ {{1433.0, 750.0, 44.0}, {1072.0, 765.0, 13.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955892324000, MOVE,
+ {{1433.0, 750.0, 42.0}, {1072.0, 763.0, 14.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955899425000, MOVE,
+ {{1434.0, 750.0, 44.0}, {1073.0, 761.0, 14.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955909400000, MOVE,
+ {{1435.0, 750.0, 43.0}, {1073.0, 759.0, 15.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955915885000, MOVE,
+ {{1436.0, 750.0, 45.0}, {1074.0, 757.0, 15.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955925607000, MOVE,
+ {{1436.0, 750.0, 44.0}, {1074.0, 755.0, 15.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955932580000, MOVE,
+ {{1436.0, 750.0, 45.0}, {1074.0, 753.0, 15.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955942231000, MOVE,
+ {{1436.0, 749.0, 44.0}, {1074.0, 751.0, 15.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955949204000, MOVE,
+ {{1435.0, 748.0, 45.0}, {1074.0, 749.0, 15.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955959103000, MOVE,
+ {{1434.0, 746.0, 44.0}, {1074.0, 747.0, 14.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955965884000, MOVE,
+ {{1433.0, 744.0, 44.0}, {1075.0, 745.0, 14.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955975649000, MOVE,
+ {{1431.0, 741.0, 43.0}, {1075.0, 742.0, 13.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955982537000, MOVE,
+ {{1428.0, 738.0, 43.0}, {1076.0, 739.0, 12.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955992284000, MOVE,
+ {{1400.0, 726.0, 54.0}, {1076.0, 739.0, 13.0}}));
+ argsList = mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955999348000, POINTER_1_UP,
+ {{1362.0, 716.0, 55.0}, {1076.0, 739.0, 13.0}}));
+ ASSERT_TRUE(argsList.empty());
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955999348000, MOVE, {{1362.0, 716.0, 55.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255956008885000, MOVE, {{1347.0, 707.0, 54.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255956015791000, MOVE, {{1340.0, 698.0, 54.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255956025804000, MOVE, {{1338.0, 694.0, 55.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255956032314000, MOVE, {{1336.0, 690.0, 53.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255956042329000, MOVE, {{1334.0, 685.0, 47.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255956048979000, MOVE, {{1333.0, 679.0, 46.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255956058813000, MOVE, {{1332.0, 672.0, 45.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255956065592000, MOVE, {{1333.0, 666.0, 40.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255956075276000, MOVE, {{1336.0, 661.0, 24.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255956082198000, MOVE, {{1338.0, 656.0, 16.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255956092059000, MOVE, {{1341.0, 649.0, 1.0}}));
+ argsList = mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255956098764000, UP, {{1341.0, 649.0, 1.0}}));
+ ASSERT_TRUE(argsList.empty());
+}
+
+/**
+ * A test implementation of PalmDetectionFilter that allows you to specify which pointer you want
+ * the model to consider 'suppressed'. The pointer is specified using its position (x, y).
+ * Current limitation:
+ * Pointers may not cross each other in space during motion. Otherwise, any pointer with the
+ * position matching the suppressed position will be considered "palm".
+ */
+class TestFilter : public ::ui::PalmDetectionFilter {
+public:
+ TestFilter(::ui::SharedPalmDetectionFilterState* state,
+ std::vector<std::pair<float, float>>& suppressedPointers)
+ : ::ui::PalmDetectionFilter(state), mSuppressedPointers(suppressedPointers) {}
+
+ void Filter(const std::vector<::ui::InProgressTouchEvdev>& touches, ::base::TimeTicks time,
+ std::bitset<::ui::kNumTouchEvdevSlots>* slots_to_hold,
+ std::bitset<::ui::kNumTouchEvdevSlots>* slots_to_suppress) override {
+ updateSuppressedSlots(touches);
+ *slots_to_suppress = mSuppressedSlots;
+ }
+
+ std::string FilterNameForTesting() const override { return "test filter"; }
+
+private:
+ void updateSuppressedSlots(const std::vector<::ui::InProgressTouchEvdev>& touches) {
+ for (::ui::InProgressTouchEvdev touch : touches) {
+ for (const auto& [x, y] : mSuppressedPointers) {
+ const float dx = (touch.x - x);
+ const float dy = (touch.y - y);
+ const float distanceSquared = dx * dx + dy * dy;
+ if (distanceSquared < 1) {
+ mSuppressedSlots.set(touch.slot, true);
+ }
+ }
+ }
+ }
+
+ std::bitset<::ui::kNumTouchEvdevSlots> mSuppressedSlots;
+ std::vector<std::pair<float, float>>& mSuppressedPointers;
+};
+
+class PalmRejectorFakeFilterTest : public testing::Test {
+protected:
+ std::unique_ptr<PalmRejector> mPalmRejector;
+
+ void SetUp() override {
+ std::unique_ptr<::ui::PalmDetectionFilter> filter =
+ std::make_unique<TestFilter>(&mSharedPalmState, /*byref*/ mSuppressedPointers);
+ mPalmRejector =
+ std::make_unique<PalmRejector>(generatePalmFilterDeviceInfo(), std::move(filter));
+ }
+
+ void suppressPointerAtPosition(float x, float y) { mSuppressedPointers.push_back({x, y}); }
+
+private:
+ std::vector<std::pair<float, float>> mSuppressedPointers;
+ ::ui::SharedPalmDetectionFilterState mSharedPalmState; // unused, but we must retain ownership
+};
+
+/**
+ * When a MOVE event happens, the model identifies the pointer as palm. At that time, the palm
+ * rejector should send a POINTER_UP event for this pointer with FLAG_CANCELED, and subsequent
+ * events should have this pointer removed.
+ */
+TEST_F(PalmRejectorFakeFilterTest, OneOfTwoPointersIsCanceled) {
+ std::vector<NotifyMotionArgs> argsList;
+ constexpr nsecs_t downTime = 0;
+
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, downTime, DOWN, {{1342.0, 613.0, 79.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 1, POINTER_1_DOWN,
+ {{1417.0, 685.0, 41.0}, {1062.0, 697.0, 10.0}}));
+ // Cancel the second pointer
+ suppressPointerAtPosition(1059, 731);
+ argsList = mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955783039000, MOVE,
+ {{1414.0, 702.0, 41.0}, {1059.0, 731.0, 12.0}}));
+ ASSERT_EQ(2u, argsList.size());
+ // First event - cancel pointer 1
+ ASSERT_EQ(POINTER_1_UP, argsList[0].action);
+ ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, argsList[0].flags);
+ // Second event - send MOVE for the remaining pointer
+ ASSERT_EQ(MOVE, argsList[1].action);
+ ASSERT_EQ(0, argsList[1].flags);
+
+ // Future move events only contain 1 pointer, because the second pointer will continue
+ // to be suppressed
+ argsList = mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955783039000, MOVE,
+ {{1433.0, 751.0, 43.0}, {1072.0, 766.0, 13.0}}));
+ ASSERT_EQ(1u, argsList.size());
+ ASSERT_EQ(MOVE, argsList[0].action);
+ ASSERT_EQ(1u, argsList[0].pointerCount);
+ ASSERT_EQ(1433, argsList[0].pointerCoords[0].getX());
+ ASSERT_EQ(751, argsList[0].pointerCoords[0].getY());
+}
+
+/**
+ * Send two pointers, and suppress both of them. Check that ACTION_CANCEL is generated.
+ * Afterwards:
+ * 1) Future MOVE events are ignored.
+ * 2) When a new pointer goes down, ACTION_DOWN is generated
+ */
+TEST_F(PalmRejectorFakeFilterTest, NewDownEventAfterCancel) {
+ std::vector<NotifyMotionArgs> argsList;
+ constexpr nsecs_t downTime = 0;
+
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, downTime, DOWN, {{1342.0, 613.0, 79.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 1, POINTER_1_DOWN,
+ {{1417.0, 685.0, 41.0}, {1062.0, 697.0, 10.0}}));
+ // Cancel both pointers
+ suppressPointerAtPosition(1059, 731);
+ suppressPointerAtPosition(1400, 680);
+ argsList = mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 1, MOVE, {{1400, 680, 41}, {1059, 731, 10}}));
+ ASSERT_EQ(1u, argsList.size());
+ // Cancel all
+ ASSERT_EQ(CANCEL, argsList[0].action);
+ ASSERT_EQ(2u, argsList[0].pointerCount);
+ ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, argsList[0].flags);
+
+ // Future move events are ignored
+ argsList = mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955783039000, MOVE,
+ {{1433.0, 751.0, 43.0}, {1072.0, 766.0, 13.0}}));
+ ASSERT_EQ(0u, argsList.size());
+
+ // When a new pointer goes down, a new DOWN event is generated
+ argsList = mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955783039000, POINTER_2_DOWN,
+ {{1433.0, 751.0, 43.0}, {1072.0, 766.0, 13.0}, {1000, 700, 10}}));
+ ASSERT_EQ(1u, argsList.size());
+ ASSERT_EQ(DOWN, argsList[0].action);
+ ASSERT_EQ(1u, argsList[0].pointerCount);
+ ASSERT_EQ(2, argsList[0].pointerProperties[0].id);
+}
+
+/**
+ * 2 pointers are classified as palm simultaneously. When they are later
+ * released by Android, make sure that we drop both of these POINTER_UP events.
+ * Since they are classified as palm at the same time, we just need to receive a single CANCEL
+ * event. From MotionEvent docs: """A pointer id remains valid until the pointer eventually goes up
+ * (indicated by ACTION_UP or ACTION_POINTER_UP) or when the gesture is canceled (indicated by
+ * ACTION_CANCEL)."""
+ * This means that generating additional POINTER_UP events is not necessary.
+ * The risk here is that "oldSuppressedPointerIds" will not be correct, because it will update after
+ * each motion, but pointers are canceled one at a time by Android.
+ */
+TEST_F(PalmRejectorFakeFilterTest, TwoPointersCanceledWhenOnePointerGoesUp) {
+ std::vector<NotifyMotionArgs> argsList;
+ constexpr nsecs_t downTime = 0;
+
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, downTime, DOWN, {{1342.0, 613.0, 79.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, /*eventTime*/ 1, POINTER_1_DOWN,
+ {{1417.0, 685.0, 41.0}, {1062.0, 697.0, 10.0}}));
+ // Suppress both pointers!!
+ suppressPointerAtPosition(1414, 702);
+ suppressPointerAtPosition(1059, 731);
+ argsList = mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955783039000, POINTER_1_UP,
+ {{1414.0, 702.0, 41.0}, {1059.0, 731.0, 12.0}}));
+ ASSERT_EQ(1u, argsList.size());
+ ASSERT_EQ(CANCEL, argsList[0].action) << MotionEvent::actionToString(argsList[0].action);
+ ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, argsList[0].flags);
+
+ // Future move events should not go to the listener.
+ argsList = mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955783049000, MOVE, {{1435.0, 755.0, 43.0}}));
+ ASSERT_EQ(0u, argsList.size());
+
+ argsList = mPalmRejector->processMotion(
+ generateMotionArgs(downTime, 255955783059000, UP, {{1436.0, 756.0, 43.0}}));
+ ASSERT_EQ(0u, argsList.size());
+}
+
+/**
+ * Send 3 pointers, and then cancel one of them during a MOVE event. We should see ACTION_POINTER_UP
+ * generated for that. Next, another pointer is canceled during ACTION_POINTER_DOWN. For that
+ * pointer, we simply shouldn't send the event.
+ */
+TEST_F(PalmRejectorFakeFilterTest, CancelTwoPointers) {
+ std::vector<NotifyMotionArgs> argsList;
+ constexpr nsecs_t downTime = 0;
+
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, downTime, DOWN, {{1342.0, 613.0, 79.0}}));
+ mPalmRejector->processMotion(
+ generateMotionArgs(downTime, /*eventTime*/ 1, POINTER_1_DOWN,
+ {{1417.0, 685.0, 41.0}, {1062.0, 697.0, 10.0}}));
+
+ // Suppress second pointer (pointer 1)
+ suppressPointerAtPosition(1060, 700);
+ argsList = mPalmRejector->processMotion(
+ generateMotionArgs(downTime, /*eventTime*/ 1, MOVE,
+ {{1417.0, 685.0, 41.0}, {1060, 700, 10.0}}));
+ ASSERT_EQ(2u, argsList.size());
+ ASSERT_EQ(POINTER_1_UP, argsList[0].action);
+ ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, argsList[0].flags);
+
+ ASSERT_EQ(MOVE, argsList[1].action) << MotionEvent::actionToString(argsList[1].action);
+ ASSERT_EQ(0, argsList[1].flags);
+
+ // A new pointer goes down and gets suppressed right away. It should just be dropped
+ suppressPointerAtPosition(1001, 601);
+ argsList = mPalmRejector->processMotion(
+ generateMotionArgs(downTime, /*eventTime*/ 1, POINTER_2_DOWN,
+ {{1417.0, 685.0, 41.0}, {1062.0, 697.0, 10.0}, {1001, 601, 5}}));
+
+ ASSERT_EQ(0u, argsList.size());
+ // Likewise, pointer that's already canceled should be ignored
+ argsList = mPalmRejector->processMotion(
+ generateMotionArgs(downTime, /*eventTime*/ 1, POINTER_2_UP,
+ {{1417.0, 685.0, 41.0}, {1062.0, 697.0, 10.0}, {1001, 601, 5}}));
+ ASSERT_EQ(0u, argsList.size());
+
+ // Cancel all pointers when pointer 1 goes up. Pointer 1 was already canceled earlier.
+ suppressPointerAtPosition(1417, 685);
+ argsList = mPalmRejector->processMotion(
+ generateMotionArgs(downTime, /*eventTime*/ 1, POINTER_1_UP,
+ {{1417.0, 685.0, 41.0}, {1062.0, 697.0, 10.0}}));
+ ASSERT_EQ(1u, argsList.size());
+ ASSERT_EQ(CANCEL, argsList[0].action);
+}
+
+} // namespace android
diff --git a/services/sensorservice/AidlSensorHalWrapper.cpp b/services/sensorservice/AidlSensorHalWrapper.cpp
index cdd95ca..86c8b0d 100644
--- a/services/sensorservice/AidlSensorHalWrapper.cpp
+++ b/services/sensorservice/AidlSensorHalWrapper.cpp
@@ -250,6 +250,46 @@
break;
}
+ case SensorType::ACCELEROMETER_LIMITED_AXES:
+ case SensorType::GYROSCOPE_LIMITED_AXES:
+ dst->limited_axes_imu.x = src.payload.get<Event::EventPayload::limitedAxesImu>().x;
+ dst->limited_axes_imu.y = src.payload.get<Event::EventPayload::limitedAxesImu>().y;
+ dst->limited_axes_imu.z = src.payload.get<Event::EventPayload::limitedAxesImu>().z;
+ dst->limited_axes_imu.x_supported =
+ src.payload.get<Event::EventPayload::limitedAxesImu>().xSupported;
+ dst->limited_axes_imu.y_supported =
+ src.payload.get<Event::EventPayload::limitedAxesImu>().ySupported;
+ dst->limited_axes_imu.z_supported =
+ src.payload.get<Event::EventPayload::limitedAxesImu>().zSupported;
+ break;
+
+ case SensorType::ACCELEROMETER_LIMITED_AXES_UNCALIBRATED:
+ case SensorType::GYROSCOPE_LIMITED_AXES_UNCALIBRATED:
+ dst->limited_axes_imu_uncalibrated.x_uncalib =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().x;
+ dst->limited_axes_imu_uncalibrated.y_uncalib =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().y;
+ dst->limited_axes_imu_uncalibrated.z_uncalib =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().z;
+ dst->limited_axes_imu_uncalibrated.x_bias =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().xBias;
+ dst->limited_axes_imu_uncalibrated.y_bias =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().yBias;
+ dst->limited_axes_imu_uncalibrated.z_bias =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().zBias;
+ dst->limited_axes_imu_uncalibrated.x_supported =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().xSupported;
+ dst->limited_axes_imu_uncalibrated.y_supported =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().ySupported;
+ dst->limited_axes_imu_uncalibrated.z_supported =
+ 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);
@@ -264,7 +304,7 @@
*dst = {
.timestamp = src.timestamp,
.sensorHandle = src.sensor,
- .sensorType = (SensorType) src.type,
+ .sensorType = (SensorType)src.type,
};
switch (dst->sensorType) {
@@ -409,6 +449,43 @@
break;
}
+ case SensorType::ACCELEROMETER_LIMITED_AXES:
+ case SensorType::GYROSCOPE_LIMITED_AXES: {
+ Event::EventPayload::LimitedAxesImu limitedAxesImu;
+ limitedAxesImu.x = src.limited_axes_imu.x;
+ limitedAxesImu.y = src.limited_axes_imu.y;
+ limitedAxesImu.z = src.limited_axes_imu.z;
+ limitedAxesImu.xSupported = src.limited_axes_imu.x_supported;
+ limitedAxesImu.ySupported = src.limited_axes_imu.y_supported;
+ limitedAxesImu.zSupported = src.limited_axes_imu.z_supported;
+ dst->payload.set<Event::EventPayload::Tag::limitedAxesImu>(limitedAxesImu);
+ break;
+ }
+
+ case SensorType::ACCELEROMETER_LIMITED_AXES_UNCALIBRATED:
+ case SensorType::GYROSCOPE_LIMITED_AXES_UNCALIBRATED: {
+ Event::EventPayload::LimitedAxesImuUncal limitedAxesImuUncal;
+ limitedAxesImuUncal.x = src.limited_axes_imu_uncalibrated.x_uncalib;
+ limitedAxesImuUncal.y = src.limited_axes_imu_uncalibrated.y_uncalib;
+ limitedAxesImuUncal.z = src.limited_axes_imu_uncalibrated.z_uncalib;
+ limitedAxesImuUncal.xBias = src.limited_axes_imu_uncalibrated.x_bias;
+ limitedAxesImuUncal.yBias = src.limited_axes_imu_uncalibrated.y_bias;
+ limitedAxesImuUncal.zBias = src.limited_axes_imu_uncalibrated.z_bias;
+ limitedAxesImuUncal.xSupported = src.limited_axes_imu_uncalibrated.x_supported;
+ limitedAxesImuUncal.ySupported = src.limited_axes_imu_uncalibrated.y_supported;
+ limitedAxesImuUncal.zSupported = src.limited_axes_imu_uncalibrated.z_supported;
+ dst->payload.set<Event::EventPayload::Tag::limitedAxesImuUncal>(limitedAxesImuUncal);
+ 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/Android.bp b/services/sensorservice/Android.bp
index d5b629d..3c4f8d9 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -17,6 +17,7 @@
"Fusion.cpp",
"GravitySensor.cpp",
"HidlSensorHalWrapper.cpp",
+ "LimitedAxesImuSensor.cpp",
"LinearAccelerationSensor.cpp",
"OrientationSensor.cpp",
"RecentEventLogger.cpp",
diff --git a/services/sensorservice/LimitedAxesImuSensor.cpp b/services/sensorservice/LimitedAxesImuSensor.cpp
new file mode 100644
index 0000000..2f91479
--- /dev/null
+++ b/services/sensorservice/LimitedAxesImuSensor.cpp
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ * 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 <math.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+
+#include <hardware/sensors.h>
+
+#include "LimitedAxesImuSensor.h"
+#include "SensorDevice.h"
+#include "SensorFusion.h"
+#include "SensorServiceUtils.h"
+
+namespace android {
+
+namespace {
+const sensor_t DUMMY_SENSOR = {.name = "",
+ .vendor = "",
+ .stringType = "",
+ .requiredPermission = ""};
+} // unnamed namespace
+
+LimitedAxesImuSensor::LimitedAxesImuSensor(sensor_t const* list, size_t count,
+ int32_t imu3dSensorType)
+ : BaseSensor(DUMMY_SENSOR) {
+ for (size_t i = 0; i < count; i++) {
+ if (list[i].type == imu3dSensorType) {
+ mImu3dSensor = Sensor(list + i);
+ break;
+ }
+ }
+
+ const int32_t imuLimitedAxesSensorType = convertImu3dToLimitedAxesSensorType(imu3dSensorType);
+
+ const sensor_t sensor = {
+ .name = convertLimitedAxesSensorTypeToName(imuLimitedAxesSensorType),
+ .vendor = "AOSP",
+ .version = 1,
+ .handle = convertLimitedAxesSensorTypeToHandle(imuLimitedAxesSensorType),
+ .type = imuLimitedAxesSensorType,
+ .maxRange = mImu3dSensor.getMaxValue(),
+ .resolution = mImu3dSensor.getResolution(),
+ .power = mImu3dSensor.getPowerUsage(),
+ .minDelay = mImu3dSensor.getMinDelay(),
+ };
+ mSensor = Sensor(&sensor);
+}
+
+bool LimitedAxesImuSensor::process(sensors_event_t* outEvent, const sensors_event_t& event) {
+ if (event.type == mImu3dSensor.getType()) {
+ *outEvent = event;
+ size_t imu3dDataSize = SensorServiceUtil::eventSizeBySensorType(mImu3dSensor.getType());
+ outEvent->data[0 + imu3dDataSize] = 1;
+ outEvent->data[1 + imu3dDataSize] = 1;
+ outEvent->data[2 + imu3dDataSize] = 1;
+ outEvent->sensor = mSensor.getHandle();
+ outEvent->type = mSensor.getType();
+ return true;
+ }
+ return false;
+}
+
+status_t LimitedAxesImuSensor::activate(void* ident, bool enabled) {
+ return mSensorDevice.activate(ident, mImu3dSensor.getHandle(), enabled);
+}
+
+status_t LimitedAxesImuSensor::setDelay(void* ident, int /*handle*/, int64_t ns) {
+ return mSensorDevice.setDelay(ident, mImu3dSensor.getHandle(), ns);
+}
+
+int32_t LimitedAxesImuSensor::convertImu3dToLimitedAxesSensorType(int32_t imu3dSensorType) {
+ switch (imu3dSensorType) {
+ case SENSOR_TYPE_ACCELEROMETER:
+ return SENSOR_TYPE_ACCELEROMETER_LIMITED_AXES;
+ case SENSOR_TYPE_GYROSCOPE:
+ return SENSOR_TYPE_GYROSCOPE_LIMITED_AXES;
+ case SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED:
+ return SENSOR_TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED;
+ case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
+ return SENSOR_TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED;
+ default:
+ return 0;
+ }
+}
+
+int32_t LimitedAxesImuSensor::convertLimitedAxesSensorTypeToHandle(
+ int32_t imuLimitedAxesSensorType) {
+ switch (imuLimitedAxesSensorType) {
+ case SENSOR_TYPE_ACCELEROMETER_LIMITED_AXES:
+ return '_ala';
+ case SENSOR_TYPE_GYROSCOPE_LIMITED_AXES:
+ return '_gla';
+ case SENSOR_TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED:
+ return '_alc';
+ case SENSOR_TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED:
+ return '_glc';
+ default:
+ return 0;
+ }
+}
+
+const char* LimitedAxesImuSensor::convertLimitedAxesSensorTypeToName(
+ int32_t imuLimitedAxesSensorType) {
+ switch (imuLimitedAxesSensorType) {
+ case SENSOR_TYPE_ACCELEROMETER_LIMITED_AXES:
+ return "Accelerometer Limited Axes Sensor";
+ case SENSOR_TYPE_GYROSCOPE_LIMITED_AXES:
+ return "Gyroscope Limited Axes Sensor";
+ case SENSOR_TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED:
+ return "Accelerometer Limited Axes Uncalibrated Sensor";
+ case SENSOR_TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED:
+ return "Gyroscope Limited Axes Uncalibrated Sensor";
+ default:
+ return "";
+ }
+}
+
+}; // namespace android
diff --git a/services/sensorservice/LimitedAxesImuSensor.h b/services/sensorservice/LimitedAxesImuSensor.h
new file mode 100644
index 0000000..fd46a98
--- /dev/null
+++ b/services/sensorservice/LimitedAxesImuSensor.h
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ * 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 <stdint.h>
+#include <sys/types.h>
+
+#include <sensor/Sensor.h>
+
+#include "SensorInterface.h"
+
+namespace android {
+
+class SensorDevice;
+
+class LimitedAxesImuSensor : public BaseSensor {
+ Sensor mImu3dSensor;
+
+public:
+ LimitedAxesImuSensor(sensor_t const* list, size_t count, int32_t imuSensorType);
+ virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event) override;
+ virtual status_t activate(void* ident, bool enabled) override;
+ virtual status_t setDelay(void* ident, int handle, int64_t ns) override;
+ virtual bool isVirtual() const override { return true; }
+
+private:
+ int32_t convertImu3dToLimitedAxesSensorType(int32_t imu3dSensorType);
+ int32_t convertLimitedAxesSensorTypeToHandle(int32_t imuLimitedAxesSensorType);
+ const char* convertLimitedAxesSensorTypeToName(int32_t imuLimitedAxesSensorType);
+};
+
+}; // namespace android
\ No newline at end of file
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 517d383..971491d 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -38,6 +38,7 @@
#include "BatteryService.h"
#include "CorrectedGyroSensor.h"
#include "GravitySensor.h"
+#include "LimitedAxesImuSensor.h"
#include "LinearAccelerationSensor.h"
#include "OrientationSensor.h"
#include "RotationVectorSensor.h"
@@ -101,6 +102,33 @@
static const String16 sLocationHardwarePermission("android.permission.LOCATION_HARDWARE");
static const String16 sManageSensorsPermission("android.permission.MANAGE_SENSORS");
+static bool isAutomotive() {
+ sp<IServiceManager> serviceManager = defaultServiceManager();
+ if (serviceManager.get() == nullptr) {
+ ALOGE("%s: unable to access native ServiceManager", __func__);
+ return false;
+ }
+
+ sp<content::pm::IPackageManagerNative> packageManager;
+ sp<IBinder> binder = serviceManager->waitForService(String16("package_native"));
+ packageManager = interface_cast<content::pm::IPackageManagerNative>(binder);
+ if (packageManager == nullptr) {
+ ALOGE("%s: unable to access native PackageManager", __func__);
+ return false;
+ }
+
+ bool isAutomotive = false;
+ binder::Status status =
+ packageManager->hasSystemFeature(String16("android.hardware.type.automotive"), 0,
+ &isAutomotive);
+ if (!status.isOk()) {
+ ALOGE("%s: hasSystemFeature failed: %s", __func__, status.exceptionMessage().c_str());
+ return false;
+ }
+
+ return isAutomotive;
+}
+
SensorService::SensorService()
: mInitCheck(NO_INIT), mSocketBufferSize(SOCKET_BUFFER_SIZE_NON_BATCHED),
mWakeLockAcquired(false), mLastReportedProxIsActive(false) {
@@ -165,6 +193,8 @@
ssize_t count = dev.getSensorList(&list);
if (count > 0) {
bool hasGyro = false, hasAccel = false, hasMag = false;
+ bool hasGyroUncalibrated = false;
+ bool hasAccelUncalibrated = false;
uint32_t virtualSensorsNeeds =
(1<<SENSOR_TYPE_GRAVITY) |
(1<<SENSOR_TYPE_LINEAR_ACCELERATION) |
@@ -179,13 +209,18 @@
case SENSOR_TYPE_ACCELEROMETER:
hasAccel = true;
break;
+ case SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED:
+ hasAccelUncalibrated = true;
+ break;
case SENSOR_TYPE_MAGNETIC_FIELD:
hasMag = true;
break;
case SENSOR_TYPE_GYROSCOPE:
- case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
hasGyro = true;
break;
+ case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
+ hasGyroUncalibrated = true;
+ break;
case SENSOR_TYPE_GRAVITY:
case SENSOR_TYPE_LINEAR_ACCELERATION:
case SENSOR_TYPE_ROTATION_VECTOR:
@@ -216,7 +251,7 @@
// registered)
SensorFusion::getInstance();
- if (hasGyro && hasAccel && hasMag) {
+ if ((hasGyro || hasGyroUncalibrated) && hasAccel && hasMag) {
// Add Android virtual sensors if they're not already
// available in the HAL
bool needRotationVector =
@@ -230,7 +265,7 @@
registerSensor( new GyroDriftSensor(), true, true);
}
- if (hasAccel && hasGyro) {
+ if (hasAccel && (hasGyro || hasGyroUncalibrated)) {
bool needGravitySensor = (virtualSensorsNeeds & (1<<SENSOR_TYPE_GRAVITY)) != 0;
registerSensor(new GravitySensor(list, count), !needGravitySensor, true);
@@ -250,6 +285,30 @@
registerSensor(new GeoMagRotationVectorSensor(), !needGeoMagRotationVector, true);
}
+ if (isAutomotive()) {
+ if (hasAccel) {
+ registerSensor(new LimitedAxesImuSensor(list, count, SENSOR_TYPE_ACCELEROMETER),
+ /*isDebug=*/false, /*isVirtual=*/true);
+ }
+
+ if (hasGyro) {
+ registerSensor(new LimitedAxesImuSensor(list, count, SENSOR_TYPE_GYROSCOPE),
+ /*isDebug=*/false, /*isVirtual=*/true);
+ }
+
+ if (hasAccelUncalibrated) {
+ registerSensor(new LimitedAxesImuSensor(list, count,
+ SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED),
+ /*isDebug=*/false, /*isVirtual=*/true);
+ }
+
+ if (hasGyroUncalibrated) {
+ registerSensor(new LimitedAxesImuSensor(list, count,
+ SENSOR_TYPE_GYROSCOPE_UNCALIBRATED),
+ /*isDebug=*/false, /*isVirtual=*/true);
+ }
+ }
+
// Check if the device really supports batching by looking at the FIFO event
// counts for each sensor.
bool batchingSupported = false;
diff --git a/services/sensorservice/SensorServiceUtils.cpp b/services/sensorservice/SensorServiceUtils.cpp
index baa01c9..7dd2331 100644
--- a/services/sensorservice/SensorServiceUtils.cpp
+++ b/services/sensorservice/SensorServiceUtils.cpp
@@ -30,12 +30,18 @@
case SENSOR_TYPE_POSE_6DOF:
return 16;
+ case SENSOR_TYPE_ACCELEROMETER_LIMITED_AXES_UNCALIBRATED:
+ case SENSOR_TYPE_GYROSCOPE_LIMITED_AXES_UNCALIBRATED:
+ return 9;
+
case SENSOR_TYPE_ROTATION_VECTOR:
case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR:
return 5;
case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
+ case SENSOR_TYPE_ACCELEROMETER_LIMITED_AXES:
+ case SENSOR_TYPE_GYROSCOPE_LIMITED_AXES:
return 6;
case SENSOR_TYPE_GAME_ROTATION_VECTOR:
@@ -61,6 +67,9 @@
case SENSOR_TYPE_HEAD_TRACKER:
return 7;
+ case SENSOR_TYPE_HEADING:
+ return 2;
+
default:
return 3;
}
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index af0f524..d9958f3 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -118,9 +118,6 @@
cc_defaults {
name: "libsurfaceflinger_production_defaults",
defaults: ["libsurfaceflinger_defaults"],
- cflags: [
- "-fvisibility=hidden",
- ],
lto: {
thin: true,
},
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index e797b5d..18a6bae 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -306,7 +306,7 @@
: aidl::android::hardware::graphics::composer3::Composition::DEVICE;
}
- compositionState->buffer = mBufferInfo.mBuffer->getBuffer();
+ compositionState->buffer = getBuffer();
compositionState->bufferSlot = (mBufferInfo.mBufferSlot == BufferQueue::INVALID_BUFFER_SLOT)
? 0
: mBufferInfo.mBufferSlot;
@@ -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/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index 16aebef..ee0c53d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -26,8 +26,18 @@
// Defines the interface used by the CompositionEngine to make requests
// of the front-end layer.
class LayerFE : public compositionengine::LayerFE {
-public:
+private:
+ // Making the constructor private as this class implements RefBase,
+ // and constructing it with a different way than sp<LayerFE>::make() causes
+ // a memory leak of the shared state.
LayerFE();
+
+ // friends class to allow instantiation via sp<LayerFE>::make() and
+ // sp<StrictMock<LayerFE>>::make()
+ friend class sp<LayerFE>;
+ friend class testing::StrictMock<LayerFE>;
+
+public:
virtual ~LayerFE();
MOCK_CONST_METHOD0(getCompositionState, const LayerFECompositionState*());
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 1ea13a7..29c146b 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -59,9 +59,13 @@
setName(args.name);
bool isBootModeSupported = getCompositionEngine().getHwComposer().getBootDisplayModeSupport();
const auto physicalId = PhysicalDisplayId::tryCast(mId);
- if (physicalId && isBootModeSupported) {
- mPreferredBootDisplayModeId = static_cast<int32_t>(
- getCompositionEngine().getHwComposer().getPreferredBootDisplayMode(*physicalId));
+ if (!physicalId || !isBootModeSupported) {
+ return;
+ }
+ std::optional<hal::HWConfigId> preferredBootModeId =
+ getCompositionEngine().getHwComposer().getPreferredBootDisplayMode(*physicalId);
+ if (preferredBootModeId.has_value()) {
+ mPreferredBootDisplayModeId = static_cast<int32_t>(preferredBootModeId.value());
}
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
index 325361b..de9de01 100644
--- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
@@ -203,9 +203,9 @@
*/
struct CompositionTestPreComposition : public CompositionEngineTest {
- sp<StrictMock<mock::LayerFE>> mLayer1FE{new StrictMock<mock::LayerFE>()};
- sp<StrictMock<mock::LayerFE>> mLayer2FE{new StrictMock<mock::LayerFE>()};
- sp<StrictMock<mock::LayerFE>> mLayer3FE{new StrictMock<mock::LayerFE>()};
+ sp<StrictMock<mock::LayerFE>> mLayer1FE = sp<StrictMock<mock::LayerFE>>::make();
+ sp<StrictMock<mock::LayerFE>> mLayer2FE = sp<StrictMock<mock::LayerFE>>::make();
+ sp<StrictMock<mock::LayerFE>> mLayer3FE = sp<StrictMock<mock::LayerFE>>::make();
};
TEST_F(CompositionTestPreComposition, preCompositionSetsFrameTimestamp) {
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 03c6f8d..125ce74 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -74,7 +74,7 @@
EXPECT_CALL(*outputLayer, getHwcLayer()).WillRepeatedly(Return(&hwc2Layer));
}
- sp<mock::LayerFE> layerFE = new StrictMock<mock::LayerFE>();
+ sp<StrictMock<mock::LayerFE>> layerFE = sp<StrictMock<mock::LayerFE>>::make();
StrictMock<mock::OutputLayer>* outputLayer = new StrictMock<mock::OutputLayer>();
StrictMock<HWC2::mock::Layer> hwc2Layer;
};
@@ -85,7 +85,7 @@
EXPECT_CALL(*outputLayer, getHwcLayer()).WillRepeatedly(Return(nullptr));
}
- sp<mock::LayerFE> layerFE = new StrictMock<mock::LayerFE>();
+ sp<StrictMock<mock::LayerFE>> layerFE = sp<StrictMock<mock::LayerFE>>::make();
StrictMock<mock::OutputLayer>* outputLayer = new StrictMock<mock::OutputLayer>();
};
@@ -469,7 +469,7 @@
using DisplayCreateOutputLayerTest = FullDisplayImplTestCommon;
TEST_F(DisplayCreateOutputLayerTest, setsHwcLayer) {
- sp<mock::LayerFE> layerFE = new StrictMock<mock::LayerFE>();
+ sp<StrictMock<mock::LayerFE>> layerFE = sp<StrictMock<mock::LayerFE>>::make();
auto hwcLayer = std::make_shared<StrictMock<HWC2::mock::Layer>>();
EXPECT_CALL(mHwComposer, createLayer(HalDisplayId(DEFAULT_DISPLAY_ID)))
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index bcd4dc2..660f664 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -108,7 +108,7 @@
hal::VsyncPeriodChangeTimeline*));
MOCK_METHOD2(setBootDisplayMode, status_t(PhysicalDisplayId, hal::HWConfigId));
MOCK_METHOD1(clearBootDisplayMode, status_t(PhysicalDisplayId));
- MOCK_METHOD1(getPreferredBootDisplayMode, hal::HWConfigId(PhysicalDisplayId));
+ MOCK_METHOD1(getPreferredBootDisplayMode, std::optional<hal::HWConfigId>(PhysicalDisplayId));
MOCK_METHOD0(getBootDisplayModeSupport, bool());
MOCK_METHOD2(setAutoLowLatencyMode, status_t(PhysicalDisplayId, bool));
MOCK_METHOD2(getSupportedContentTypes,
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 0b123b1..82dcc66 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -109,8 +109,8 @@
}
compositionengine::mock::Output mOutput;
- sp<compositionengine::mock::LayerFE> mLayerFE{
- new StrictMock<compositionengine::mock::LayerFE>()};
+ sp<StrictMock<compositionengine::mock::LayerFE>> mLayerFE =
+ sp<StrictMock<compositionengine::mock::LayerFE>>::make();
OutputLayer mOutputLayer{mOutput, mLayerFE};
LayerFECompositionState mLayerFEState;
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index f7d5991..e72bc9f 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -106,7 +106,7 @@
}
mock::OutputLayer* outputLayer = {new StrictMock<mock::OutputLayer>};
- sp<StrictMock<mock::LayerFE>> layerFE = new StrictMock<mock::LayerFE>();
+ sp<StrictMock<mock::LayerFE>> layerFE = sp<StrictMock<mock::LayerFE>>::make();
LayerFECompositionState layerFEState;
impl::OutputLayerCompositionState outputLayerState;
};
@@ -123,7 +123,7 @@
}
mock::OutputLayer outputLayer;
- sp<StrictMock<mock::LayerFE>> layerFE = new StrictMock<mock::LayerFE>();
+ sp<StrictMock<mock::LayerFE>> layerFE = sp<StrictMock<mock::LayerFE>>::make();
LayerFECompositionState layerFEState;
impl::OutputLayerCompositionState outputLayerState;
};
@@ -722,9 +722,9 @@
using OutputSetReleasedLayersTest = OutputTest;
TEST_F(OutputSetReleasedLayersTest, setReleasedLayersTakesGivenLayers) {
- sp<StrictMock<mock::LayerFE>> layer1FE{new StrictMock<mock::LayerFE>()};
- sp<StrictMock<mock::LayerFE>> layer2FE{new StrictMock<mock::LayerFE>()};
- sp<StrictMock<mock::LayerFE>> layer3FE{new StrictMock<mock::LayerFE>()};
+ sp<StrictMock<mock::LayerFE>> layer1FE = sp<StrictMock<mock::LayerFE>>::make();
+ sp<StrictMock<mock::LayerFE>> layer2FE = sp<StrictMock<mock::LayerFE>>::make();
+ sp<StrictMock<mock::LayerFE>> layer3FE = sp<StrictMock<mock::LayerFE>>::make();
Output::ReleasedLayers layers;
layers.push_back(layer1FE);
@@ -1209,7 +1209,7 @@
StrictMock<mock::OutputLayer> outputLayer;
impl::OutputLayerCompositionState outputLayerState;
- sp<StrictMock<mock::LayerFE>> layerFE{new StrictMock<mock::LayerFE>()};
+ sp<StrictMock<mock::LayerFE>> layerFE = sp<StrictMock<mock::LayerFE>>::make();
};
OutputCollectVisibleLayersTest() {
@@ -2987,9 +2987,9 @@
EXPECT_CALL(mOutput, getOutputLayerCount()).WillOnce(Return(0u));
// Load up the released layers with some mock instances
- sp<StrictMock<mock::LayerFE>> releasedLayer1{new StrictMock<mock::LayerFE>()};
- sp<StrictMock<mock::LayerFE>> releasedLayer2{new StrictMock<mock::LayerFE>()};
- sp<StrictMock<mock::LayerFE>> releasedLayer3{new StrictMock<mock::LayerFE>()};
+ sp<StrictMock<mock::LayerFE>> releasedLayer1 = sp<StrictMock<mock::LayerFE>>::make();
+ sp<StrictMock<mock::LayerFE>> releasedLayer2 = sp<StrictMock<mock::LayerFE>>::make();
+ sp<StrictMock<mock::LayerFE>> releasedLayer3 = sp<StrictMock<mock::LayerFE>>::make();
Output::ReleasedLayers layers;
layers.push_back(releasedLayer1);
layers.push_back(releasedLayer2);
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
index 84b3fc5..0b1c262 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
@@ -107,7 +107,7 @@
EXPECT_EQ(fields, rhs.getDifferingFields(lhs));
}
- mock::LayerFE mLayerFE;
+ sp<mock::LayerFE> mLayerFE = sp<mock::LayerFE>::make();
mock::OutputLayer mOutputLayer;
std::unique_ptr<LayerState> mLayerState;
};
@@ -115,7 +115,7 @@
TEST_F(LayerStateTest, getOutputLayer) {
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
EXPECT_EQ(&mOutputLayer, mLayerState->getOutputLayer());
@@ -124,14 +124,14 @@
TEST_F(LayerStateTest, updateOutputLayer) {
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
EXPECT_EQ(&mOutputLayer, mLayerState->getOutputLayer());
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState->update(&newOutputLayer);
EXPECT_EQ(&newOutputLayer, mLayerState->getOutputLayer());
@@ -140,7 +140,7 @@
TEST_F(LayerStateTest, getId) {
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
EXPECT_EQ(sSequenceId, mLayerState->getId());
@@ -149,13 +149,13 @@
TEST_F(LayerStateTest, updateId) {
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionState, sSequenceIdTwo);
Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
EXPECT_EQ(sSequenceIdTwo, mLayerState->getId());
@@ -165,12 +165,12 @@
TEST_F(LayerStateTest, compareId) {
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionState, sSequenceIdTwo);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
@@ -185,7 +185,7 @@
TEST_F(LayerStateTest, getName) {
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
EXPECT_EQ(sDebugName, mLayerState->getName());
@@ -194,13 +194,13 @@
TEST_F(LayerStateTest, updateName) {
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionState, sSequenceId, sDebugNameTwo);
Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
EXPECT_EQ(sDebugNameTwo, mLayerState->getName());
@@ -210,12 +210,12 @@
TEST_F(LayerStateTest, compareName) {
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionState, sSequenceId, sDebugNameTwo);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
@@ -231,7 +231,7 @@
OutputLayerCompositionState outputLayerCompositionState;
outputLayerCompositionState.displayFrame = sRectOne;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
EXPECT_EQ(sRectOne, mLayerState->getDisplayFrame());
@@ -241,15 +241,15 @@
OutputLayerCompositionState outputLayerCompositionState;
outputLayerCompositionState.displayFrame = sRectOne;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateTwo;
outputLayerCompositionStateTwo.displayFrame = sRectTwo;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo,
layerFECompositionState);
Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
EXPECT_EQ(sRectTwo, mLayerState->getDisplayFrame());
@@ -260,14 +260,14 @@
OutputLayerCompositionState outputLayerCompositionState;
outputLayerCompositionState.displayFrame = sRectOne;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateTwo;
outputLayerCompositionStateTwo.displayFrame = sRectTwo;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo,
layerFECompositionState);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
@@ -282,7 +282,7 @@
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.compositionType = Composition::DEVICE;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
EXPECT_EQ(Composition::DEVICE, mLayerState->getCompositionType());
@@ -293,7 +293,7 @@
outputLayerCompositionState.forceClientComposition = true;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.compositionType = Composition::DEVICE;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
EXPECT_EQ(Composition::CLIENT, mLayerState->getCompositionType());
@@ -303,15 +303,15 @@
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.compositionType = Composition::DEVICE;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.compositionType = Composition::SOLID_COLOR;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
EXPECT_EQ(Composition::SOLID_COLOR, mLayerState->getCompositionType());
@@ -322,14 +322,14 @@
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.compositionType = Composition::DEVICE;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.compositionType = Composition::SOLID_COLOR;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
@@ -345,15 +345,15 @@
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.buffer = new GraphicBuffer();
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.buffer = new GraphicBuffer();
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Buffer), updates);
@@ -363,14 +363,14 @@
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.buffer = new GraphicBuffer();
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.buffer = new GraphicBuffer();
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
@@ -386,15 +386,15 @@
OutputLayerCompositionState outputLayerCompositionState;
outputLayerCompositionState.sourceCrop = sFloatRectOne;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateTwo;
outputLayerCompositionStateTwo.sourceCrop = sFloatRectTwo;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo,
layerFECompositionState);
Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SourceCrop), updates);
@@ -404,14 +404,14 @@
OutputLayerCompositionState outputLayerCompositionState;
outputLayerCompositionState.sourceCrop = sFloatRectOne;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateTwo;
outputLayerCompositionStateTwo.sourceCrop = sFloatRectTwo;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo,
layerFECompositionState);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
@@ -425,15 +425,15 @@
OutputLayerCompositionState outputLayerCompositionState;
outputLayerCompositionState.bufferTransform = Hwc2::Transform::FLIP_H;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateTwo;
outputLayerCompositionStateTwo.bufferTransform = Hwc2::Transform::FLIP_V;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo,
layerFECompositionState);
Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
EXPECT_EQ(Flags<LayerStateField>(LayerStateField::BufferTransform), updates);
@@ -443,14 +443,14 @@
OutputLayerCompositionState outputLayerCompositionState;
outputLayerCompositionState.bufferTransform = Hwc2::Transform::FLIP_H;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateTwo;
outputLayerCompositionStateTwo.bufferTransform = Hwc2::Transform::FLIP_V;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo,
layerFECompositionState);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
@@ -465,15 +465,15 @@
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.blendMode = hal::BlendMode::COVERAGE;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.blendMode = hal::BlendMode::PREMULTIPLIED;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
EXPECT_EQ(Flags<LayerStateField>(LayerStateField::BlendMode), updates);
@@ -483,14 +483,14 @@
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.blendMode = hal::BlendMode::COVERAGE;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.blendMode = hal::BlendMode::PREMULTIPLIED;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
@@ -504,15 +504,15 @@
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.alpha = sAlphaOne;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.alpha = sAlphaTwo;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Alpha), updates);
@@ -522,14 +522,14 @@
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.alpha = sAlphaOne;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.alpha = sAlphaTwo;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
@@ -543,15 +543,15 @@
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.metadata[sMetadataKeyOne] = sMetadataValueOne;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.metadata[sMetadataKeyTwo] = sMetadataValueTwo;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
EXPECT_EQ(Flags<LayerStateField>(LayerStateField::LayerMetadata), updates);
@@ -561,14 +561,14 @@
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.metadata[sMetadataKeyOne] = sMetadataValueOne;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.metadata[sMetadataKeyTwo] = sMetadataValueTwo;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
@@ -582,7 +582,7 @@
OutputLayerCompositionState outputLayerCompositionState;
outputLayerCompositionState.visibleRegion = sRegionOne;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
EXPECT_TRUE(mLayerState->getVisibleRegion().hasSameRects(sRegionOne));
@@ -592,15 +592,15 @@
OutputLayerCompositionState outputLayerCompositionState;
outputLayerCompositionState.visibleRegion = sRegionOne;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateTwo;
outputLayerCompositionStateTwo.visibleRegion = sRegionTwo;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo,
layerFECompositionState);
Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
EXPECT_EQ(Flags<LayerStateField>(LayerStateField::VisibleRegion), updates);
@@ -610,14 +610,14 @@
OutputLayerCompositionState outputLayerCompositionState;
outputLayerCompositionState.visibleRegion = sRegionOne;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateTwo;
outputLayerCompositionStateTwo.visibleRegion = sRegionTwo;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo,
layerFECompositionState);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
@@ -631,15 +631,15 @@
OutputLayerCompositionState outputLayerCompositionState;
outputLayerCompositionState.dataspace = ui::Dataspace::SRGB;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateTwo;
outputLayerCompositionStateTwo.dataspace = ui::Dataspace::DISPLAY_P3;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo,
layerFECompositionState);
Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Dataspace), updates);
@@ -649,14 +649,14 @@
OutputLayerCompositionState outputLayerCompositionState;
outputLayerCompositionState.dataspace = ui::Dataspace::SRGB;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateTwo;
outputLayerCompositionStateTwo.dataspace = ui::Dataspace::DISPLAY_P3;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo,
layerFECompositionState);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
@@ -674,19 +674,19 @@
AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
"buffer1");
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.buffer =
new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBX_8888,
AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
"buffer2");
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Buffer) |
@@ -702,18 +702,18 @@
AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
"buffer1");
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.buffer =
new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBX_8888,
AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
"buffer2");
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
@@ -729,16 +729,16 @@
LayerFECompositionState layerFECompositionState;
layerFECompositionState.colorTransformIsIdentity = true;
layerFECompositionState.colorTransform = mat4();
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.colorTransformIsIdentity = false;
layerFECompositionStateTwo.colorTransform = sMat4One;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
EXPECT_EQ(Flags<LayerStateField>(LayerStateField::ColorTransform), updates);
@@ -749,15 +749,15 @@
LayerFECompositionState layerFECompositionState;
layerFECompositionState.colorTransformIsIdentity = true;
layerFECompositionState.colorTransform = mat4();
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.colorTransformIsIdentity = false;
layerFECompositionStateTwo.colorTransform = sMat4One;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
@@ -771,15 +771,15 @@
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.sidebandStream = NativeHandle::create(sFakeSidebandStreamOne, false);
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.sidebandStream = NativeHandle::create(sFakeSidebandStreamTwo, false);
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SidebandStream), updates);
@@ -789,14 +789,14 @@
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.sidebandStream = NativeHandle::create(sFakeSidebandStreamOne, false);
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.sidebandStream = NativeHandle::create(sFakeSidebandStreamTwo, false);
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
@@ -810,15 +810,15 @@
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.color = sHalf4One;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.color = sHalf4Two;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SolidColor), updates);
@@ -828,14 +828,14 @@
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.color = sHalf4One;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.color = sHalf4Two;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
@@ -849,15 +849,15 @@
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.backgroundBlurRadius = sBgBlurRadiusOne;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.backgroundBlurRadius = sBgBlurRadiusTwo;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
EXPECT_EQ(Flags<LayerStateField>(LayerStateField::BackgroundBlurRadius), updates);
@@ -867,14 +867,14 @@
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.backgroundBlurRadius = sBgBlurRadiusOne;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.backgroundBlurRadius = sBgBlurRadiusTwo;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
@@ -889,15 +889,15 @@
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.blurRegions.push_back(sBlurRegionOne);
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.blurRegions.push_back(sBlurRegionTwo);
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
EXPECT_EQ(Flags<LayerStateField>(LayerStateField::BlurRegions), updates);
@@ -907,14 +907,14 @@
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.blurRegions.push_back(sBlurRegionOne);
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.blurRegions.push_back(sBlurRegionTwo);
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
@@ -927,7 +927,7 @@
TEST_F(LayerStateTest, hasBlurBehind_noBlur_returnsFalse) {
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
EXPECT_FALSE(mLayerState->hasBlurBehind());
@@ -937,7 +937,7 @@
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.backgroundBlurRadius = sBgBlurRadiusOne;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
EXPECT_TRUE(mLayerState->hasBlurBehind());
@@ -947,7 +947,7 @@
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.blurRegions.push_back(sBlurRegionOne);
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
EXPECT_TRUE(mLayerState->hasBlurBehind());
@@ -956,7 +956,7 @@
TEST_F(LayerStateTest, dumpDoesNotCrash) {
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
std::string dump;
@@ -967,7 +967,7 @@
TEST_F(LayerStateTest, framesSinceBufferUpdate) {
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
@@ -982,14 +982,14 @@
OutputLayerCompositionState outputLayerCompositionState;
outputLayerCompositionState.displayFrame = sRectOne;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateTwo;
outputLayerCompositionStateTwo.displayFrame = sRectTwo;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo,
layerFECompositionState);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
@@ -1001,14 +1001,14 @@
OutputLayerCompositionState outputLayerCompositionState;
outputLayerCompositionState.displayFrame = sRectOne;
LayerFECompositionState layerFECompositionState;
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateTwo;
outputLayerCompositionStateTwo.displayFrame = sRectTwo;
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionStateTwo,
layerFECompositionState);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
@@ -1020,15 +1020,15 @@
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.buffer = new GraphicBuffer();
- setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
- mock::LayerFE newLayerFE;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.buffer = new GraphicBuffer();
- setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp
index 6038268..68c72e0 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp
@@ -73,26 +73,26 @@
TEST_F(LayerStackTest, getApproximateMatch_doesNotMatchSizeDifferences) {
mock::OutputLayer outputLayerOne;
- mock::LayerFE layerFEOne;
+ sp<mock::LayerFE> layerFEOne = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateOne;
LayerFECompositionState layerFECompositionStateOne;
- setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
+ setupMocksForLayer(outputLayerOne, *layerFEOne, outputLayerCompositionStateOne,
layerFECompositionStateOne);
LayerState layerStateOne(&outputLayerOne);
mock::OutputLayer outputLayerTwo;
- mock::LayerFE layerFETwo;
+ sp<mock::LayerFE> layerFETwo = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateTwo;
LayerFECompositionState layerFECompositionStateTwo;
- setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo,
+ setupMocksForLayer(outputLayerTwo, *layerFETwo, outputLayerCompositionStateTwo,
layerFECompositionStateTwo);
LayerState layerStateTwo(&outputLayerTwo);
mock::OutputLayer outputLayerThree;
- mock::LayerFE layerFEThree;
+ sp<mock::LayerFE> layerFEThree = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateThree;
LayerFECompositionState layerFECompositionStateThree;
- setupMocksForLayer(outputLayerThree, layerFEThree, outputLayerCompositionStateThree,
+ setupMocksForLayer(outputLayerThree, *layerFEThree, outputLayerCompositionStateThree,
layerFECompositionStateThree);
LayerState layerStateThree(&outputLayerThree);
@@ -104,20 +104,20 @@
TEST_F(LayerStackTest, getApproximateMatch_doesNotMatchDifferentCompositionTypes) {
mock::OutputLayer outputLayerOne;
- mock::LayerFE layerFEOne;
+ sp<mock::LayerFE> layerFEOne = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateOne;
LayerFECompositionState layerFECompositionStateOne;
layerFECompositionStateOne.compositionType = Composition::DEVICE;
- setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
+ setupMocksForLayer(outputLayerOne, *layerFEOne, outputLayerCompositionStateOne,
layerFECompositionStateOne);
LayerState layerStateOne(&outputLayerOne);
mock::OutputLayer outputLayerTwo;
- mock::LayerFE layerFETwo;
+ sp<mock::LayerFE> layerFETwo = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateTwo;
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.compositionType = Composition::SOLID_COLOR;
- setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo,
+ setupMocksForLayer(outputLayerTwo, *layerFETwo, outputLayerCompositionStateTwo,
layerFECompositionStateTwo);
LayerState layerStateTwo(&outputLayerTwo);
@@ -128,22 +128,22 @@
TEST_F(LayerStackTest, getApproximateMatch_matchesSingleDifferenceInSingleLayer) {
mock::OutputLayer outputLayerOne;
- mock::LayerFE layerFEOne;
+ sp<mock::LayerFE> layerFEOne = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateOne{
.sourceCrop = sFloatRectOne,
};
LayerFECompositionState layerFECompositionStateOne;
- setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
+ setupMocksForLayer(outputLayerOne, *layerFEOne, outputLayerCompositionStateOne,
layerFECompositionStateOne);
LayerState layerStateOne(&outputLayerOne);
mock::OutputLayer outputLayerTwo;
- mock::LayerFE layerFETwo;
+ sp<mock::LayerFE> layerFETwo = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateTwo{
.sourceCrop = sFloatRectTwo,
};
LayerFECompositionState layerFECompositionStateTwo;
- setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo,
+ setupMocksForLayer(outputLayerTwo, *layerFETwo, outputLayerCompositionStateTwo,
layerFECompositionStateTwo);
LayerState layerStateTwo(&outputLayerTwo);
@@ -159,22 +159,22 @@
TEST_F(LayerStackTest, getApproximateMatch_matchesSingleDifferenceInMultiLayerStack) {
mock::OutputLayer outputLayerOne;
- mock::LayerFE layerFEOne;
+ sp<mock::LayerFE> layerFEOne = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateOne{
.sourceCrop = sFloatRectOne,
};
LayerFECompositionState layerFECompositionStateOne;
- setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
+ setupMocksForLayer(outputLayerOne, *layerFEOne, outputLayerCompositionStateOne,
layerFECompositionStateOne);
LayerState layerStateOne(&outputLayerOne);
mock::OutputLayer outputLayerTwo;
- mock::LayerFE layerFETwo;
+ sp<mock::LayerFE> layerFETwo = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateTwo{
.sourceCrop = sFloatRectTwo,
};
LayerFECompositionState layerFECompositionStateTwo;
- setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo,
+ setupMocksForLayer(outputLayerTwo, *layerFETwo, outputLayerCompositionStateTwo,
layerFECompositionStateTwo);
LayerState layerStateTwo(&outputLayerTwo);
@@ -190,7 +190,7 @@
TEST_F(LayerStackTest, getApproximateMatch_doesNotMatchManyDifferences) {
mock::OutputLayer outputLayerOne;
- mock::LayerFE layerFEOne;
+ sp<mock::LayerFE> layerFEOne = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateOne{
.visibleRegion = sRegionOne,
.displayFrame = sRectOne,
@@ -201,12 +201,12 @@
layerFECompositionStateOne.alpha = sAlphaOne;
layerFECompositionStateOne.colorTransformIsIdentity = true;
layerFECompositionStateOne.blendMode = hal::BlendMode::NONE;
- setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
+ setupMocksForLayer(outputLayerOne, *layerFEOne, outputLayerCompositionStateOne,
layerFECompositionStateOne);
LayerState layerStateOne(&outputLayerOne);
mock::OutputLayer outputLayerTwo;
- mock::LayerFE layerFETwo;
+ sp<mock::LayerFE> layerFETwo = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateTwo{
.visibleRegion = sRegionTwo,
.displayFrame = sRectTwo,
@@ -218,7 +218,7 @@
layerFECompositionStateTwo.colorTransformIsIdentity = false;
layerFECompositionStateTwo.colorTransform = sMat4One;
layerFECompositionStateTwo.blendMode = hal::BlendMode::PREMULTIPLIED;
- setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo,
+ setupMocksForLayer(outputLayerTwo, *layerFETwo, outputLayerCompositionStateTwo,
layerFECompositionStateTwo);
LayerState layerStateTwo(&outputLayerTwo);
@@ -230,20 +230,20 @@
TEST_F(LayerStackTest, getApproximateMatch_exactMatchesSameBuffer) {
sp<GraphicBuffer> buffer = new GraphicBuffer();
mock::OutputLayer outputLayerOne;
- mock::LayerFE layerFEOne;
+ sp<mock::LayerFE> layerFEOne = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateOne;
LayerFECompositionState layerFECompositionStateOne;
layerFECompositionStateOne.buffer = buffer;
- setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
+ setupMocksForLayer(outputLayerOne, *layerFEOne, outputLayerCompositionStateOne,
layerFECompositionStateOne);
LayerState layerStateOne(&outputLayerOne);
mock::OutputLayer outputLayerTwo;
- mock::LayerFE layerFETwo;
+ sp<mock::LayerFE> layerFETwo = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateTwo;
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.buffer = buffer;
- setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo,
+ setupMocksForLayer(outputLayerTwo, *layerFETwo, outputLayerCompositionStateTwo,
layerFECompositionStateTwo);
LayerState layerStateTwo(&outputLayerTwo);
@@ -259,7 +259,7 @@
TEST_F(LayerStackTest, getApproximateMatch_alwaysMatchesClientComposition) {
mock::OutputLayer outputLayerOne;
- mock::LayerFE layerFEOne;
+ sp<mock::LayerFE> layerFEOne = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateOne{
.visibleRegion = sRegionOne,
.forceClientComposition = true,
@@ -271,12 +271,12 @@
layerFECompositionStateOne.buffer = new GraphicBuffer();
layerFECompositionStateOne.alpha = sAlphaOne;
layerFECompositionStateOne.colorTransformIsIdentity = true;
- setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
+ setupMocksForLayer(outputLayerOne, *layerFEOne, outputLayerCompositionStateOne,
layerFECompositionStateOne);
LayerState layerStateOne(&outputLayerOne);
mock::OutputLayer outputLayerTwo;
- mock::LayerFE layerFETwo;
+ sp<mock::LayerFE> layerFETwo = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateTwo{
.visibleRegion = sRegionTwo,
.forceClientComposition = true,
@@ -289,7 +289,7 @@
layerFECompositionStateTwo.alpha = sAlphaTwo;
layerFECompositionStateTwo.colorTransformIsIdentity = false;
layerFECompositionStateTwo.colorTransform = sMat4One;
- setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo,
+ setupMocksForLayer(outputLayerTwo, *layerFETwo, outputLayerCompositionStateTwo,
layerFECompositionStateTwo);
LayerState layerStateTwo(&outputLayerTwo);
@@ -305,24 +305,24 @@
TEST_F(LayerStackTest, getApproximateMatch_doesNotMatchMultipleApproximations) {
mock::OutputLayer outputLayerOne;
- mock::LayerFE layerFEOne;
+ sp<mock::LayerFE> layerFEOne = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateOne{
.sourceCrop = sFloatRectOne,
};
LayerFECompositionState layerFECompositionStateOne;
layerFECompositionStateOne.buffer = new GraphicBuffer();
- setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
+ setupMocksForLayer(outputLayerOne, *layerFEOne, outputLayerCompositionStateOne,
layerFECompositionStateOne);
LayerState layerStateOne(&outputLayerOne);
mock::OutputLayer outputLayerTwo;
- mock::LayerFE layerFETwo;
+ sp<mock::LayerFE> layerFETwo = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateTwo{
.sourceCrop = sFloatRectTwo,
};
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.buffer = new GraphicBuffer();
- setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo,
+ setupMocksForLayer(outputLayerTwo, *layerFETwo, outputLayerCompositionStateTwo,
layerFECompositionStateTwo);
LayerState layerStateTwo(&outputLayerTwo);
@@ -348,22 +348,22 @@
TEST_F(LayerStackTest, reorderingChangesNonBufferHash) {
mock::OutputLayer outputLayerOne;
- mock::LayerFE layerFEOne;
+ sp<mock::LayerFE> layerFEOne = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateOne{
.sourceCrop = sFloatRectOne,
};
LayerFECompositionState layerFECompositionStateOne;
- setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
+ setupMocksForLayer(outputLayerOne, *layerFEOne, outputLayerCompositionStateOne,
layerFECompositionStateOne);
LayerState layerStateOne(&outputLayerOne);
mock::OutputLayer outputLayerTwo;
- mock::LayerFE layerFETwo;
+ sp<mock::LayerFE> layerFETwo = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateTwo{
.sourceCrop = sFloatRectTwo,
};
LayerFECompositionState layerFECompositionStateTwo;
- setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo,
+ setupMocksForLayer(outputLayerTwo, *layerFETwo, outputLayerCompositionStateTwo,
layerFECompositionStateTwo);
LayerState layerStateTwo(&outputLayerTwo);
@@ -443,11 +443,11 @@
TEST_F(PredictorTest, getPredictedPlan_recordCandidateAndRetrieveExactMatch) {
mock::OutputLayer outputLayerOne;
- mock::LayerFE layerFEOne;
+ sp<mock::LayerFE> layerFEOne = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateOne;
LayerFECompositionState layerFECompositionStateOne;
layerFECompositionStateOne.compositionType = Composition::DEVICE;
- setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
+ setupMocksForLayer(outputLayerOne, *layerFEOne, outputLayerCompositionStateOne,
layerFECompositionStateOne);
LayerState layerStateOne(&outputLayerOne);
@@ -468,22 +468,22 @@
TEST_F(PredictorTest, getPredictedPlan_recordCandidateAndRetrieveApproximateMatch) {
mock::OutputLayer outputLayerOne;
- mock::LayerFE layerFEOne;
+ sp<mock::LayerFE> layerFEOne = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateOne{
.sourceCrop = sFloatRectOne,
};
LayerFECompositionState layerFECompositionStateOne;
- setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
+ setupMocksForLayer(outputLayerOne, *layerFEOne, outputLayerCompositionStateOne,
layerFECompositionStateOne);
LayerState layerStateOne(&outputLayerOne);
mock::OutputLayer outputLayerTwo;
- mock::LayerFE layerFETwo;
+ sp<mock::LayerFE> layerFETwo = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateTwo{
.sourceCrop = sFloatRectTwo,
};
LayerFECompositionState layerFECompositionStateTwo;
- setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo,
+ setupMocksForLayer(outputLayerTwo, *layerFETwo, outputLayerCompositionStateTwo,
layerFECompositionStateTwo);
LayerState layerStateTwo(&outputLayerTwo);
@@ -505,22 +505,22 @@
TEST_F(PredictorTest, recordMissedPlan_skipsApproximateMatch) {
mock::OutputLayer outputLayerOne;
- mock::LayerFE layerFEOne;
+ sp<mock::LayerFE> layerFEOne = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateOne{
.sourceCrop = sFloatRectOne,
};
LayerFECompositionState layerFECompositionStateOne;
- setupMocksForLayer(outputLayerOne, layerFEOne, outputLayerCompositionStateOne,
+ setupMocksForLayer(outputLayerOne, *layerFEOne, outputLayerCompositionStateOne,
layerFECompositionStateOne);
LayerState layerStateOne(&outputLayerOne);
mock::OutputLayer outputLayerTwo;
- mock::LayerFE layerFETwo;
+ sp<mock::LayerFE> layerFETwo = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateTwo{
.sourceCrop = sFloatRectTwo,
};
LayerFECompositionState layerFECompositionStateTwo;
- setupMocksForLayer(outputLayerTwo, layerFETwo, outputLayerCompositionStateTwo,
+ setupMocksForLayer(outputLayerTwo, *layerFETwo, outputLayerCompositionStateTwo,
layerFECompositionStateTwo);
LayerState layerStateTwo(&outputLayerTwo);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 9174ec7..2696bd8 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -772,18 +772,16 @@
return NO_ERROR;
}
-hal::HWConfigId HWComposer::getPreferredBootDisplayMode(PhysicalDisplayId displayId) {
- RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
- hal::HWConfigId displayModeId = -1;
+std::optional<hal::HWConfigId> HWComposer::getPreferredBootDisplayMode(
+ PhysicalDisplayId displayId) {
+ RETURN_IF_INVALID_DISPLAY(displayId, std::nullopt);
+ hal::HWConfigId displayModeId;
const auto error =
mDisplayData[displayId].hwcDisplay->getPreferredBootDisplayConfig(&displayModeId);
- if (error == hal::Error::UNSUPPORTED) {
- RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION);
+ if (error != hal::Error::NONE) {
+ LOG_DISPLAY_ERROR(displayId, to_string(error).c_str());
+ return std::nullopt;
}
- if (error == hal::Error::BAD_PARAMETER) {
- RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE);
- }
- RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
return displayModeId;
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 3e68028..29335d5 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -260,7 +260,7 @@
virtual bool getBootDisplayModeSupport() = 0;
virtual status_t setBootDisplayMode(PhysicalDisplayId, hal::HWConfigId) = 0;
virtual status_t clearBootDisplayMode(PhysicalDisplayId) = 0;
- virtual hal::HWConfigId getPreferredBootDisplayMode(PhysicalDisplayId) = 0;
+ virtual std::optional<hal::HWConfigId> getPreferredBootDisplayMode(PhysicalDisplayId) = 0;
};
namespace impl {
@@ -391,7 +391,7 @@
bool getBootDisplayModeSupport() override;
status_t setBootDisplayMode(PhysicalDisplayId, hal::HWConfigId) override;
status_t clearBootDisplayMode(PhysicalDisplayId) override;
- hal::HWConfigId getPreferredBootDisplayMode(PhysicalDisplayId) override;
+ std::optional<hal::HWConfigId> getPreferredBootDisplayMode(PhysicalDisplayId) override;
// for debugging ----------------------------------------------------------
void dump(std::string& out) const 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 61da45d..b3c3a41 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2523,6 +2523,7 @@
mTimeStats->recordDisplayEventConnectionCount(sfConnections + appConnections);
if (isDisplayConnected && !display->isPoweredOn()) {
+ getRenderEngine().cleanupPostRender();
return;
}
@@ -3562,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();
}
}
@@ -3914,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 "
@@ -3950,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 7eebd9b..b0d216e 100644
--- a/services/surfaceflinger/fuzzer/Android.bp
+++ b/services/surfaceflinger/fuzzer/Android.bp
@@ -78,3 +78,27 @@
"surfaceflinger_fuzzer.cpp",
],
}
+
+cc_fuzz {
+ name: "surfaceflinger_displayhardware_fuzzer",
+ defaults: [
+ "surfaceflinger_fuzz_defaults",
+ ],
+ srcs: [
+ "surfaceflinger_displayhardware_fuzzer.cpp",
+ ],
+ header_libs: [
+ "android.hardware.graphics.composer@2.4-command-buffer",
+ "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 7b244fc..6231ca5 100644
--- a/services/surfaceflinger/fuzzer/README.md
+++ b/services/surfaceflinger/fuzzer/README.md
@@ -1,6 +1,8 @@
# Fuzzers for SurfaceFlinger
## Table of contents
+ [SurfaceFlinger](#SurfaceFlinger)
++ [DisplayHardware](#DisplayHardware)
++ [Scheduler](#Scheduler)
# <a name="SurfaceFlinger"></a> Fuzzer for SurfaceFlinger
@@ -22,3 +24,49 @@
$ adb sync data
$ adb shell /data/fuzz/arm64/surfaceflinger_fuzzer/surfaceflinger_fuzzer
```
+
+# <a name="DisplayHardware"></a> Fuzzer for DisplayHardware
+
+DisplayHardware supports the following parameters:
+1. Hal Capability (parameter name: `hasCapability`)
+2. Hal BlendMode (parameter name: `setBlendMode`)
+3. Hal Composition (parameter name: `setCompositionType`)
+4. Hal Display Capability (parameter name: `hasDisplayCapability`)
+5. Composition Types (parameter name: `prepareFrame`)
+6. Color Modes (parameter name: `setActiveColorMode`)
+7. Render Intents (parameter name: `setActiveColorMode`)
+8. Power Modes (parameter name: `setPowerMode`)
+9. Content Types (parameter name: `setContentType`)
+10. Data Space (parameter name: `setDataspace`)
+11. Transforms (parameter name: `setLayerTransform`)
+
+You can find the possible values in the fuzzer's source code.
+
+#### Steps to run
+1. Build the fuzzer
+```
+ $ mm -j$(nproc) surfaceflinger_displayhardware_fuzzer
+```
+2. Run on device
+```
+ $ 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_displayhardware_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
new file mode 100644
index 0000000..816d2f1
--- /dev/null
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
@@ -0,0 +1,657 @@
+/*
+ * 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 <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <compositionengine/impl/OutputCompositionState.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <gui/BLASTBufferQueue.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/IProducerListener.h>
+#include <gui/LayerDebugInfo.h>
+#include <gui/SurfaceComposerClient.h>
+#include <hidl/ServiceManagement.h>
+#include <hwbinder/ProcessState.h>
+#include <ui/DisplayIdentification.h>
+
+#include "DisplayHardware/AidlComposerHal.h"
+#include "DisplayHardware/DisplayMode.h"
+#include "DisplayHardware/FramebufferSurface.h"
+#include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/PowerAdvisor.h"
+#include "DisplayHardware/VirtualDisplaySurface.h"
+#include "SurfaceFlinger.h"
+#include "surfaceflinger_displayhardware_fuzzer_utils.h"
+
+#include <FuzzableDataspaces.h>
+
+namespace android::fuzz {
+
+using namespace android::hardware::graphics::common;
+using namespace android::hardware::graphics::composer;
+namespace hal = android::hardware::graphics::composer::hal;
+using Config = hal::V2_1::Config;
+using Display = hal::V2_1::Display;
+using RenderIntent = V1_1::RenderIntent;
+using IComposerClient = hal::V2_4::IComposerClient;
+using VsyncPeriodChangeTimeline = hal::V2_4::VsyncPeriodChangeTimeline;
+using PerFrameMetadata = IComposerClient::PerFrameMetadata;
+using PerFrameMetadataBlob = IComposerClient::PerFrameMetadataBlob;
+using Vsync = IComposerClient::Vsync;
+
+static constexpr hal::Transform kTransforms[] = {hal::Transform::FLIP_H, hal::Transform::FLIP_V,
+ hal::Transform::ROT_90, hal::Transform::ROT_180,
+ hal::Transform::ROT_270};
+
+static constexpr hal::Capability kCapability[] = {hal::Capability::INVALID,
+ hal::Capability::SIDEBAND_STREAM,
+ hal::Capability::SKIP_CLIENT_COLOR_TRANSFORM,
+ hal::Capability::PRESENT_FENCE_IS_NOT_RELIABLE};
+
+static constexpr hal::BlendMode kBlendModes[] = {hal::BlendMode::INVALID, hal::BlendMode::NONE,
+ hal::BlendMode::PREMULTIPLIED,
+ hal::BlendMode::COVERAGE};
+
+static constexpr Composition kCompositions[] = {Composition::INVALID, Composition::CLIENT,
+ Composition::DEVICE, Composition::SOLID_COLOR,
+ Composition::CURSOR, Composition::SIDEBAND};
+
+static constexpr DisplayCapability kDisplayCapability[] =
+ {DisplayCapability::INVALID,
+ DisplayCapability::SKIP_CLIENT_COLOR_TRANSFORM,
+ DisplayCapability::DOZE,
+ DisplayCapability::BRIGHTNESS,
+ DisplayCapability::PROTECTED_CONTENTS,
+ DisplayCapability::AUTO_LOW_LATENCY_MODE};
+
+static constexpr VirtualDisplaySurface::CompositionType kCompositionTypes[] =
+ {VirtualDisplaySurface::CompositionType::Unknown,
+ VirtualDisplaySurface::CompositionType::Gpu, VirtualDisplaySurface::CompositionType::Hwc,
+ VirtualDisplaySurface::CompositionType::Mixed};
+
+static constexpr ui::RenderIntent kRenderIntents[] = {ui::RenderIntent::COLORIMETRIC,
+ ui::RenderIntent::ENHANCE,
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC,
+ ui::RenderIntent::TONE_MAP_ENHANCE};
+
+static constexpr hal::PowerMode kPowerModes[] = {hal::PowerMode::OFF, hal::PowerMode::DOZE,
+ hal::PowerMode::DOZE_SUSPEND, hal::PowerMode::ON,
+ hal::PowerMode::ON_SUSPEND};
+
+static constexpr hal::ContentType kContentTypes[] = {hal::ContentType::NONE,
+ hal::ContentType::GRAPHICS,
+ hal::ContentType::PHOTO,
+ hal::ContentType::CINEMA,
+ hal::ContentType::GAME};
+
+const unsigned char kInternalEdid[] =
+ "\x00\xff\xff\xff\xff\xff\xff\x00\x4c\xa3\x42\x31\x00\x00\x00\x00"
+ "\x00\x15\x01\x03\x80\x1a\x10\x78\x0a\xd3\xe5\x95\x5c\x60\x90\x27"
+ "\x19\x50\x54\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
+ "\x01\x01\x01\x01\x01\x01\x9e\x1b\x00\xa0\x50\x20\x12\x30\x10\x30"
+ "\x13\x00\x05\xa3\x10\x00\x00\x19\x00\x00\x00\x0f\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x23\x87\x02\x64\x00\x00\x00\x00\xfe\x00\x53"
+ "\x41\x4d\x53\x55\x4e\x47\x0a\x20\x20\x20\x20\x20\x00\x00\x00\xfe"
+ "\x00\x31\x32\x31\x41\x54\x31\x31\x2d\x38\x30\x31\x0a\x20\x00\x45";
+
+static constexpr hal::HWConfigId kActiveConfig = 0;
+
+class DisplayHardwareFuzzer {
+public:
+ DisplayHardwareFuzzer(const uint8_t* data, size_t size) : mFdp(data, size) {
+ mPhysicalDisplayId = SurfaceComposerClient::getInternalDisplayId().value();
+ };
+ void process();
+
+private:
+ void invokeComposer();
+ void invokeDisplayIdentification();
+ void invokeLayer(HWC2::Layer* layer);
+ void setSidebandStream(HWC2::Layer* layer);
+ void setCursorPosition(HWC2::Layer* layer);
+ void setBuffer(HWC2::Layer* layer);
+ void setSurfaceDamage(HWC2::Layer* layer);
+ void setDisplayFrame(HWC2::Layer* layer);
+ void setVisibleRegion(HWC2::Layer* layer);
+ void setLayerGenericMetadata(HWC2::Layer* layer);
+ void invokeFrameBufferSurface();
+ void invokeVirtualDisplaySurface();
+ void invokeAidlComposer();
+ Display createVirtualDisplay(Hwc2::AidlComposer*);
+ void validateDisplay(Hwc2::AidlComposer*, Display);
+ void presentOrValidateDisplay(Hwc2::AidlComposer*, Display);
+ void setOutputBuffer(Hwc2::AidlComposer*, Display);
+ void setLayerSidebandStream(Hwc2::AidlComposer*, Display, Hwc2::V2_4::hal::Layer);
+ void invokeComposerHal2_2(Hwc2::AidlComposer*, Display, Hwc2::V2_4::hal::Layer);
+ void invokeComposerHal2_3(Hwc2::AidlComposer*, Display, Hwc2::V2_4::hal::Layer);
+ void invokeComposerHal2_4(Hwc2::AidlComposer*, Display, Hwc2::V2_4::hal::Layer);
+ void getDisplayVsyncPeriod();
+ void setActiveModeWithConstraints();
+ void getDisplayIdentificationData();
+ void dumpHwc();
+ void getDisplayedContentSamplingAttributes(HalDisplayId);
+ void getDeviceCompositionChanges(HalDisplayId);
+ void getHdrCapabilities(HalDisplayId);
+ void getDisplayedContentSample(HalDisplayId);
+ void getSupportedContentTypes();
+ ui::Size getFuzzedSize();
+ mat4 getFuzzedMatrix();
+
+ DisplayIdGenerator<HalVirtualDisplayId> mGenerator;
+ FuzzedDataProvider mFdp;
+ PhysicalDisplayId mPhysicalDisplayId;
+ android::impl::HWComposer mHwc{std::make_unique<Hwc2::mock::Composer>()};
+};
+
+void DisplayHardwareFuzzer::validateDisplay(Hwc2::AidlComposer* composer, Display display) {
+ uint32_t outNumTypes, outNumRequests;
+ composer->validateDisplay(display, mFdp.ConsumeIntegral<nsecs_t>(), &outNumTypes,
+ &outNumRequests);
+}
+
+void DisplayHardwareFuzzer::presentOrValidateDisplay(Hwc2::AidlComposer* composer,
+ Display display) {
+ int32_t outPresentFence;
+ uint32_t outNumTypes, outNumRequests, state;
+ composer->presentOrValidateDisplay(display, mFdp.ConsumeIntegral<nsecs_t>(), &outNumTypes,
+ &outNumRequests, &outPresentFence, &state);
+}
+
+void DisplayHardwareFuzzer::setOutputBuffer(Hwc2::AidlComposer* composer, Display display) {
+ const native_handle_t buffer{};
+ composer->setOutputBuffer(display, &buffer, mFdp.ConsumeIntegral<int32_t>() /*releaseFence*/);
+}
+
+void DisplayHardwareFuzzer::setLayerSidebandStream(Hwc2::AidlComposer* composer, Display display,
+ Hwc2::V2_4::hal::Layer outLayer) {
+ const native_handle_t stream{};
+ composer->setLayerSidebandStream(display, outLayer, &stream);
+}
+
+Display DisplayHardwareFuzzer::createVirtualDisplay(Hwc2::AidlComposer* composer) {
+ namespace types = hardware::graphics::common;
+ using types::V1_2::PixelFormat;
+ PixelFormat format{};
+ Display display;
+ composer->createVirtualDisplay(mFdp.ConsumeIntegral<uint32_t>() /*width*/,
+ mFdp.ConsumeIntegral<uint32_t>() /*height*/, &format, &display);
+ return display;
+}
+
+void DisplayHardwareFuzzer::getDisplayVsyncPeriod() {
+ nsecs_t outVsyncPeriod;
+ mHwc.getDisplayVsyncPeriod(mPhysicalDisplayId, &outVsyncPeriod);
+}
+
+void DisplayHardwareFuzzer::setActiveModeWithConstraints() {
+ hal::VsyncPeriodChangeTimeline outTimeline;
+ mHwc.setActiveModeWithConstraints(mPhysicalDisplayId, kActiveConfig, {} /*constraints*/,
+ &outTimeline);
+}
+
+void DisplayHardwareFuzzer::getDisplayIdentificationData() {
+ uint8_t outPort;
+ DisplayIdentificationData outData;
+ mHwc.getDisplayIdentificationData(kHwDisplayId, &outPort, &outData);
+}
+
+void DisplayHardwareFuzzer::dumpHwc() {
+ std::string string = mFdp.ConsumeRandomLengthString().c_str();
+ mHwc.dump(string);
+}
+
+void DisplayHardwareFuzzer::getDeviceCompositionChanges(HalDisplayId halDisplayID) {
+ std::optional<impl::HWComposer::DeviceRequestedChanges> outChanges;
+ mHwc.getDeviceCompositionChanges(halDisplayID,
+ mFdp.ConsumeBool() /*frameUsesClientComposition*/,
+ std::chrono::steady_clock::now(), FenceTime::NO_FENCE,
+ mFdp.ConsumeIntegral<nsecs_t>(), &outChanges);
+}
+
+void DisplayHardwareFuzzer::getDisplayedContentSamplingAttributes(HalDisplayId halDisplayID) {
+ uint8_t outComponentMask;
+ ui::Dataspace dataSpace;
+ ui::PixelFormat pixelFormat;
+ mHwc.getDisplayedContentSamplingAttributes(halDisplayID, &pixelFormat, &dataSpace,
+ &outComponentMask);
+}
+
+void DisplayHardwareFuzzer::getHdrCapabilities(HalDisplayId halDisplayID) {
+ HdrCapabilities outCapabilities;
+ mHwc.getHdrCapabilities(halDisplayID, &outCapabilities);
+}
+
+void DisplayHardwareFuzzer::getDisplayedContentSample(HalDisplayId halDisplayID) {
+ DisplayedFrameStats outStats;
+ mHwc.getDisplayedContentSample(halDisplayID, mFdp.ConsumeIntegral<uint64_t>() /* maxFrames*/,
+ mFdp.ConsumeIntegral<uint64_t>() /*timestamps*/, &outStats);
+}
+
+void DisplayHardwareFuzzer::getSupportedContentTypes() {
+ std::vector<hal::ContentType> contentType{};
+ mHwc.getSupportedContentTypes(mPhysicalDisplayId, &contentType);
+}
+
+void DisplayHardwareFuzzer::invokeAidlComposer() {
+ hardware::ProcessState::self()->startThreadPool();
+ ProcessState::self()->startThreadPool();
+
+ if (!Hwc2::AidlComposer::isDeclared("default")) {
+ return;
+ }
+
+ Hwc2::AidlComposer composer("default");
+
+ android::hardware::graphics::composer::hal::TestHWC2ComposerCallback composerCallback{};
+ composer.registerCallback(composerCallback);
+
+ Display display = createVirtualDisplay(&composer);
+
+ composer.acceptDisplayChanges(display);
+
+ Hwc2::V2_4::hal::Layer outLayer;
+ composer.createLayer(display, &outLayer);
+
+ int32_t outPresentFence;
+ composer.presentDisplay(display, &outPresentFence);
+
+ composer.setActiveConfig(display, Config{});
+
+ composer.setClientTarget(display, mFdp.ConsumeIntegral<uint32_t>(), sp<GraphicBuffer>(),
+ mFdp.ConsumeIntegral<int32_t>(), mFdp.PickValueInArray(kDataspaces),
+ {});
+
+ composer.setColorMode(display, mFdp.PickValueInArray(kColormodes),
+ mFdp.PickValueInArray(kRenderIntents));
+
+ setOutputBuffer(&composer, display);
+
+ composer.setPowerMode(display, mFdp.PickValueInArray(kPowerModes));
+ composer.setVsyncEnabled(display, mFdp.ConsumeBool() ? Vsync::ENABLE : Vsync::DISABLE);
+
+ composer.setClientTargetSlotCount(display);
+
+ validateDisplay(&composer, display);
+
+ presentOrValidateDisplay(&composer, display);
+
+ composer.setCursorPosition(display, outLayer, mFdp.ConsumeIntegral<uint8_t>() /*x*/,
+ mFdp.ConsumeIntegral<uint8_t>() /*y*/);
+
+ composer.setLayerBuffer(display, outLayer, mFdp.ConsumeIntegral<uint32_t>() /*slot*/,
+ sp<GraphicBuffer>(), mFdp.ConsumeIntegral<int32_t>() /*acquireFence*/);
+
+ composer.setLayerSurfaceDamage(display, outLayer, {} /*damage*/);
+
+ composer.setLayerBlendMode(display, outLayer, mFdp.PickValueInArray(kBlendModes));
+
+ composer.setLayerColor(display, outLayer,
+ {mFdp.ConsumeFloatingPoint<float>() /*red*/,
+ mFdp.ConsumeFloatingPoint<float>() /*green*/,
+ mFdp.ConsumeFloatingPoint<float>() /*blue*/,
+ mFdp.ConsumeFloatingPoint<float>() /*alpha*/});
+ composer.setLayerCompositionType(display, outLayer, mFdp.PickValueInArray(kCompositions));
+ composer.setLayerDataspace(display, outLayer, mFdp.PickValueInArray(kDataspaces));
+ composer.setLayerDisplayFrame(display, outLayer, {} /*frame*/);
+ composer.setLayerPlaneAlpha(display, outLayer, mFdp.ConsumeFloatingPoint<float>());
+
+ setLayerSidebandStream(&composer, display, outLayer);
+
+ composer.setLayerSourceCrop(display, outLayer, {} /*crop*/);
+
+ composer.setLayerTransform(display, outLayer, mFdp.PickValueInArray(kTransforms));
+
+ composer.setLayerVisibleRegion(display, outLayer, std::vector<IComposerClient::Rect>{});
+ composer.setLayerZOrder(display, outLayer, mFdp.ConsumeIntegral<uint32_t>());
+
+ invokeComposerHal2_2(&composer, display, outLayer);
+ invokeComposerHal2_3(&composer, display, outLayer);
+ invokeComposerHal2_4(&composer, display, outLayer);
+
+ composer.executeCommands();
+ composer.resetCommands();
+
+ composer.destroyLayer(display, outLayer);
+ composer.destroyVirtualDisplay(display);
+}
+
+void DisplayHardwareFuzzer::invokeComposerHal2_2(Hwc2::AidlComposer* composer, Display display,
+ Hwc2::V2_4::hal::Layer outLayer) {
+ const std::vector<PerFrameMetadata> perFrameMetadatas;
+ composer->setLayerPerFrameMetadata(display, outLayer, perFrameMetadatas);
+
+ composer->getPerFrameMetadataKeys(display);
+ std::vector<RenderIntent> outRenderIntents;
+
+ composer->getRenderIntents(display, mFdp.PickValueInArray(kColormodes), &outRenderIntents);
+ mat4 outMatrix;
+ composer->getDataspaceSaturationMatrix(mFdp.PickValueInArray(kDataspaces), &outMatrix);
+}
+
+void DisplayHardwareFuzzer::invokeComposerHal2_3(Hwc2::AidlComposer* composer, Display display,
+ Hwc2::V2_4::hal::Layer outLayer) {
+ composer->setDisplayContentSamplingEnabled(display, mFdp.ConsumeBool() /*enabled*/,
+ mFdp.ConsumeIntegral<uint8_t>() /*componentMask*/,
+ mFdp.ConsumeIntegral<uint64_t>() /*maxFrames*/);
+
+ DisplayedFrameStats outStats;
+ composer->getDisplayedContentSample(display, mFdp.ConsumeIntegral<uint64_t>() /*maxFrames*/,
+ mFdp.ConsumeIntegral<uint64_t>() /*timestamp*/, &outStats);
+
+ composer->setLayerPerFrameMetadataBlobs(display, outLayer, std::vector<PerFrameMetadataBlob>{});
+
+ composer->setDisplayBrightness(display, mFdp.ConsumeFloatingPoint<float>(),
+ Hwc2::Composer::DisplayBrightnessOptions{
+ .applyImmediately = mFdp.ConsumeIntegral<bool>()});
+}
+
+void DisplayHardwareFuzzer::invokeComposerHal2_4(Hwc2::AidlComposer* composer, Display display,
+ Hwc2::V2_4::hal::Layer outLayer) {
+ VsyncPeriodChangeTimeline outTimeline;
+ composer->setActiveConfigWithConstraints(display, Config{},
+ IComposerClient::VsyncPeriodChangeConstraints{},
+ &outTimeline);
+
+ composer->setAutoLowLatencyMode(display, mFdp.ConsumeBool());
+
+ composer->setContentType(display, mFdp.PickValueInArray(kContentTypes));
+
+ std::vector<uint8_t> value;
+ value.push_back(mFdp.ConsumeIntegral<uint8_t>());
+ composer->setLayerGenericMetadata(display, outLayer, mFdp.ConsumeRandomLengthString() /*key*/,
+ mFdp.ConsumeBool() /*mandatory*/, value);
+}
+
+ui::Size DisplayHardwareFuzzer::getFuzzedSize() {
+ ui::Size size{mFdp.ConsumeIntegral<int32_t>() /*width*/,
+ mFdp.ConsumeIntegral<int32_t>() /*height*/};
+ return size;
+}
+
+mat4 DisplayHardwareFuzzer::getFuzzedMatrix() {
+ mat4 matrix{mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>(),
+ mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>(),
+ mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>(),
+ mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>(),
+ mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>(),
+ mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>(),
+ mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>(),
+ mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>()};
+ return matrix;
+}
+
+void DisplayHardwareFuzzer::setCursorPosition(HWC2::Layer* layer) {
+ layer->setCursorPosition(mFdp.ConsumeIntegral<int32_t>() /*x*/,
+ mFdp.ConsumeIntegral<int32_t>() /*y*/);
+}
+
+void DisplayHardwareFuzzer::setBuffer(HWC2::Layer* layer) {
+ layer->setBuffer(mFdp.ConsumeIntegral<uint32_t>() /*slot*/, sp<GraphicBuffer>(),
+ sp<Fence>::make());
+}
+
+void DisplayHardwareFuzzer::setSurfaceDamage(HWC2::Layer* layer) {
+ Rect rhs{mFdp.ConsumeIntegral<uint32_t>() /*width*/,
+ mFdp.ConsumeIntegral<uint32_t>() /*height*/};
+ const Region damage{rhs};
+ layer->setSurfaceDamage(damage);
+}
+
+void DisplayHardwareFuzzer::setVisibleRegion(HWC2::Layer* layer) {
+ uint32_t width = mFdp.ConsumeIntegral<uint32_t>();
+ uint32_t height = mFdp.ConsumeIntegral<uint32_t>();
+ Rect rect{width, height};
+ const Region region{rect};
+ layer->setVisibleRegion(region);
+}
+
+void DisplayHardwareFuzzer::setDisplayFrame(HWC2::Layer* layer) {
+ uint32_t width = mFdp.ConsumeIntegral<uint32_t>();
+ uint32_t height = mFdp.ConsumeIntegral<uint32_t>();
+ const Rect frame{width, height};
+ layer->setDisplayFrame(frame);
+}
+
+void DisplayHardwareFuzzer::setLayerGenericMetadata(HWC2::Layer* layer) {
+ std::vector<uint8_t> value;
+ value.push_back(mFdp.ConsumeIntegral<uint8_t>());
+ layer->setLayerGenericMetadata(mFdp.ConsumeRandomLengthString().c_str() /*name*/,
+ mFdp.ConsumeBool() /*mandatory*/, value);
+}
+
+void DisplayHardwareFuzzer::setSidebandStream(HWC2::Layer* layer) {
+ const native_handle_t stream{};
+ layer->setSidebandStream(&stream);
+}
+
+void DisplayHardwareFuzzer::invokeLayer(HWC2::Layer* layer) {
+ setCursorPosition(layer);
+ setBuffer(layer);
+ setSurfaceDamage(layer);
+
+ layer->setBlendMode(mFdp.PickValueInArray(kBlendModes));
+ layer->setColor({mFdp.ConsumeFloatingPoint<float>() /*red*/,
+ mFdp.ConsumeFloatingPoint<float>() /*green*/,
+ mFdp.ConsumeFloatingPoint<float>() /*blue*/,
+ mFdp.ConsumeFloatingPoint<float>() /*alpha*/});
+ layer->setCompositionType(mFdp.PickValueInArray(kCompositions));
+ layer->setDataspace(mFdp.PickValueInArray(kDataspaces));
+
+ layer->setPerFrameMetadata(mFdp.ConsumeIntegral<int32_t>(), getFuzzedHdrMetadata(&mFdp));
+ setDisplayFrame(layer);
+
+ layer->setPlaneAlpha(mFdp.ConsumeFloatingPoint<float>());
+
+ setSidebandStream(layer);
+
+ layer->setSourceCrop(getFuzzedFloatRect(&mFdp));
+ layer->setTransform(mFdp.PickValueInArray(kTransforms));
+
+ setVisibleRegion(layer);
+
+ layer->setZOrder(mFdp.ConsumeIntegral<uint32_t>());
+
+ layer->setColorTransform(getFuzzedMatrix());
+
+ setLayerGenericMetadata(layer);
+}
+
+void DisplayHardwareFuzzer::invokeFrameBufferSurface() {
+ sp<IGraphicBufferProducer> bqProducer = sp<mock::GraphicBufferProducer>::make();
+ sp<IGraphicBufferConsumer> bqConsumer;
+ BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
+
+ sp<FramebufferSurface> surface =
+ new FramebufferSurface(mHwc, mPhysicalDisplayId, bqConsumer, getFuzzedSize() /*size*/,
+ getFuzzedSize() /*maxSize*/);
+ surface->beginFrame(mFdp.ConsumeBool());
+
+ surface->prepareFrame(mFdp.PickValueInArray(kCompositionTypes));
+ surface->advanceFrame();
+ surface->onFrameCommitted();
+ String8 result = String8(mFdp.ConsumeRandomLengthString().c_str());
+ surface->dumpAsString(result);
+ surface->resizeBuffers(getFuzzedSize());
+ surface->getClientTargetAcquireFence();
+}
+
+void DisplayHardwareFuzzer::invokeVirtualDisplaySurface() {
+ DisplayIdGenerator<HalVirtualDisplayId> mGenerator;
+ VirtualDisplayId VirtualDisplayId = mGenerator.generateId().value();
+
+ sp<SurfaceComposerClient> mClient = new SurfaceComposerClient();
+ sp<SurfaceControl> mSurfaceControl =
+ mClient->createSurface(String8("TestSurface"), 100, 100, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState,
+ /*parent*/ nullptr);
+
+ sp<BLASTBufferQueue> mBlastBufferQueueAdapter =
+ new BLASTBufferQueue("TestBLASTBufferQueue", mSurfaceControl, 100, 100,
+ PIXEL_FORMAT_RGBA_8888);
+
+ sp<IGraphicBufferProducer> sink = mBlastBufferQueueAdapter->getIGraphicBufferProducer();
+ sp<IGraphicBufferProducer> bqProducer = mBlastBufferQueueAdapter->getIGraphicBufferProducer();
+ sp<IGraphicBufferConsumer> bqConsumer;
+ BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
+ BufferQueue::createBufferQueue(&sink, &bqConsumer);
+
+ sp<VirtualDisplaySurface> surface =
+ new VirtualDisplaySurface(mHwc, VirtualDisplayId, sink, bqProducer, bqConsumer,
+ mFdp.ConsumeRandomLengthString().c_str() /*name*/);
+
+ surface->beginFrame(mFdp.ConsumeBool());
+ surface->prepareFrame(mFdp.PickValueInArray(kCompositionTypes));
+ surface->resizeBuffers(getFuzzedSize());
+ surface->getClientTargetAcquireFence();
+ surface->advanceFrame();
+ surface->onFrameCommitted();
+ String8 result = String8(mFdp.ConsumeRandomLengthString().c_str());
+ surface->dumpAsString(result);
+}
+
+void DisplayHardwareFuzzer::invokeComposer() {
+ HalVirtualDisplayId halVirtualDisplayId = mGenerator.generateId().value();
+ HalDisplayId halDisplayID = HalDisplayId{halVirtualDisplayId};
+
+ android::hardware::graphics::composer::hal::TestHWC2ComposerCallback composerCallback{};
+ mHwc.setCallback(composerCallback);
+
+ ui::PixelFormat pixelFormat{};
+ if (!mHwc.allocateVirtualDisplay(halVirtualDisplayId, getFuzzedSize(), &pixelFormat)) {
+ return;
+ }
+
+ getDisplayIdentificationData();
+
+ mHwc.hasDisplayCapability(halDisplayID, mFdp.PickValueInArray(kDisplayCapability));
+
+ mHwc.allocatePhysicalDisplay(kHwDisplayId, mPhysicalDisplayId);
+
+ static auto hwcLayer = mHwc.createLayer(halDisplayID);
+ HWC2::Layer* layer = hwcLayer.get();
+ invokeLayer(layer);
+
+ getDeviceCompositionChanges(halDisplayID);
+
+ mHwc.setClientTarget(halDisplayID, mFdp.ConsumeIntegral<uint32_t>(), Fence::NO_FENCE,
+ sp<GraphicBuffer>::make(), mFdp.PickValueInArray(kDataspaces));
+
+ mHwc.presentAndGetReleaseFences(halDisplayID, std::chrono::steady_clock::now(),
+ FenceTime::NO_FENCE);
+
+ mHwc.setPowerMode(mPhysicalDisplayId, mFdp.PickValueInArray(kPowerModes));
+
+ mHwc.setColorTransform(halDisplayID, getFuzzedMatrix());
+
+ mHwc.getPresentFence(halDisplayID);
+
+ mHwc.getLayerReleaseFence(halDisplayID, layer);
+
+ mHwc.setOutputBuffer(halVirtualDisplayId, sp<Fence>::make().get(), sp<GraphicBuffer>::make());
+
+ mHwc.clearReleaseFences(halDisplayID);
+
+ getHdrCapabilities(halDisplayID);
+
+ mHwc.getSupportedPerFrameMetadata(halDisplayID);
+
+ mHwc.getRenderIntents(halDisplayID, ui::ColorMode());
+
+ mHwc.getDataspaceSaturationMatrix(halDisplayID, ui::Dataspace());
+
+ getDisplayedContentSamplingAttributes(halDisplayID);
+
+ mHwc.setDisplayContentSamplingEnabled(halDisplayID, mFdp.ConsumeBool() /*enabled*/,
+ mFdp.ConsumeIntegral<uint8_t>() /*componentMask*/,
+ mFdp.ConsumeIntegral<uint64_t>() /*maxFrames*/);
+
+ getDisplayedContentSample(halDisplayID);
+
+ mHwc.setDisplayBrightness(mPhysicalDisplayId, mFdp.ConsumeFloatingPoint<float>(),
+ Hwc2::Composer::DisplayBrightnessOptions{
+ .applyImmediately = mFdp.ConsumeIntegral<bool>()});
+
+ mHwc.onHotplug(kHwDisplayId, hal::Connection::CONNECTED);
+ mHwc.updatesDeviceProductInfoOnHotplugReconnect();
+
+ mHwc.onVsync(kHwDisplayId, mFdp.ConsumeIntegral<int64_t>());
+ mHwc.setVsyncEnabled(mPhysicalDisplayId,
+ mFdp.ConsumeBool() ? hal::Vsync::ENABLE : hal::Vsync::DISABLE);
+
+ mHwc.isConnected(mPhysicalDisplayId);
+ mHwc.getModes(mPhysicalDisplayId);
+ mHwc.getActiveMode(mPhysicalDisplayId);
+ mHwc.getColorModes(mPhysicalDisplayId);
+ mHwc.hasCapability(mFdp.PickValueInArray(kCapability));
+
+ mHwc.setActiveColorMode(mPhysicalDisplayId, mFdp.PickValueInArray(kColormodes),
+ mFdp.PickValueInArray(kRenderIntents));
+
+ mHwc.getDisplayConnectionType(mPhysicalDisplayId);
+ mHwc.isVsyncPeriodSwitchSupported(mPhysicalDisplayId);
+
+ getDisplayVsyncPeriod();
+
+ setActiveModeWithConstraints();
+
+ mHwc.setAutoLowLatencyMode(mPhysicalDisplayId, mFdp.ConsumeBool());
+
+ getSupportedContentTypes();
+
+ mHwc.setContentType(mPhysicalDisplayId, mFdp.PickValueInArray(kContentTypes));
+
+ dumpHwc();
+
+ mHwc.toPhysicalDisplayId(kHwDisplayId);
+ mHwc.fromPhysicalDisplayId(mPhysicalDisplayId);
+ mHwc.disconnectDisplay(halDisplayID);
+
+ static hal::HWDisplayId displayId = mFdp.ConsumeIntegral<hal::HWDisplayId>();
+ mHwc.onHotplug(displayId,
+ mFdp.ConsumeBool() ? hal::Connection::DISCONNECTED : hal::Connection::CONNECTED);
+}
+
+template <size_t N>
+DisplayIdentificationData asDisplayIdentificationData(const unsigned char (&bytes)[N]) {
+ return DisplayIdentificationData(bytes, bytes + N - 1);
+}
+
+void DisplayHardwareFuzzer::invokeDisplayIdentification() {
+ static const DisplayIdentificationData data = asDisplayIdentificationData(kInternalEdid);
+ isEdid(data);
+ parseEdid(data);
+ parseDisplayIdentificationData(mFdp.ConsumeIntegral<uint8_t>(), data);
+ getPnpId(getVirtualDisplayId(mFdp.ConsumeIntegral<uint32_t>()));
+ getPnpId(mFdp.ConsumeIntegral<uint8_t>());
+}
+
+void DisplayHardwareFuzzer::process() {
+ invokeComposer();
+ invokeAidlComposer();
+ invokeDisplayIdentification();
+ invokeFrameBufferSurface();
+ invokeVirtualDisplaySurface();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ DisplayHardwareFuzzer displayHardwareFuzzer(data, size);
+ displayHardwareFuzzer.process();
+ return 0;
+}
+
+} // namespace android::fuzz
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer_utils.h
new file mode 100644
index 0000000..6a6e3db
--- /dev/null
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer_utils.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <utils/Condition.h>
+#include <chrono>
+#include <vector>
+
+#include <android/hardware/graphics/composer/2.4/IComposer.h>
+#include <composer-hal/2.1/ComposerClient.h>
+#include <composer-hal/2.2/ComposerClient.h>
+#include <composer-hal/2.3/ComposerClient.h>
+#include <composer-hal/2.4/ComposerClient.h>
+
+#include "DisplayHardware/HWC2.h"
+#include "surfaceflinger_fuzzers_utils.h"
+
+namespace {
+class LayerImpl;
+class Frame;
+class DelayedEventGenerator;
+} // namespace
+
+namespace android {
+class SurfaceComposerClient;
+} // namespace android
+
+namespace android::hardware::graphics::composer::hal {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::HWC2::ComposerCallback;
+
+class ComposerCallbackBridge : public IComposerCallback {
+public:
+ ComposerCallbackBridge(ComposerCallback* callback, bool vsyncSwitchingSupported)
+ : mCallback(callback), mVsyncSwitchingSupported(vsyncSwitchingSupported) {}
+
+ Return<void> onHotplug(HWDisplayId display, Connection connection) override {
+ mCallback->onComposerHalHotplug(display, connection);
+ return Void();
+ }
+
+ Return<void> onRefresh(HWDisplayId display) override {
+ mCallback->onComposerHalRefresh(display);
+ return Void();
+ }
+
+ Return<void> onVsync(HWDisplayId display, int64_t timestamp) override {
+ if (!mVsyncSwitchingSupported) {
+ mCallback->onComposerHalVsync(display, timestamp, std::nullopt);
+ }
+ return Void();
+ }
+
+ Return<void> onVsync_2_4(HWDisplayId display, int64_t timestamp,
+ VsyncPeriodNanos vsyncPeriodNanos) override {
+ if (mVsyncSwitchingSupported) {
+ mCallback->onComposerHalVsync(display, timestamp, vsyncPeriodNanos);
+ }
+ return Void();
+ }
+
+ Return<void> onVsyncPeriodTimingChanged(HWDisplayId display,
+ const VsyncPeriodChangeTimeline& timeline) override {
+ mCallback->onComposerHalVsyncPeriodTimingChanged(display, timeline);
+ return Void();
+ }
+
+ Return<void> onSeamlessPossible(HWDisplayId display) override {
+ mCallback->onComposerHalSeamlessPossible(display);
+ return Void();
+ }
+
+private:
+ ComposerCallback* const mCallback;
+ const bool mVsyncSwitchingSupported;
+};
+
+struct TestHWC2ComposerCallback : public HWC2::ComposerCallback {
+ virtual ~TestHWC2ComposerCallback() = default;
+ void onComposerHalHotplug(HWDisplayId, Connection){};
+ void onComposerHalRefresh(HWDisplayId) {}
+ void onComposerHalVsync(HWDisplayId, int64_t, std::optional<VsyncPeriodNanos>) {}
+ void onComposerHalVsyncPeriodTimingChanged(HWDisplayId, const VsyncPeriodChangeTimeline&) {}
+ void onComposerHalSeamlessPossible(HWDisplayId) {}
+ void onComposerHalVsyncIdle(HWDisplayId) {}
+};
+
+} // namespace android::hardware::graphics::composer::hal
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.