Merge "Revert "batteryservice: add BATTERY_PROP_STATE_OF_HEALTH"" into udc-dev
diff --git a/include/input/VirtualInputDevice.h b/include/input/VirtualInputDevice.h
new file mode 100644
index 0000000..13ffb58
--- /dev/null
+++ b/include/input/VirtualInputDevice.h
@@ -0,0 +1,97 @@
+/*
+ * 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 <android-base/unique_fd.h>
+
+namespace android {
+
+enum class UinputAction {
+ RELEASE = 0,
+ PRESS = 1,
+ MOVE = 2,
+ CANCEL = 3,
+};
+
+class VirtualInputDevice {
+public:
+ VirtualInputDevice(android::base::unique_fd fd);
+ virtual ~VirtualInputDevice();
+
+protected:
+ const android::base::unique_fd mFd;
+ bool writeInputEvent(uint16_t type, uint16_t code, int32_t value);
+ bool writeEvKeyEvent(int32_t androidCode, int32_t androidAction,
+ const std::map<int, int>& evKeyCodeMapping,
+ const std::map<int, UinputAction>& actionMapping);
+};
+
+class VirtualKeyboard : public VirtualInputDevice {
+public:
+ static const std::map<int, int> KEY_CODE_MAPPING;
+ // Expose to share with VirtualDpad.
+ static const std::map<int, UinputAction> KEY_ACTION_MAPPING;
+ VirtualKeyboard(android::base::unique_fd fd);
+ virtual ~VirtualKeyboard() override;
+ bool writeKeyEvent(int32_t androidKeyCode, int32_t androidAction);
+};
+
+class VirtualDpad : public VirtualInputDevice {
+public:
+ static const std::map<int, int> DPAD_KEY_CODE_MAPPING;
+ VirtualDpad(android::base::unique_fd fd);
+ virtual ~VirtualDpad() override;
+ bool writeDpadKeyEvent(int32_t androidKeyCode, int32_t androidAction);
+};
+
+class VirtualMouse : public VirtualInputDevice {
+public:
+ VirtualMouse(android::base::unique_fd fd);
+ virtual ~VirtualMouse() override;
+ bool writeButtonEvent(int32_t androidButtonCode, int32_t androidAction);
+ // TODO(b/259554911): changing float parameters to int32_t.
+ bool writeRelativeEvent(float relativeX, float relativeY);
+ bool writeScrollEvent(float xAxisMovement, float yAxisMovement);
+
+private:
+ static const std::map<int, UinputAction> BUTTON_ACTION_MAPPING;
+ static const std::map<int, int> BUTTON_CODE_MAPPING;
+};
+
+class VirtualTouchscreen : public VirtualInputDevice {
+public:
+ VirtualTouchscreen(android::base::unique_fd fd);
+ virtual ~VirtualTouchscreen() override;
+ // TODO(b/259554911): changing float parameters to int32_t.
+ bool writeTouchEvent(int32_t pointerId, int32_t toolType, int32_t action, float locationX,
+ float locationY, float pressure, float majorAxisSize);
+
+private:
+ static const std::map<int, UinputAction> TOUCH_ACTION_MAPPING;
+ static const std::map<int, int> TOOL_TYPE_MAPPING;
+
+ /* The set of active touch pointers on this device.
+ * We only allow pointer id to go up to MAX_POINTERS because the maximum slots of virtual
+ * touchscreen is set up with MAX_POINTERS. Note that in other cases Android allows pointer id
+ * to go up to MAX_POINTERS_ID.
+ */
+ std::bitset<MAX_POINTERS> mActivePointers{};
+ bool isValidPointerId(int32_t pointerId, UinputAction uinputAction);
+ bool handleTouchDown(int32_t pointerId);
+ bool handleTouchUp(int32_t pointerId);
+};
+} // 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/binder/OWNERS b/libs/binder/OWNERS
index f954e74..bb17683 100644
--- a/libs/binder/OWNERS
+++ b/libs/binder/OWNERS
@@ -1,6 +1,4 @@
# Bug component: 32456
-ctate@google.com
-hackbod@google.com
maco@google.com
smoreland@google.com
tkjos@google.com
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index e609987..2a4fc48 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -397,6 +397,11 @@
cc_test {
name: "binderRpcTest",
+ // TODO(b/269799024)
+ test_options: {
+ unit_test: false,
+ },
+
defaults: [
"binderRpcTest_defaults",
"binderRpcTest_shared_defaults",
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index a6276e5..f6bba16 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -189,6 +189,7 @@
SAFE_PARCEL(output.writeParcelable, trustedPresentationListener);
SAFE_PARCEL(output.writeFloat, currentSdrHdrRatio);
SAFE_PARCEL(output.writeFloat, desiredSdrHdrRatio);
+ SAFE_PARCEL(output.writeInt32, static_cast<int32_t>(cachingHint))
return NO_ERROR;
}
@@ -328,6 +329,10 @@
SAFE_PARCEL(input.readFloat, &tmpFloat);
desiredSdrHdrRatio = tmpFloat;
+ int32_t tmpInt32;
+ SAFE_PARCEL(input.readInt32, &tmpInt32);
+ cachingHint = static_cast<gui::CachingHint>(tmpInt32);
+
return NO_ERROR;
}
@@ -580,6 +585,10 @@
desiredSdrHdrRatio = other.desiredSdrHdrRatio;
currentSdrHdrRatio = other.currentSdrHdrRatio;
}
+ if (other.what & eCachingHintChanged) {
+ what |= eCachingHintChanged;
+ cachingHint = other.cachingHint;
+ }
if (other.what & eHdrMetadataChanged) {
what |= eHdrMetadataChanged;
hdrMetadata = other.hdrMetadata;
@@ -731,6 +740,7 @@
CHECK_DIFF(diff, eDataspaceChanged, other, dataspace);
CHECK_DIFF2(diff, eExtendedRangeBrightnessChanged, other, currentSdrHdrRatio,
desiredSdrHdrRatio);
+ CHECK_DIFF(diff, eCachingHintChanged, other, cachingHint);
CHECK_DIFF(diff, eHdrMetadataChanged, other, hdrMetadata);
if (other.what & eSurfaceDamageRegionChanged &&
(!surfaceDamageRegion.hasSameRects(other.surfaceDamageRegion))) {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index c508917..001d475 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1729,6 +1729,20 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCachingHint(
+ const sp<SurfaceControl>& sc, gui::CachingHint cachingHint) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eCachingHintChanged;
+ s->cachingHint = cachingHint;
+
+ registerSurfaceControlForCallback(sc);
+ return *this;
+}
+
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setHdrMetadata(
const sp<SurfaceControl>& sc, const HdrMetadata& hdrMetadata) {
layer_state_t* s = getLayerState(sc);
diff --git a/libs/gui/aidl/android/gui/CachingHint.aidl b/libs/gui/aidl/android/gui/CachingHint.aidl
new file mode 100644
index 0000000..b35c795
--- /dev/null
+++ b/libs/gui/aidl/android/gui/CachingHint.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright 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.
+ */
+
+package android.gui;
+
+/*
+ * Hint for configuring caching behavior for a layer
+ * @hide
+ */
+@Backing(type="int")
+enum CachingHint {
+ // Caching is disabled. A layer may explicitly disable caching for
+ // improving image quality for some scenes.
+ Disabled = 0,
+ // Caching is enabled. A layer is cacheable by default.
+ Enabled = 1
+}
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index ae56f9f..1e67225 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -16,6 +16,7 @@
#pragma once
+#include <android/gui/CachingHint.h>
#include <android/gui/DisplayBrightness.h>
#include <android/gui/FrameTimelineInfo.h>
#include <android/gui/IDisplayEventConnection.h>
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index ddaf473..da144bd 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -172,7 +172,7 @@
eFlagsChanged = 0x00000040,
eLayerStackChanged = 0x00000080,
eFlushJankData = 0x00000100,
- /* unused = 0x00000200, */
+ eCachingHintChanged = 0x00000200,
eDimmingEnabledChanged = 0x00000400,
eShadowRadiusChanged = 0x00000800,
eRenderBorderChanged = 0x00001000,
@@ -211,7 +211,8 @@
eStretchChanged = 0x2000'00000000,
eTrustedOverlayChanged = 0x4000'00000000,
eDropInputModeChanged = 0x8000'00000000,
- eExtendedRangeBrightnessChanged = 0x10000'00000000
+ eExtendedRangeBrightnessChanged = 0x10000'00000000,
+
};
layer_state_t();
@@ -391,6 +392,8 @@
float currentSdrHdrRatio = 1.f;
float desiredSdrHdrRatio = 1.f;
+ gui::CachingHint cachingHint = gui::CachingHint::Enabled;
+
TrustedPresentationThresholds trustedPresentationThresholds;
TrustedPresentationListener trustedPresentationListener;
};
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 44e78ec..d431b43 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -566,6 +566,7 @@
Transaction& setDataspace(const sp<SurfaceControl>& sc, ui::Dataspace dataspace);
Transaction& setExtendedRangeBrightness(const sp<SurfaceControl>& sc,
float currentBufferRatio, float desiredRatio);
+ Transaction& setCachingHint(const sp<SurfaceControl>& sc, gui::CachingHint cachingHint);
Transaction& setHdrMetadata(const sp<SurfaceControl>& sc, const HdrMetadata& hdrMetadata);
Transaction& setSurfaceDamageRegion(const sp<SurfaceControl>& sc,
const Region& surfaceDamageRegion);
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index fd4fc16..3809b6d 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -57,6 +57,7 @@
"TouchVideoFrame.cpp",
"VelocityControl.cpp",
"VelocityTracker.cpp",
+ "VirtualInputDevice.cpp",
"VirtualKeyMap.cpp",
],
@@ -124,6 +125,8 @@
enabled: false,
},
include_dirs: [
+ "bionic/libc/kernel/android/uapi/",
+ "bionic/libc/kernel/uapi",
"frameworks/native/libs/arect/include",
],
},
diff --git a/libs/input/VirtualInputDevice.cpp b/libs/input/VirtualInputDevice.cpp
new file mode 100644
index 0000000..3c1f2b6
--- /dev/null
+++ b/libs/input/VirtualInputDevice.cpp
@@ -0,0 +1,378 @@
+/*
+ * 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 "VirtualInputDevice"
+
+#include <android/input.h>
+#include <android/keycodes.h>
+#include <fcntl.h>
+#include <input/Input.h>
+#include <input/VirtualInputDevice.h>
+#include <linux/uinput.h>
+#include <math.h>
+#include <utils/Log.h>
+
+#include <map>
+#include <string>
+
+using android::base::unique_fd;
+
+/**
+ * Log debug messages about native virtual input devices.
+ * Enable this via "adb shell setprop log.tag.VirtualInputDevice DEBUG"
+ */
+static bool isDebug() {
+ return __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO);
+}
+
+namespace android {
+VirtualInputDevice::VirtualInputDevice(unique_fd fd) : mFd(std::move(fd)) {}
+VirtualInputDevice::~VirtualInputDevice() {
+ ioctl(mFd, UI_DEV_DESTROY);
+}
+
+bool VirtualInputDevice::writeInputEvent(uint16_t type, uint16_t code, int32_t value) {
+ struct input_event ev = {.type = type, .code = code, .value = value};
+ return TEMP_FAILURE_RETRY(write(mFd, &ev, sizeof(struct input_event))) == sizeof(ev);
+}
+
+/** Utility method to write keyboard key events or mouse button events. */
+bool VirtualInputDevice::writeEvKeyEvent(int32_t androidCode, int32_t androidAction,
+ const std::map<int, int>& evKeyCodeMapping,
+ const std::map<int, UinputAction>& actionMapping) {
+ auto evKeyCodeIterator = evKeyCodeMapping.find(androidCode);
+ if (evKeyCodeIterator == evKeyCodeMapping.end()) {
+ ALOGE("Unsupported native EV keycode for android code %d", androidCode);
+ return false;
+ }
+ auto actionIterator = actionMapping.find(androidAction);
+ if (actionIterator == actionMapping.end()) {
+ return false;
+ }
+ if (!writeInputEvent(EV_KEY, static_cast<uint16_t>(evKeyCodeIterator->second),
+ static_cast<int32_t>(actionIterator->second))) {
+ return false;
+ }
+ if (!writeInputEvent(EV_SYN, SYN_REPORT, 0)) {
+ return false;
+ }
+ return true;
+}
+
+// --- VirtualKeyboard ---
+const std::map<int, UinputAction> VirtualKeyboard::KEY_ACTION_MAPPING = {
+ {AKEY_EVENT_ACTION_DOWN, UinputAction::PRESS},
+ {AKEY_EVENT_ACTION_UP, UinputAction::RELEASE},
+};
+// Keycode mapping from https://source.android.com/devices/input/keyboard-devices
+const std::map<int, int> VirtualKeyboard::KEY_CODE_MAPPING = {
+ {AKEYCODE_0, KEY_0},
+ {AKEYCODE_1, KEY_1},
+ {AKEYCODE_2, KEY_2},
+ {AKEYCODE_3, KEY_3},
+ {AKEYCODE_4, KEY_4},
+ {AKEYCODE_5, KEY_5},
+ {AKEYCODE_6, KEY_6},
+ {AKEYCODE_7, KEY_7},
+ {AKEYCODE_8, KEY_8},
+ {AKEYCODE_9, KEY_9},
+ {AKEYCODE_A, KEY_A},
+ {AKEYCODE_B, KEY_B},
+ {AKEYCODE_C, KEY_C},
+ {AKEYCODE_D, KEY_D},
+ {AKEYCODE_E, KEY_E},
+ {AKEYCODE_F, KEY_F},
+ {AKEYCODE_G, KEY_G},
+ {AKEYCODE_H, KEY_H},
+ {AKEYCODE_I, KEY_I},
+ {AKEYCODE_J, KEY_J},
+ {AKEYCODE_K, KEY_K},
+ {AKEYCODE_L, KEY_L},
+ {AKEYCODE_M, KEY_M},
+ {AKEYCODE_N, KEY_N},
+ {AKEYCODE_O, KEY_O},
+ {AKEYCODE_P, KEY_P},
+ {AKEYCODE_Q, KEY_Q},
+ {AKEYCODE_R, KEY_R},
+ {AKEYCODE_S, KEY_S},
+ {AKEYCODE_T, KEY_T},
+ {AKEYCODE_U, KEY_U},
+ {AKEYCODE_V, KEY_V},
+ {AKEYCODE_W, KEY_W},
+ {AKEYCODE_X, KEY_X},
+ {AKEYCODE_Y, KEY_Y},
+ {AKEYCODE_Z, KEY_Z},
+ {AKEYCODE_GRAVE, KEY_GRAVE},
+ {AKEYCODE_MINUS, KEY_MINUS},
+ {AKEYCODE_EQUALS, KEY_EQUAL},
+ {AKEYCODE_LEFT_BRACKET, KEY_LEFTBRACE},
+ {AKEYCODE_RIGHT_BRACKET, KEY_RIGHTBRACE},
+ {AKEYCODE_BACKSLASH, KEY_BACKSLASH},
+ {AKEYCODE_SEMICOLON, KEY_SEMICOLON},
+ {AKEYCODE_APOSTROPHE, KEY_APOSTROPHE},
+ {AKEYCODE_COMMA, KEY_COMMA},
+ {AKEYCODE_PERIOD, KEY_DOT},
+ {AKEYCODE_SLASH, KEY_SLASH},
+ {AKEYCODE_ALT_LEFT, KEY_LEFTALT},
+ {AKEYCODE_ALT_RIGHT, KEY_RIGHTALT},
+ {AKEYCODE_CTRL_LEFT, KEY_LEFTCTRL},
+ {AKEYCODE_CTRL_RIGHT, KEY_RIGHTCTRL},
+ {AKEYCODE_SHIFT_LEFT, KEY_LEFTSHIFT},
+ {AKEYCODE_SHIFT_RIGHT, KEY_RIGHTSHIFT},
+ {AKEYCODE_META_LEFT, KEY_LEFTMETA},
+ {AKEYCODE_META_RIGHT, KEY_RIGHTMETA},
+ {AKEYCODE_CAPS_LOCK, KEY_CAPSLOCK},
+ {AKEYCODE_SCROLL_LOCK, KEY_SCROLLLOCK},
+ {AKEYCODE_NUM_LOCK, KEY_NUMLOCK},
+ {AKEYCODE_ENTER, KEY_ENTER},
+ {AKEYCODE_TAB, KEY_TAB},
+ {AKEYCODE_SPACE, KEY_SPACE},
+ {AKEYCODE_DPAD_DOWN, KEY_DOWN},
+ {AKEYCODE_DPAD_UP, KEY_UP},
+ {AKEYCODE_DPAD_LEFT, KEY_LEFT},
+ {AKEYCODE_DPAD_RIGHT, KEY_RIGHT},
+ {AKEYCODE_MOVE_END, KEY_END},
+ {AKEYCODE_MOVE_HOME, KEY_HOME},
+ {AKEYCODE_PAGE_DOWN, KEY_PAGEDOWN},
+ {AKEYCODE_PAGE_UP, KEY_PAGEUP},
+ {AKEYCODE_DEL, KEY_BACKSPACE},
+ {AKEYCODE_FORWARD_DEL, KEY_DELETE},
+ {AKEYCODE_INSERT, KEY_INSERT},
+ {AKEYCODE_ESCAPE, KEY_ESC},
+ {AKEYCODE_BREAK, KEY_PAUSE},
+ {AKEYCODE_F1, KEY_F1},
+ {AKEYCODE_F2, KEY_F2},
+ {AKEYCODE_F3, KEY_F3},
+ {AKEYCODE_F4, KEY_F4},
+ {AKEYCODE_F5, KEY_F5},
+ {AKEYCODE_F6, KEY_F6},
+ {AKEYCODE_F7, KEY_F7},
+ {AKEYCODE_F8, KEY_F8},
+ {AKEYCODE_F9, KEY_F9},
+ {AKEYCODE_F10, KEY_F10},
+ {AKEYCODE_F11, KEY_F11},
+ {AKEYCODE_F12, KEY_F12},
+ {AKEYCODE_BACK, KEY_BACK},
+ {AKEYCODE_FORWARD, KEY_FORWARD},
+ {AKEYCODE_NUMPAD_1, KEY_KP1},
+ {AKEYCODE_NUMPAD_2, KEY_KP2},
+ {AKEYCODE_NUMPAD_3, KEY_KP3},
+ {AKEYCODE_NUMPAD_4, KEY_KP4},
+ {AKEYCODE_NUMPAD_5, KEY_KP5},
+ {AKEYCODE_NUMPAD_6, KEY_KP6},
+ {AKEYCODE_NUMPAD_7, KEY_KP7},
+ {AKEYCODE_NUMPAD_8, KEY_KP8},
+ {AKEYCODE_NUMPAD_9, KEY_KP9},
+ {AKEYCODE_NUMPAD_0, KEY_KP0},
+ {AKEYCODE_NUMPAD_ADD, KEY_KPPLUS},
+ {AKEYCODE_NUMPAD_SUBTRACT, KEY_KPMINUS},
+ {AKEYCODE_NUMPAD_MULTIPLY, KEY_KPASTERISK},
+ {AKEYCODE_NUMPAD_DIVIDE, KEY_KPSLASH},
+ {AKEYCODE_NUMPAD_DOT, KEY_KPDOT},
+ {AKEYCODE_NUMPAD_ENTER, KEY_KPENTER},
+ {AKEYCODE_NUMPAD_EQUALS, KEY_KPEQUAL},
+ {AKEYCODE_NUMPAD_COMMA, KEY_KPCOMMA},
+};
+VirtualKeyboard::VirtualKeyboard(unique_fd fd) : VirtualInputDevice(std::move(fd)) {}
+VirtualKeyboard::~VirtualKeyboard() {}
+
+bool VirtualKeyboard::writeKeyEvent(int32_t androidKeyCode, int32_t androidAction) {
+ return writeEvKeyEvent(androidKeyCode, androidAction, KEY_CODE_MAPPING, KEY_ACTION_MAPPING);
+}
+
+// --- VirtualDpad ---
+// Dpad keycode mapping from https://source.android.com/devices/input/keyboard-devices
+const std::map<int, int> VirtualDpad::DPAD_KEY_CODE_MAPPING = {
+ // clang-format off
+ {AKEYCODE_DPAD_DOWN, KEY_DOWN},
+ {AKEYCODE_DPAD_UP, KEY_UP},
+ {AKEYCODE_DPAD_LEFT, KEY_LEFT},
+ {AKEYCODE_DPAD_RIGHT, KEY_RIGHT},
+ {AKEYCODE_DPAD_CENTER, KEY_SELECT},
+ {AKEYCODE_BACK, KEY_BACK},
+ // clang-format on
+};
+
+VirtualDpad::VirtualDpad(unique_fd fd) : VirtualInputDevice(std::move(fd)) {}
+
+VirtualDpad::~VirtualDpad() {}
+
+bool VirtualDpad::writeDpadKeyEvent(int32_t androidKeyCode, int32_t androidAction) {
+ return writeEvKeyEvent(androidKeyCode, androidAction, DPAD_KEY_CODE_MAPPING,
+ VirtualKeyboard::KEY_ACTION_MAPPING);
+}
+
+// --- VirtualMouse ---
+const std::map<int, UinputAction> VirtualMouse::BUTTON_ACTION_MAPPING = {
+ {AMOTION_EVENT_ACTION_BUTTON_PRESS, UinputAction::PRESS},
+ {AMOTION_EVENT_ACTION_BUTTON_RELEASE, UinputAction::RELEASE},
+};
+
+// Button code mapping from https://source.android.com/devices/input/touch-devices
+const std::map<int, int> VirtualMouse::BUTTON_CODE_MAPPING = {
+ // clang-format off
+ {AMOTION_EVENT_BUTTON_PRIMARY, BTN_LEFT},
+ {AMOTION_EVENT_BUTTON_SECONDARY, BTN_RIGHT},
+ {AMOTION_EVENT_BUTTON_TERTIARY, BTN_MIDDLE},
+ {AMOTION_EVENT_BUTTON_BACK, BTN_BACK},
+ {AMOTION_EVENT_BUTTON_FORWARD, BTN_FORWARD},
+ // clang-format on
+};
+
+VirtualMouse::VirtualMouse(unique_fd fd) : VirtualInputDevice(std::move(fd)) {}
+
+VirtualMouse::~VirtualMouse() {}
+
+bool VirtualMouse::writeButtonEvent(int32_t androidButtonCode, int32_t androidAction) {
+ return writeEvKeyEvent(androidButtonCode, androidAction, BUTTON_CODE_MAPPING,
+ BUTTON_ACTION_MAPPING);
+}
+
+bool VirtualMouse::writeRelativeEvent(float relativeX, float relativeY) {
+ return writeInputEvent(EV_REL, REL_X, relativeX) && writeInputEvent(EV_REL, REL_Y, relativeY) &&
+ writeInputEvent(EV_SYN, SYN_REPORT, 0);
+}
+
+bool VirtualMouse::writeScrollEvent(float xAxisMovement, float yAxisMovement) {
+ return writeInputEvent(EV_REL, REL_HWHEEL, xAxisMovement) &&
+ writeInputEvent(EV_REL, REL_WHEEL, yAxisMovement) &&
+ writeInputEvent(EV_SYN, SYN_REPORT, 0);
+}
+
+// --- VirtualTouchscreen ---
+const std::map<int, UinputAction> VirtualTouchscreen::TOUCH_ACTION_MAPPING = {
+ {AMOTION_EVENT_ACTION_DOWN, UinputAction::PRESS},
+ {AMOTION_EVENT_ACTION_UP, UinputAction::RELEASE},
+ {AMOTION_EVENT_ACTION_MOVE, UinputAction::MOVE},
+ {AMOTION_EVENT_ACTION_CANCEL, UinputAction::CANCEL},
+};
+// Tool type mapping from https://source.android.com/devices/input/touch-devices
+const std::map<int, int> VirtualTouchscreen::TOOL_TYPE_MAPPING = {
+ {AMOTION_EVENT_TOOL_TYPE_FINGER, MT_TOOL_FINGER},
+ {AMOTION_EVENT_TOOL_TYPE_PALM, MT_TOOL_PALM},
+};
+
+VirtualTouchscreen::VirtualTouchscreen(unique_fd fd) : VirtualInputDevice(std::move(fd)) {}
+
+VirtualTouchscreen::~VirtualTouchscreen() {}
+
+bool VirtualTouchscreen::isValidPointerId(int32_t pointerId, UinputAction uinputAction) {
+ if (pointerId < -1 || pointerId >= (int)MAX_POINTERS) {
+ ALOGE("Virtual touch event has invalid pointer id %d; value must be between -1 and %zu",
+ pointerId, MAX_POINTERS - 0);
+ return false;
+ }
+
+ if (uinputAction == UinputAction::PRESS && mActivePointers.test(pointerId)) {
+ ALOGE("Repetitive action DOWN event received on a pointer %d that is already down.",
+ pointerId);
+ return false;
+ }
+ if (uinputAction == UinputAction::RELEASE && !mActivePointers.test(pointerId)) {
+ ALOGE("PointerId %d action UP received with no prior action DOWN on touchscreen %d.",
+ pointerId, mFd.get());
+ return false;
+ }
+ return true;
+}
+
+bool VirtualTouchscreen::writeTouchEvent(int32_t pointerId, int32_t toolType, int32_t action,
+ float locationX, float locationY, float pressure,
+ float majorAxisSize) {
+ auto actionIterator = TOUCH_ACTION_MAPPING.find(action);
+ if (actionIterator == TOUCH_ACTION_MAPPING.end()) {
+ return false;
+ }
+ UinputAction uinputAction = actionIterator->second;
+ if (!isValidPointerId(pointerId, uinputAction)) {
+ return false;
+ }
+ if (!writeInputEvent(EV_ABS, ABS_MT_SLOT, pointerId)) {
+ return false;
+ }
+ auto toolTypeIterator = TOOL_TYPE_MAPPING.find(toolType);
+ if (toolTypeIterator == TOOL_TYPE_MAPPING.end()) {
+ return false;
+ }
+ if (!writeInputEvent(EV_ABS, ABS_MT_TOOL_TYPE,
+ static_cast<int32_t>(toolTypeIterator->second))) {
+ return false;
+ }
+ if (uinputAction == UinputAction::PRESS && !handleTouchDown(pointerId)) {
+ return false;
+ }
+ if (uinputAction == UinputAction::RELEASE && !handleTouchUp(pointerId)) {
+ return false;
+ }
+ if (!writeInputEvent(EV_ABS, ABS_MT_POSITION_X, locationX)) {
+ return false;
+ }
+ if (!writeInputEvent(EV_ABS, ABS_MT_POSITION_Y, locationY)) {
+ return false;
+ }
+ if (!isnan(pressure)) {
+ if (!writeInputEvent(EV_ABS, ABS_MT_PRESSURE, pressure)) {
+ return false;
+ }
+ }
+ if (!isnan(majorAxisSize)) {
+ if (!writeInputEvent(EV_ABS, ABS_MT_TOUCH_MAJOR, majorAxisSize)) {
+ return false;
+ }
+ }
+ return writeInputEvent(EV_SYN, SYN_REPORT, 0);
+}
+
+bool VirtualTouchscreen::handleTouchUp(int32_t pointerId) {
+ if (!writeInputEvent(EV_ABS, ABS_MT_TRACKING_ID, static_cast<int32_t>(-1))) {
+ return false;
+ }
+ // When a pointer is no longer in touch, remove the pointer id from the corresponding
+ // entry in the unreleased touches map.
+ mActivePointers.reset(pointerId);
+ ALOGD_IF(isDebug(), "Pointer %d erased from the touchscreen %d", pointerId, mFd.get());
+
+ // Only sends the BTN UP event when there's no pointers on the touchscreen.
+ if (mActivePointers.none()) {
+ if (!writeInputEvent(EV_KEY, BTN_TOUCH, static_cast<int32_t>(UinputAction::RELEASE))) {
+ return false;
+ }
+ ALOGD_IF(isDebug(), "No pointers on touchscreen %d, BTN UP event sent.", mFd.get());
+ }
+ return true;
+}
+
+bool VirtualTouchscreen::handleTouchDown(int32_t pointerId) {
+ // When a new pointer is down on the touchscreen, add the pointer id in the corresponding
+ // entry in the unreleased touches map.
+ if (mActivePointers.none()) {
+ // Only sends the BTN Down event when the first pointer on the touchscreen is down.
+ if (!writeInputEvent(EV_KEY, BTN_TOUCH, static_cast<int32_t>(UinputAction::PRESS))) {
+ return false;
+ }
+ ALOGD_IF(isDebug(), "First pointer %d down under touchscreen %d, BTN DOWN event sent",
+ pointerId, mFd.get());
+ }
+
+ mActivePointers.set(pointerId);
+ ALOGD_IF(isDebug(), "Added pointer %d under touchscreen %d in the map", pointerId, mFd.get());
+ if (!writeInputEvent(EV_ABS, ABS_MT_TRACKING_ID, static_cast<int32_t>(pointerId))) {
+ return false;
+ }
+ return true;
+}
+
+} // namespace android
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index ce7c882..621543a 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -23,11 +23,17 @@
#include <cutils/atomic.h>
#include <inttypes.h>
-using android::base::GetBoolProperty;
using android::base::StringPrintf;
namespace android::inputdispatcher {
+static const bool DEBUGGABLE =
+#if defined(__ANDROID__)
+ android::base::GetBoolProperty("ro.debuggable", false);
+#else
+ true;
+#endif
+
VerifiedKeyEvent verifiedKeyEventFromKeyEntry(const KeyEntry& entry) {
return {{VerifiedInputEvent::Type::KEY, entry.deviceId, entry.eventTime, entry.source,
entry.displayId},
@@ -172,7 +178,7 @@
KeyEntry::~KeyEntry() {}
std::string KeyEntry::getDescription() const {
- if (!GetBoolProperty("ro.debuggable", false)) {
+ if (!DEBUGGABLE) {
return "KeyEvent";
}
return StringPrintf("KeyEvent(deviceId=%d, eventTime=%" PRIu64 ", source=%s, displayId=%" PRId32
@@ -242,7 +248,7 @@
MotionEntry::~MotionEntry() {}
std::string MotionEntry::getDescription() const {
- if (!GetBoolProperty("ro.debuggable", false)) {
+ if (!DEBUGGABLE) {
return "MotionEvent";
}
std::string msg;
@@ -292,7 +298,7 @@
deviceId, inputEventSourceToString(source).c_str(),
ftl::enum_string(sensorType).c_str(), accuracy, hwTimestamp);
- if (!GetBoolProperty("ro.debuggable", false)) {
+ if (DEBUGGABLE) {
for (size_t i = 0; i < values.size(); i++) {
if (i > 0) {
msg += ", ";
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 9d5bbbd..08ae376 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2184,18 +2184,20 @@
const bool newGesture = isDown || maskedAction == AMOTION_EVENT_ACTION_SCROLL || isHoverAction;
const bool isFromMouse = isFromSource(entry.source, AINPUT_SOURCE_MOUSE);
+ // If pointers are already down, let's finish the current gesture and ignore the new events
+ // from another device. However, if the new event is a down event, let's cancel the current
+ // touch and let the new one take over.
+ if (switchedDevice && wasDown && !isDown) {
+ LOG(INFO) << "Dropping event because a pointer for device " << oldState->deviceId
+ << " is already down in display " << displayId << ": " << entry.getDescription();
+ // TODO(b/211379801): test multiple simultaneous input streams.
+ outInjectionResult = InputEventInjectionResult::FAILED;
+ return {}; // wrong device
+ }
+
if (newGesture) {
- // If pointers are already down, let's finish the current gesture and ignore the new events
- // from another device.
- if (switchedDevice && wasDown) {
- ALOGI("Dropping event because a pointer for a different device is already down "
- "in display %" PRId32,
- displayId);
- // TODO: test multiple simultaneous input streams.
- outInjectionResult = InputEventInjectionResult::FAILED;
- return {}; // wrong device
- }
- tempTouchState.clearWindowsWithoutPointers();
+ // If a new gesture is starting, clear the touch state completely.
+ tempTouchState.reset();
tempTouchState.deviceId = entry.deviceId;
tempTouchState.source = entry.source;
isSplit = false;
@@ -2203,7 +2205,7 @@
ALOGI("Dropping move event because a pointer for a different device is already active "
"in display %" PRId32,
displayId);
- // TODO: test multiple simultaneous input streams.
+ // TODO(b/211379801): test multiple simultaneous input streams.
outInjectionResult = InputEventInjectionResult::FAILED;
return {}; // wrong device
}
@@ -2317,6 +2319,10 @@
const bool isDownOrPointerDown = maskedAction == AMOTION_EVENT_ACTION_DOWN ||
maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN;
+ // TODO(b/211379801): Currently, even if pointerIds are empty (hover case), we would
+ // still add a window to the touch state. We should avoid doing that, but some of the
+ // later checks ("at least one foreground window") rely on this in order to dispatch
+ // the event properly, so that needs to be updated, possibly by looking at InputTargets.
tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, pointerIds,
isDownOrPointerDown
? std::make_optional(entry.eventTime)
@@ -2369,10 +2375,9 @@
// If the pointer is not currently down, then ignore the event.
if (!tempTouchState.isDown()) {
- ALOGD_IF(DEBUG_FOCUS,
- "Dropping event because the pointer is not down or we previously "
- "dropped the pointer down event in display %" PRId32 ": %s",
- displayId, entry.getDescription().c_str());
+ LOG(INFO) << "Dropping event because the pointer is not down or we previously "
+ "dropped the pointer down event in display "
+ << displayId << ": " << entry.getDescription();
outInjectionResult = InputEventInjectionResult::FAILED;
return {};
}
@@ -2530,7 +2535,6 @@
}
// Success! Output targets from the touch state.
- tempTouchState.clearWindowsWithoutPointers();
for (const TouchedWindow& touchedWindow : tempTouchState.windows) {
if (touchedWindow.pointerIds.none() && !touchedWindow.hasHoveringPointers(entry.deviceId)) {
// Windows with hovering pointers are getting persisted inside TouchState.
@@ -2570,14 +2574,13 @@
} else if (maskedAction == AMOTION_EVENT_ACTION_UP) {
// Pointer went up.
tempTouchState.removeTouchedPointer(entry.pointerProperties[0].id);
- tempTouchState.clearWindowsWithoutPointers();
} else if (maskedAction == AMOTION_EVENT_ACTION_CANCEL) {
// All pointers up or canceled.
tempTouchState.reset();
} else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
// First pointer went down.
- if (oldState && oldState->isDown()) {
- ALOGD("Conflicting pointer actions: Down received while already down.");
+ if (oldState && (oldState->isDown() || oldState->hasHoveringPointers())) {
+ ALOGD("Conflicting pointer actions: Down received while already down or hovering.");
*outConflictingPointerActions = true;
}
} else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {
@@ -2600,6 +2603,7 @@
// state was only valid for this one action.
if (maskedAction != AMOTION_EVENT_ACTION_SCROLL) {
if (displayId >= 0) {
+ tempTouchState.clearWindowsWithoutPointers();
mTouchStatesByDisplay[displayId] = tempTouchState;
} else {
mTouchStatesByDisplay.erase(displayId);
@@ -3048,9 +3052,13 @@
const MotionEntry& originalMotionEntry = static_cast<const MotionEntry&>(*eventEntry);
if (inputTarget.pointerIds.count() != originalMotionEntry.pointerCount) {
- LOG_ALWAYS_FATAL_IF(!inputTarget.firstDownTimeInTarget.has_value(),
- "Splitting motion events requires a down time to be set for the "
- "target");
+ if (!inputTarget.firstDownTimeInTarget.has_value()) {
+ logDispatchStateLocked();
+ LOG(FATAL) << "Splitting motion events requires a down time to be set for the "
+ "target on connection "
+ << connection->getInputChannelName() << " for "
+ << originalMotionEntry.getDescription();
+ }
std::unique_ptr<MotionEntry> splitMotionEntry =
splitMotionEvent(originalMotionEntry, inputTarget.pointerIds,
inputTarget.firstDownTimeInTarget.value());
@@ -3931,8 +3939,8 @@
// in this way.
ALOGW("Dropping split motion event because the pointer count is %d but "
"we expected there to be %zu pointers. This probably means we received "
- "a broken sequence of pointer ids from the input device.",
- splitPointerCount, pointerIds.count());
+ "a broken sequence of pointer ids from the input device: %s",
+ splitPointerCount, pointerIds.count(), originalMotionEntry.getDescription().c_str());
return nullptr;
}
diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp
index ad5a7fd..cc9cc4e 100644
--- a/services/inputflinger/dispatcher/InputState.cpp
+++ b/services/inputflinger/dispatcher/InputState.cpp
@@ -28,10 +28,6 @@
InputState::~InputState() {}
-bool InputState::isNeutral() const {
- return mKeyMementos.empty() && mMotionMementos.empty();
-}
-
bool InputState::isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const {
for (const MotionMemento& memento : mMotionMementos) {
if (memento.deviceId == deviceId && memento.source == source &&
diff --git a/services/inputflinger/dispatcher/InputState.h b/services/inputflinger/dispatcher/InputState.h
index 42d8cc6..d788e47 100644
--- a/services/inputflinger/dispatcher/InputState.h
+++ b/services/inputflinger/dispatcher/InputState.h
@@ -34,9 +34,6 @@
explicit InputState(const IdGenerator& idGenerator);
~InputState();
- // Returns true if there is no state to be canceled.
- bool isNeutral() const;
-
// Returns true if the specified source is known to have received a hover enter
// motion event.
bool isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const;
diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp
index 4258471..9c443f1 100644
--- a/services/inputflinger/dispatcher/TouchState.cpp
+++ b/services/inputflinger/dispatcher/TouchState.cpp
@@ -35,6 +35,7 @@
for (TouchedWindow& touchedWindow : windows) {
touchedWindow.removeTouchingPointer(pointerId);
}
+ clearWindowsWithoutPointers();
}
void TouchState::removeTouchedPointerFromWindow(
@@ -42,6 +43,7 @@
for (TouchedWindow& touchedWindow : windows) {
if (touchedWindow.windowHandle == windowHandle) {
touchedWindow.removeTouchingPointer(pointerId);
+ clearWindowsWithoutPointers();
return;
}
}
@@ -51,6 +53,7 @@
for (TouchedWindow& touchedWindow : windows) {
touchedWindow.clearHoveringPointers();
}
+ clearWindowsWithoutPointers();
}
void TouchState::clearWindowsWithoutPointers() {
@@ -135,7 +138,7 @@
w.pointerIds &= ~pointerIds;
}
});
- std::erase_if(windows, [](const TouchedWindow& w) { return w.pointerIds.none(); });
+ clearWindowsWithoutPointers();
}
/**
@@ -164,7 +167,7 @@
w.pilferedPointerIds ^ allPilferedPointerIds;
w.pointerIds &= ~pilferedByOtherWindows;
});
- std::erase_if(windows, [](const TouchedWindow& w) { return w.pointerIds.none(); });
+ clearWindowsWithoutPointers();
}
sp<WindowInfoHandle> TouchState::getFirstForegroundWindowHandle() const {
@@ -216,6 +219,11 @@
[](const TouchedWindow& window) { return window.pointerIds.any(); });
}
+bool TouchState::hasHoveringPointers() const {
+ return std::any_of(windows.begin(), windows.end(),
+ [](const TouchedWindow& window) { return window.hasHoveringPointers(); });
+}
+
std::set<sp<WindowInfoHandle>> TouchState::getWindowsWithHoveringPointer(int32_t hoveringDeviceId,
int32_t pointerId) const {
std::set<sp<WindowInfoHandle>> out;
@@ -231,9 +239,7 @@
for (TouchedWindow& window : windows) {
window.removeHoveringPointer(hoveringDeviceId, hoveringPointerId);
}
- std::erase_if(windows, [](const TouchedWindow& w) {
- return w.pointerIds.none() && !w.hasHoveringPointers();
- });
+ clearWindowsWithoutPointers();
}
std::string TouchState::dump() const {
diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h
index 6e965d8..a20080f 100644
--- a/services/inputflinger/dispatcher/TouchState.h
+++ b/services/inputflinger/dispatcher/TouchState.h
@@ -71,6 +71,7 @@
const sp<android::gui::WindowInfoHandle>& windowHandle) const;
// Whether any of the windows are currently being touched
bool isDown() const;
+ bool hasHoveringPointers() const;
std::set<sp<android::gui::WindowInfoHandle>> getWindowsWithHoveringPointer(
int32_t deviceId, int32_t pointerId) const;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index e71cdce..bd9038d 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -58,8 +58,23 @@
static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT;
static constexpr int32_t SECOND_DISPLAY_ID = 1;
+static constexpr int32_t ACTION_DOWN = AMOTION_EVENT_ACTION_DOWN;
+static constexpr int32_t ACTION_MOVE = AMOTION_EVENT_ACTION_MOVE;
+static constexpr int32_t ACTION_UP = AMOTION_EVENT_ACTION_UP;
+static constexpr int32_t ACTION_HOVER_ENTER = AMOTION_EVENT_ACTION_HOVER_ENTER;
+static constexpr int32_t ACTION_HOVER_EXIT = AMOTION_EVENT_ACTION_HOVER_EXIT;
static constexpr int32_t ACTION_OUTSIDE = AMOTION_EVENT_ACTION_OUTSIDE;
static constexpr int32_t ACTION_CANCEL = AMOTION_EVENT_ACTION_CANCEL;
+/**
+ * The POINTER_DOWN(0) is an unusual, but valid, action. It just means that the new pointer in the
+ * MotionEvent is at the index 0 rather than 1 (or later). That is, the pointer id=0 (which is at
+ * index 0) is the new pointer going down. The same pointer could have been placed at a different
+ * index, and the action would become POINTER_1_DOWN, 2, etc..; these would all be valid. In
+ * general, we try to place pointer id = 0 at the index 0. Of course, this is not possible if
+ * pointer id=0 leaves but the pointer id=1 remains.
+ */
+static constexpr int32_t POINTER_0_DOWN =
+ AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
static constexpr int32_t POINTER_1_DOWN =
AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
static constexpr int32_t POINTER_2_DOWN =
@@ -145,6 +160,10 @@
return arg.getDisplayId() == displayId;
}
+MATCHER_P(WithDeviceId, deviceId, "InputEvent with specified deviceId") {
+ return arg.getDeviceId() == deviceId;
+}
+
MATCHER_P(WithSource, source, "InputEvent with specified source") {
*result_listener << "expected source " << inputEventSourceToString(source) << ", but got "
<< inputEventSourceToString(arg.getSource());
@@ -163,6 +182,10 @@
return arg.getX(/*pointerIndex=*/0) == x && arg.getY(/*pointerIndex=*/0) == y;
}
+MATCHER_P(WithPointerCount, pointerCount, "MotionEvent with specified number of pointers") {
+ return arg.getPointerCount() == pointerCount;
+}
+
MATCHER_P(WithPointers, pointers, "MotionEvent with specified pointers") {
// Build a map for the received pointers, by pointer id
std::map<int32_t /*pointerId*/, PointF> actualPointers;
@@ -2365,6 +2388,165 @@
}
/**
+ * Two windows: a window on the left and a window on the right.
+ * Mouse is clicked on the left window and remains down. Touch is touched on the right and remains
+ * down. Then, on the left window, also place second touch pointer down.
+ * This test tries to reproduce a crash.
+ * In the buggy implementation, second pointer down on the left window would cause a crash.
+ */
+TEST_F(InputDispatcherTest, MultiDeviceSplitTouch) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> leftWindow =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
+ leftWindow->setFrame(Rect(0, 0, 200, 200));
+
+ sp<FakeWindowHandle> rightWindow =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
+ rightWindow->setFrame(Rect(200, 0, 400, 200));
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {leftWindow, rightWindow}}});
+
+ const int32_t touchDeviceId = 4;
+ const int32_t mouseDeviceId = 6;
+ NotifyMotionArgs args;
+
+ // Start hovering over the left window
+ mDispatcher->notifyMotion(&(
+ args = MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
+ .deviceId(mouseDeviceId)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(100).y(100))
+ .build()));
+ leftWindow->consumeMotionEvent(
+ AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
+
+ // Mouse down on left window
+ mDispatcher->notifyMotion(&(
+ args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
+ .deviceId(mouseDeviceId)
+ .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(100).y(100))
+ .build()));
+
+ leftWindow->consumeMotionEvent(
+ AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId)));
+ leftWindow->consumeMotionEvent(
+ AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
+
+ mDispatcher->notifyMotion(&(
+ args = MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
+ .deviceId(mouseDeviceId)
+ .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
+ .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(100).y(100))
+ .build()));
+ leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
+
+ // First touch pointer down on right window
+ mDispatcher->notifyMotion(&(
+ args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .deviceId(touchDeviceId)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(300).y(100))
+ .build()));
+ leftWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
+
+ rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
+
+ // Second touch pointer down on left window
+ mDispatcher->notifyMotion(&(
+ args = MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .deviceId(touchDeviceId)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(300).y(100))
+ .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100))
+ .build()));
+ leftWindow->consumeMotionEvent(
+ AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId)));
+ // This MOVE event is not necessary (doesn't carry any new information), but it's there in the
+ // current implementation.
+ const std::map<int32_t, PointF> expectedPointers{{0, PointF{100, 100}}};
+ rightWindow->consumeMotionEvent(
+ AllOf(WithMotionAction(ACTION_MOVE), WithPointers(expectedPointers)));
+
+ leftWindow->assertNoEvents();
+ rightWindow->assertNoEvents();
+}
+
+/**
+ * On a single window, use two different devices: mouse and touch.
+ * Touch happens first, with two pointers going down, and then the first pointer leaving.
+ * Mouse is clicked next, which causes the touch stream to be aborted with ACTION_CANCEL.
+ * Finally, a second touch pointer goes down again. Ensure the second touch pointer is ignored,
+ * because the mouse is currently down, and a POINTER_DOWN event from the touchscreen does not
+ * represent a new gesture.
+ */
+TEST_F(InputDispatcherTest, MixedTouchAndMouseWithPointerDown) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
+ window->setFrame(Rect(0, 0, 400, 400));
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+
+ const int32_t touchDeviceId = 4;
+ const int32_t mouseDeviceId = 6;
+ NotifyMotionArgs args;
+
+ // First touch pointer down on right window
+ mDispatcher->notifyMotion(&(
+ args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .deviceId(touchDeviceId)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(300).y(100))
+ .build()));
+ // Second touch pointer down
+ mDispatcher->notifyMotion(&(
+ args = MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .deviceId(touchDeviceId)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(300).y(100))
+ .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(350).y(100))
+ .build()));
+ // First touch pointer lifts. The second one remains down
+ mDispatcher->notifyMotion(&(
+ args = MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN)
+ .deviceId(touchDeviceId)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(300).y(100))
+ .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(350).y(100))
+ .build()));
+ window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
+ window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
+ window->consumeMotionEvent(WithMotionAction(POINTER_0_UP));
+
+ // Mouse down. The touch should be canceled
+ mDispatcher->notifyMotion(&(
+ args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
+ .deviceId(mouseDeviceId)
+ .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(320).y(100))
+ .build()));
+
+ window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
+ WithPointerCount(2u)));
+ window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
+
+ mDispatcher->notifyMotion(&(
+ args = MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
+ .deviceId(mouseDeviceId)
+ .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
+ .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(320).y(100))
+ .build()));
+ window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
+
+ // Second touch pointer down.
+ mDispatcher->notifyMotion(&(
+ args = MotionArgsBuilder(POINTER_0_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .deviceId(touchDeviceId)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(300).y(100))
+ .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(350).y(100))
+ .build()));
+ // The pointer_down event should be ignored
+ window->assertNoEvents();
+}
+
+/**
* This test is similar to the test above, but the sequence of injected events is different.
*
* Two windows: a window on the left and a window on the right.
@@ -2541,6 +2723,182 @@
}
/**
+ * A spy window above a window with no input channel.
+ * Start hovering with a stylus device, and then tap with it.
+ * Ensure spy window receives the entire sequence.
+ */
+TEST_F(InputDispatcherTest, StylusHoverAndDownNoInputChannel) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> spyWindow =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
+ spyWindow->setFrame(Rect(0, 0, 200, 200));
+ spyWindow->setTrustedOverlay(true);
+ spyWindow->setSpy(true);
+ sp<FakeWindowHandle> window =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
+ window->setNoInputChannel(true);
+ window->setFrame(Rect(0, 0, 200, 200));
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyWindow, window}}});
+
+ NotifyMotionArgs args;
+
+ // Start hovering with stylus
+ mDispatcher->notifyMotion(
+ &(args = MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS).x(50).y(50))
+ .build()));
+ spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
+ // Stop hovering
+ mDispatcher->notifyMotion(
+ &(args = MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS).x(50).y(50))
+ .build()));
+ spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
+
+ // Stylus touches down
+ mDispatcher->notifyMotion(
+ &(args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS).x(50).y(50))
+ .build()));
+ spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
+
+ // Stylus goes up
+ mDispatcher->notifyMotion(
+ &(args = MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS).x(50).y(50))
+ .build()));
+ spyWindow->consumeMotionEvent(WithMotionAction(ACTION_UP));
+
+ // Again hover
+ mDispatcher->notifyMotion(
+ &(args = MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS).x(50).y(50))
+ .build()));
+ spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
+ // Stop hovering
+ mDispatcher->notifyMotion(
+ &(args = MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS).x(50).y(50))
+ .build()));
+ spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
+
+ // No more events
+ spyWindow->assertNoEvents();
+ window->assertNoEvents();
+}
+
+/**
+ * Start hovering with a mouse, and then tap with a touch device. Pilfer the touch stream.
+ * Next, click with the mouse device. Both windows (spy and regular) should receive the new mouse
+ * ACTION_DOWN event because that's a new gesture, and pilfering should no longer be active.
+ * While the mouse is down, new move events from the touch device should be ignored.
+ */
+TEST_F(InputDispatcherTest, TouchPilferAndMouseMove) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> spyWindow =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
+ spyWindow->setFrame(Rect(0, 0, 200, 200));
+ spyWindow->setTrustedOverlay(true);
+ spyWindow->setSpy(true);
+ sp<FakeWindowHandle> window =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
+ window->setFrame(Rect(0, 0, 200, 200));
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyWindow, window}}});
+
+ const int32_t mouseDeviceId = 7;
+ const int32_t touchDeviceId = 4;
+ NotifyMotionArgs args;
+
+ // Hover a bit with mouse first
+ mDispatcher->notifyMotion(&(
+ args = MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
+ .deviceId(mouseDeviceId)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(100).y(100))
+ .build()));
+ spyWindow->consumeMotionEvent(
+ AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
+ window->consumeMotionEvent(
+ AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId)));
+
+ // Start touching
+ mDispatcher->notifyMotion(
+ &(args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .deviceId(touchDeviceId)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+ .build()));
+ spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
+ window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
+ spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
+ window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
+
+ mDispatcher->notifyMotion(
+ &(args = MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
+ .deviceId(touchDeviceId)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(55).y(55))
+ .build()));
+ spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
+ window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
+
+ // Pilfer the stream
+ EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken()));
+ window->consumeMotionEvent(WithMotionAction(ACTION_CANCEL));
+
+ mDispatcher->notifyMotion(
+ &(args = MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
+ .deviceId(touchDeviceId)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(60).y(60))
+ .build()));
+ spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
+
+ // Mouse down
+ mDispatcher->notifyMotion(&(
+ args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
+ .deviceId(mouseDeviceId)
+ .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(100).y(100))
+ .build()));
+
+ spyWindow->consumeMotionEvent(
+ AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId)));
+ spyWindow->consumeMotionEvent(
+ AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
+ window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
+
+ mDispatcher->notifyMotion(&(
+ args = MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
+ .deviceId(mouseDeviceId)
+ .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
+ .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(100).y(100))
+ .build()));
+ spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
+ window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
+
+ // Mouse move!
+ mDispatcher->notifyMotion(&(
+ args = MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
+ .deviceId(mouseDeviceId)
+ .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(110).y(110))
+ .build()));
+ spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
+ window->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
+
+ // Touch move!
+ mDispatcher->notifyMotion(
+ &(args = MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
+ .deviceId(touchDeviceId)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(65).y(65))
+ .build()));
+
+ // No more events
+ spyWindow->assertNoEvents();
+ window->assertNoEvents();
+}
+
+/**
* On the display, have a single window, and also an area where there's no window.
* First pointer touches the "no window" area of the screen. Second pointer touches the window.
* Make sure that the window receives the second pointer, and first pointer is simply ignored.
@@ -2705,7 +3063,8 @@
.x(300)
.y(400))
.build()));
- windowLeft->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ windowLeft->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
+ windowLeft->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectMotionEvent(mDispatcher,
@@ -2750,7 +3109,6 @@
.x(900)
.y(400))
.build()));
- windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
// No more events
@@ -2758,6 +3116,70 @@
windowRight->assertNoEvents();
}
+/**
+ * Put two fingers down (and don't release them) and click the mouse button.
+ * The clicking of mouse is a new ACTION_DOWN event. Since it's from a different device, the
+ * currently active gesture should be canceled, and the new one should proceed.
+ */
+TEST_F(InputDispatcherTest, TwoPointersDownMouseClick) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
+ window->setFrame(Rect(0, 0, 600, 800));
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+
+ const int32_t touchDeviceId = 4;
+ const int32_t mouseDeviceId = 6;
+ NotifyMotionArgs args;
+
+ // Two pointers down
+ mDispatcher->notifyMotion(&(
+ args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .deviceId(touchDeviceId)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100))
+ .build()));
+
+ mDispatcher->notifyMotion(&(
+ args = MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .deviceId(touchDeviceId)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100))
+ .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(120).y(120))
+ .build()));
+ window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
+ window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
+
+ // Inject a series of mouse events for a mouse click
+ mDispatcher->notifyMotion(&(
+ args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
+ .deviceId(mouseDeviceId)
+ .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(300).y(400))
+ .build()));
+ window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId),
+ WithPointerCount(2u)));
+ window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId)));
+
+ mDispatcher->notifyMotion(&(
+ args = MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE)
+ .deviceId(mouseDeviceId)
+ .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
+ .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(300).y(400))
+ .build()));
+ window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
+
+ // Try to send more touch events while the mouse is down. Since it's a continuation of an
+ // already canceled gesture, it should be ignored.
+ mDispatcher->notifyMotion(&(
+ args = MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
+ .deviceId(touchDeviceId)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(101).y(101))
+ .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(121).y(121))
+ .build()));
+ window->assertNoEvents();
+}
+
TEST_F(InputDispatcherTest, HoverWithSpyWindows) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
@@ -2940,7 +3362,8 @@
.x(300)
.y(400))
.build()));
- window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
+ window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectMotionEvent(mDispatcher,
@@ -2984,7 +3407,7 @@
.x(300)
.y(400))
.build()));
- window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
+ window->assertNoEvents();
}
/**
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index 32684fc..0b4d20c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -18,6 +18,7 @@
#include <cstdint>
+#include <android/gui/CachingHint.h>
#include <gui/HdrMetadata.h>
#include <math/mat4.h>
#include <ui/BlurRegion.h>
@@ -213,6 +214,7 @@
float desiredSdrHdrRatio = 1.f;
bool isInternalDisplayOverlay = false;
+ gui::CachingHint cachingHint = gui::CachingHint::Enabled;
virtual ~LayerFECompositionState();
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
index 24a7744..d26ca9d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
@@ -149,6 +149,9 @@
bool hasSolidColorLayers() const;
+ // True if any layer in this cached set has CachingHint::Disabled
+ bool cachingHintExcludesLayers() const;
+
private:
const NonBufferHash mFingerprint;
std::chrono::steady_clock::time_point mLastUpdate = std::chrono::steady_clock::now();
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
index e309442..d5c488e 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
@@ -73,6 +73,7 @@
BackgroundBlurRadius = 1u << 17,
BlurRegions = 1u << 18,
HasProtectedContent = 1u << 19,
+ CachingHint = 1u << 20,
};
// clang-format on
@@ -250,6 +251,8 @@
bool isProtected() const { return mIsProtected.get(); }
+ gui::CachingHint getCachingHint() const { return mCachingHint.get(); }
+
bool hasSolidColorCompositionType() const {
return getOutputLayer()->getLayerFE().getCompositionState()->compositionType ==
aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR;
@@ -487,7 +490,15 @@
return layer->getLayerFE().getCompositionState()->hasProtectedContent;
}};
- static const constexpr size_t kNumNonUniqueFields = 18;
+ OutputLayerState<gui::CachingHint, LayerStateField::CachingHint>
+ mCachingHint{[](auto layer) {
+ return layer->getLayerFE().getCompositionState()->cachingHint;
+ },
+ [](const gui::CachingHint& cachingHint) {
+ return std::vector<std::string>{toString(cachingHint)};
+ }};
+
+ static const constexpr size_t kNumNonUniqueFields = 19;
std::array<StateInterface*, kNumNonUniqueFields> getNonUniqueFields() {
std::array<const StateInterface*, kNumNonUniqueFields> constFields =
@@ -501,13 +512,11 @@
}
std::array<const StateInterface*, kNumNonUniqueFields> getNonUniqueFields() const {
- return {
- &mDisplayFrame, &mSourceCrop, &mBufferTransform, &mBlendMode,
+ return {&mDisplayFrame, &mSourceCrop, &mBufferTransform, &mBlendMode,
&mAlpha, &mLayerMetadata, &mVisibleRegion, &mOutputDataspace,
&mPixelFormat, &mColorTransform, &mCompositionType, &mSidebandStream,
&mBuffer, &mSolidColor, &mBackgroundBlurRadius, &mBlurRegions,
- &mFrameNumber, &mIsProtected,
- };
+ &mFrameNumber, &mIsProtected, &mCachingHint};
}
};
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
index 531b659..615d04b 100644
--- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
@@ -126,6 +126,7 @@
dumpVal(out, "desired sdr/hdr ratio", desiredSdrHdrRatio);
}
dumpVal(out, "colorTransform", colorTransform);
+ dumpVal(out, "caching hint", toString(cachingHint));
out.append("\n");
}
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index ed9a88d..a00ce57 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -393,6 +393,18 @@
});
}
+bool CachedSet::cachingHintExcludesLayers() const {
+ const bool shouldExcludeLayers =
+ std::any_of(mLayers.cbegin(), mLayers.cend(), [](const Layer& layer) {
+ return layer.getState()->getCachingHint() == gui::CachingHint::Disabled;
+ });
+
+ LOG_ALWAYS_FATAL_IF(shouldExcludeLayers && getLayerCount() > 1,
+ "CachedSet is invalid: should be excluded but contains %zu layers",
+ getLayerCount());
+ return shouldExcludeLayers;
+}
+
void CachedSet::dump(std::string& result) const {
const auto now = std::chrono::steady_clock::now();
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index 9175dd0..13b6307 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -413,6 +413,7 @@
for (auto currentSet = mLayers.cbegin(); currentSet != mLayers.cend(); ++currentSet) {
bool layerIsInactive = now - currentSet->getLastUpdate() > mTunables.mActiveLayerTimeout;
const bool layerHasBlur = currentSet->hasBlurBehind();
+ const bool layerDeniedFromCaching = currentSet->cachingHintExcludesLayers();
// Layers should also be considered inactive whenever their framerate is lower than 1fps.
if (!layerIsInactive && currentSet->getLayerCount() == kNumLayersFpsConsideration) {
@@ -424,7 +425,8 @@
}
}
- if (layerIsInactive && (firstLayer || runHasFirstLayer || !layerHasBlur) &&
+ if (!layerDeniedFromCaching && layerIsInactive &&
+ (firstLayer || runHasFirstLayer || !layerHasBlur) &&
!currentSet->hasUnsupportedDataspace()) {
if (isPartOfRun) {
builder.increment();
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index d5d688e..ca5ba69 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -577,6 +577,20 @@
cachedSet.append(CachedSet(layer3));
}
+TEST_F(CachedSetTest, cachingHintIncludesLayersByDefault) {
+ CachedSet cachedSet(*mTestLayers[0]->cachedSetLayer.get());
+ EXPECT_FALSE(cachedSet.cachingHintExcludesLayers());
+}
+
+TEST_F(CachedSetTest, cachingHintExcludesLayersWhenDisabled) {
+ CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get();
+ mTestLayers[0]->layerFECompositionState.cachingHint = gui::CachingHint::Disabled;
+ mTestLayers[0]->layerState->update(&mTestLayers[0]->outputLayer);
+
+ CachedSet cachedSet(layer1);
+ EXPECT_TRUE(cachedSet.cachingHintExcludesLayers());
+}
+
TEST_F(CachedSetTest, holePunch_requiresBuffer) {
CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get();
auto& layerFECompositionState = mTestLayers[0]->layerFECompositionState;
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index 86cfee6..778a0a8 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -1112,6 +1112,55 @@
true);
}
+TEST_F(FlattenerTest, flattenLayers_skipsLayersDisabledFromCaching) {
+ auto& layerState1 = mTestLayers[0]->layerState;
+ const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer;
+
+ auto& layerState2 = mTestLayers[1]->layerState;
+ const auto& overrideBuffer2 = layerState2->getOutputLayer()->getState().overrideInfo.buffer;
+
+ // The third layer has a CachingHint that prevents caching from running
+ auto& layerState3 = mTestLayers[2]->layerState;
+ const auto& overrideBuffer3 = layerState3->getOutputLayer()->getState().overrideInfo.buffer;
+ mTestLayers[2]->layerFECompositionState.cachingHint = gui::CachingHint::Disabled;
+ mTestLayers[2]->layerState->update(&mTestLayers[2]->outputLayer);
+
+ const std::vector<const LayerState*> layers = {
+ layerState1.get(),
+ layerState2.get(),
+ layerState3.get(),
+ };
+
+ initializeFlattener(layers);
+
+ mTime += 200ms;
+ initializeOverrideBuffer(layers);
+ EXPECT_EQ(getNonBufferHash(layers),
+ mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
+
+ // This will render a CachedSet.
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _))
+ .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
+
+ // We've rendered a CachedSet, but we haven't merged it in.
+ EXPECT_EQ(nullptr, overrideBuffer1);
+ EXPECT_EQ(nullptr, overrideBuffer2);
+ EXPECT_EQ(nullptr, overrideBuffer3);
+
+ // This time we merge the CachedSet in, so we have a new hash, and we should
+ // only have two sets.
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0);
+ initializeOverrideBuffer(layers);
+ EXPECT_NE(getNonBufferHash(layers),
+ mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
+
+ EXPECT_NE(nullptr, overrideBuffer1);
+ EXPECT_EQ(overrideBuffer1, overrideBuffer2);
+ EXPECT_EQ(nullptr, overrideBuffer3);
+}
+
TEST_F(FlattenerTest, flattenLayers_skipsBT601_625) {
auto& layerState1 = mTestLayers[0]->layerState;
const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer;
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
index 47b6820..044917e 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
@@ -994,6 +994,45 @@
EXPECT_TRUE(mLayerState->hasBlurBehind());
}
+TEST_F(LayerStateTest, updateCachingHint) {
+ OutputLayerCompositionState outputLayerCompositionState;
+ LayerFECompositionState layerFECompositionState;
+ layerFECompositionState.cachingHint = gui::CachingHint::Enabled;
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
+ layerFECompositionState);
+ mLayerState = std::make_unique<LayerState>(&mOutputLayer);
+
+ mock::OutputLayer newOutputLayer;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
+ LayerFECompositionState layerFECompositionStateTwo;
+ layerFECompositionStateTwo.cachingHint = gui::CachingHint::Disabled;
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
+ layerFECompositionStateTwo);
+ ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::CachingHint), updates);
+}
+
+TEST_F(LayerStateTest, compareCachingHint) {
+ OutputLayerCompositionState outputLayerCompositionState;
+ LayerFECompositionState layerFECompositionState;
+ layerFECompositionState.cachingHint = gui::CachingHint::Enabled;
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
+ layerFECompositionState);
+ mLayerState = std::make_unique<LayerState>(&mOutputLayer);
+ mock::OutputLayer newOutputLayer;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
+ LayerFECompositionState layerFECompositionStateTwo;
+ layerFECompositionStateTwo.cachingHint = gui::CachingHint::Disabled;
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
+ layerFECompositionStateTwo);
+ auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
+
+ verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::CachingHint);
+
+ EXPECT_TRUE(mLayerState->compare(*otherLayerState));
+ EXPECT_TRUE(otherLayerState->compare(*mLayerState));
+}
+
TEST_F(LayerStateTest, dumpDoesNotCrash) {
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index c9aeb24..d740350 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -727,6 +727,7 @@
snapshot.dimmingEnabled = requested.dimmingEnabled;
snapshot.layerOpaqueFlagSet =
(requested.flags & layer_state_t::eLayerOpaque) == layer_state_t::eLayerOpaque;
+ snapshot.cachingHint = requested.cachingHint;
}
if (forceUpdate || snapshot.changes.any(RequestedLayerState::Changes::Content)) {
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index 2834084..09523d3 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -137,6 +137,7 @@
dataspace = ui::Dataspace::V0_SRGB;
gameMode = gui::GameMode::Unsupported;
requestedFrameRate = {};
+ cachingHint = gui::CachingHint::Enabled;
}
void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerState) {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 084d9b9..dac0916 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -566,6 +566,7 @@
: Hwc2::IComposerClient::BlendMode::COVERAGE;
}
+ // Please keep in sync with LayerSnapshotBuilder
auto* snapshot = editLayerSnapshot();
snapshot->outputFilter = getOutputFilter();
snapshot->isVisible = isVisible();
@@ -592,6 +593,7 @@
const auto& drawingState{getDrawingState()};
auto* snapshot = editLayerSnapshot();
+ // Please keep in sync with LayerSnapshotBuilder
snapshot->geomBufferSize = getBufferSize(drawingState);
snapshot->geomContentCrop = getBufferCrop();
snapshot->geomCrop = getCrop(drawingState);
@@ -624,6 +626,7 @@
void Layer::preparePerFrameCompositionState() {
const auto& drawingState{getDrawingState()};
+ // Please keep in sync with LayerSnapshotBuilder
auto* snapshot = editLayerSnapshot();
snapshot->forceClientComposition = false;
@@ -637,6 +640,7 @@
snapshot->dimmingEnabled = isDimmingEnabled();
snapshot->currentSdrHdrRatio = getCurrentSdrHdrRatio();
snapshot->desiredSdrHdrRatio = getDesiredSdrHdrRatio();
+ snapshot->cachingHint = getCachingHint();
const bool usesRoundedCorners = hasRoundedCorners();
@@ -666,8 +670,9 @@
}
void Layer::preparePerFrameBufferCompositionState() {
- // Sideband layers
+ // Please keep in sync with LayerSnapshotBuilder
auto* snapshot = editLayerSnapshot();
+ // Sideband layers
if (snapshot->sidebandStream.get() && !snapshot->sidebandStreamHasFrame) {
snapshot->compositionType =
aidl::android::hardware::graphics::composer3::Composition::SIDEBAND;
@@ -690,6 +695,7 @@
}
void Layer::preparePerFrameEffectsCompositionState() {
+ // Please keep in sync with LayerSnapshotBuilder
auto* snapshot = editLayerSnapshot();
snapshot->color = getColor();
snapshot->compositionType =
@@ -698,6 +704,7 @@
void Layer::prepareCursorCompositionState() {
const State& drawingState{getDrawingState()};
+ // Please keep in sync with LayerSnapshotBuilder
auto* snapshot = editLayerSnapshot();
// Apply the layer's transform, followed by the display's global transform
@@ -3091,6 +3098,14 @@
return true;
}
+bool Layer::setCachingHint(gui::CachingHint cachingHint) {
+ if (mDrawingState.cachingHint == cachingHint) return false;
+ mDrawingState.cachingHint = cachingHint;
+ mDrawingState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
bool Layer::setHdrMetadata(const HdrMetadata& hdrMetadata) {
if (mDrawingState.hdrMetadata == hdrMetadata) return false;
mDrawingState.hdrMetadata = hdrMetadata;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2955daf..7d40774 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -227,6 +227,7 @@
bool dimmingEnabled = true;
float currentSdrHdrRatio = 1.f;
float desiredSdrHdrRatio = 1.f;
+ gui::CachingHint cachingHint = gui::CachingHint::Enabled;
};
explicit Layer(const LayerCreationArgs& args);
@@ -296,6 +297,7 @@
virtual bool isDimmingEnabled() const { return getDrawingState().dimmingEnabled; }
float getDesiredSdrHdrRatio() const { return getDrawingState().desiredSdrHdrRatio; }
float getCurrentSdrHdrRatio() const { return getDrawingState().currentSdrHdrRatio; }
+ gui::CachingHint getCachingHint() const { return getDrawingState().cachingHint; }
bool setTransform(uint32_t /*transform*/);
bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/);
@@ -305,6 +307,7 @@
std::optional<nsecs_t> /* dequeueTime */, const FrameTimelineInfo& /*info*/);
bool setDataspace(ui::Dataspace /*dataspace*/);
bool setExtendedRangeBrightness(float currentBufferRatio, float desiredRatio);
+ bool setCachingHint(gui::CachingHint cachingHint);
bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/);
bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/);
bool setApi(int32_t /*api*/);
diff --git a/services/surfaceflinger/LayerFE.h b/services/surfaceflinger/LayerFE.h
index 01da019..c23bd31 100644
--- a/services/surfaceflinger/LayerFE.h
+++ b/services/surfaceflinger/LayerFE.h
@@ -16,6 +16,7 @@
#pragma once
+#include <android/gui/CachingHint.h>
#include <gui/LayerMetadata.h>
#include "FrontEnd/LayerSnapshot.h"
#include "compositionengine/LayerFE.h"
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
index 4f5842a..5052e6e 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h
@@ -32,7 +32,6 @@
#include <scheduler/Seamlessness.h>
#include "DisplayHardware/DisplayMode.h"
-#include "DisplayHardware/HWComposer.h"
#include "Scheduler/OneShotTimer.h"
#include "Scheduler/StrongTyping.h"
#include "ThreadContext.h"
@@ -297,6 +296,8 @@
RefreshRateSelector(const RefreshRateSelector&) = delete;
RefreshRateSelector& operator=(const RefreshRateSelector&) = delete;
+ const DisplayModes& displayModes() const { return mDisplayModes; }
+
// Returns whether switching modes (refresh rate or resolution) is possible.
// TODO(b/158780872): Consider HAL support, and skip frame rate detection if the modes only
// differ in resolution. Once Config::FrameRateOverride::Enabled becomes the default,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 5f95859..5c8579c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -4783,6 +4783,11 @@
flags |= eTraversalNeeded;
}
}
+ if (what & layer_state_t::eCachingHintChanged) {
+ if (layer->setCachingHint(s.cachingHint)) {
+ flags |= eTraversalNeeded;
+ }
+ }
if (what & layer_state_t::eHdrMetadataChanged) {
if (layer->setHdrMetadata(s.hdrMetadata)) flags |= eTraversalNeeded;
}
diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
index ab98dbf..31f4723 100644
--- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
@@ -191,29 +191,20 @@
return false;
}
- Factory mFactory;
- sp<MockSurfaceFlinger> flinger = sp<MockSurfaceFlinger>::make(mFactory);
- TestableSurfaceFlinger mFlinger(flinger);
- mFlinger.setupRenderEngine(
+ Factory factory;
+ sp<MockSurfaceFlinger> flingerPtr = sp<MockSurfaceFlinger>::make(factory);
+ TestableSurfaceFlinger flinger(flingerPtr);
+ flinger.setupRenderEngine(
std::make_unique<testing::NiceMock<renderengine::mock::RenderEngine>>());
- mock::VsyncController* mVsyncController = new testing::NiceMock<mock::VsyncController>();
- mock::VSyncTracker* mVSyncTracker = new testing::NiceMock<mock::VSyncTracker>();
- mock::EventThread* mEventThread = new testing::NiceMock<mock::EventThread>();
- mock::EventThread* mSFEventThread = new testing::NiceMock<mock::EventThread>();
- mFlinger.setupScheduler(std::unique_ptr<scheduler::VsyncController>(mVsyncController),
- std::unique_ptr<scheduler::VSyncTracker>(mVSyncTracker),
- std::unique_ptr<EventThread>(mEventThread),
- std::unique_ptr<EventThread>(mSFEventThread),
- TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp,
- TestableSurfaceFlinger::kOneDisplayMode, true /* useNiceMock */);
+ flinger.setupMockScheduler({.useNiceMock = true});
- Hwc2::mock::Composer* mComposer = new testing::NiceMock<Hwc2::mock::Composer>();
- mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
- mFlinger.mutableMaxRenderTargetSize() = 16384;
+ Hwc2::mock::Composer* composerPtr = new testing::NiceMock<Hwc2::mock::Composer>();
+ flinger.setupComposer(std::unique_ptr<Hwc2::Composer>(composerPtr));
+ flinger.mutableMaxRenderTargetSize() = 16384;
- flinger->setLayerTracingFlags(LayerTracing::TRACE_INPUT | LayerTracing::TRACE_BUFFERS);
- flinger->setLayerTraceSize(512 * 1024); // 512MB buffer size
- flinger->startLayerTracing(traceFile.entry(0).elapsed_realtime_nanos());
+ flingerPtr->setLayerTracingFlags(LayerTracing::TRACE_INPUT | LayerTracing::TRACE_BUFFERS);
+ flingerPtr->setLayerTraceSize(512 * 1024); // 512MB buffer size
+ flingerPtr->startLayerTracing(traceFile.entry(0).elapsed_realtime_nanos());
std::unique_ptr<TraceGenFlingerDataMapper> mapper =
std::make_unique<TraceGenFlingerDataMapper>();
TraceGenFlingerDataMapper* dataMapper = mapper.get();
@@ -234,7 +225,7 @@
parser.fromProto(entry.added_layers(j), tracingArgs);
gui::CreateSurfaceResult outResult;
- LayerCreationArgs args(mFlinger.flinger(), nullptr /* client */, tracingArgs.name,
+ LayerCreationArgs args(flinger.flinger(), nullptr /* client */, tracingArgs.name,
tracingArgs.flags, LayerMetadata(),
std::make_optional<int32_t>(tracingArgs.layerId));
@@ -247,10 +238,10 @@
} else if (tracingArgs.parentId != -1) {
parentHandle = dataMapper->getLayerHandle(tracingArgs.parentId);
}
- mFlinger.createLayer(args, parentHandle, outResult);
+ flinger.createLayer(args, parentHandle, outResult);
} else {
sp<IBinder> mirrorFromHandle = dataMapper->getLayerHandle(tracingArgs.mirrorFromId);
- mFlinger.mirrorLayer(args, mirrorFromHandle, outResult);
+ flinger.mirrorLayer(args, mirrorFromHandle, outResult);
}
LOG_ALWAYS_FATAL_IF(outResult.layerId != tracingArgs.layerId,
"Could not create layer expected:%d actual:%d", tracingArgs.layerId,
@@ -261,19 +252,19 @@
for (int j = 0; j < entry.transactions_size(); j++) {
// apply transactions
TransactionState transaction = parser.fromProto(entry.transactions(j));
- mFlinger.setTransactionStateInternal(transaction);
+ flinger.setTransactionStateInternal(transaction);
}
const auto frameTime = TimePoint::fromNs(entry.elapsed_realtime_nanos());
const auto vsyncId = VsyncId{entry.vsync_id()};
- mFlinger.commit(frameTime, vsyncId);
+ flinger.commit(frameTime, vsyncId);
for (int j = 0; j < entry.removed_layer_handles_size(); j++) {
dataMapper->mLayerHandles.erase(entry.removed_layer_handles(j));
}
}
- flinger->stopLayerTracing(outputLayersTracePath);
+ flingerPtr->stopLayerTracing(outputLayersTracePath);
ALOGD("End of generating trace file. File written to %s", outputLayersTracePath);
dataMapper->mLayerHandles.clear();
return true;
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 0416e93..17ef6ff 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -99,7 +99,7 @@
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
- setupScheduler();
+ mFlinger.setupMockScheduler({.displayId = DEFAULT_DISPLAY_ID});
EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0)));
@@ -122,36 +122,6 @@
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
}
- void setupScheduler() {
- auto eventThread = std::make_unique<mock::EventThread>();
- auto sfEventThread = std::make_unique<mock::EventThread>();
-
- EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
- mock::EventThread::kCallingUid,
- ResyncCallback())));
-
- EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
- mock::EventThread::kCallingUid,
- ResyncCallback())));
-
- auto vsyncController = std::make_unique<mock::VsyncController>();
- auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
-
- EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
- EXPECT_CALL(*vsyncTracker, currentPeriod())
- .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
- EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
-
- mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
- std::move(eventThread), std::move(sfEventThread),
- TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp,
- TestableSurfaceFlinger::kTwoDisplayModes);
- }
-
void setupForceGeometryDirty() {
// TODO: This requires the visible region and other related
// state to be set, and is problematic for BufferLayers since they are
@@ -176,7 +146,6 @@
bool mDisplayOff = false;
TestableSurfaceFlinger mFlinger;
sp<DisplayDevice> mDisplay;
- sp<DisplayDevice> mExternalDisplay;
sp<compositionengine::mock::DisplaySurface> mDisplaySurface =
sp<compositionengine::mock::DisplaySurface>::make();
sp<mock::NativeWindow> mNativeWindow = sp<mock::NativeWindow>::make();
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index e0b508a..52dc695 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -29,9 +29,7 @@
using android::hardware::graphics::composer::hal::HWDisplayId;
-using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
-
-DisplayTransactionTest::DisplayTransactionTest() {
+DisplayTransactionTest::DisplayTransactionTest(bool withMockScheduler) {
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
@@ -48,7 +46,10 @@
return nullptr;
});
- injectMockScheduler();
+ if (withMockScheduler) {
+ injectMockScheduler(PhysicalDisplayId::fromPort(0));
+ }
+
mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
injectMockComposer(0);
@@ -61,7 +62,9 @@
mFlinger.resetScheduler(nullptr);
}
-void DisplayTransactionTest::injectMockScheduler() {
+void DisplayTransactionTest::injectMockScheduler(PhysicalDisplayId displayId) {
+ LOG_ALWAYS_FATAL_IF(mFlinger.scheduler());
+
EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*mEventThread, createEventConnection(_, _))
.WillOnce(Return(sp<EventThreadConnection>::make(mEventThread,
@@ -78,6 +81,7 @@
std::unique_ptr<scheduler::VSyncTracker>(mVSyncTracker),
std::unique_ptr<EventThread>(mEventThread),
std::unique_ptr<EventThread>(mSFEventThread),
+ TestableSurfaceFlinger::DefaultDisplayMode{displayId},
TestableSurfaceFlinger::SchedulerCallbackImpl::kMock);
}
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 223f4db..23a8bd1 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -85,7 +85,7 @@
// --------------------------------------------------------------------
// Mock/Fake injection
- void injectMockScheduler();
+ void injectMockScheduler(PhysicalDisplayId);
void injectMockComposer(int virtualDisplayCount);
void injectFakeBufferQueueFactory();
void injectFakeNativeWindowSurfaceFactory();
@@ -139,7 +139,7 @@
surfaceflinger::mock::NativeWindowSurface* mNativeWindowSurface = nullptr;
protected:
- DisplayTransactionTest();
+ DisplayTransactionTest(bool withMockScheduler = true);
};
constexpr int32_t DEFAULT_VSYNC_PERIOD = 16'666'667;
@@ -158,7 +158,6 @@
#define BOOL_SUBSTITUTE(TYPENAME) enum class TYPENAME : bool { FALSE = false, TRUE = true };
BOOL_SUBSTITUTE(Async);
-BOOL_SUBSTITUTE(Critical);
BOOL_SUBSTITUTE(Primary);
BOOL_SUBSTITUTE(Secure);
BOOL_SUBSTITUTE(Virtual);
@@ -238,8 +237,8 @@
// 1) PhysicalDisplayIdType<...> for generated ID of physical display backed by HWC.
// 2) HalVirtualDisplayIdType<...> for hard-coded ID of virtual display backed by HWC.
// 3) GpuVirtualDisplayIdType for virtual display without HWC backing.
-template <typename DisplayIdType, int width, int height, Critical critical, Async async,
- Secure secure, Primary primary, int grallocUsage, int displayFlags>
+template <typename DisplayIdType, int width, int height, Async async, Secure secure,
+ Primary primary, int grallocUsage, int displayFlags>
struct DisplayVariant {
using DISPLAY_ID = DisplayIdGetter<DisplayIdType>;
using CONNECTION_TYPE = DisplayConnectionTypeGetter<DisplayIdType>;
@@ -255,9 +254,6 @@
static constexpr Virtual VIRTUAL =
IsPhysicalDisplayId<DisplayIdType>{} ? Virtual::FALSE : Virtual::TRUE;
- // When creating native window surfaces for the framebuffer, whether those should be critical
- static constexpr Critical CRITICAL = critical;
-
// When creating native window surfaces for the framebuffer, whether those should be async
static constexpr Async ASYNC = async;
@@ -486,17 +482,16 @@
constexpr int PHYSICAL_DISPLAY_FLAGS = 0x1;
-template <typename PhysicalDisplay, int width, int height, Critical critical>
+template <typename PhysicalDisplay, int width, int height>
struct PhysicalDisplayVariant
- : DisplayVariant<PhysicalDisplayIdType<PhysicalDisplay>, width, height, critical,
- Async::FALSE, Secure::TRUE, PhysicalDisplay::PRIMARY,
- GRALLOC_USAGE_PHYSICAL_DISPLAY, PHYSICAL_DISPLAY_FLAGS>,
- HwcDisplayVariant<
- PhysicalDisplay::HWC_DISPLAY_ID, DisplayType::PHYSICAL,
- DisplayVariant<PhysicalDisplayIdType<PhysicalDisplay>, width, height, critical,
- Async::FALSE, Secure::TRUE, PhysicalDisplay::PRIMARY,
- GRALLOC_USAGE_PHYSICAL_DISPLAY, PHYSICAL_DISPLAY_FLAGS>,
- PhysicalDisplay> {};
+ : DisplayVariant<PhysicalDisplayIdType<PhysicalDisplay>, width, height, Async::FALSE,
+ Secure::TRUE, PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY,
+ PHYSICAL_DISPLAY_FLAGS>,
+ HwcDisplayVariant<PhysicalDisplay::HWC_DISPLAY_ID, DisplayType::PHYSICAL,
+ DisplayVariant<PhysicalDisplayIdType<PhysicalDisplay>, width, height,
+ Async::FALSE, Secure::TRUE, PhysicalDisplay::PRIMARY,
+ GRALLOC_USAGE_PHYSICAL_DISPLAY, PHYSICAL_DISPLAY_FLAGS>,
+ PhysicalDisplay> {};
template <bool hasIdentificationData>
struct PrimaryDisplay {
@@ -525,15 +520,9 @@
static constexpr auto GET_IDENTIFICATION_DATA = getExternalEdid;
};
-// A primary display is a physical display that is critical
-using PrimaryDisplayVariant =
- PhysicalDisplayVariant<PrimaryDisplay<false>, 3840, 2160, Critical::TRUE>;
-
-// An external display is physical display that is not critical.
-using ExternalDisplayVariant =
- PhysicalDisplayVariant<ExternalDisplay<false>, 1920, 1280, Critical::FALSE>;
-
-using TertiaryDisplayVariant = PhysicalDisplayVariant<TertiaryDisplay, 1600, 1200, Critical::FALSE>;
+using PrimaryDisplayVariant = PhysicalDisplayVariant<PrimaryDisplay<false>, 3840, 2160>;
+using ExternalDisplayVariant = PhysicalDisplayVariant<ExternalDisplay<false>, 1920, 1280>;
+using TertiaryDisplayVariant = PhysicalDisplayVariant<TertiaryDisplay, 1600, 1200>;
// A virtual display not supported by the HWC.
constexpr uint32_t GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY = 0;
@@ -542,12 +531,11 @@
template <int width, int height, Secure secure>
struct NonHwcVirtualDisplayVariant
- : DisplayVariant<GpuVirtualDisplayIdType, width, height, Critical::FALSE, Async::TRUE, secure,
- Primary::FALSE, GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY,
- VIRTUAL_DISPLAY_FLAGS> {
- using Base = DisplayVariant<GpuVirtualDisplayIdType, width, height, Critical::FALSE,
- Async::TRUE, secure, Primary::FALSE,
- GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY, VIRTUAL_DISPLAY_FLAGS>;
+ : DisplayVariant<GpuVirtualDisplayIdType, width, height, Async::TRUE, secure, Primary::FALSE,
+ GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY, VIRTUAL_DISPLAY_FLAGS> {
+ using Base = DisplayVariant<GpuVirtualDisplayIdType, width, height, Async::TRUE, secure,
+ Primary::FALSE, GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY,
+ VIRTUAL_DISPLAY_FLAGS>;
static void injectHwcDisplay(DisplayTransactionTest*) {}
@@ -589,17 +577,14 @@
template <int width, int height, Secure secure>
struct HwcVirtualDisplayVariant
- : DisplayVariant<HalVirtualDisplayIdType<42>, width, height, Critical::FALSE, Async::TRUE,
- secure, Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY,
- VIRTUAL_DISPLAY_FLAGS>,
- HwcDisplayVariant<
- HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID, DisplayType::VIRTUAL,
- DisplayVariant<HalVirtualDisplayIdType<42>, width, height, Critical::FALSE,
- Async::TRUE, secure, Primary::FALSE,
- GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY, VIRTUAL_DISPLAY_FLAGS>> {
- using Base = DisplayVariant<HalVirtualDisplayIdType<42>, width, height, Critical::FALSE,
- Async::TRUE, secure, Primary::FALSE, GRALLOC_USAGE_HW_COMPOSER,
- VIRTUAL_DISPLAY_FLAGS>;
+ : DisplayVariant<HalVirtualDisplayIdType<42>, width, height, Async::TRUE, secure,
+ Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY, VIRTUAL_DISPLAY_FLAGS>,
+ HwcDisplayVariant<HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID, DisplayType::VIRTUAL,
+ DisplayVariant<HalVirtualDisplayIdType<42>, width, height, Async::TRUE,
+ secure, Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY,
+ VIRTUAL_DISPLAY_FLAGS>> {
+ using Base = DisplayVariant<HalVirtualDisplayIdType<42>, width, height, Async::TRUE, secure,
+ Primary::FALSE, GRALLOC_USAGE_HW_COMPOSER, VIRTUAL_DISPLAY_FLAGS>;
using Self = HwcVirtualDisplayVariant<width, height, secure>;
static std::shared_ptr<compositionengine::Display> injectCompositionDisplay(
diff --git a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp
index 1cd9e49..f695b09 100644
--- a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp
@@ -29,9 +29,7 @@
#include "TestableSurfaceFlinger.h"
#include "fake/FakeClock.h"
#include "mock/DisplayHardware/MockComposer.h"
-#include "mock/MockEventThread.h"
#include "mock/MockFrameTimeline.h"
-#include "mock/MockVsyncController.h"
namespace android {
@@ -47,7 +45,6 @@
using android::Hwc2::IComposer;
using android::Hwc2::IComposerClient;
-using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
using gui::LayerMetadata;
struct TestableFpsListener : public gui::BnFpsListener {
@@ -77,7 +74,6 @@
static constexpr uint32_t LAYER_FLAGS = 0;
static constexpr int32_t PRIORITY_UNSET = -1;
- void setupScheduler();
sp<Layer> createBufferStateLayer(LayerMetadata metadata);
TestableSurfaceFlinger mFlinger;
@@ -102,7 +98,7 @@
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
- setupScheduler();
+ mFlinger.setupMockScheduler();
mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
mFpsListener = sp<TestableFpsListener>::make();
@@ -120,33 +116,6 @@
return sp<Layer>::make(args);
}
-void FpsReporterTest::setupScheduler() {
- auto eventThread = std::make_unique<mock::EventThread>();
- auto sfEventThread = std::make_unique<mock::EventThread>();
-
- EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
- mock::EventThread::kCallingUid,
- ResyncCallback())));
-
- EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
- mock::EventThread::kCallingUid,
- ResyncCallback())));
-
- auto vsyncController = std::make_unique<mock::VsyncController>();
- auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
-
- EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
- EXPECT_CALL(*vsyncTracker, currentPeriod())
- .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
- EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
- mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
- std::move(eventThread), std::move(sfEventThread));
-}
-
namespace {
TEST_F(FpsReporterTest, callsListeners) {
diff --git a/services/surfaceflinger/tests/unittests/FrameRateSelectionPriorityTest.cpp b/services/surfaceflinger/tests/unittests/FrameRateSelectionPriorityTest.cpp
index ac63a0e..1c9aee7 100644
--- a/services/surfaceflinger/tests/unittests/FrameRateSelectionPriorityTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameRateSelectionPriorityTest.cpp
@@ -24,8 +24,6 @@
#include "Layer.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
-#include "mock/MockEventThread.h"
-#include "mock/MockVsyncController.h"
namespace android {
@@ -38,8 +36,6 @@
using android::Hwc2::IComposer;
using android::Hwc2::IComposerClient;
-using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
-
/**
* This class covers all the test that are related to refresh rate selection.
*/
@@ -56,7 +52,6 @@
static constexpr uint32_t LAYER_FLAGS = 0;
static constexpr int32_t PRIORITY_UNSET = -1;
- void setupScheduler();
sp<Layer> createBufferStateLayer();
sp<Layer> createEffectLayer();
@@ -76,7 +71,7 @@
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
- setupScheduler();
+ mFlinger.setupMockScheduler();
mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
}
@@ -108,37 +103,8 @@
layer->commitTransaction(c);
}
-void RefreshRateSelectionTest::setupScheduler() {
- auto eventThread = std::make_unique<mock::EventThread>();
- auto sfEventThread = std::make_unique<mock::EventThread>();
-
- EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
- mock::EventThread::kCallingUid,
- ResyncCallback())));
-
- EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
- mock::EventThread::kCallingUid,
- ResyncCallback())));
-
- auto vsyncController = std::make_unique<mock::VsyncController>();
- auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
-
- EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
- EXPECT_CALL(*vsyncTracker, currentPeriod())
- .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
- EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
- mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
- std::move(eventThread), std::move(sfEventThread));
-}
-
namespace {
-/* ------------------------------------------------------------------------
- * Test cases
- */
+
TEST_F(RefreshRateSelectionTest, testPriorityOnBufferStateLayers) {
mParent = createBufferStateLayer();
mChild = createBufferStateLayer();
diff --git a/services/surfaceflinger/tests/unittests/GameModeTest.cpp b/services/surfaceflinger/tests/unittests/GameModeTest.cpp
index 29aa717..1b5c6e7 100644
--- a/services/surfaceflinger/tests/unittests/GameModeTest.cpp
+++ b/services/surfaceflinger/tests/unittests/GameModeTest.cpp
@@ -25,15 +25,13 @@
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
-#include "mock/MockEventThread.h"
-#include "mock/MockVsyncController.h"
namespace android {
using testing::_;
using testing::Mock;
using testing::Return;
-using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+
using gui::GameMode;
using gui::LayerMetadata;
@@ -43,7 +41,7 @@
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
- setupScheduler();
+ mFlinger.setupMockScheduler();
setupComposer();
}
@@ -59,33 +57,6 @@
return sp<Layer>::make(args);
}
- void setupScheduler() {
- auto eventThread = std::make_unique<mock::EventThread>();
- auto sfEventThread = std::make_unique<mock::EventThread>();
-
- EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
- mock::EventThread::kCallingUid,
- ResyncCallback())));
-
- EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
- mock::EventThread::kCallingUid,
- ResyncCallback())));
-
- auto vsyncController = std::make_unique<mock::VsyncController>();
- auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
-
- EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
- EXPECT_CALL(*vsyncTracker, currentPeriod())
- .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
- EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
- mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
- std::move(eventThread), std::move(sfEventThread));
- }
-
void setupComposer() {
mComposer = new Hwc2::mock::Composer();
mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
diff --git a/services/surfaceflinger/tests/unittests/LayerTestUtils.cpp b/services/surfaceflinger/tests/unittests/LayerTestUtils.cpp
index ee42e19..803e807 100644
--- a/services/surfaceflinger/tests/unittests/LayerTestUtils.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerTestUtils.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright 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.
@@ -16,15 +16,8 @@
#include "LayerTestUtils.h"
-#include "mock/MockEventThread.h"
-
namespace android {
-using testing::_;
-using testing::Return;
-
-using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
-
sp<Layer> BufferStateLayerFactory::createLayer(TestableSurfaceFlinger& flinger) {
sp<Client> client;
LayerCreationArgs args(flinger.flinger(), client, "buffer-state-layer", LAYER_FLAGS,
@@ -44,36 +37,7 @@
}
BaseLayerTest::BaseLayerTest() {
- setupScheduler();
-}
-
-void BaseLayerTest::setupScheduler() {
- auto eventThread = std::make_unique<mock::EventThread>();
- auto sfEventThread = std::make_unique<mock::EventThread>();
-
- EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
- mock::EventThread::kCallingUid,
- ResyncCallback())));
-
- EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
- mock::EventThread::kCallingUid,
- ResyncCallback())));
-
- auto vsyncController = std::make_unique<mock::VsyncController>();
- auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
-
- EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
- EXPECT_CALL(*vsyncTracker, currentPeriod())
- .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
- EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
- mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
- std::move(eventThread), std::move(sfEventThread),
- TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp,
- TestableSurfaceFlinger::kTwoDisplayModes);
+ mFlinger.setupMockScheduler();
}
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/LayerTestUtils.h b/services/surfaceflinger/tests/unittests/LayerTestUtils.h
index ab446fa..0773d90 100644
--- a/services/surfaceflinger/tests/unittests/LayerTestUtils.h
+++ b/services/surfaceflinger/tests/unittests/LayerTestUtils.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright 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.
@@ -63,8 +63,6 @@
protected:
BaseLayerTest();
- void setupScheduler();
-
TestableSurfaceFlinger mFlinger;
};
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
index 43af595..019502f 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
@@ -50,7 +50,7 @@
mFlinger.configureAndCommit();
mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this)
- .setDisplayModes(kModes, kModeId60, std::move(selectorPtr))
+ .setRefreshRateSelector(std::move(selectorPtr))
.inject();
// isVsyncPeriodSwitchSupported should return true, otherwise the SF's HWC proxy
@@ -109,8 +109,8 @@
EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
std::move(eventThread), std::move(sfEventThread),
- TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp,
- std::move(selectorPtr));
+ std::move(selectorPtr),
+ TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp);
}
TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithRefreshRequired) {
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
index 622717f..9699fc2 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
@@ -28,9 +28,7 @@
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
#include "mock/DisplayHardware/MockPowerAdvisor.h"
-#include "mock/MockEventThread.h"
#include "mock/MockTimeStats.h"
-#include "mock/MockVsyncController.h"
#include "mock/system/window/MockNativeWindow.h"
using namespace android;
@@ -53,8 +51,6 @@
public:
void SetUp() override;
- void setupScheduler();
-
protected:
TestableSurfaceFlinger mFlinger;
renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
@@ -68,7 +64,7 @@
};
void SurfaceFlingerPowerHintTest::SetUp() {
- setupScheduler();
+ mFlinger.setupMockScheduler({.displayId = DEFAULT_DISPLAY_ID});
mComposer = new Hwc2::mock::Composer();
mPowerAdvisor = new Hwc2::mock::PowerAdvisor();
mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
@@ -99,36 +95,6 @@
.inject();
}
-void SurfaceFlingerPowerHintTest::setupScheduler() {
- auto eventThread = std::make_unique<mock::EventThread>();
- auto sfEventThread = std::make_unique<mock::EventThread>();
-
- EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
- mock::EventThread::kCallingUid,
- ResyncCallback())));
-
- EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
- mock::EventThread::kCallingUid,
- ResyncCallback())));
-
- auto vsyncController = std::make_unique<mock::VsyncController>();
- auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
-
- EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
- EXPECT_CALL(*vsyncTracker, currentPeriod())
- .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
- EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
-
- mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
- std::move(eventThread), std::move(sfEventThread),
- TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp,
- TestableSurfaceFlinger::kTwoDisplayModes);
-}
-
TEST_F(SurfaceFlingerPowerHintTest, sendDurationsIncludingHwcWaitTime) {
ON_CALL(*mPowerAdvisor, usePowerHintSession()).WillByDefault(Return(true));
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_UpdateLayerMetadataSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_UpdateLayerMetadataSnapshotTest.cpp
index fed6a1a..0e5f1ea 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_UpdateLayerMetadataSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_UpdateLayerMetadataSnapshotTest.cpp
@@ -3,47 +3,17 @@
#include <gui/LayerMetadata.h>
#include "TestableSurfaceFlinger.h"
-#include "mock/MockEventThread.h"
-#include "mock/MockVsyncController.h"
namespace android {
using testing::_;
using testing::Return;
-using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
class SurfaceFlingerUpdateLayerMetadataSnapshotTest : public testing::Test {
public:
- SurfaceFlingerUpdateLayerMetadataSnapshotTest() { setupScheduler(); }
+ SurfaceFlingerUpdateLayerMetadataSnapshotTest() { mFlinger.setupMockScheduler(); }
protected:
- void setupScheduler() {
- auto eventThread = std::make_unique<mock::EventThread>();
- auto sfEventThread = std::make_unique<mock::EventThread>();
-
- EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
- mock::EventThread::kCallingUid,
- ResyncCallback())));
-
- EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
- mock::EventThread::kCallingUid,
- ResyncCallback())));
-
- auto vsyncController = std::make_unique<mock::VsyncController>();
- auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
-
- EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
- EXPECT_CALL(*vsyncTracker, currentPeriod())
- .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
- EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
- mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
- std::move(eventThread), std::move(sfEventThread));
- }
-
sp<Layer> createLayer(const char* name, LayerMetadata& inOutlayerMetadata) {
LayerCreationArgs args =
LayerCreationArgs{mFlinger.flinger(), nullptr, name, 0, inOutlayerMetadata};
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 89a661f..8703359 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -28,6 +28,7 @@
#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <compositionengine/mock/DisplaySurface.h>
#include <ftl/fake_guard.h>
+#include <ftl/match.h>
#include <gui/ScreenCaptureResults.h>
#include <ui/DynamicDisplayInfo.h>
@@ -47,14 +48,12 @@
#include "TestableScheduler.h"
#include "mock/DisplayHardware/MockComposer.h"
#include "mock/DisplayHardware/MockDisplayMode.h"
+#include "mock/MockEventThread.h"
#include "mock/MockFrameTimeline.h"
#include "mock/MockFrameTracer.h"
#include "mock/MockSchedulerCallback.h"
namespace android {
-
-class EventThread;
-
namespace renderengine {
class RenderEngine;
@@ -151,6 +150,11 @@
CreateCompositionEngineFunction mCreateCompositionEngine;
};
+struct MockSchedulerOptions {
+ PhysicalDisplayId displayId = PhysicalDisplayId::fromPort(0);
+ bool useNiceMock = false;
+};
+
} // namespace surfaceflinger::test
class TestableSurfaceFlinger {
@@ -189,38 +193,31 @@
enum class SchedulerCallbackImpl { kNoOp, kMock };
- static constexpr struct OneDisplayMode {
- } kOneDisplayMode;
+ struct DefaultDisplayMode {
+ // The ID of the injected RefreshRateSelector and its default display mode.
+ PhysicalDisplayId displayId;
+ };
- static constexpr struct TwoDisplayModes {
- } kTwoDisplayModes;
+ using RefreshRateSelectorPtr = scheduler::Scheduler::RefreshRateSelectorPtr;
- using RefreshRateSelectorPtr = std::shared_ptr<scheduler::RefreshRateSelector>;
-
- using DisplayModesVariant =
- std::variant<OneDisplayMode, TwoDisplayModes, RefreshRateSelectorPtr>;
+ using DisplayModesVariant = std::variant<DefaultDisplayMode, RefreshRateSelectorPtr>;
void setupScheduler(std::unique_ptr<scheduler::VsyncController> vsyncController,
std::unique_ptr<scheduler::VSyncTracker> vsyncTracker,
std::unique_ptr<EventThread> appEventThread,
std::unique_ptr<EventThread> sfEventThread,
+ DisplayModesVariant modesVariant,
SchedulerCallbackImpl callbackImpl = SchedulerCallbackImpl::kNoOp,
- DisplayModesVariant modesVariant = kOneDisplayMode,
bool useNiceMock = false) {
- RefreshRateSelectorPtr selectorPtr;
- if (std::holds_alternative<RefreshRateSelectorPtr>(modesVariant)) {
- selectorPtr = std::move(std::get<RefreshRateSelectorPtr>(modesVariant));
- } else {
- constexpr DisplayModeId kModeId60{0};
- DisplayModes modes = makeModes(mock::createDisplayMode(kModeId60, 60_Hz));
-
- if (std::holds_alternative<TwoDisplayModes>(modesVariant)) {
- constexpr DisplayModeId kModeId90{1};
- modes.try_emplace(kModeId90, mock::createDisplayMode(kModeId90, 90_Hz));
- }
-
- selectorPtr = std::make_shared<scheduler::RefreshRateSelector>(modes, kModeId60);
- }
+ RefreshRateSelectorPtr selectorPtr = ftl::match(
+ modesVariant,
+ [](DefaultDisplayMode arg) {
+ constexpr DisplayModeId kModeId60{0};
+ return std::make_shared<scheduler::RefreshRateSelector>(
+ makeModes(mock::createDisplayMode(arg.displayId, kModeId60, 60_Hz)),
+ kModeId60);
+ },
+ [](RefreshRateSelectorPtr selectorPtr) { return selectorPtr; });
const auto fps = selectorPtr->getActiveMode().fps;
mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(fps);
@@ -260,6 +257,37 @@
resetScheduler(mScheduler);
}
+ void setupMockScheduler(test::MockSchedulerOptions options = {}) {
+ using testing::_;
+ using testing::Return;
+
+ auto eventThread = makeMock<mock::EventThread>(options.useNiceMock);
+ auto sfEventThread = makeMock<mock::EventThread>(options.useNiceMock);
+
+ EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*eventThread, createEventConnection(_, _))
+ .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
+
+ EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+ .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
+
+ auto vsyncController = makeMock<mock::VsyncController>(options.useNiceMock);
+ auto vsyncTracker = makeMock<mock::VSyncTracker>(options.useNiceMock);
+
+ EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+ EXPECT_CALL(*vsyncTracker, currentPeriod())
+ .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
+ EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+ setupScheduler(std::move(vsyncController), std::move(vsyncTracker), std::move(eventThread),
+ std::move(sfEventThread), DefaultDisplayMode{options.displayId},
+ SchedulerCallbackImpl::kNoOp, options.useNiceMock);
+ }
+
void resetScheduler(scheduler::Scheduler* scheduler) { mFlinger->mScheduler.reset(scheduler); }
scheduler::TestableScheduler& mutableScheduler() { return *mScheduler; }
@@ -773,16 +801,16 @@
return mFlinger.mutableDisplays().get(mDisplayToken)->get();
}
- // If `selectorPtr` is nullptr, the injector creates RefreshRateSelector from the `modes`.
- // Otherwise, it uses `selectorPtr`, which the caller must create using the same `modes`.
- //
- // TODO(b/182939859): Once `modes` can be retrieved from RefreshRateSelector, remove
- // the `selectorPtr` parameter in favor of an alternative setRefreshRateSelector API.
- auto& setDisplayModes(
- DisplayModes modes, DisplayModeId activeModeId,
- std::shared_ptr<scheduler::RefreshRateSelector> selectorPtr = nullptr) {
+ auto& setDisplayModes(DisplayModes modes, DisplayModeId activeModeId) {
mDisplayModes = std::move(modes);
mCreationArgs.activeModeId = activeModeId;
+ mCreationArgs.refreshRateSelector = nullptr;
+ return *this;
+ }
+
+ auto& setRefreshRateSelector(RefreshRateSelectorPtr selectorPtr) {
+ mDisplayModes = selectorPtr->displayModes();
+ mCreationArgs.activeModeId = selectorPtr->getActiveMode().modePtr->getId();
mCreationArgs.refreshRateSelector = std::move(selectorPtr);
return *this;
}
@@ -911,6 +939,11 @@
};
private:
+ template <typename T>
+ static std::unique_ptr<T> makeMock(bool useNiceMock) {
+ return useNiceMock ? std::make_unique<testing::NiceMock<T>>() : std::make_unique<T>();
+ }
+
static constexpr VsyncId kVsyncId{123};
surfaceflinger::test::Factory mFactory;
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 859f702..c78148f 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -33,15 +33,12 @@
#include "FrontEnd/TransactionHandler.h"
#include "TestableSurfaceFlinger.h"
#include "TransactionState.h"
-#include "mock/MockEventThread.h"
-#include "mock/MockVsyncController.h"
namespace android {
using testing::_;
using testing::Return;
-using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
using frontend::TransactionHandler;
constexpr nsecs_t TRANSACTION_TIMEOUT = s2ns(5);
@@ -52,7 +49,9 @@
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
- setupScheduler();
+ mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
+ mFlinger.setupMockScheduler();
+ mFlinger.flinger()->addTransactionReadyFilters();
}
~TransactionApplicationTest() {
@@ -61,38 +60,8 @@
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
}
- void setupScheduler() {
- auto eventThread = std::make_unique<mock::EventThread>();
- auto sfEventThread = std::make_unique<mock::EventThread>();
-
- EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
- mock::EventThread::kCallingUid,
- ResyncCallback())));
-
- EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
- mock::EventThread::kCallingUid,
- ResyncCallback())));
-
- EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
- EXPECT_CALL(*mVSyncTracker, currentPeriod())
- .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
-
- mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
- mFlinger.setupScheduler(std::unique_ptr<mock::VsyncController>(mVsyncController),
- std::unique_ptr<mock::VSyncTracker>(mVSyncTracker),
- std::move(eventThread), std::move(sfEventThread));
- mFlinger.flinger()->addTransactionReadyFilters();
- }
-
TestableSurfaceFlinger mFlinger;
- mock::VsyncController* mVsyncController = new mock::VsyncController();
- mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker();
-
struct TransactionInfo {
Vector<ComposerState> states;
Vector<DisplayState> displays;
diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
index 1173d1c..764d19b 100644
--- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
@@ -28,15 +28,13 @@
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
-#include "mock/MockEventThread.h"
-#include "mock/MockVsyncController.h"
namespace android {
using testing::_;
using testing::Mock;
using testing::Return;
-using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+
using PresentState = frametimeline::SurfaceFrame::PresentState;
class TransactionFrameTracerTest : public testing::Test {
@@ -45,7 +43,7 @@
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
- setupScheduler();
+ mFlinger.setupMockScheduler();
mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
}
@@ -68,33 +66,6 @@
layer->commitTransaction(c);
}
- void setupScheduler() {
- auto eventThread = std::make_unique<mock::EventThread>();
- auto sfEventThread = std::make_unique<mock::EventThread>();
-
- EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
- mock::EventThread::kCallingUid,
- ResyncCallback())));
-
- EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
- mock::EventThread::kCallingUid,
- ResyncCallback())));
-
- auto vsyncController = std::make_unique<mock::VsyncController>();
- auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
-
- EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
- EXPECT_CALL(*vsyncTracker, currentPeriod())
- .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
- EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
- mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
- std::move(eventThread), std::move(sfEventThread));
- }
-
TestableSurfaceFlinger mFlinger;
renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
index ae03db4..e2c6491 100644
--- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
@@ -28,15 +28,13 @@
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
-#include "mock/MockEventThread.h"
-#include "mock/MockVsyncController.h"
namespace android {
using testing::_;
using testing::Mock;
using testing::Return;
-using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+
using PresentState = frametimeline::SurfaceFrame::PresentState;
class TransactionSurfaceFrameTest : public testing::Test {
@@ -45,7 +43,7 @@
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
- setupScheduler();
+ mFlinger.setupMockScheduler();
mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
}
@@ -67,33 +65,6 @@
layer->commitTransaction(c);
}
- void setupScheduler() {
- auto eventThread = std::make_unique<mock::EventThread>();
- auto sfEventThread = std::make_unique<mock::EventThread>();
-
- EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
- mock::EventThread::kCallingUid,
- ResyncCallback())));
-
- EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
- mock::EventThread::kCallingUid,
- ResyncCallback())));
-
- auto vsyncController = std::make_unique<mock::VsyncController>();
- auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
-
- EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
- EXPECT_CALL(*vsyncTracker, currentPeriod())
- .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
- EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
- mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
- std::move(eventThread), std::move(sfEventThread));
- }
-
TestableSurfaceFlinger mFlinger;
renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
diff --git a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp
index da87f1d..108151e 100644
--- a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp
@@ -25,7 +25,6 @@
#include "TestableSurfaceFlinger.h"
#include "TunnelModeEnabledReporter.h"
#include "mock/DisplayHardware/MockComposer.h"
-#include "mock/MockEventThread.h"
namespace android {
@@ -36,8 +35,6 @@
using android::Hwc2::IComposer;
using android::Hwc2::IComposerClient;
-using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
-
constexpr int DEFAULT_SIDEBAND_STREAM = 51;
struct TestableTunnelModeEnabledListener : public gui::BnTunnelModeEnabledListener {
@@ -61,8 +58,6 @@
static constexpr uint32_t HEIGHT = 100;
static constexpr uint32_t LAYER_FLAGS = 0;
- void setupScheduler();
- void setupComposer(uint32_t virtualDisplayCount);
sp<Layer> createBufferStateLayer(LayerMetadata metadata);
TestableSurfaceFlinger mFlinger;
@@ -80,7 +75,7 @@
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
- setupScheduler();
+ mFlinger.setupMockScheduler();
mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
mFlinger.flinger()->mTunnelModeEnabledReporter = mTunnelModeEnabledReporter;
mTunnelModeEnabledReporter->dispatchTunnelModeEnabled(false);
@@ -100,33 +95,6 @@
return sp<Layer>::make(args);
}
-void TunnelModeEnabledReporterTest::setupScheduler() {
- auto eventThread = std::make_unique<mock::EventThread>();
- auto sfEventThread = std::make_unique<mock::EventThread>();
-
- EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
- mock::EventThread::kCallingUid,
- ResyncCallback())));
-
- EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
- mock::EventThread::kCallingUid,
- ResyncCallback())));
-
- auto vsyncController = std::make_unique<mock::VsyncController>();
- auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
-
- EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
- EXPECT_CALL(*vsyncTracker, currentPeriod())
- .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
- EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
- mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
- std::move(eventThread), std::move(sfEventThread));
-}
-
namespace {
TEST_F(TunnelModeEnabledReporterTest, callsAddedListeners) {