Merge "Add test for HOVER_EXIT when another device is touched" into udc-dev
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 1c52792..a1be542 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -38,6 +38,7 @@
#include <binder/IBinder.h>
#include <binder/Parcelable.h>
#include <input/Input.h>
+#include <input/InputVerifier.h>
#include <sys/stat.h>
#include <ui/Transform.h>
#include <utils/BitSet.h>
@@ -444,6 +445,7 @@
private:
std::shared_ptr<InputChannel> mChannel;
+ InputVerifier mInputVerifier;
};
/*
diff --git a/include/input/InputVerifier.h b/include/input/InputVerifier.h
new file mode 100644
index 0000000..d4589f5
--- /dev/null
+++ b/include/input/InputVerifier.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <input/Input.h>
+#include <map>
+
+namespace android {
+
+/*
+ * Crash if the provided touch stream is inconsistent.
+ *
+ * TODO(b/211379801): Add support for hover events:
+ * - No hover move without enter
+ * - No touching pointers when hover enter
+ * - No hovering pointers when touching
+ * - Only 1 hovering pointer max
+ */
+class InputVerifier {
+public:
+ InputVerifier(const std::string& name);
+
+ void processMovement(int32_t deviceId, int32_t action, uint32_t pointerCount,
+ const PointerProperties* pointerProperties,
+ const PointerCoords* pointerCoords, int32_t flags);
+
+private:
+ const std::string mName;
+ std::map<int32_t /*deviceId*/, std::bitset<MAX_POINTER_ID + 1>> mTouchingPointerIdsByDevice;
+ void ensureTouchingPointersMatch(int32_t deviceId, uint32_t pointerCount,
+ const PointerProperties* pointerProperties,
+ const char* action) const;
+};
+
+} // namespace android
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index c4c8ffb..24642d2 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -547,7 +547,8 @@
// Do not expand the visibility.
visibility: [
":__subpackages__",
- "//packages/modules/Virtualization:__subpackages__",
+ "//packages/modules/Virtualization/javalib/jni",
+ "//packages/modules/Virtualization/vm_payload",
"//device/google/cuttlefish/shared/minidroid:__subpackages__",
],
}
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 3809b6d..48cb72c 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -47,6 +47,7 @@
"Input.cpp",
"InputDevice.cpp",
"InputEventLabels.cpp",
+ "InputVerifier.cpp",
"Keyboard.cpp",
"KeyCharacterMap.cpp",
"KeyLayoutMap.cpp",
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 9f0a314..d1cd50c 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -76,6 +76,14 @@
*/
static const char* PROPERTY_RESAMPLING_ENABLED = "ro.input.resampling";
+/**
+ * Crash if the events that are getting sent to the InputPublisher are inconsistent.
+ * Enable this via "adb shell setprop log.tag.InputTransportVerifyEvents DEBUG"
+ */
+static bool verifyEvents() {
+ return __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "VerifyEvents", ANDROID_LOG_INFO);
+}
+
template<typename T>
inline static T min(const T& a, const T& b) {
return a < b ? a : b;
@@ -492,7 +500,8 @@
// --- InputPublisher ---
-InputPublisher::InputPublisher(const std::shared_ptr<InputChannel>& channel) : mChannel(channel) {}
+InputPublisher::InputPublisher(const std::shared_ptr<InputChannel>& channel)
+ : mChannel(channel), mInputVerifier(channel->getName()) {}
InputPublisher::~InputPublisher() {
}
@@ -555,6 +564,10 @@
mChannel->getName().c_str(), action);
ATRACE_NAME(message.c_str());
}
+ if (verifyEvents()) {
+ mInputVerifier.processMovement(deviceId, action, pointerCount, pointerProperties,
+ pointerCoords, flags);
+ }
if (DEBUG_TRANSPORT_ACTIONS) {
std::string transformString;
transform.dump(transformString, "transform", " ");
diff --git a/libs/input/InputVerifier.cpp b/libs/input/InputVerifier.cpp
new file mode 100644
index 0000000..eb75804
--- /dev/null
+++ b/libs/input/InputVerifier.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "InputVerifier"
+
+#include <android-base/logging.h>
+#include <input/InputVerifier.h>
+
+namespace android {
+
+/**
+ * Log all of the movements that are sent to this verifier. Helps to identify the streams that lead
+ * to inconsistent events.
+ * Enable this via "adb shell setprop log.tag.InputVerifierLogEvents DEBUG"
+ */
+static bool logEvents() {
+ return __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "LogEvents", ANDROID_LOG_INFO);
+}
+
+// --- InputVerifier ---
+
+InputVerifier::InputVerifier(const std::string& name) : mName(name){};
+
+void InputVerifier::processMovement(int32_t deviceId, int32_t action, uint32_t pointerCount,
+ const PointerProperties* pointerProperties,
+ const PointerCoords* pointerCoords, int32_t flags) {
+ if (logEvents()) {
+ LOG(ERROR) << "Processing " << MotionEvent::actionToString(action) << " for device "
+ << deviceId << " (" << pointerCount << " pointer"
+ << (pointerCount == 1 ? "" : "s") << ") on " << mName;
+ }
+
+ switch (MotionEvent::getActionMasked(action)) {
+ case AMOTION_EVENT_ACTION_DOWN: {
+ auto [it, inserted] = mTouchingPointerIdsByDevice.insert({deviceId, {}});
+ if (!inserted) {
+ LOG(FATAL) << "Got ACTION_DOWN, but already have touching pointers " << it->second
+ << " for device " << deviceId << " on " << mName;
+ }
+ it->second.set(pointerProperties[0].id);
+ break;
+ }
+ case AMOTION_EVENT_ACTION_POINTER_DOWN: {
+ auto it = mTouchingPointerIdsByDevice.find(deviceId);
+ if (it == mTouchingPointerIdsByDevice.end()) {
+ LOG(FATAL) << "Got POINTER_DOWN, but no touching pointers for device " << deviceId
+ << " on " << mName;
+ }
+ it->second.set(pointerProperties[MotionEvent::getActionIndex(action)].id);
+ break;
+ }
+ case AMOTION_EVENT_ACTION_MOVE: {
+ ensureTouchingPointersMatch(deviceId, pointerCount, pointerProperties, "MOVE");
+ break;
+ }
+ case AMOTION_EVENT_ACTION_POINTER_UP: {
+ auto it = mTouchingPointerIdsByDevice.find(deviceId);
+ if (it == mTouchingPointerIdsByDevice.end()) {
+ LOG(FATAL) << "Got POINTER_UP, but no touching pointers for device " << deviceId
+ << " on " << mName;
+ }
+ it->second.reset(pointerProperties[MotionEvent::getActionIndex(action)].id);
+ break;
+ }
+ case AMOTION_EVENT_ACTION_UP: {
+ auto it = mTouchingPointerIdsByDevice.find(deviceId);
+ if (it == mTouchingPointerIdsByDevice.end()) {
+ LOG(FATAL) << "Got ACTION_UP, but no record for deviceId " << deviceId << " on "
+ << mName;
+ }
+ const auto& [_, touchingPointerIds] = *it;
+ if (touchingPointerIds.count() != 1) {
+ LOG(FATAL) << "Got ACTION_UP, but we have pointers: " << touchingPointerIds
+ << " for deviceId " << deviceId << " on " << mName;
+ }
+ const int32_t pointerId = pointerProperties[0].id;
+ if (!touchingPointerIds.test(pointerId)) {
+ LOG(FATAL) << "Got ACTION_UP, but pointerId " << pointerId
+ << " is not touching. Touching pointers: " << touchingPointerIds
+ << " for deviceId " << deviceId << " on " << mName;
+ }
+ mTouchingPointerIdsByDevice.erase(it);
+ break;
+ }
+ case AMOTION_EVENT_ACTION_CANCEL: {
+ if ((flags & AMOTION_EVENT_FLAG_CANCELED) != AMOTION_EVENT_FLAG_CANCELED) {
+ LOG(FATAL) << "For ACTION_CANCEL, must set FLAG_CANCELED";
+ }
+ ensureTouchingPointersMatch(deviceId, pointerCount, pointerProperties, "CANCEL");
+ mTouchingPointerIdsByDevice.erase(deviceId);
+ break;
+ }
+ }
+}
+
+void InputVerifier::ensureTouchingPointersMatch(int32_t deviceId, uint32_t pointerCount,
+ const PointerProperties* pointerProperties,
+ const char* action) const {
+ auto it = mTouchingPointerIdsByDevice.find(deviceId);
+ if (it == mTouchingPointerIdsByDevice.end()) {
+ LOG(FATAL) << "Got " << action << ", but no touching pointers for device " << deviceId
+ << " on " << mName;
+ }
+ const auto& [_, touchingPointerIds] = *it;
+ for (size_t i = 0; i < pointerCount; i++) {
+ const int32_t pointerId = pointerProperties[i].id;
+ if (!touchingPointerIds.test(pointerId)) {
+ LOG(FATAL) << "Got " << action << " for pointerId " << pointerId
+ << " but the touching pointers are " << touchingPointerIds << " on "
+ << mName;
+ }
+ }
+};
+
+} // namespace android
diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp
index 2278d39..e2aac8c 100644
--- a/libs/sensor/ISensorServer.cpp
+++ b/libs/sensor/ISensorServer.cpp
@@ -67,7 +67,11 @@
v.setCapacity(n);
while (n) {
n--;
- reply.read(s);
+ if(reply.read(s) != OK) {
+ ALOGE("Failed to read reply from getSensorList");
+ v.clear();
+ break;
+ }
v.add(s);
}
return v;
@@ -85,7 +89,11 @@
v.setCapacity(n);
while (n) {
n--;
- reply.read(s);
+ if(reply.read(s) != OK) {
+ ALOGE("Failed to read reply from getDynamicSensorList");
+ v.clear();
+ break;
+ }
v.add(s);
}
return v;
diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp
index fb895f5..b6ea77d 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -628,7 +628,13 @@
return false;
}
outputString8.setTo(static_cast<char const*>(buffer), len);
+
+ if (size < FlattenableUtils::align<4>(len)) {
+ ALOGE("Malformed Sensor String8 field. Should be in a 4-byte aligned buffer but is not.");
+ return false;
+ }
FlattenableUtils::advance(buffer, size, FlattenableUtils::align<4>(len));
+
return true;
}
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index 2748276..44a208d 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -92,6 +92,16 @@
return *sensorManager;
}
+void SensorManager::removeInstanceForPackage(const String16& packageName) {
+ Mutex::Autolock _l(sLock);
+ auto iterator = sPackageInstances.find(packageName);
+ if (iterator != sPackageInstances.end()) {
+ SensorManager* sensorManager = iterator->second;
+ delete sensorManager;
+ sPackageInstances.erase(iterator);
+ }
+}
+
SensorManager::SensorManager(const String16& opPackageName)
: mSensorList(nullptr), mOpPackageName(opPackageName), mDirectConnectionHandle(1) {
Mutex::Autolock _l(mLock);
@@ -166,6 +176,11 @@
mSensors = mSensorServer->getSensorList(mOpPackageName);
size_t count = mSensors.size();
+ if (count == 0) {
+ ALOGE("Failed to get Sensor list");
+ mSensorServer.clear();
+ return UNKNOWN_ERROR;
+ }
mSensorList =
static_cast<Sensor const**>(malloc(count * sizeof(Sensor*)));
LOG_ALWAYS_FATAL_IF(mSensorList == nullptr, "mSensorList NULL");
diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h
index 0798da2..c31f648 100644
--- a/libs/sensor/include/sensor/SensorManager.h
+++ b/libs/sensor/include/sensor/SensorManager.h
@@ -54,6 +54,7 @@
{
public:
static SensorManager& getInstanceForPackage(const String16& packageName);
+ static void removeInstanceForPackage(const String16& packageName);
~SensorManager();
ssize_t getSensorList(Sensor const* const** list);
diff --git a/services/batteryservice/include/batteryservice/BatteryService.h b/services/batteryservice/include/batteryservice/BatteryService.h
index bf6189d..a2e4115 100644
--- a/services/batteryservice/include/batteryservice/BatteryService.h
+++ b/services/batteryservice/include/batteryservice/BatteryService.h
@@ -37,7 +37,6 @@
BATTERY_PROP_CHARGING_POLICY = 7, // equals BATTERY_PROPERTY_CHARGING_POLICY
BATTERY_PROP_MANUFACTURING_DATE = 8, // equals BATTERY_PROPERTY_MANUFACTURING_DATE
BATTERY_PROP_FIRST_USAGE_DATE = 9, // equals BATTERY_PROPERTY_FIRST_USAGE_DATE
- BATTERY_PROP_STATE_OF_HEALTH = 10, // equals BATTERY_PROPERTY_STATE_OF_HEALTH
};
struct BatteryProperties {
diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp
index cc9cc4e..94f3813 100644
--- a/services/inputflinger/dispatcher/InputState.cpp
+++ b/services/inputflinger/dispatcher/InputState.cpp
@@ -247,10 +247,19 @@
}
void InputState::MotionMemento::setPointers(const MotionEntry& entry) {
- pointerCount = entry.pointerCount;
+ pointerCount = 0;
for (uint32_t i = 0; i < entry.pointerCount; i++) {
- pointerProperties[i].copyFrom(entry.pointerProperties[i]);
- pointerCoords[i].copyFrom(entry.pointerCoords[i]);
+ if (MotionEvent::getActionMasked(entry.action) == AMOTION_EVENT_ACTION_POINTER_UP) {
+ // In POINTER_UP events, the pointer is leaving. Since the action is not stored,
+ // this departing pointer should not be recorded.
+ const uint8_t actionIndex = MotionEvent::getActionIndex(entry.action);
+ if (i == actionIndex) {
+ continue;
+ }
+ }
+ pointerProperties[pointerCount].copyFrom(entry.pointerProperties[i]);
+ pointerCoords[pointerCount].copyFrom(entry.pointerCoords[i]);
+ pointerCount++;
}
}
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
index 9f32311..8ab6748 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
@@ -16,6 +16,7 @@
#include "../Macros.h"
+#include <limits>
#include <optional>
#include <android/input.h>
@@ -30,6 +31,76 @@
namespace {
+// Describes a segment of the acceleration curve.
+struct CurveSegment {
+ // The maximum pointer speed which this segment should apply. The last segment in a curve should
+ // always set this to infinity.
+ double maxPointerSpeedMmPerS;
+ double slope;
+ double intercept;
+};
+
+const std::vector<CurveSegment> segments = {
+ {10.922, 3.19, 0},
+ {31.750, 4.79, -17.526},
+ {98.044, 7.28, -96.52},
+ {std::numeric_limits<double>::infinity(), 15.04, -857.758},
+};
+
+const std::vector<double> sensitivityFactors = {1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 20};
+
+std::vector<double> createAccelerationCurveForSensitivity(int32_t sensitivity,
+ size_t propertySize) {
+ LOG_ALWAYS_FATAL_IF(propertySize < 4 * segments.size());
+ std::vector<double> output(propertySize, 0);
+
+ // The Gestures library uses functions of the following form to define curve segments, where a,
+ // b, and c can be specified by us:
+ // output_speed(input_speed_mm) = a * input_speed_mm ^ 2 + b * input_speed_mm + c
+ //
+ // (a, b, and c are also called sqr_, mul_, and int_ in the Gestures library code.)
+ //
+ // We are trying to implement the following function, where slope and intercept are the
+ // parameters specified in the `segments` array above:
+ // gain(input_speed_mm) =
+ // 0.64 * (sensitivityFactor / 10) * (slope + intercept / input_speed_mm)
+ // Where "gain" is a multiplier applied to the input speed to produce the output speed:
+ // output_speed(input_speed_mm) = input_speed_mm * gain(input_speed_mm)
+ //
+ // To put our function in the library's form, we substitute it into the function above:
+ // output_speed(input_speed_mm) =
+ // input_speed_mm * (0.64 * (sensitivityFactor / 10) *
+ // (slope + 25.4 * intercept / input_speed_mm))
+ // then expand the brackets so that input_speed_mm cancels out for the intercept term:
+ // gain(input_speed_mm) =
+ // 0.64 * (sensitivityFactor / 10) * slope * input_speed_mm +
+ // 0.64 * (sensitivityFactor / 10) * intercept
+ //
+ // This gives us the following parameters for the Gestures library function form:
+ // a = 0
+ // b = 0.64 * (sensitivityFactor / 10) * slope
+ // c = 0.64 * (sensitivityFactor / 10) * intercept
+
+ double commonFactor = 0.64 * sensitivityFactors[sensitivity + 7] / 10;
+
+ size_t i = 0;
+ for (CurveSegment seg : segments) {
+ // The library's curve format consists of four doubles per segment:
+ // * maximum pointer speed for the segment (mm/s)
+ // * multiplier for the x² term (a.k.a. "a" or "sqr")
+ // * multiplier for the x term (a.k.a. "b" or "mul")
+ // * the intercept (a.k.a. "c" or "int")
+ // (see struct CurveSegment in the library's AccelFilterInterpreter)
+ output[i + 0] = seg.maxPointerSpeedMmPerS;
+ output[i + 1] = 0;
+ output[i + 2] = commonFactor * seg.slope;
+ output[i + 3] = commonFactor * seg.intercept;
+ i += 4;
+ }
+
+ return output;
+}
+
short getMaxTouchCount(const InputDeviceContext& context) {
if (context.hasScanCode(BTN_TOOL_QUINTTAP)) return 5;
if (context.hasScanCode(BTN_TOOL_QUADTAP)) return 4;
@@ -147,10 +218,12 @@
mGestureConverter.setOrientation(orientation);
}
if (!changes || (changes & InputReaderConfiguration::CHANGE_TOUCHPAD_SETTINGS)) {
- // TODO(b/265798483): load an Android-specific acceleration curve instead of mapping to one
- // of five ChromeOS curves.
- const int pointerSensitivity = (config->touchpadPointerSpeed + 7) / 3 + 1;
- mPropertyProvider.getProperty("Pointer Sensitivity").setIntValues({pointerSensitivity});
+ mPropertyProvider.getProperty("Use Custom Touchpad Pointer Accel Curve")
+ .setBoolValues({true});
+ GesturesProp accelCurveProp = mPropertyProvider.getProperty("Pointer Accel Curve");
+ accelCurveProp.setRealValues(
+ createAccelerationCurveForSensitivity(config->touchpadPointerSpeed,
+ accelCurveProp.getCount()));
mPropertyProvider.getProperty("Invert Scrolling")
.setBoolValues({config->touchpadNaturalScrollingEnabled});
mPropertyProvider.getProperty("Tap Enable")
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index cda677e..df1787b 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -1945,6 +1945,48 @@
}
/**
+ * Two fingers down on the window, and lift off the first finger.
+ * Next, cancel the gesture to the window by removing the window. Make sure that the CANCEL event
+ * contains a single pointer.
+ */
+TEST_F(InputDispatcherTest, CancelAfterPointer0Up) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ NotifyMotionArgs args;
+ // First touch pointer down on right window
+ mDispatcher->notifyMotion(&(
+ args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100))
+ .build()));
+ // Second touch pointer down
+ mDispatcher->notifyMotion(&(
+ args = MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100))
+ .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(110).y(100))
+ .build()));
+ // First touch pointer lifts. The second one remains down
+ mDispatcher->notifyMotion(&(
+ args = MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
+
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100))
+ .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(110).y(100))
+ .build()));
+ window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
+ window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
+ window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
+
+ // Remove the window. The gesture should be canceled
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {}}});
+ const std::map<int32_t, PointF> expectedPointers{{1, PointF{110, 100}}};
+ window->consumeMotionEvent(
+ AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedPointers)));
+}
+
+/**
* Same test as WhenForegroundWindowDisappears_WallpaperTouchIsCanceled above,
* with the following differences:
* After ACTION_DOWN, Wallpaper window hangs up its channel, which forces the dispatcher to
@@ -2052,8 +2094,17 @@
wallpaperWindow->consumeMotionPointerUp(0, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
- {100, 100}))
+ injectMotionEvent(mDispatcher,
+ MotionEventBuilder(AMOTION_EVENT_ACTION_UP,
+ AINPUT_SOURCE_TOUCHSCREEN)
+ .displayId(ADISPLAY_ID_DEFAULT)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(PointerBuilder(/* id */ 1,
+ AMOTION_EVENT_TOOL_TYPE_FINGER)
+ .x(100)
+ .y(100))
+ .build(),
+ INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT))
<< "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
foregroundWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
wallpaperWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
@@ -2523,7 +2574,7 @@
.build()));
window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
- WithPointerCount(2u)));
+ WithPointerCount(1u)));
window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
mDispatcher->notifyMotion(&(
@@ -3007,8 +3058,8 @@
window1->assertNoEvents();
// Now move the pointer on the first window
- mDispatcher->notifyMotion(
- &(args = generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{51, 51}, {151, 51}})));
+ mDispatcher->notifyMotion(&(
+ args = generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{51, 51}, {151, 51}, {150, 50}})));
mDispatcher->waitForIdle();
window1->consumeMotionEvent(WithDownTime(downTimeForWindow1));
@@ -5501,6 +5552,13 @@
windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID);
monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID);
+ // Lift up the touch from the second display
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ windowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID);
+ monitorInSecondary.consumeMotionUp(SECOND_DISPLAY_ID);
+
// Test inject a non-pointer motion event.
// If specific a display, it will dispatch to the focused window of particular display,
// or it will dispatch to the focused window of focused display.
diff --git a/services/sensorservice/aidl/SensorManager.cpp b/services/sensorservice/aidl/SensorManager.cpp
index b7aecdf..08e00b4 100644
--- a/services/sensorservice/aidl/SensorManager.cpp
+++ b/services/sensorservice/aidl/SensorManager.cpp
@@ -59,6 +59,9 @@
if (mPollThread.joinable()) {
mPollThread.join();
}
+
+ ::android::SensorManager::removeInstanceForPackage(
+ String16(ISensorManager::descriptor));
}
ndk::ScopedAStatus createDirectChannel(::android::SensorManager& manager, size_t size, int type,
diff --git a/services/sensorservice/hidl/SensorManager.cpp b/services/sensorservice/hidl/SensorManager.cpp
index f04712c..3d148e1 100644
--- a/services/sensorservice/hidl/SensorManager.cpp
+++ b/services/sensorservice/hidl/SensorManager.cpp
@@ -60,6 +60,9 @@
if (mPollThread.joinable()) {
mPollThread.join();
}
+
+ ::android::SensorManager::removeInstanceForPackage(
+ String16(ISensorManager::descriptor));
}
// Methods from ::android::frameworks::sensorservice::V1_0::ISensorManager follow.
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index eb6d7e4..b78b92b 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -384,23 +384,13 @@
return vsyncEventData;
}
-void EventThread::onScreenReleased() {
+void EventThread::enableSyntheticVsync(bool enable) {
std::lock_guard<std::mutex> lock(mMutex);
- if (!mVSyncState || mVSyncState->synthetic) {
+ if (!mVSyncState || mVSyncState->synthetic == enable) {
return;
}
- mVSyncState->synthetic = true;
- mCondition.notify_all();
-}
-
-void EventThread::onScreenAcquired() {
- std::lock_guard<std::mutex> lock(mMutex);
- if (!mVSyncState || !mVSyncState->synthetic) {
- return;
- }
-
- mVSyncState->synthetic = false;
+ mVSyncState->synthetic = enable;
mCondition.notify_all();
}
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 347dc4a..5037860 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -106,11 +106,8 @@
virtual sp<EventThreadConnection> createEventConnection(
ResyncCallback, EventRegistrationFlags eventRegistration = {}) const = 0;
- // called before the screen is turned off from main thread
- virtual void onScreenReleased() = 0;
-
- // called after the screen is turned on from main thread
- virtual void onScreenAcquired() = 0;
+ // Feed clients with fake VSYNC, e.g. while the display is off.
+ virtual void enableSyntheticVsync(bool) = 0;
virtual void onHotplugReceived(PhysicalDisplayId displayId, bool connected) = 0;
@@ -159,11 +156,7 @@
VsyncEventData getLatestVsyncEventData(
const sp<EventThreadConnection>& connection) const override;
- // called before the screen is turned off from main thread
- void onScreenReleased() override;
-
- // called after the screen is turned on from main thread
- void onScreenAcquired() override;
+ void enableSyntheticVsync(bool) override;
void onHotplugReceived(PhysicalDisplayId displayId, bool connected) override;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index dab01ba..0daabe2 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -265,24 +265,16 @@
thread->onHotplugReceived(displayId, connected);
}
-void Scheduler::onScreenAcquired(ConnectionHandle handle) {
+void Scheduler::enableSyntheticVsync(bool enable) {
+ // TODO(b/241285945): Remove connection handles.
+ const ConnectionHandle handle = mAppConnectionHandle;
android::EventThread* thread;
{
std::lock_guard<std::mutex> lock(mConnectionsLock);
RETURN_IF_INVALID_HANDLE(handle);
thread = mConnections[handle].thread.get();
}
- thread->onScreenAcquired();
-}
-
-void Scheduler::onScreenReleased(ConnectionHandle handle) {
- android::EventThread* thread;
- {
- std::lock_guard<std::mutex> lock(mConnectionsLock);
- RETURN_IF_INVALID_HANDLE(handle);
- thread = mConnections[handle].thread.get();
- }
- thread->onScreenReleased();
+ thread->enableSyntheticVsync(enable);
}
void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDisplayId displayId) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index a340919..67f4daa 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -157,8 +157,8 @@
void onHotplugReceived(ConnectionHandle, PhysicalDisplayId, bool connected);
void onPrimaryDisplayModeChanged(ConnectionHandle, const FrameRateMode&) EXCLUDES(mPolicyLock);
void onNonPrimaryDisplayModeChanged(ConnectionHandle, const FrameRateMode&);
- void onScreenAcquired(ConnectionHandle);
- void onScreenReleased(ConnectionHandle);
+
+ void enableSyntheticVsync(bool = true) REQUIRES(kMainThreadContext);
void onFrameRateOverridesChanged(ConnectionHandle, PhysicalDisplayId)
EXCLUDES(mConnectionsLock);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 5c8579c..51dc02c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -5210,7 +5210,6 @@
return;
}
- const bool isActiveDisplay = displayId == mActiveDisplayId;
const bool isInternalDisplay = mPhysicalDisplays.get(displayId)
.transform(&PhysicalDisplay::isInternal)
.value_or(false);
@@ -5247,10 +5246,10 @@
ALOGW("Couldn't set SCHED_FIFO on display on: %s\n", strerror(errno));
}
getHwComposer().setPowerMode(displayId, mode);
- if (isActiveDisplay && mode != hal::PowerMode::DOZE_SUSPEND) {
+ if (displayId == mActiveDisplayId && mode != hal::PowerMode::DOZE_SUSPEND) {
setHWCVsyncEnabled(displayId,
mScheduler->getVsyncSchedule().getPendingHardwareVsyncState());
- mScheduler->onScreenAcquired(mAppConnectionHandle);
+ mScheduler->enableSyntheticVsync(false);
mScheduler->resyncToHardwareVsync(true, refreshRate);
}
@@ -5264,9 +5263,9 @@
if (SurfaceFlinger::setSchedAttr(false) != NO_ERROR) {
ALOGW("Couldn't set uclamp.min on display off: %s\n", strerror(errno));
}
- if (isActiveDisplay && *currentModeOpt != hal::PowerMode::DOZE_SUSPEND) {
+ if (displayId == mActiveDisplayId && *currentModeOpt != hal::PowerMode::DOZE_SUSPEND) {
mScheduler->disableHardwareVsync(true);
- mScheduler->onScreenReleased(mAppConnectionHandle);
+ mScheduler->enableSyntheticVsync();
}
// Make sure HWVsync is disabled before turning off the display
@@ -5278,18 +5277,18 @@
} else if (mode == hal::PowerMode::DOZE || mode == hal::PowerMode::ON) {
// Update display while dozing
getHwComposer().setPowerMode(displayId, mode);
- if (isActiveDisplay && *currentModeOpt == hal::PowerMode::DOZE_SUSPEND) {
+ if (displayId == mActiveDisplayId && *currentModeOpt == hal::PowerMode::DOZE_SUSPEND) {
ALOGI("Force repainting for DOZE_SUSPEND -> DOZE or ON.");
mVisibleRegionsDirty = true;
scheduleRepaint();
- mScheduler->onScreenAcquired(mAppConnectionHandle);
+ mScheduler->enableSyntheticVsync(false);
mScheduler->resyncToHardwareVsync(true, refreshRate);
}
} else if (mode == hal::PowerMode::DOZE_SUSPEND) {
// Leave display going to doze
- if (isActiveDisplay) {
+ if (displayId == mActiveDisplayId) {
mScheduler->disableHardwareVsync(true);
- mScheduler->onScreenReleased(mAppConnectionHandle);
+ mScheduler->enableSyntheticVsync();
}
getHwComposer().setPowerMode(displayId, mode);
} else {
@@ -5297,7 +5296,7 @@
getHwComposer().setPowerMode(displayId, mode);
}
- if (isActiveDisplay) {
+ if (displayId == mActiveDisplayId) {
mTimeStats->setPowerMode(mode);
mRefreshRateStats->setPowerMode(mode);
mScheduler->setDisplayPowerMode(mode);
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index 61fb29a..80486a2 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -109,8 +109,7 @@
thread->setDuration((std::chrono::nanoseconds)mFdp.ConsumeIntegral<uint64_t>(),
(std::chrono::nanoseconds)mFdp.ConsumeIntegral<uint64_t>());
thread->registerDisplayEventConnection(connection);
- thread->onScreenAcquired();
- thread->onScreenReleased();
+ thread->enableSyntheticVsync(mFdp.ConsumeBool());
dump<android::impl::EventThread>(thread.get(), &mFdp);
}
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 87c3c65..a5b508a 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -105,6 +105,7 @@
"SurfaceFlinger_DisplayTransactionCommitTest.cpp",
"SurfaceFlinger_GetDisplayNativePrimariesTest.cpp",
"SurfaceFlinger_HotplugTest.cpp",
+ "SurfaceFlinger_MultiDisplayLeaderTest.cpp",
"SurfaceFlinger_NotifyPowerBoostTest.cpp",
"SurfaceFlinger_OnInitializeDisplaysTest.cpp",
"SurfaceFlinger_PowerHintTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 23a8bd1..57d1d9c 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -503,14 +503,16 @@
static constexpr auto GET_IDENTIFICATION_DATA = getInternalEdid;
};
-template <bool hasIdentificationData>
-struct ExternalDisplay {
- static constexpr auto CONNECTION_TYPE = ui::DisplayConnectionType::External;
+template <ui::DisplayConnectionType connectionType, bool hasIdentificationData>
+struct SecondaryDisplay {
+ static constexpr auto CONNECTION_TYPE = connectionType;
static constexpr Primary PRIMARY = Primary::FALSE;
static constexpr uint8_t PORT = 254;
static constexpr HWDisplayId HWC_DISPLAY_ID = 1002;
static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
- static constexpr auto GET_IDENTIFICATION_DATA = getExternalEdid;
+ static constexpr auto GET_IDENTIFICATION_DATA =
+ connectionType == ui::DisplayConnectionType::Internal ? getInternalEdid
+ : getExternalEdid;
};
struct TertiaryDisplay {
@@ -521,7 +523,16 @@
};
using PrimaryDisplayVariant = PhysicalDisplayVariant<PrimaryDisplay<false>, 3840, 2160>;
-using ExternalDisplayVariant = PhysicalDisplayVariant<ExternalDisplay<false>, 1920, 1280>;
+
+using InnerDisplayVariant = PhysicalDisplayVariant<PrimaryDisplay<true>, 1840, 2208>;
+using OuterDisplayVariant =
+ PhysicalDisplayVariant<SecondaryDisplay<ui::DisplayConnectionType::Internal, true>, 1080,
+ 2092>;
+
+using ExternalDisplayVariant =
+ PhysicalDisplayVariant<SecondaryDisplay<ui::DisplayConnectionType::External, false>, 1920,
+ 1280>;
+
using TertiaryDisplayVariant = PhysicalDisplayVariant<TertiaryDisplay, 1600, 1200>;
// A virtual display not supported by the HWC.
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 4b15385..422fa1c 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -122,12 +122,6 @@
EXPECT_CALL(*mEventThread, onHotplugReceived(_, _)).Times(0);
mScheduler->onHotplugReceived(handle, kDisplayId1, false);
- EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(0);
- mScheduler->onScreenAcquired(handle);
-
- EXPECT_CALL(*mEventThread, onScreenReleased()).Times(0);
- mScheduler->onScreenReleased(handle);
-
std::string output;
EXPECT_CALL(*mEventThread, dump(_)).Times(0);
mScheduler->dump(handle, output);
@@ -147,12 +141,6 @@
EXPECT_CALL(*mEventThread, onHotplugReceived(kDisplayId1, false)).Times(1);
mScheduler->onHotplugReceived(mConnectionHandle, kDisplayId1, false);
- EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(1);
- mScheduler->onScreenAcquired(mConnectionHandle);
-
- EXPECT_CALL(*mEventThread, onScreenReleased()).Times(1);
- mScheduler->onScreenReleased(mConnectionHandle);
-
std::string output("dump");
EXPECT_CALL(*mEventThread, dump(output)).Times(1);
mScheduler->dump(mConnectionHandle, output);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_MultiDisplayLeaderTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_MultiDisplayLeaderTest.cpp
new file mode 100644
index 0000000..9c58943
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_MultiDisplayLeaderTest.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include "DisplayTransactionTestHelpers.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace {
+
+struct MultiDisplayLeaderTest : DisplayTransactionTest {
+ static constexpr bool kWithMockScheduler = false;
+ MultiDisplayLeaderTest() : DisplayTransactionTest(kWithMockScheduler) {}
+};
+
+TEST_F(MultiDisplayLeaderTest, foldable) {
+ injectMockScheduler(InnerDisplayVariant::DISPLAY_ID::get());
+
+ // Inject inner and outer displays with uninitialized power modes.
+ sp<DisplayDevice> innerDisplay, outerDisplay;
+ constexpr bool kInitPowerMode = false;
+ {
+ InnerDisplayVariant::injectHwcDisplay<kInitPowerMode>(this);
+ auto injector = InnerDisplayVariant::makeFakeExistingDisplayInjector(this);
+ injector.setPowerMode(std::nullopt);
+ injector.setRefreshRateSelector(mFlinger.scheduler()->refreshRateSelector());
+ innerDisplay = injector.inject();
+ }
+ {
+ OuterDisplayVariant::injectHwcDisplay<kInitPowerMode>(this);
+ auto injector = OuterDisplayVariant::makeFakeExistingDisplayInjector(this);
+ injector.setPowerMode(std::nullopt);
+ outerDisplay = injector.inject();
+ }
+
+ // When the device boots, the inner display should be the leader.
+ ASSERT_EQ(mFlinger.scheduler()->leaderDisplayId(), innerDisplay->getPhysicalId());
+
+ // ...and should still be after powering on.
+ mFlinger.setPowerModeInternal(innerDisplay, PowerMode::ON);
+ ASSERT_EQ(mFlinger.scheduler()->leaderDisplayId(), innerDisplay->getPhysicalId());
+
+ // The outer display should become the leader after folding.
+ mFlinger.setPowerModeInternal(innerDisplay, PowerMode::OFF);
+ mFlinger.setPowerModeInternal(outerDisplay, PowerMode::ON);
+ ASSERT_EQ(mFlinger.scheduler()->leaderDisplayId(), outerDisplay->getPhysicalId());
+
+ // The inner display should become the leader after unfolding.
+ mFlinger.setPowerModeInternal(outerDisplay, PowerMode::OFF);
+ mFlinger.setPowerModeInternal(innerDisplay, PowerMode::ON);
+ ASSERT_EQ(mFlinger.scheduler()->leaderDisplayId(), innerDisplay->getPhysicalId());
+
+ // The inner display should stay the leader if both are powered on.
+ // TODO(b/256196556): The leader should depend on the displays' VSYNC phases.
+ mFlinger.setPowerModeInternal(outerDisplay, PowerMode::ON);
+ ASSERT_EQ(mFlinger.scheduler()->leaderDisplayId(), innerDisplay->getPhysicalId());
+
+ // The outer display should become the leader if designated.
+ mFlinger.scheduler()->setLeaderDisplay(outerDisplay->getPhysicalId());
+ ASSERT_EQ(mFlinger.scheduler()->leaderDisplayId(), outerDisplay->getPhysicalId());
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
index a0aaa68..17b4714 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
@@ -59,47 +59,34 @@
};
struct EventThreadBaseSupportedVariant {
- static void setupVsyncAndEventThreadNoCallExpectations(DisplayTransactionTest* test) {
- // The callback should not be notified to toggle VSYNC.
+ static void setupVsyncNoCallExpectations(DisplayTransactionTest* test) {
+ // Expect no change to hardware nor synthetic VSYNC.
EXPECT_CALL(test->mFlinger.mockSchedulerCallback(), setVsyncEnabled(_)).Times(0);
-
- // The event thread should not be notified.
- EXPECT_CALL(*test->mEventThread, onScreenReleased()).Times(0);
- EXPECT_CALL(*test->mEventThread, onScreenAcquired()).Times(0);
+ EXPECT_CALL(*test->mEventThread, enableSyntheticVsync(_)).Times(0);
}
};
struct EventThreadNotSupportedVariant : public EventThreadBaseSupportedVariant {
- static void setupAcquireAndEnableVsyncCallExpectations(DisplayTransactionTest* test) {
- // These calls are only expected for the primary display.
-
- // Instead expect no calls.
- setupVsyncAndEventThreadNoCallExpectations(test);
+ static void setupEnableVsyncCallExpectations(DisplayTransactionTest* test) {
+ setupVsyncNoCallExpectations(test);
}
- static void setupReleaseAndDisableVsyncCallExpectations(DisplayTransactionTest* test) {
- // These calls are only expected for the primary display.
-
- // Instead expect no calls.
- setupVsyncAndEventThreadNoCallExpectations(test);
+ static void setupDisableVsyncCallExpectations(DisplayTransactionTest* test) {
+ setupVsyncNoCallExpectations(test);
}
};
struct EventThreadIsSupportedVariant : public EventThreadBaseSupportedVariant {
- static void setupAcquireAndEnableVsyncCallExpectations(DisplayTransactionTest* test) {
- // The callback should be notified to enable VSYNC.
+ static void setupEnableVsyncCallExpectations(DisplayTransactionTest* test) {
+ // Expect to enable hardware VSYNC and disable synthetic VSYNC.
EXPECT_CALL(test->mFlinger.mockSchedulerCallback(), setVsyncEnabled(true)).Times(1);
-
- // The event thread should be notified that the screen was acquired.
- EXPECT_CALL(*test->mEventThread, onScreenAcquired()).Times(1);
+ EXPECT_CALL(*test->mEventThread, enableSyntheticVsync(false)).Times(1);
}
- static void setupReleaseAndDisableVsyncCallExpectations(DisplayTransactionTest* test) {
- // The callback should be notified to disable VSYNC.
+ static void setupDisableVsyncCallExpectations(DisplayTransactionTest* test) {
+ // Expect to disable hardware VSYNC and enable synthetic VSYNC.
EXPECT_CALL(test->mFlinger.mockSchedulerCallback(), setVsyncEnabled(false)).Times(1);
-
- // The event thread should not be notified that the screen was released.
- EXPECT_CALL(*test->mEventThread, onScreenReleased()).Times(1);
+ EXPECT_CALL(*test->mEventThread, enableSyntheticVsync(true)).Times(1);
}
};
@@ -133,7 +120,7 @@
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
- Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
+ Case::EventThread::setupEnableVsyncCallExpectations(test);
Case::DispSync::setupResetModelCallExpectations(test);
Case::setupRepaintEverythingCallExpectations(test);
}
@@ -148,7 +135,7 @@
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND);
- Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
+ Case::EventThread::setupVsyncNoCallExpectations(test);
Case::setupRepaintEverythingCallExpectations(test);
}
@@ -160,7 +147,7 @@
struct TransitionOnToOffVariant : public TransitionVariantCommon<PowerMode::ON, PowerMode::OFF> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
+ Case::EventThread::setupDisableVsyncCallExpectations(test);
Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::OFF);
}
@@ -173,7 +160,7 @@
: public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::OFF> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
+ Case::EventThread::setupVsyncNoCallExpectations(test);
Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::OFF);
}
@@ -185,7 +172,7 @@
struct TransitionOnToDozeVariant : public TransitionVariantCommon<PowerMode::ON, PowerMode::DOZE> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
+ Case::EventThread::setupVsyncNoCallExpectations(test);
Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE);
}
};
@@ -194,7 +181,7 @@
: public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::DOZE> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
+ Case::EventThread::setupEnableVsyncCallExpectations(test);
Case::DispSync::setupResetModelCallExpectations(test);
Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE);
}
@@ -203,7 +190,7 @@
struct TransitionDozeToOnVariant : public TransitionVariantCommon<PowerMode::DOZE, PowerMode::ON> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
+ Case::EventThread::setupVsyncNoCallExpectations(test);
Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
}
};
@@ -212,7 +199,7 @@
: public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::ON> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
+ Case::EventThread::setupEnableVsyncCallExpectations(test);
Case::DispSync::setupResetModelCallExpectations(test);
Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
}
@@ -222,7 +209,7 @@
: public TransitionVariantCommon<PowerMode::ON, PowerMode::DOZE_SUSPEND> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
+ Case::EventThread::setupDisableVsyncCallExpectations(test);
Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND);
}
};
@@ -231,7 +218,7 @@
: public TransitionVariantCommon<PowerMode::ON, static_cast<PowerMode>(POWER_MODE_LEET)> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
+ Case::EventThread::setupVsyncNoCallExpectations(test);
Case::setupNoComposerPowerModeCallExpectations(test);
}
};
@@ -484,38 +471,5 @@
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToUnknownVariant>>();
}
-// TODO(b/262417075)
-TEST_F(SetPowerModeInternalTest, DISABLED_designatesLeaderDisplay) {
- using Case = SimplePrimaryDisplayCase;
-
- // --------------------------------------------------------------------
- // Preconditions
-
- // Inject a primary display with uninitialized power mode.
- constexpr bool kInitPowerMode = false;
- Case::Display::injectHwcDisplay<kInitPowerMode>(this);
- auto injector = Case::Display::makeFakeExistingDisplayInjector(this);
- injector.setPowerMode(std::nullopt);
- const auto display = injector.inject();
-
- // --------------------------------------------------------------------
- // Invocation
-
- // FakeDisplayDeviceInjector registers the display with Scheduler, so it has already been
- // designated as the leader. Set an arbitrary leader to verify that `setPowerModeInternal`
- // designates a leader regardless of any preceding `Scheduler::registerDisplay` call(s).
- constexpr PhysicalDisplayId kPlaceholderId = PhysicalDisplayId::fromPort(42);
- ASSERT_NE(display->getPhysicalId(), kPlaceholderId);
- mFlinger.scheduler()->setLeaderDisplay(kPlaceholderId);
-
- mFlinger.setPowerModeInternal(display, PowerMode::ON);
-
- // --------------------------------------------------------------------
- // Postconditions
-
- // The primary display should be designated as the leader.
- EXPECT_EQ(mFlinger.scheduler()->leaderDisplayId(), display->getPhysicalId());
-}
-
} // namespace
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index bd3f3ca..48c5d48 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -91,6 +91,7 @@
Scheduler::setLeaderDisplay(displayId);
}
+ auto& mutableAppConnectionHandle() { return mAppConnectionHandle; }
auto& mutableVsyncModulator() { return *mVsyncModulator; }
auto& mutableLayerHistory() { return mLayerHistory; }
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 8703359..4488038 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -252,7 +252,10 @@
mScheduler->initVsync(mScheduler->getVsyncSchedule().getDispatch(), *mTokenManager, 0ms);
- mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread));
+ mScheduler->mutableAppConnectionHandle() =
+ mScheduler->createConnection(std::move(appEventThread));
+
+ mFlinger->mAppConnectionHandle = mScheduler->mutableAppConnectionHandle();
mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread));
resetScheduler(mScheduler);
}
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index f8567bd..8026a7a 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -31,8 +31,7 @@
MOCK_CONST_METHOD2(createEventConnection,
sp<EventThreadConnection>(ResyncCallback, EventRegistrationFlags));
- MOCK_METHOD0(onScreenReleased, void());
- MOCK_METHOD0(onScreenAcquired, void());
+ MOCK_METHOD(void, enableSyntheticVsync, (bool), (override));
MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool));
MOCK_METHOD1(onModeChanged, void(const scheduler::FrameRateMode &));
MOCK_METHOD2(onFrameRateOverridesChanged,