Merge "Revert "InputDispatcher: Blame the window from the focus request for ANR""
diff --git a/cmds/dumpstate/TEST_MAPPING b/cmds/dumpstate/TEST_MAPPING
index 839a2c3..649a13e 100644
--- a/cmds/dumpstate/TEST_MAPPING
+++ b/cmds/dumpstate/TEST_MAPPING
@@ -9,15 +9,15 @@
]
},
{
- "name": "dumpstate_smoke_test"
- },
- {
"name": "dumpstate_test"
}
],
"postsubmit": [
{
"name": "BugreportManagerTestCases"
+ },
+ {
+ "name": "dumpstate_smoke_test"
}
],
"imports": [
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 2c8adc7..a278a48 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -99,6 +99,8 @@
static constexpr const char* kDataMirrorCePath = "/data_mirror/data_ce";
static constexpr const char* kDataMirrorDePath = "/data_mirror/data_de";
+static constexpr const char* kMiscMirrorCePath = "/data_mirror/misc_ce";
+static constexpr const char* kMiscMirrorDePath = "/data_mirror/misc_de";
static constexpr const int MIN_RESTRICTED_HOME_SDK_VERSION = 24; // > M
@@ -3579,16 +3581,28 @@
std::string mirrorVolCePath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_));
if (fs_prepare_dir(mirrorVolCePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
- return error("Failed to create CE mirror");
+ return error("Failed to create CE data mirror");
}
std::string mirrorVolDePath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_));
if (fs_prepare_dir(mirrorVolDePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
- return error("Failed to create DE mirror");
+ return error("Failed to create DE data mirror");
+ }
+
+ std::string mirrorVolMiscCePath(StringPrintf("%s/%s", kMiscMirrorCePath, uuid_));
+ if (fs_prepare_dir(mirrorVolMiscCePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
+ return error("Failed to create CE misc mirror");
+ }
+
+ std::string mirrorVolMiscDePath(StringPrintf("%s/%s", kMiscMirrorDePath, uuid_));
+ if (fs_prepare_dir(mirrorVolMiscDePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
+ return error("Failed to create DE misc mirror");
}
auto cePath = StringPrintf("%s/user", create_data_path(uuid_).c_str());
auto dePath = StringPrintf("%s/user_de", create_data_path(uuid_).c_str());
+ auto miscCePath = StringPrintf("%s/misc_ce", create_data_path(uuid_).c_str());
+ auto miscDePath = StringPrintf("%s/misc_de", create_data_path(uuid_).c_str());
if (access(cePath.c_str(), F_OK) != 0) {
return error("Cannot access CE path: " + cePath);
@@ -3596,6 +3610,12 @@
if (access(dePath.c_str(), F_OK) != 0) {
return error("Cannot access DE path: " + dePath);
}
+ if (access(miscCePath.c_str(), F_OK) != 0) {
+ return error("Cannot access misc CE path: " + cePath);
+ }
+ if (access(miscDePath.c_str(), F_OK) != 0) {
+ return error("Cannot access misc DE path: " + dePath);
+ }
struct stat ceStat, mirrorCeStat;
if (stat(cePath.c_str(), &ceStat) != 0) {
@@ -3623,6 +3643,21 @@
MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC, nullptr)) == -1) {
return error("Failed to mount " + mirrorVolDePath);
}
+
+ // Mount misc CE mirror
+ if (TEMP_FAILURE_RETRY(mount(miscCePath.c_str(), mirrorVolMiscCePath.c_str(), NULL,
+ MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC,
+ nullptr)) == -1) {
+ return error("Failed to mount " + mirrorVolMiscCePath);
+ }
+
+ // Mount misc DE mirror
+ if (TEMP_FAILURE_RETRY(mount(miscDePath.c_str(), mirrorVolMiscDePath.c_str(), NULL,
+ MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC,
+ nullptr)) == -1) {
+ return error("Failed to mount " + mirrorVolMiscDePath);
+ }
+
return ok();
}
@@ -3645,6 +3680,8 @@
std::string mirrorCeVolPath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_));
std::string mirrorDeVolPath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_));
+ std::string mirrorMiscCeVolPath(StringPrintf("%s/%s", kMiscMirrorCePath, uuid_));
+ std::string mirrorMiscDeVolPath(StringPrintf("%s/%s", kMiscMirrorDePath, uuid_));
std::lock_guard<std::recursive_mutex> lock(mMountsLock);
@@ -3669,6 +3706,29 @@
if (delete_dir_contents_and_dir(mirrorDeVolPath, true) != 0) {
res = error("Failed to delete " + mirrorDeVolPath);
}
+
+ // Unmount misc CE storage
+ if (TEMP_FAILURE_RETRY(umount(mirrorMiscCeVolPath.c_str())) != 0) {
+ if (errno != ENOENT) {
+ res = error(StringPrintf("Failed to umount %s %s", mirrorMiscCeVolPath.c_str(),
+ strerror(errno)));
+ }
+ }
+ if (delete_dir_contents_and_dir(mirrorMiscCeVolPath, true) != 0) {
+ res = error("Failed to delete " + mirrorMiscCeVolPath);
+ }
+
+ // Unmount misc DE storage
+ if (TEMP_FAILURE_RETRY(umount(mirrorMiscDeVolPath.c_str())) != 0) {
+ if (errno != ENOENT) {
+ res = error(StringPrintf("Failed to umount %s %s", mirrorMiscDeVolPath.c_str(),
+ strerror(errno)));
+ }
+ }
+ if (delete_dir_contents_and_dir(mirrorMiscDeVolPath, true) != 0) {
+ res = error("Failed to delete " + mirrorMiscDeVolPath);
+ }
+
return res;
}
diff --git a/include/android/keycodes.h b/include/android/keycodes.h
index 214559d..16a13d6 100644
--- a/include/android/keycodes.h
+++ b/include/android/keycodes.h
@@ -776,7 +776,48 @@
AKEYCODE_THUMBS_DOWN = 287,
/** Used to switch current account that is consuming content.
* May be consumed by system to switch current viewer profile. */
- AKEYCODE_PROFILE_SWITCH = 288
+ AKEYCODE_PROFILE_SWITCH = 288,
+ /** Video Application key #1. */
+ AKEYCODE_VIDEO_APP_1 = 289,
+ /** Video Application key #2. */
+ AKEYCODE_VIDEO_APP_2 = 290,
+ /** Video Application key #3. */
+ AKEYCODE_VIDEO_APP_3 = 291,
+ /** Video Application key #4. */
+ AKEYCODE_VIDEO_APP_4 = 292,
+ /** Video Application key #5. */
+ AKEYCODE_VIDEO_APP_5 = 293,
+ /** Video Application key #6. */
+ AKEYCODE_VIDEO_APP_6 = 294,
+ /** Video Application key #7. */
+ AKEYCODE_VIDEO_APP_7 = 295,
+ /** Video Application key #8. */
+ AKEYCODE_VIDEO_APP_8 = 296,
+ /** Featured Application key #1. */
+ AKEYCODE_FEATURED_APP_1 = 297,
+ /** Featured Application key #2. */
+ AKEYCODE_FEATURED_APP_2 = 298,
+ /** Featured Application key #3. */
+ AKEYCODE_FEATURED_APP_3 = 299,
+ /** Featured Application key #4. */
+ AKEYCODE_FEATURED_APP_4 = 300,
+ /** Demo Application key #1. */
+ AKEYCODE_DEMO_APP_1 = 301,
+ /** Demo Application key #2. */
+ AKEYCODE_DEMO_APP_2 = 302,
+ /** Demo Application key #3. */
+ AKEYCODE_DEMO_APP_3 = 303,
+ /** Demo Application key #4. */
+ AKEYCODE_DEMO_APP_4 = 304,
+ /** Keyboard backlight Down key.
+ * Adjusts the keyboard backlight brightness down. */
+ AKEYCODE_KEYBOARD_BACKLIGHT_DOWN = 305,
+ /** Keyboard backlight Up key.
+ * Adjusts the keyboard backlight brightness up. */
+ AKEYCODE_KEYBOARD_BACKLIGHT_UP = 306,
+ /** Keyboard backlight Toggle key.
+ * Toggles the keyboard backlight on/off. */
+ AKEYCODE_KEYBOARD_BACKLIGHT_TOGGLE = 307,
// NOTE: If you add a new keycode here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
diff --git a/include/ftl/algorithm.h b/include/ftl/algorithm.h
new file mode 100644
index 0000000..c5ff03b
--- /dev/null
+++ b/include/ftl/algorithm.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <functional>
+#include <utility>
+
+#include <ftl/optional.h>
+
+namespace android::ftl {
+
+// Adapter for std::find_if that converts the return value from iterator to optional.
+//
+// const ftl::StaticVector vector = {"upside"sv, "down"sv, "cake"sv};
+// assert(ftl::find_if(vector, [](const auto& str) { return str.front() == 'c'; }) == "cake"sv);
+//
+template <typename Container, typename Predicate, typename V = typename Container::value_type>
+constexpr auto find_if(const Container& container, Predicate&& predicate)
+ -> Optional<std::reference_wrapper<const V>> {
+ const auto it = std::find_if(std::cbegin(container), std::cend(container),
+ std::forward<Predicate>(predicate));
+ if (it == std::cend(container)) return {};
+ return std::cref(*it);
+}
+
+// Transformers for ftl::find_if on a map-like `Container` that contains key-value pairs.
+//
+// const ftl::SmallMap map = ftl::init::map<int, ftl::StaticVector<std::string_view, 3>>(
+// 12, "snow"sv, "cone"sv)(13, "tiramisu"sv)(14, "upside"sv, "down"sv, "cake"sv);
+//
+// using Map = decltype(map);
+//
+// assert(14 == ftl::find_if(map, [](const auto& pair) {
+// return pair.second.size() == 3;
+// }).transform(ftl::to_key<Map>));
+//
+// const auto opt = ftl::find_if(map, [](const auto& pair) {
+// return pair.second.size() == 1;
+// }).transform(ftl::to_mapped_ref<Map>);
+//
+// assert(opt);
+// assert(opt->get() == ftl::StaticVector("tiramisu"sv));
+//
+template <typename Map, typename Pair = typename Map::value_type,
+ typename Key = typename Map::key_type>
+constexpr auto to_key(const Pair& pair) -> Key {
+ return pair.first;
+}
+
+template <typename Map, typename Pair = typename Map::value_type,
+ typename Mapped = typename Map::mapped_type>
+constexpr auto to_mapped_ref(const Pair& pair) -> std::reference_wrapper<const Mapped> {
+ return std::cref(pair.second);
+}
+
+} // namespace android::ftl
diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h
index 9148fee..98a18c9 100644
--- a/include/input/DisplayViewport.h
+++ b/include/input/DisplayViewport.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBINPUT_DISPLAY_VIEWPORT_H
-#define _LIBINPUT_DISPLAY_VIEWPORT_H
+#pragma once
#include <android-base/stringprintf.h>
#include <ftl/enum.h>
@@ -144,5 +143,3 @@
};
} // namespace android
-
-#endif // _LIBINPUT_DISPLAY_VIEWPORT_H
diff --git a/include/input/Input.h b/include/input/Input.h
index a3c9f33..2dd651e 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBINPUT_INPUT_H
-#define _LIBINPUT_INPUT_H
+#pragma once
#pragma GCC system_header
@@ -1104,5 +1103,3 @@
};
} // namespace android
-
-#endif // _LIBINPUT_INPUT_H
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index d51d6a7..415080d 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBINPUT_INPUT_DEVICE_H
-#define _LIBINPUT_INPUT_DEVICE_H
+#pragma once
#include <android/sensor.h>
#include <input/Input.h>
@@ -341,5 +340,3 @@
};
} // namespace android
-
-#endif // _LIBINPUT_INPUT_DEVICE_H
diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h
index 2a742f9..b4374ac 100644
--- a/include/input/InputEventLabels.h
+++ b/include/input/InputEventLabels.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBINPUT_INPUT_EVENT_LABELS_H
-#define _LIBINPUT_INPUT_EVENT_LABELS_H
+#pragma once
#include <input/Input.h>
#include <android/keycodes.h>
@@ -68,4 +67,3 @@
};
} // namespace android
-#endif // _LIBINPUT_INPUT_EVENT_LABELS_H
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index dbc7bfa..1c52792 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBINPUT_INPUT_TRANSPORT_H
-#define _LIBINPUT_INPUT_TRANSPORT_H
+#pragma once
#pragma GCC system_header
@@ -674,5 +673,3 @@
};
} // namespace android
-
-#endif // _LIBINPUT_INPUT_TRANSPORT_H
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index 1c9a5ea..dc928b8 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBINPUT_KEY_CHARACTER_MAP_H
-#define _LIBINPUT_KEY_CHARACTER_MAP_H
+#pragma once
#include <stdint.h>
#include <list>
@@ -270,5 +269,3 @@
};
} // namespace android
-
-#endif // _LIBINPUT_KEY_CHARACTER_MAP_H
diff --git a/include/input/KeyLayoutMap.h b/include/input/KeyLayoutMap.h
index a6c696d..e203d19 100644
--- a/include/input/KeyLayoutMap.h
+++ b/include/input/KeyLayoutMap.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBINPUT_KEY_LAYOUT_MAP_H
-#define _LIBINPUT_KEY_LAYOUT_MAP_H
+#pragma once
#include <android-base/result.h>
#include <stdint.h>
@@ -131,5 +130,3 @@
};
} // namespace android
-
-#endif // _LIBINPUT_KEY_LAYOUT_MAP_H
diff --git a/include/input/Keyboard.h b/include/input/Keyboard.h
index 9a3e15f..f7f960f 100644
--- a/include/input/Keyboard.h
+++ b/include/input/Keyboard.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBINPUT_KEYBOARD_H
-#define _LIBINPUT_KEYBOARD_H
+#pragma once
#include <input/Input.h>
#include <input/InputDevice.h>
@@ -88,5 +87,3 @@
extern bool isMetaKey(int32_t keyCode);
} // namespace android
-
-#endif // _LIBINPUT_KEYBOARD_H
diff --git a/include/input/PrintTools.h b/include/input/PrintTools.h
index 0a75278..55f730b 100644
--- a/include/input/PrintTools.h
+++ b/include/input/PrintTools.h
@@ -17,6 +17,7 @@
#pragma once
#include <map>
+#include <optional>
#include <set>
#include <string>
@@ -28,6 +29,15 @@
}
/**
+ * Convert an optional type to string.
+ */
+template <typename T>
+std::string toString(const std::optional<T>& optional,
+ std::string (*toString)(const T&) = constToString) {
+ return optional ? toString(*optional) : "<not set>";
+}
+
+/**
* Convert a set of integral types to string.
*/
template <typename T>
diff --git a/include/input/PropertyMap.h b/include/input/PropertyMap.h
index b1e3f85..28e4816 100644
--- a/include/input/PropertyMap.h
+++ b/include/input/PropertyMap.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UTILS_PROPERTY_MAP_H
-#define _UTILS_PROPERTY_MAP_H
+#pragma once
#include <android-base/result.h>
#include <utils/Tokenizer.h>
@@ -98,5 +97,3 @@
};
} // namespace android
-
-#endif // _UTILS_PROPERTY_MAP_H
diff --git a/include/input/TouchVideoFrame.h b/include/input/TouchVideoFrame.h
index eda628e..a616a95 100644
--- a/include/input/TouchVideoFrame.h
+++ b/include/input/TouchVideoFrame.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBINPUT_TOUCHVIDEOFRAME_H
-#define _LIBINPUT_TOUCHVIDEOFRAME_H
+#pragma once
#include <stdint.h>
#include <sys/time.h>
@@ -75,5 +74,3 @@
};
} // namespace android
-
-#endif // _LIBINPUT_TOUCHVIDEOFRAME_H
diff --git a/include/input/VelocityControl.h b/include/input/VelocityControl.h
index 1acc2ae..f72a1bd 100644
--- a/include/input/VelocityControl.h
+++ b/include/input/VelocityControl.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBINPUT_VELOCITY_CONTROL_H
-#define _LIBINPUT_VELOCITY_CONTROL_H
+#pragma once
#include <input/Input.h>
#include <input/VelocityTracker.h>
@@ -98,10 +97,8 @@
VelocityControlParameters mParameters;
nsecs_t mLastMovementTime;
- VelocityTracker::Position mRawPosition;
+ float mRawPositionX, mRawPositionY;
VelocityTracker mVelocityTracker;
};
} // namespace android
-
-#endif // _LIBINPUT_VELOCITY_CONTROL_H
diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h
index 886f1f7..6144f5b 100644
--- a/include/input/VelocityTracker.h
+++ b/include/input/VelocityTracker.h
@@ -14,12 +14,13 @@
* limitations under the License.
*/
-#ifndef _LIBINPUT_VELOCITY_TRACKER_H
-#define _LIBINPUT_VELOCITY_TRACKER_H
+#pragma once
#include <input/Input.h>
#include <utils/BitSet.h>
#include <utils/Timers.h>
+#include <map>
+#include <set>
namespace android {
@@ -46,18 +47,14 @@
MAX = LEGACY,
};
- struct Position {
- float x, y;
- };
-
struct Estimator {
static const size_t MAX_DEGREE = 4;
// Estimator time base.
nsecs_t time;
- // Polynomial coefficients describing motion in X and Y.
- float xCoeff[MAX_DEGREE + 1], yCoeff[MAX_DEGREE + 1];
+ // Polynomial coefficients describing motion.
+ float coeff[MAX_DEGREE + 1];
// Polynomial degree (number of coefficients), or zero if no information is
// available.
@@ -71,14 +68,40 @@
degree = 0;
confidence = 0;
for (size_t i = 0; i <= MAX_DEGREE; i++) {
- xCoeff[i] = 0;
- yCoeff[i] = 0;
+ coeff[i] = 0;
}
}
};
- // Creates a velocity tracker using the specified strategy.
+ /*
+ * Contains all available velocity data from a VelocityTracker.
+ */
+ struct ComputedVelocity {
+ inline std::optional<float> getVelocity(int32_t axis, uint32_t id) const {
+ const auto& axisVelocities = mVelocities.find(axis);
+ if (axisVelocities == mVelocities.end()) {
+ return {};
+ }
+
+ const auto& axisIdVelocity = axisVelocities->second.find(id);
+ if (axisIdVelocity == axisVelocities->second.end()) {
+ return {};
+ }
+
+ return axisIdVelocity->second;
+ }
+
+ inline void addVelocity(int32_t axis, uint32_t id, float velocity) {
+ mVelocities[axis][id] = velocity;
+ }
+
+ private:
+ std::map<int32_t /*axis*/, std::map<int32_t /*pointerId*/, float /*velocity*/>> mVelocities;
+ };
+
+ // Creates a velocity tracker using the specified strategy for each supported axis.
// If strategy is not provided, uses the default strategy for the platform.
+ // TODO(b/32830165): support axis-specific strategies.
VelocityTracker(const Strategy strategy = Strategy::DEFAULT);
~VelocityTracker();
@@ -92,45 +115,56 @@
void clearPointers(BitSet32 idBits);
// Adds movement information for a set of pointers.
- // The idBits bitfield specifies the pointer ids of the pointers whose positions
+ // The idBits bitfield specifies the pointer ids of the pointers whose data points
// are included in the movement.
- // The positions array contains position information for each pointer in order by
- // increasing id. Its size should be equal to the number of one bits in idBits.
- void addMovement(nsecs_t eventTime, BitSet32 idBits, const std::vector<Position>& positions);
+ // The positions map contains a mapping of an axis to positions array.
+ // The positions arrays contain information for each pointer in order by increasing id.
+ // Each array's size should be equal to the number of one bits in idBits.
+ void addMovement(nsecs_t eventTime, BitSet32 idBits,
+ const std::map<int32_t, std::vector<float>>& positions);
// Adds movement information for all pointers in a MotionEvent, including historical samples.
void addMovement(const MotionEvent* event);
- // Gets the velocity of the specified pointer id in position units per second.
- // Returns false and sets the velocity components to zero if there is
- // insufficient movement information for the pointer.
- bool getVelocity(uint32_t id, float* outVx, float* outVy) const;
+ // Returns the velocity of the specified pointer id and axis in position units per second.
+ // Returns empty optional if there is insufficient movement information for the pointer, or if
+ // the given axis is not supported for velocity tracking.
+ std::optional<float> getVelocity(int32_t axis, uint32_t id) const;
- // Gets an estimator for the recent movements of the specified pointer id.
+ // Returns a ComputedVelocity instance with all available velocity data, using the given units
+ // (reference: units == 1 means "per millisecond"), and clamping each velocity between
+ // [-maxVelocity, maxVelocity], inclusive.
+ ComputedVelocity getComputedVelocity(int32_t units, float maxVelocity);
+
+ // Gets an estimator for the recent movements of the specified pointer id for the given axis.
// Returns false and clears the estimator if there is no information available
// about the pointer.
- bool getEstimator(uint32_t id, Estimator* outEstimator) const;
+ bool getEstimator(int32_t axis, uint32_t id, Estimator* outEstimator) const;
// Gets the active pointer id, or -1 if none.
inline int32_t getActivePointerId() const { return mActivePointerId; }
- // Gets a bitset containing all pointer ids from the most recent movement.
- inline BitSet32 getCurrentPointerIdBits() const { return mCurrentPointerIdBits; }
-
private:
// The default velocity tracker strategy.
// Although other strategies are available for testing and comparison purposes,
// this is the strategy that applications will actually use. Be very careful
// when adjusting the default strategy because it can dramatically affect
// (often in a bad way) the user experience.
+ // TODO(b/32830165): define default strategy per axis.
static const Strategy DEFAULT_STRATEGY = Strategy::LSQ2;
+ // Set of all axes supported for velocity tracking.
+ static const std::set<int32_t> SUPPORTED_AXES;
+
+ // Axes specifying location on a 2D plane (i.e. X and Y).
+ static const std::set<int32_t> PLANAR_AXES;
+
nsecs_t mLastEventTime;
BitSet32 mCurrentPointerIdBits;
int32_t mActivePointerId;
- std::unique_ptr<VelocityTrackerStrategy> mStrategy;
+ std::map<int32_t /*axis*/, std::unique_ptr<VelocityTrackerStrategy>> mStrategies;
- bool configureStrategy(const Strategy strategy);
+ void configureStrategy(int32_t axis, const Strategy strategy);
static std::unique_ptr<VelocityTrackerStrategy> createStrategy(const Strategy strategy);
};
@@ -149,7 +183,7 @@
virtual void clear() = 0;
virtual void clearPointers(BitSet32 idBits) = 0;
virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::vector<VelocityTracker::Position>& positions) = 0;
+ const std::vector<float>& positions) = 0;
virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const = 0;
};
@@ -181,7 +215,7 @@
virtual void clear();
virtual void clearPointers(BitSet32 idBits);
void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::vector<VelocityTracker::Position>& positions) override;
+ const std::vector<float>& positions) override;
virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
private:
@@ -196,11 +230,9 @@
struct Movement {
nsecs_t eventTime;
BitSet32 idBits;
- VelocityTracker::Position positions[MAX_POINTERS];
+ float positions[MAX_POINTERS];
- inline const VelocityTracker::Position& getPosition(uint32_t id) const {
- return positions[idBits.getIndexOfBit(id)];
- }
+ inline float getPosition(uint32_t id) const { return positions[idBits.getIndexOfBit(id)]; }
};
float chooseWeight(uint32_t index) const;
@@ -224,7 +256,7 @@
virtual void clear();
virtual void clearPointers(BitSet32 idBits);
void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::vector<VelocityTracker::Position>& positions) override;
+ const std::vector<float>& positions) override;
virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
private:
@@ -233,16 +265,15 @@
nsecs_t updateTime;
uint32_t degree;
- float xpos, xvel, xaccel;
- float ypos, yvel, yaccel;
+ float pos, vel, accel;
};
const uint32_t mDegree;
BitSet32 mPointerIdBits;
State mPointerState[MAX_POINTER_ID + 1];
- void initState(State& state, nsecs_t eventTime, float xpos, float ypos) const;
- void updateState(State& state, nsecs_t eventTime, float xpos, float ypos) const;
+ void initState(State& state, nsecs_t eventTime, float pos) const;
+ void updateState(State& state, nsecs_t eventTime, float pos) const;
void populateEstimator(const State& state, VelocityTracker::Estimator* outEstimator) const;
};
@@ -258,7 +289,7 @@
virtual void clear();
virtual void clearPointers(BitSet32 idBits);
void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::vector<VelocityTracker::Position>& positions) override;
+ const std::vector<float>& positions) override;
virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
private:
@@ -274,11 +305,9 @@
struct Movement {
nsecs_t eventTime;
BitSet32 idBits;
- VelocityTracker::Position positions[MAX_POINTERS];
+ float positions[MAX_POINTERS];
- inline const VelocityTracker::Position& getPosition(uint32_t id) const {
- return positions[idBits.getIndexOfBit(id)];
- }
+ inline float getPosition(uint32_t id) const { return positions[idBits.getIndexOfBit(id)]; }
};
uint32_t mIndex;
@@ -293,7 +322,7 @@
virtual void clear();
virtual void clearPointers(BitSet32 idBits);
void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::vector<VelocityTracker::Position>& positions) override;
+ const std::vector<float>& positions) override;
virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
private:
@@ -308,11 +337,9 @@
struct Movement {
nsecs_t eventTime;
BitSet32 idBits;
- VelocityTracker::Position positions[MAX_POINTERS];
+ float positions[MAX_POINTERS];
- inline const VelocityTracker::Position& getPosition(uint32_t id) const {
- return positions[idBits.getIndexOfBit(id)];
- }
+ inline float getPosition(uint32_t id) const { return positions[idBits.getIndexOfBit(id)]; }
};
size_t mIndex;
@@ -320,5 +347,3 @@
};
} // namespace android
-
-#endif // _LIBINPUT_VELOCITY_TRACKER_H
diff --git a/include/input/VirtualKeyMap.h b/include/input/VirtualKeyMap.h
index 6e8e2c9..a4381ea 100644
--- a/include/input/VirtualKeyMap.h
+++ b/include/input/VirtualKeyMap.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _LIBINPUT_VIRTUAL_KEY_MAP_H
-#define _LIBINPUT_VIRTUAL_KEY_MAP_H
+#pragma once
#include <stdint.h>
@@ -77,5 +76,3 @@
};
} // namespace android
-
-#endif // _LIBINPUT_KEY_CHARACTER_MAP_H
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index ac4cbdf..481d704 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -407,9 +407,12 @@
Extras* e = mExtras.load(std::memory_order_acquire);
AutoMutex lock(e->mLock);
if (mRecordingOn) {
+ Parcel emptyReply;
auto transaction =
android::binder::debug::RecordedTransaction::fromDetails(code, flags, data,
- *reply, err);
+ reply ? *reply
+ : emptyReply,
+ err);
if (transaction) {
if (status_t err = transaction->dumpToFile(e->mRecordingFd); err != NO_ERROR) {
LOG(INFO) << "Failed to dump RecordedTransaction to file with error " << err;
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index b50cfb3..bfcf39a 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -1318,6 +1318,13 @@
LOG_ONEWAY("Sending reply to %d!", mCallingPid);
if (error < NO_ERROR) reply.setError(error);
+ // b/238777741: clear buffer before we send the reply.
+ // Otherwise, there is a race where the client may
+ // receive the reply and send another transaction
+ // here and the space used by this transaction won't
+ // be freed for the client.
+ buffer.setDataSize(0);
+
constexpr uint32_t kForwardReplyFlags = TF_CLEAR_BUF;
sendReply(reply, (tr.flags & kForwardReplyFlags));
} else {
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index c0a8d74..5db3eef 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "ServiceManager"
+#define LOG_TAG "ServiceManagerCppClient"
#include <binder/IServiceManager.h>
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index e460d2c..92d132f 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -605,6 +605,7 @@
shared_libs: [
"libbinder",
"liblog",
+ "libcutils",
"libutils",
"libutilscallstack",
"libbase",
diff --git a/libs/binder/tests/binderAllocationLimits.cpp b/libs/binder/tests/binderAllocationLimits.cpp
index a2ab8ab..55a3916 100644
--- a/libs/binder/tests/binderAllocationLimits.cpp
+++ b/libs/binder/tests/binderAllocationLimits.cpp
@@ -20,6 +20,7 @@
#include <binder/Parcel.h>
#include <binder/RpcServer.h>
#include <binder/RpcSession.h>
+#include <cutils/trace.h>
#include <gtest/gtest.h>
#include <utils/CallStack.h>
@@ -223,5 +224,10 @@
return 1;
}
::testing::InitGoogleTest(&argc, argv);
+
+ // if tracing is enabled, take in one-time cost
+ (void)ATRACE_INIT();
+ (void)ATRACE_GET_ENABLED_TAGS();
+
return RUN_ALL_TESTS();
}
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 5de08bd..6e1c8ac 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -1161,8 +1161,7 @@
// see ProcessState.cpp BINDER_VM_SIZE = 1MB.
// This value is not exposed, but some code in the framework relies on being able to use
// buffers near the cap size.
-// TODO(b/238777741): why do larger values, like 300K fail sometimes
-constexpr size_t kSizeBytesAlmostFull = 100'000;
+constexpr size_t kSizeBytesAlmostFull = 950'000;
constexpr size_t kSizeBytesOverFull = 1'050'000;
TEST_F(BinderLibTest, GargantuanVectorSent) {
diff --git a/libs/fakeservicemanager/Android.bp b/libs/fakeservicemanager/Android.bp
index 47c0657..29924ff 100644
--- a/libs/fakeservicemanager/Android.bp
+++ b/libs/fakeservicemanager/Android.bp
@@ -28,6 +28,7 @@
cc_library {
name: "libfakeservicemanager",
defaults: ["fakeservicemanager_defaults"],
+ export_include_dirs: ["include/fakeservicemanager"],
}
cc_test_host {
@@ -37,4 +38,5 @@
"test_sm.cpp",
],
static_libs: ["libgmock"],
+ local_include_dirs: ["include/fakeservicemanager"],
}
diff --git a/libs/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/include/fakeservicemanager/ServiceManager.h
similarity index 100%
rename from libs/fakeservicemanager/ServiceManager.h
rename to libs/fakeservicemanager/include/fakeservicemanager/ServiceManager.h
diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp
index 8f89e7d..a25a493 100644
--- a/libs/ftl/Android.bp
+++ b/libs/ftl/Android.bp
@@ -14,6 +14,7 @@
address: true,
},
srcs: [
+ "algorithm_test.cpp",
"cast_test.cpp",
"concat_test.cpp",
"enum_test.cpp",
diff --git a/libs/ftl/algorithm_test.cpp b/libs/ftl/algorithm_test.cpp
new file mode 100644
index 0000000..8052caf
--- /dev/null
+++ b/libs/ftl/algorithm_test.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#include <ftl/algorithm.h>
+#include <ftl/small_map.h>
+#include <ftl/static_vector.h>
+#include <gtest/gtest.h>
+
+#include <string_view>
+
+namespace android::test {
+
+// Keep in sync with example usage in header file.
+TEST(Algorithm, FindIf) {
+ using namespace std::string_view_literals;
+
+ const ftl::StaticVector vector = {"upside"sv, "down"sv, "cake"sv};
+ EXPECT_EQ(ftl::find_if(vector, [](const auto& str) { return str.front() == 'c'; }), "cake"sv);
+
+ const ftl::SmallMap map = ftl::init::map<int, ftl::StaticVector<std::string_view, 3>>(
+ 12, "snow"sv, "cone"sv)(13, "tiramisu"sv)(14, "upside"sv, "down"sv, "cake"sv);
+
+ using Map = decltype(map);
+
+ EXPECT_EQ(14, ftl::find_if(map, [](const auto& pair) {
+ return pair.second.size() == 3;
+ }).transform(ftl::to_key<Map>));
+
+ const auto opt = ftl::find_if(map, [](const auto& pair) {
+ return pair.second.size() == 1;
+ }).transform(ftl::to_mapped_ref<Map>);
+
+ ASSERT_TRUE(opt);
+ EXPECT_EQ(opt->get(), ftl::StaticVector("tiramisu"sv));
+}
+
+} // namespace android::test
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 3bf2e19..3afa339 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -1083,50 +1083,6 @@
return mLastAcquiredFrameNumber;
}
-void BLASTBufferQueue::abandon() {
- std::unique_lock _lock{mMutex};
- // flush out the shadow queue
- while (mNumFrameAvailable > 0) {
- acquireAndReleaseBuffer();
- }
-
- // Clear submitted buffer states
- mNumAcquired = 0;
- mSubmitted.clear();
- mPendingRelease.clear();
-
- if (!mPendingTransactions.empty()) {
- BQA_LOGD("Applying pending transactions on abandon %d",
- static_cast<uint32_t>(mPendingTransactions.size()));
- SurfaceComposerClient::Transaction t;
- mergePendingTransactions(&t, std::numeric_limits<uint64_t>::max() /* frameNumber */);
- // All transactions on our apply token are one-way. See comment on mAppliedLastTransaction
- t.setApplyToken(mApplyToken).apply(false, true);
- }
-
- // Clear sync states
- if (!mSyncedFrameNumbers.empty()) {
- BQA_LOGD("mSyncedFrameNumbers cleared");
- mSyncedFrameNumbers.clear();
- }
-
- if (mSyncTransaction != nullptr) {
- BQA_LOGD("mSyncTransaction cleared mAcquireSingleBuffer=%s",
- mAcquireSingleBuffer ? "true" : "false");
- mSyncTransaction = nullptr;
- mAcquireSingleBuffer = false;
- }
-
- // abandon buffer queue
- if (mBufferItemConsumer != nullptr) {
- mBufferItemConsumer->abandon();
- mBufferItemConsumer->setFrameAvailableListener(nullptr);
- }
- mBufferItemConsumer = nullptr;
- mConsumer = nullptr;
- mProducer = nullptr;
-}
-
bool BLASTBufferQueue::isSameSurfaceControl(const sp<SurfaceControl>& surfaceControl) const {
std::unique_lock _lock{mMutex};
return SurfaceControl::isSameSurface(mSurfaceControl, surfaceControl);
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 95df811..4535c98 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -108,7 +108,6 @@
uint32_t getLastTransformHint() const;
uint64_t getLastAcquiredFrameNum();
- void abandon();
/**
* Set a callback to be invoked when we are hung. The boolean parameter
diff --git a/libs/input/InputEventLabels.cpp b/libs/input/InputEventLabels.cpp
index c0aa2e2..5990ee0 100644
--- a/libs/input/InputEventLabels.cpp
+++ b/libs/input/InputEventLabels.cpp
@@ -314,7 +314,26 @@
DEFINE_KEYCODE(REFRESH), \
DEFINE_KEYCODE(THUMBS_UP), \
DEFINE_KEYCODE(THUMBS_DOWN), \
- DEFINE_KEYCODE(PROFILE_SWITCH)
+ DEFINE_KEYCODE(PROFILE_SWITCH), \
+ DEFINE_KEYCODE(VIDEO_APP_1), \
+ DEFINE_KEYCODE(VIDEO_APP_2), \
+ DEFINE_KEYCODE(VIDEO_APP_3), \
+ DEFINE_KEYCODE(VIDEO_APP_4), \
+ DEFINE_KEYCODE(VIDEO_APP_5), \
+ DEFINE_KEYCODE(VIDEO_APP_6), \
+ DEFINE_KEYCODE(VIDEO_APP_7), \
+ DEFINE_KEYCODE(VIDEO_APP_8), \
+ DEFINE_KEYCODE(FEATURED_APP_1), \
+ DEFINE_KEYCODE(FEATURED_APP_2), \
+ DEFINE_KEYCODE(FEATURED_APP_3), \
+ DEFINE_KEYCODE(FEATURED_APP_4), \
+ DEFINE_KEYCODE(DEMO_APP_1), \
+ DEFINE_KEYCODE(DEMO_APP_2), \
+ DEFINE_KEYCODE(DEMO_APP_3), \
+ DEFINE_KEYCODE(DEMO_APP_4), \
+ DEFINE_KEYCODE(KEYBOARD_BACKLIGHT_DOWN), \
+ DEFINE_KEYCODE(KEYBOARD_BACKLIGHT_UP), \
+ DEFINE_KEYCODE(KEYBOARD_BACKLIGHT_TOGGLE)
// NOTE: If you add a new axis here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list.
diff --git a/libs/input/PropertyMap.cpp b/libs/input/PropertyMap.cpp
index 662e568..16ffa10 100644
--- a/libs/input/PropertyMap.cpp
+++ b/libs/input/PropertyMap.cpp
@@ -75,7 +75,7 @@
}
char* end;
- int value = strtol(stringValue.c_str(), &end, 10);
+ int32_t value = static_cast<int32_t>(strtol(stringValue.c_str(), &end, 10));
if (*end != '\0') {
ALOGW("Property key '%s' has invalid value '%s'. Expected an integer.", key.c_str(),
stringValue.c_str());
diff --git a/libs/input/VelocityControl.cpp b/libs/input/VelocityControl.cpp
index 6e991e9..e2bfb50 100644
--- a/libs/input/VelocityControl.cpp
+++ b/libs/input/VelocityControl.cpp
@@ -44,8 +44,8 @@
void VelocityControl::reset() {
mLastMovementTime = LLONG_MIN;
- mRawPosition.x = 0;
- mRawPosition.y = 0;
+ mRawPositionX = 0;
+ mRawPositionY = 0;
mVelocityTracker.clear();
}
@@ -61,17 +61,20 @@
mLastMovementTime = eventTime;
if (deltaX) {
- mRawPosition.x += *deltaX;
+ mRawPositionX += *deltaX;
}
if (deltaY) {
- mRawPosition.y += *deltaY;
+ mRawPositionY += *deltaY;
}
- mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)), {mRawPosition});
+ mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)),
+ {{AMOTION_EVENT_AXIS_X, {mRawPositionX}},
+ {AMOTION_EVENT_AXIS_Y, {mRawPositionY}}});
- float vx, vy;
+ std::optional<float> vx = mVelocityTracker.getVelocity(AMOTION_EVENT_AXIS_X, 0);
+ std::optional<float> vy = mVelocityTracker.getVelocity(AMOTION_EVENT_AXIS_Y, 0);
float scale = mParameters.scale;
- if (mVelocityTracker.getVelocity(0, &vx, &vy)) {
- float speed = hypotf(vx, vy) * scale;
+ if (vx && vy) {
+ float speed = hypotf(*vx, *vy) * scale;
if (speed >= mParameters.highThreshold) {
// Apply full acceleration above the high speed threshold.
scale *= mParameters.acceleration;
@@ -85,10 +88,9 @@
if (DEBUG_ACCELERATION) {
ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): "
- "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f",
- mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
- mParameters.acceleration,
- vx, vy, speed, scale / mParameters.scale);
+ "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f",
+ mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
+ mParameters.acceleration, *vx, *vy, speed, scale / mParameters.scale);
}
} else {
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index 76aaf61..6f88a38 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -125,29 +125,39 @@
// --- VelocityTracker ---
+const std::set<int32_t> VelocityTracker::SUPPORTED_AXES = {AMOTION_EVENT_AXIS_X,
+ AMOTION_EVENT_AXIS_Y};
+
+const std::set<int32_t> VelocityTracker::PLANAR_AXES = {AMOTION_EVENT_AXIS_X, AMOTION_EVENT_AXIS_Y};
+
VelocityTracker::VelocityTracker(const Strategy strategy)
: mLastEventTime(0), mCurrentPointerIdBits(0), mActivePointerId(-1) {
- // Configure the strategy.
- if (!configureStrategy(strategy)) {
- ALOGE("Unrecognized velocity tracker strategy %" PRId32 ".", strategy);
- if (!configureStrategy(VelocityTracker::DEFAULT_STRATEGY)) {
- LOG_ALWAYS_FATAL("Could not create the default velocity tracker strategy '%" PRId32
- "'!",
- strategy);
- }
+ // Configure the strategy for each axis.
+ for (int32_t axis : SUPPORTED_AXES) {
+ configureStrategy(axis, strategy);
}
}
VelocityTracker::~VelocityTracker() {
}
-bool VelocityTracker::configureStrategy(Strategy strategy) {
+void VelocityTracker::configureStrategy(int32_t axis, const Strategy strategy) {
+ std::unique_ptr<VelocityTrackerStrategy> createdStrategy;
+
if (strategy == VelocityTracker::Strategy::DEFAULT) {
- mStrategy = createStrategy(VelocityTracker::DEFAULT_STRATEGY);
+ createdStrategy = createStrategy(VelocityTracker::DEFAULT_STRATEGY);
} else {
- mStrategy = createStrategy(strategy);
+ createdStrategy = createStrategy(strategy);
}
- return mStrategy != nullptr;
+
+ if (createdStrategy == nullptr) {
+ ALOGE("Unrecognized velocity tracker strategy %" PRId32 ".", strategy);
+ createdStrategy = createStrategy(VelocityTracker::DEFAULT_STRATEGY);
+ LOG_ALWAYS_FATAL_IF(createdStrategy == nullptr,
+ "Could not create the default velocity tracker strategy '%" PRId32 "'!",
+ strategy);
+ }
+ mStrategies[axis] = std::move(createdStrategy);
}
std::unique_ptr<VelocityTrackerStrategy> VelocityTracker::createStrategy(
@@ -201,8 +211,9 @@
void VelocityTracker::clear() {
mCurrentPointerIdBits.clear();
mActivePointerId = -1;
-
- mStrategy->clear();
+ for (int32_t axis : SUPPORTED_AXES) {
+ mStrategies[axis]->clear();
+ }
}
void VelocityTracker::clearPointers(BitSet32 idBits) {
@@ -213,14 +224,13 @@
mActivePointerId = !remainingIdBits.isEmpty() ? remainingIdBits.firstMarkedBit() : -1;
}
- mStrategy->clearPointers(idBits);
+ for (int32_t axis : SUPPORTED_AXES) {
+ mStrategies[axis]->clearPointers(idBits);
+ }
}
void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::vector<VelocityTracker::Position>& positions) {
- LOG_ALWAYS_FATAL_IF(idBits.count() != positions.size(),
- "Mismatching number of pointers, idBits=%" PRIu32 ", positions=%zu",
- idBits.count(), positions.size());
+ const std::map<int32_t /*axis*/, std::vector<float>>& positions) {
while (idBits.count() > MAX_POINTERS) {
idBits.clearLastMarkedBit();
}
@@ -232,7 +242,9 @@
// We have not received any movements for too long. Assume that all pointers
// have stopped.
- mStrategy->clear();
+ for (const auto& [_, strategy] : mStrategies) {
+ strategy->clear();
+ }
}
mLastEventTime = eventTime;
@@ -241,29 +253,37 @@
mActivePointerId = idBits.isEmpty() ? -1 : idBits.firstMarkedBit();
}
- mStrategy->addMovement(eventTime, idBits, positions);
+ for (const auto& [axis, positionValues] : positions) {
+ LOG_ALWAYS_FATAL_IF(idBits.count() != positionValues.size(),
+ "Mismatching number of pointers, idBits=%" PRIu32 ", positions=%zu",
+ idBits.count(), positionValues.size());
+ mStrategies[axis]->addMovement(eventTime, idBits, positionValues);
+ }
if (DEBUG_VELOCITY) {
ALOGD("VelocityTracker: addMovement eventTime=%" PRId64
", idBits=0x%08x, activePointerId=%d",
eventTime, idBits.value, mActivePointerId);
- for (BitSet32 iterBits(idBits); !iterBits.isEmpty();) {
- uint32_t id = iterBits.firstMarkedBit();
- uint32_t index = idBits.getIndexOfBit(id);
- iterBits.clearBit(id);
- Estimator estimator;
- getEstimator(id, &estimator);
- ALOGD(" %d: position (%0.3f, %0.3f), "
- "estimator (degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f)",
- id, positions[index].x, positions[index].y, int(estimator.degree),
- vectorToString(estimator.xCoeff, estimator.degree + 1).c_str(),
- vectorToString(estimator.yCoeff, estimator.degree + 1).c_str(),
- estimator.confidence);
+ for (const auto& positionsEntry : positions) {
+ for (BitSet32 iterBits(idBits); !iterBits.isEmpty();) {
+ uint32_t id = iterBits.firstMarkedBit();
+ uint32_t index = idBits.getIndexOfBit(id);
+ iterBits.clearBit(id);
+ Estimator estimator;
+ getEstimator(positionsEntry.first, id, &estimator);
+ ALOGD(" %d: axis=%d, position=%0.3f, "
+ "estimator (degree=%d, coeff=%s, confidence=%f)",
+ id, positionsEntry.first, positionsEntry.second[index], int(estimator.degree),
+ vectorToString(estimator.coeff, estimator.degree + 1).c_str(),
+ estimator.confidence);
+ }
}
}
}
void VelocityTracker::addMovement(const MotionEvent* event) {
+ // Stores data about which axes to process based on the incoming motion event.
+ std::set<int32_t> axesToProcess;
int32_t actionMasked = event->getActionMasked();
switch (actionMasked) {
@@ -271,6 +291,9 @@
case AMOTION_EVENT_ACTION_HOVER_ENTER:
// Clear all pointers on down before adding the new movement.
clear();
+ for (int32_t axis : PLANAR_AXES) {
+ axesToProcess.insert(axis);
+ }
break;
case AMOTION_EVENT_ACTION_POINTER_DOWN: {
// Start a new movement trace for a pointer that just went down.
@@ -279,10 +302,16 @@
BitSet32 downIdBits;
downIdBits.markBit(event->getPointerId(event->getActionIndex()));
clearPointers(downIdBits);
+ for (int32_t axis : PLANAR_AXES) {
+ axesToProcess.insert(axis);
+ }
break;
}
case AMOTION_EVENT_ACTION_MOVE:
case AMOTION_EVENT_ACTION_HOVER_MOVE:
+ for (int32_t axis : PLANAR_AXES) {
+ axesToProcess.insert(axis);
+ }
break;
case AMOTION_EVENT_ACTION_POINTER_UP:
case AMOTION_EVENT_ACTION_UP: {
@@ -293,7 +322,9 @@
toString(delaySinceLastEvent).c_str());
// We have not received any movements for too long. Assume that all pointers
// have stopped.
- mStrategy->clear();
+ for (int32_t axis : PLANAR_AXES) {
+ mStrategies[axis]->clear();
+ }
}
// These actions because they do not convey any new information about
// pointer movement. We also want to preserve the last known velocity of the pointers.
@@ -325,37 +356,56 @@
pointerIndex[i] = idBits.getIndexOfBit(event->getPointerId(i));
}
- std::vector<Position> positions;
- positions.resize(pointerCount);
+ std::map<int32_t, std::vector<float>> positions;
+ for (int32_t axis : axesToProcess) {
+ positions[axis].resize(pointerCount);
+ }
size_t historySize = event->getHistorySize();
for (size_t h = 0; h <= historySize; h++) {
nsecs_t eventTime = event->getHistoricalEventTime(h);
- for (size_t i = 0; i < pointerCount; i++) {
- uint32_t index = pointerIndex[i];
- positions[index].x = event->getHistoricalX(i, h);
- positions[index].y = event->getHistoricalY(i, h);
+ for (int32_t axis : axesToProcess) {
+ for (size_t i = 0; i < pointerCount; i++) {
+ positions[axis][pointerIndex[i]] = event->getHistoricalAxisValue(axis, i, h);
+ }
}
addMovement(eventTime, idBits, positions);
}
}
-bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const {
+std::optional<float> VelocityTracker::getVelocity(int32_t axis, uint32_t id) const {
Estimator estimator;
- if (getEstimator(id, &estimator) && estimator.degree >= 1) {
- *outVx = estimator.xCoeff[1];
- *outVy = estimator.yCoeff[1];
- return true;
+ bool validVelocity = getEstimator(axis, id, &estimator) && estimator.degree >= 1;
+ if (validVelocity) {
+ return estimator.coeff[1];
}
- *outVx = 0;
- *outVy = 0;
- return false;
+ return {};
}
-bool VelocityTracker::getEstimator(uint32_t id, Estimator* outEstimator) const {
- return mStrategy->getEstimator(id, outEstimator);
+VelocityTracker::ComputedVelocity VelocityTracker::getComputedVelocity(int32_t units,
+ float maxVelocity) {
+ ComputedVelocity computedVelocity;
+ for (int32_t axis : SUPPORTED_AXES) {
+ BitSet32 copyIdBits = BitSet32(mCurrentPointerIdBits);
+ while (!copyIdBits.isEmpty()) {
+ uint32_t id = copyIdBits.clearFirstMarkedBit();
+ std::optional<float> velocity = getVelocity(axis, id);
+ if (velocity) {
+ float adjustedVelocity =
+ std::clamp(*velocity * units / 1000, -maxVelocity, maxVelocity);
+ computedVelocity.addVelocity(axis, id, adjustedVelocity);
+ }
+ }
+ }
+ return computedVelocity;
}
+bool VelocityTracker::getEstimator(int32_t axis, uint32_t id, Estimator* outEstimator) const {
+ if (SUPPORTED_AXES.find(axis) == SUPPORTED_AXES.end()) {
+ return false;
+ }
+ return mStrategies.at(axis)->getEstimator(id, outEstimator);
+}
// --- LeastSquaresVelocityTrackerStrategy ---
@@ -378,9 +428,8 @@
mMovements[mIndex].idBits = remainingIdBits;
}
-void LeastSquaresVelocityTrackerStrategy::addMovement(
- nsecs_t eventTime, BitSet32 idBits,
- const std::vector<VelocityTracker::Position>& positions) {
+void LeastSquaresVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
+ const std::vector<float>& positions) {
if (mMovements[mIndex].eventTime != eventTime) {
// When ACTION_POINTER_DOWN happens, we will first receive ACTION_MOVE with the coordinates
// of the existing pointers, and then ACTION_POINTER_DOWN with the coordinates that include
@@ -627,8 +676,7 @@
outEstimator->clear();
// Iterate over movement samples in reverse time order and collect samples.
- std::vector<float> x;
- std::vector<float> y;
+ std::vector<float> positions;
std::vector<float> w;
std::vector<float> time;
@@ -645,15 +693,13 @@
break;
}
- const VelocityTracker::Position& position = movement.getPosition(id);
- x.push_back(position.x);
- y.push_back(position.y);
+ positions.push_back(movement.getPosition(id));
w.push_back(chooseWeight(index));
time.push_back(-age * 0.000000001f);
index = (index == 0 ? HISTORY_SIZE : index) - 1;
- } while (x.size() < HISTORY_SIZE);
+ } while (positions.size() < HISTORY_SIZE);
- const size_t m = x.size();
+ const size_t m = positions.size();
if (m == 0) {
return false; // no data
}
@@ -666,39 +712,36 @@
if (degree == 2 && mWeighting == WEIGHTING_NONE) {
// Optimize unweighted, quadratic polynomial fit
- std::optional<std::array<float, 3>> xCoeff = solveUnweightedLeastSquaresDeg2(time, x);
- std::optional<std::array<float, 3>> yCoeff = solveUnweightedLeastSquaresDeg2(time, y);
- if (xCoeff && yCoeff) {
+ std::optional<std::array<float, 3>> coeff =
+ solveUnweightedLeastSquaresDeg2(time, positions);
+ if (coeff) {
outEstimator->time = newestMovement.eventTime;
outEstimator->degree = 2;
outEstimator->confidence = 1;
for (size_t i = 0; i <= outEstimator->degree; i++) {
- outEstimator->xCoeff[i] = (*xCoeff)[i];
- outEstimator->yCoeff[i] = (*yCoeff)[i];
+ outEstimator->coeff[i] = (*coeff)[i];
}
return true;
}
} else if (degree >= 1) {
// General case for an Nth degree polynomial fit
- float xdet, ydet;
+ float det;
uint32_t n = degree + 1;
- if (solveLeastSquares(time, x, w, n, outEstimator->xCoeff, &xdet) &&
- solveLeastSquares(time, y, w, n, outEstimator->yCoeff, &ydet)) {
+ if (solveLeastSquares(time, positions, w, n, outEstimator->coeff, &det)) {
outEstimator->time = newestMovement.eventTime;
outEstimator->degree = degree;
- outEstimator->confidence = xdet * ydet;
+ outEstimator->confidence = det;
- ALOGD_IF(DEBUG_STRATEGY, "estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f",
- int(outEstimator->degree), vectorToString(outEstimator->xCoeff, n).c_str(),
- vectorToString(outEstimator->yCoeff, n).c_str(), outEstimator->confidence);
+ ALOGD_IF(DEBUG_STRATEGY, "estimate: degree=%d, coeff=%s, confidence=%f",
+ int(outEstimator->degree), vectorToString(outEstimator->coeff, n).c_str(),
+ outEstimator->confidence);
return true;
}
}
// No velocity data available for this pointer, but we do have its current position.
- outEstimator->xCoeff[0] = x[0];
- outEstimator->yCoeff[0] = y[0];
+ outEstimator->coeff[0] = positions[0];
outEstimator->time = newestMovement.eventTime;
outEstimator->degree = 0;
outEstimator->confidence = 1;
@@ -790,18 +833,17 @@
mPointerIdBits.value &= ~idBits.value;
}
-void IntegratingVelocityTrackerStrategy::addMovement(
- nsecs_t eventTime, BitSet32 idBits,
- const std::vector<VelocityTracker::Position>& positions) {
+void IntegratingVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
+ const std::vector<float>& positions) {
uint32_t index = 0;
for (BitSet32 iterIdBits(idBits); !iterIdBits.isEmpty();) {
uint32_t id = iterIdBits.clearFirstMarkedBit();
State& state = mPointerState[id];
- const VelocityTracker::Position& position = positions[index++];
+ const float position = positions[index++];
if (mPointerIdBits.hasBit(id)) {
- updateState(state, eventTime, position.x, position.y);
+ updateState(state, eventTime, position);
} else {
- initState(state, eventTime, position.x, position.y);
+ initState(state, eventTime, position);
}
}
@@ -821,21 +863,18 @@
return false;
}
-void IntegratingVelocityTrackerStrategy::initState(State& state,
- nsecs_t eventTime, float xpos, float ypos) const {
+void IntegratingVelocityTrackerStrategy::initState(State& state, nsecs_t eventTime,
+ float pos) const {
state.updateTime = eventTime;
state.degree = 0;
- state.xpos = xpos;
- state.xvel = 0;
- state.xaccel = 0;
- state.ypos = ypos;
- state.yvel = 0;
- state.yaccel = 0;
+ state.pos = pos;
+ state.accel = 0;
+ state.vel = 0;
}
-void IntegratingVelocityTrackerStrategy::updateState(State& state,
- nsecs_t eventTime, float xpos, float ypos) const {
+void IntegratingVelocityTrackerStrategy::updateState(State& state, nsecs_t eventTime,
+ float pos) const {
const nsecs_t MIN_TIME_DELTA = 2 * NANOS_PER_MS;
const float FILTER_TIME_CONSTANT = 0.010f; // 10 milliseconds
@@ -846,34 +885,26 @@
float dt = (eventTime - state.updateTime) * 0.000000001f;
state.updateTime = eventTime;
- float xvel = (xpos - state.xpos) / dt;
- float yvel = (ypos - state.ypos) / dt;
+ float vel = (pos - state.pos) / dt;
if (state.degree == 0) {
- state.xvel = xvel;
- state.yvel = yvel;
+ state.vel = vel;
state.degree = 1;
} else {
float alpha = dt / (FILTER_TIME_CONSTANT + dt);
if (mDegree == 1) {
- state.xvel += (xvel - state.xvel) * alpha;
- state.yvel += (yvel - state.yvel) * alpha;
+ state.vel += (vel - state.vel) * alpha;
} else {
- float xaccel = (xvel - state.xvel) / dt;
- float yaccel = (yvel - state.yvel) / dt;
+ float accel = (vel - state.vel) / dt;
if (state.degree == 1) {
- state.xaccel = xaccel;
- state.yaccel = yaccel;
+ state.accel = accel;
state.degree = 2;
} else {
- state.xaccel += (xaccel - state.xaccel) * alpha;
- state.yaccel += (yaccel - state.yaccel) * alpha;
+ state.accel += (accel - state.accel) * alpha;
}
- state.xvel += (state.xaccel * dt) * alpha;
- state.yvel += (state.yaccel * dt) * alpha;
+ state.vel += (state.accel * dt) * alpha;
}
}
- state.xpos = xpos;
- state.ypos = ypos;
+ state.pos = pos;
}
void IntegratingVelocityTrackerStrategy::populateEstimator(const State& state,
@@ -881,12 +912,9 @@
outEstimator->time = state.updateTime;
outEstimator->confidence = 1.0f;
outEstimator->degree = state.degree;
- outEstimator->xCoeff[0] = state.xpos;
- outEstimator->xCoeff[1] = state.xvel;
- outEstimator->xCoeff[2] = state.xaccel / 2;
- outEstimator->yCoeff[0] = state.ypos;
- outEstimator->yCoeff[1] = state.yvel;
- outEstimator->yCoeff[2] = state.yaccel / 2;
+ outEstimator->coeff[0] = state.pos;
+ outEstimator->coeff[1] = state.vel;
+ outEstimator->coeff[2] = state.accel / 2;
}
@@ -909,9 +937,8 @@
mMovements[mIndex].idBits = remainingIdBits;
}
-void LegacyVelocityTrackerStrategy::addMovement(
- nsecs_t eventTime, BitSet32 idBits,
- const std::vector<VelocityTracker::Position>& positions) {
+void LegacyVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
+ const std::vector<float>& positions) {
if (++mIndex == HISTORY_SIZE) {
mIndex = 0;
}
@@ -959,12 +986,11 @@
// overestimate the velocity at that time point. Most samples might be measured
// 16ms apart but some consecutive samples could be only 0.5sm apart because
// the hardware or driver reports them irregularly or in bursts.
- float accumVx = 0;
- float accumVy = 0;
+ float accumV = 0;
uint32_t index = oldestIndex;
uint32_t samplesUsed = 0;
const Movement& oldestMovement = mMovements[oldestIndex];
- const VelocityTracker::Position& oldestPosition = oldestMovement.getPosition(id);
+ float oldestPosition = oldestMovement.getPosition(id);
nsecs_t lastDuration = 0;
while (numTouches-- > 1) {
@@ -978,26 +1004,22 @@
// the velocity. Consequently, we impose a minimum duration constraint on the
// samples that we include in the calculation.
if (duration >= MIN_DURATION) {
- const VelocityTracker::Position& position = movement.getPosition(id);
+ float position = movement.getPosition(id);
float scale = 1000000000.0f / duration; // one over time delta in seconds
- float vx = (position.x - oldestPosition.x) * scale;
- float vy = (position.y - oldestPosition.y) * scale;
- accumVx = (accumVx * lastDuration + vx * duration) / (duration + lastDuration);
- accumVy = (accumVy * lastDuration + vy * duration) / (duration + lastDuration);
+ float v = (position - oldestPosition) * scale;
+ accumV = (accumV * lastDuration + v * duration) / (duration + lastDuration);
lastDuration = duration;
samplesUsed += 1;
}
}
// Report velocity.
- const VelocityTracker::Position& newestPosition = newestMovement.getPosition(id);
+ float newestPosition = newestMovement.getPosition(id);
outEstimator->time = newestMovement.eventTime;
outEstimator->confidence = 1;
- outEstimator->xCoeff[0] = newestPosition.x;
- outEstimator->yCoeff[0] = newestPosition.y;
+ outEstimator->coeff[0] = newestPosition;
if (samplesUsed) {
- outEstimator->xCoeff[1] = accumVx;
- outEstimator->yCoeff[1] = accumVy;
+ outEstimator->coeff[1] = accumV;
outEstimator->degree = 1;
} else {
outEstimator->degree = 0;
@@ -1024,9 +1046,8 @@
mMovements[mIndex].idBits = remainingIdBits;
}
-void ImpulseVelocityTrackerStrategy::addMovement(
- nsecs_t eventTime, BitSet32 idBits,
- const std::vector<VelocityTracker::Position>& positions) {
+void ImpulseVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
+ const std::vector<float>& positions) {
if (mMovements[mIndex].eventTime != eventTime) {
// When ACTION_POINTER_DOWN happens, we will first receive ACTION_MOVE with the coordinates
// of the existing pointers, and then ACTION_POINTER_DOWN with the coordinates that include
@@ -1163,8 +1184,7 @@
outEstimator->clear();
// Iterate over movement samples in reverse time order and collect samples.
- float x[HISTORY_SIZE];
- float y[HISTORY_SIZE];
+ float positions[HISTORY_SIZE];
nsecs_t time[HISTORY_SIZE];
size_t m = 0; // number of points that will be used for fitting
size_t index = mIndex;
@@ -1180,9 +1200,7 @@
break;
}
- const VelocityTracker::Position& position = movement.getPosition(id);
- x[m] = position.x;
- y[m] = position.y;
+ positions[m] = movement.getPosition(id);
time[m] = movement.eventTime;
index = (index == 0 ? HISTORY_SIZE : index) - 1;
} while (++m < HISTORY_SIZE);
@@ -1190,33 +1208,30 @@
if (m == 0) {
return false; // no data
}
- outEstimator->xCoeff[0] = 0;
- outEstimator->yCoeff[0] = 0;
- outEstimator->xCoeff[1] = calculateImpulseVelocity(time, x, m);
- outEstimator->yCoeff[1] = calculateImpulseVelocity(time, y, m);
- outEstimator->xCoeff[2] = 0;
- outEstimator->yCoeff[2] = 0;
+ outEstimator->coeff[0] = 0;
+ outEstimator->coeff[1] = calculateImpulseVelocity(time, positions, m);
+ outEstimator->coeff[2] = 0;
+
outEstimator->time = newestMovement.eventTime;
outEstimator->degree = 2; // similar results to 2nd degree fit
outEstimator->confidence = 1;
- ALOGD_IF(DEBUG_STRATEGY, "velocity: (%.1f, %.1f)", outEstimator->xCoeff[1],
- outEstimator->yCoeff[1]);
+ ALOGD_IF(DEBUG_STRATEGY, "velocity: %.1f", outEstimator->coeff[1]);
if (DEBUG_IMPULSE) {
// TODO(b/134179997): delete this block once the switch to 'impulse' is complete.
- // Calculate the lsq2 velocity for the same inputs to allow runtime comparisons
+ // Calculate the lsq2 velocity for the same inputs to allow runtime comparisons.
+ // X axis chosen arbitrarily for velocity comparisons.
VelocityTracker lsq2(VelocityTracker::Strategy::LSQ2);
BitSet32 idBits;
const uint32_t pointerId = 0;
idBits.markBit(pointerId);
for (ssize_t i = m - 1; i >= 0; i--) {
- lsq2.addMovement(time[i], idBits, {{x[i], y[i]}});
+ lsq2.addMovement(time[i], idBits, {{AMOTION_EVENT_AXIS_X, {positions[i]}}});
}
- float outVx = 0, outVy = 0;
- const bool computed = lsq2.getVelocity(pointerId, &outVx, &outVy);
- if (computed) {
- ALOGD("lsq2 velocity: (%.1f, %.1f)", outVx, outVy);
+ std::optional<float> v = lsq2.getVelocity(AMOTION_EVENT_AXIS_X, pointerId);
+ if (v) {
+ ALOGD("lsq2 velocity: %.1f", *v);
} else {
ALOGD("lsq2 velocity: could not compute velocity");
}
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index 4a445de..f8e5052 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -16,9 +16,10 @@
#define LOG_TAG "VelocityTracker_test"
+#include <math.h>
#include <array>
#include <chrono>
-#include <math.h>
+#include <limits>
#include <android-base/stringprintf.h>
#include <attestation/HmacKeyManager.h>
@@ -198,25 +199,13 @@
const std::vector<MotionEventEntry>& motions, int32_t axis,
float targetVelocity, uint32_t pointerId = DEFAULT_POINTER_ID) {
VelocityTracker vt(strategy);
- float Vx, Vy;
std::vector<MotionEvent> events = createMotionEventStream(motions);
for (MotionEvent event : events) {
vt.addMovement(&event);
}
- vt.getVelocity(pointerId, &Vx, &Vy);
-
- switch (axis) {
- case AMOTION_EVENT_AXIS_X:
- checkVelocity(Vx, targetVelocity);
- break;
- case AMOTION_EVENT_AXIS_Y:
- checkVelocity(Vy, targetVelocity);
- break;
- default:
- FAIL() << "Axis must be either AMOTION_EVENT_AXIS_X or AMOTION_EVENT_AXIS_Y";
- }
+ checkVelocity(vt.getVelocity(axis, pointerId).value_or(0), targetVelocity);
}
static void computeAndCheckQuadraticEstimate(const std::vector<MotionEventEntry>& motions,
@@ -226,17 +215,99 @@
for (MotionEvent event : events) {
vt.addMovement(&event);
}
- VelocityTracker::Estimator estimator;
- EXPECT_TRUE(vt.getEstimator(0, &estimator));
+ VelocityTracker::Estimator estimatorX;
+ VelocityTracker::Estimator estimatorY;
+ EXPECT_TRUE(vt.getEstimator(AMOTION_EVENT_AXIS_X, 0, &estimatorX));
+ EXPECT_TRUE(vt.getEstimator(AMOTION_EVENT_AXIS_Y, 0, &estimatorY));
for (size_t i = 0; i< coefficients.size(); i++) {
- checkCoefficient(estimator.xCoeff[i], coefficients[i]);
- checkCoefficient(estimator.yCoeff[i], coefficients[i]);
+ checkCoefficient(estimatorX.coeff[i], coefficients[i]);
+ checkCoefficient(estimatorY.coeff[i], coefficients[i]);
}
}
/*
* ================== VelocityTracker tests generated manually =====================================
*/
+TEST_F(VelocityTrackerTest, TestComputedVelocity) {
+ VelocityTracker::ComputedVelocity computedVelocity;
+
+ computedVelocity.addVelocity(AMOTION_EVENT_AXIS_X, 0 /*id*/, 200 /*velocity*/);
+ computedVelocity.addVelocity(AMOTION_EVENT_AXIS_X, 26U /*id*/, 400 /*velocity*/);
+ computedVelocity.addVelocity(AMOTION_EVENT_AXIS_X, 27U /*id*/, 650 /*velocity*/);
+ computedVelocity.addVelocity(AMOTION_EVENT_AXIS_X, MAX_POINTER_ID, 750 /*velocity*/);
+ computedVelocity.addVelocity(AMOTION_EVENT_AXIS_Y, 0 /*id*/, 1000 /*velocity*/);
+ computedVelocity.addVelocity(AMOTION_EVENT_AXIS_Y, 26U /*id*/, 2000 /*velocity*/);
+ computedVelocity.addVelocity(AMOTION_EVENT_AXIS_Y, 27U /*id*/, 3000 /*velocity*/);
+ computedVelocity.addVelocity(AMOTION_EVENT_AXIS_Y, MAX_POINTER_ID, 4000 /*velocity*/);
+
+ // Check the axes/indices with velocity.
+ EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, 0U /*id*/)), 200);
+ EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, 26U /*id*/)), 400);
+ EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, 27U /*id*/)), 650);
+ EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, MAX_POINTER_ID)), 750);
+ EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, 0U /*id*/)), 1000);
+ EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, 26U /*id*/)), 2000);
+ EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, 27U /*id*/)), 3000);
+ EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, MAX_POINTER_ID)), 4000);
+ for (uint32_t id = 0; id <= MAX_POINTER_ID; id++) {
+ // Since no data was added for AXIS_SCROLL, expect empty value for the axis for any id.
+ EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_SCROLL, id))
+ << "Empty scroll data expected at id=" << id;
+ if (id == 0 || id == 26U || id == 27U || id == MAX_POINTER_ID) {
+ // Already checked above; continue.
+ continue;
+ }
+ // No data was added to X/Y for this id, expect empty value.
+ EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, id))
+ << "Empty X data expected at id=" << id;
+ EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, id))
+ << "Empty Y data expected at id=" << id;
+ }
+ // Out-of-bounds ids should given empty values.
+ EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, -1));
+ EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, MAX_POINTER_ID + 1));
+}
+
+TEST_F(VelocityTrackerTest, TestGetComputedVelocity) {
+ std::vector<MotionEventEntry> motions = {
+ {235089067457000ns, {{528.00, 0}}}, {235089084684000ns, {{527.00, 0}}},
+ {235089093349000ns, {{527.00, 0}}}, {235089095677625ns, {{527.00, 0}}},
+ {235089101859000ns, {{527.00, 0}}}, {235089110378000ns, {{528.00, 0}}},
+ {235089112497111ns, {{528.25, 0}}}, {235089118760000ns, {{531.00, 0}}},
+ {235089126686000ns, {{535.00, 0}}}, {235089129316820ns, {{536.33, 0}}},
+ {235089135199000ns, {{540.00, 0}}}, {235089144297000ns, {{546.00, 0}}},
+ {235089146136443ns, {{547.21, 0}}}, {235089152923000ns, {{553.00, 0}}},
+ {235089160784000ns, {{559.00, 0}}}, {235089162955851ns, {{560.66, 0}}},
+ {235089162955851ns, {{560.66, 0}}}, // ACTION_UP
+ };
+ VelocityTracker vt(VelocityTracker::Strategy::IMPULSE);
+ std::vector<MotionEvent> events = createMotionEventStream(motions);
+ for (const MotionEvent& event : events) {
+ vt.addMovement(&event);
+ }
+
+ float maxFloat = std::numeric_limits<float>::max();
+ VelocityTracker::ComputedVelocity computedVelocity;
+ computedVelocity = vt.getComputedVelocity(1000 /* units */, maxFloat);
+ checkVelocity(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID)),
+ 764.345703);
+
+ // Expect X velocity to be scaled with respective to provided units.
+ computedVelocity = vt.getComputedVelocity(1000000 /* units */, maxFloat);
+ checkVelocity(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID)),
+ 764345.703);
+
+ // Expect X velocity to be clamped by provided max velocity.
+ computedVelocity = vt.getComputedVelocity(1000000 /* units */, 1000);
+ checkVelocity(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID)), 1000);
+
+ // All 0 data for Y; expect 0 velocity.
+ EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, DEFAULT_POINTER_ID)), 0);
+
+ // No data for scroll-axis; expect empty velocity.
+ EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_SCROLL, DEFAULT_POINTER_ID));
+}
+
TEST_F(VelocityTrackerTest, ThreePointsPositiveVelocityTest) {
// Same coordinate is reported 2 times in a row
// It is difficult to determine the correct answer here, but at least the direction
diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp
index a6cacad..78f692b 100644
--- a/libs/sensor/ISensorServer.cpp
+++ b/libs/sensor/ISensorServer.cpp
@@ -22,12 +22,12 @@
#include <cutils/native_handle.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
-#include <utils/Vector.h>
#include <utils/Timers.h>
+#include <utils/Vector.h>
-#include <binder/Parcel.h>
#include <binder/IInterface.h>
#include <binder/IResultReceiver.h>
+#include <binder/Parcel.h>
#include <sensor/Sensor.h>
#include <sensor/ISensorEventConnection.h>
@@ -205,9 +205,10 @@
if (resource == nullptr) {
return BAD_VALUE;
}
+ native_handle_set_fdsan_tag(resource);
sp<ISensorEventConnection> ch =
createSensorDirectConnection(opPackageName, size, type, format, resource);
- native_handle_close(resource);
+ native_handle_close_with_tag(resource);
native_handle_delete(resource);
reply->writeStrongBinder(IInterface::asBinder(ch));
return NO_ERROR;
diff --git a/libs/ui/include/ui/DisplayId.h b/libs/ui/include/ui/DisplayId.h
index 9120972..d0c03fe 100644
--- a/libs/ui/include/ui/DisplayId.h
+++ b/libs/ui/include/ui/DisplayId.h
@@ -17,9 +17,10 @@
#pragma once
#include <cstdint>
-#include <optional>
#include <string>
+#include <ftl/optional.h>
+
namespace android {
// ID of a physical or a virtual display. This class acts as a type safe wrapper around uint64_t.
@@ -68,7 +69,7 @@
// DisplayId of a physical display, such as the internal display or externally connected display.
struct PhysicalDisplayId : DisplayId {
- static constexpr std::optional<PhysicalDisplayId> tryCast(DisplayId id) {
+ static constexpr ftl::Optional<PhysicalDisplayId> tryCast(DisplayId id) {
if (id.value & FLAG_VIRTUAL) {
return std::nullopt;
}
diff --git a/libs/ui/include/ui/StaticDisplayInfo.h b/libs/ui/include/ui/StaticDisplayInfo.h
index 566e417..83da821 100644
--- a/libs/ui/include/ui/StaticDisplayInfo.h
+++ b/libs/ui/include/ui/StaticDisplayInfo.h
@@ -23,7 +23,7 @@
namespace android::ui {
-enum class DisplayConnectionType { Internal, External };
+enum class DisplayConnectionType { Internal, External, ftl_last = External };
// Immutable information about physical display.
struct StaticDisplayInfo {
diff --git a/services/inputflinger/BlockingQueue.h b/services/inputflinger/BlockingQueue.h
index 8300e8a..fe37287 100644
--- a/services/inputflinger/BlockingQueue.h
+++ b/services/inputflinger/BlockingQueue.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_BLOCKING_QUEUE_H
-#define _UI_INPUT_BLOCKING_QUEUE_H
+#pragma once
#include "android-base/thread_annotations.h"
#include <condition_variable>
@@ -106,6 +105,4 @@
std::vector<T> mQueue GUARDED_BY(mLock);
};
-
} // namespace android
-#endif
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index b40ab7f..1137193 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_MANAGER_H
-#define _UI_INPUT_MANAGER_H
+#pragma once
/**
* Native input manager.
@@ -130,5 +129,3 @@
};
} // namespace android
-
-#endif // _UI_INPUT_MANAGER_H
diff --git a/services/inputflinger/InputProcessor.h b/services/inputflinger/InputProcessor.h
index 261e012..bbf391e 100644
--- a/services/inputflinger/InputProcessor.h
+++ b/services/inputflinger/InputProcessor.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_CLASSIFIER_H
-#define _UI_INPUT_CLASSIFIER_H
+#pragma once
#include <android-base/thread_annotations.h>
#include <future>
@@ -288,4 +287,3 @@
};
} // namespace android
-#endif
diff --git a/services/inputflinger/dispatcher/AnrTracker.h b/services/inputflinger/dispatcher/AnrTracker.h
index 097dba5..5e5e0c4 100644
--- a/services/inputflinger/dispatcher/AnrTracker.h
+++ b/services/inputflinger/dispatcher/AnrTracker.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_INPUTDISPATCHER_ANRTRACKER_H
-#define _UI_INPUT_INPUTDISPATCHER_ANRTRACKER_H
+#pragma once
#include <binder/IBinder.h>
#include <utils/Timers.h>
@@ -56,5 +55,3 @@
};
} // namespace android::inputdispatcher
-
-#endif // _UI_INPUT_INPUTDISPATCHER_ANRTRACKER_H
diff --git a/services/inputflinger/dispatcher/CancelationOptions.h b/services/inputflinger/dispatcher/CancelationOptions.h
index fec5f83..d210e9e 100644
--- a/services/inputflinger/dispatcher/CancelationOptions.h
+++ b/services/inputflinger/dispatcher/CancelationOptions.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_INPUTDISPATCHER_CANCELLATIONOPTIONS_H
-#define _UI_INPUT_INPUTDISPATCHER_CANCELLATIONOPTIONS_H
+#pragma once
#include <utils/BitSet.h>
#include <optional>
@@ -55,5 +54,3 @@
} // namespace inputdispatcher
} // namespace android
-
-#endif // _UI_INPUT_INPUTDISPATCHER_CANCELLATIONOPTIONS_H
diff --git a/services/inputflinger/dispatcher/Connection.h b/services/inputflinger/dispatcher/Connection.h
index dc6a081..6040e9b 100644
--- a/services/inputflinger/dispatcher/Connection.h
+++ b/services/inputflinger/dispatcher/Connection.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_INPUTDISPATCHER_CONNECTION_H
-#define _UI_INPUT_INPUTDISPATCHER_CONNECTION_H
+#pragma once
#include "InputState.h"
@@ -74,5 +73,3 @@
};
} // namespace android::inputdispatcher
-
-#endif // _UI_INPUT_INPUTDISPATCHER_CONNECTION_H
diff --git a/services/inputflinger/dispatcher/DebugConfig.h b/services/inputflinger/dispatcher/DebugConfig.h
index 4f8995f..d2ad407 100644
--- a/services/inputflinger/dispatcher/DebugConfig.h
+++ b/services/inputflinger/dispatcher/DebugConfig.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_DISPATCHER_DEBUG_CONFIG_H
-#define _UI_INPUT_DISPATCHER_DEBUG_CONFIG_H
+#pragma once
#define LOG_TAG "InputDispatcher"
@@ -75,11 +74,8 @@
/**
* Log debug messages about touch occlusion
- * Enable this via "adb shell setprop log.tag.InputDispatcherTouchOcclusion DEBUG" (requires
- * restart)
*/
-const bool DEBUG_TOUCH_OCCLUSION =
- __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "TouchOcclusion", ANDROID_LOG_INFO);
+constexpr bool DEBUG_TOUCH_OCCLUSION = true;
/**
* Log debug messages about the app switch latency optimization.
@@ -95,5 +91,3 @@
const bool DEBUG_HOVER =
__android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Hover", ANDROID_LOG_INFO);
} // namespace android::inputdispatcher
-
-#endif // _UI_INPUT_DISPATCHER_DEBUG_CONFIG_H
\ No newline at end of file
diff --git a/services/inputflinger/dispatcher/DragState.h b/services/inputflinger/dispatcher/DragState.h
index d1c8b8a..9809148 100644
--- a/services/inputflinger/dispatcher/DragState.h
+++ b/services/inputflinger/dispatcher/DragState.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_INPUTDISPATCHER_DRAGSTATE_H
-#define _UI_INPUT_INPUTDISPATCHER_DRAGSTATE_H
+#pragma once
#include <gui/WindowInfo.h>
#include <utils/StrongPointer.h>
@@ -44,5 +43,3 @@
} // namespace inputdispatcher
} // namespace android
-
-#endif // _UI_INPUT_INPUTDISPATCHER_DRAGSTATE_H
\ No newline at end of file
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index 0f79296..1f916f3 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_INPUTDISPATCHER_ENTRY_H
-#define _UI_INPUT_INPUTDISPATCHER_ENTRY_H
+#pragma once
#include "InjectionState.h"
#include "InputTarget.h"
@@ -257,5 +256,3 @@
const ui::Transform& rawTransform);
} // namespace android::inputdispatcher
-
-#endif // _UI_INPUT_INPUTDISPATCHER_ENTRY_H
diff --git a/services/inputflinger/dispatcher/InjectionState.h b/services/inputflinger/dispatcher/InjectionState.h
index 90cf150..d9e27ba 100644
--- a/services/inputflinger/dispatcher/InjectionState.h
+++ b/services/inputflinger/dispatcher/InjectionState.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_INPUTDISPATCHER_INJECTIONSTATE_H
-#define _UI_INPUT_INPUTDISPATCHER_INJECTIONSTATE_H
+#pragma once
#include <stdint.h>
#include "InputDispatcherInterface.h"
@@ -41,5 +40,3 @@
} // namespace inputdispatcher
} // namespace android
-
-#endif // _UI_INPUT_INPUTDISPATCHER_INJECTIONSTATE_H
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index be619ae..b5bbce8 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_DISPATCHER_H
-#define _UI_INPUT_DISPATCHER_H
+#pragma once
#include "AnrTracker.h"
#include "CancelationOptions.h"
@@ -693,5 +692,3 @@
};
} // namespace android::inputdispatcher
-
-#endif // _UI_INPUT_DISPATCHER_H
diff --git a/services/inputflinger/dispatcher/InputEventTimeline.h b/services/inputflinger/dispatcher/InputEventTimeline.h
index 77b8472..daf375d 100644
--- a/services/inputflinger/dispatcher/InputEventTimeline.h
+++ b/services/inputflinger/dispatcher/InputEventTimeline.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTEVENTTIMELINE_H
-#define _UI_INPUT_INPUTDISPATCHER_INPUTEVENTTIMELINE_H
+#pragma once
#include <binder/IBinder.h>
#include <input/Input.h>
@@ -104,5 +103,3 @@
} // namespace inputdispatcher
} // namespace android
-
-#endif // _UI_INPUT_INPUTDISPATCHER_INPUTEVENTTIMELINE_H
diff --git a/services/inputflinger/dispatcher/InputState.h b/services/inputflinger/dispatcher/InputState.h
index 77a6db1..6ab48c9 100644
--- a/services/inputflinger/dispatcher/InputState.h
+++ b/services/inputflinger/dispatcher/InputState.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTSTATE_H
-#define _UI_INPUT_INPUTDISPATCHER_INPUTSTATE_H
+#pragma once
#include "CancelationOptions.h"
#include "Entry.h"
@@ -134,5 +133,3 @@
} // namespace inputdispatcher
} // namespace android
-
-#endif // _UI_INPUT_INPUTDISPATCHER_INPUTSTATE_H
diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h
index ac20dab..b2966f6 100644
--- a/services/inputflinger/dispatcher/InputTarget.h
+++ b/services/inputflinger/dispatcher/InputTarget.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTTARGET_H
-#define _UI_INPUT_INPUTDISPATCHER_INPUTTARGET_H
+#pragma once
#include <gui/constants.h>
#include <input/InputTransport.h>
@@ -136,5 +135,3 @@
std::string dispatchModeToString(int32_t dispatchMode);
} // namespace android::inputdispatcher
-
-#endif // _UI_INPUT_INPUTDISPATCHER_INPUTTARGET_H
diff --git a/services/inputflinger/dispatcher/LatencyAggregator.h b/services/inputflinger/dispatcher/LatencyAggregator.h
index ed5731f..accfc29 100644
--- a/services/inputflinger/dispatcher/LatencyAggregator.h
+++ b/services/inputflinger/dispatcher/LatencyAggregator.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_INPUTDISPATCHER_LATENCYAGGREGATOR_H
-#define _UI_INPUT_INPUTDISPATCHER_LATENCYAGGREGATOR_H
+#pragma once
#include <kll.h>
#include <statslog.h>
@@ -86,5 +85,3 @@
};
} // namespace android::inputdispatcher
-
-#endif // _UI_INPUT_INPUTDISPATCHER_LATENCYAGGREGATOR_H
diff --git a/services/inputflinger/dispatcher/LatencyTracker.h b/services/inputflinger/dispatcher/LatencyTracker.h
index 4b0c618..64dfeef 100644
--- a/services/inputflinger/dispatcher/LatencyTracker.h
+++ b/services/inputflinger/dispatcher/LatencyTracker.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_INPUTDISPATCHER_LATENCYTRACKER_H
-#define _UI_INPUT_INPUTDISPATCHER_LATENCYTRACKER_H
+#pragma once
#include <map>
#include <unordered_map>
@@ -81,5 +80,3 @@
};
} // namespace android::inputdispatcher
-
-#endif // _UI_INPUT_INPUTDISPATCHER_LATENCYTRACKER_H
diff --git a/services/inputflinger/dispatcher/Monitor.h b/services/inputflinger/dispatcher/Monitor.h
index 365d5be..7b51191 100644
--- a/services/inputflinger/dispatcher/Monitor.h
+++ b/services/inputflinger/dispatcher/Monitor.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_INPUTDISPATCHER_MONITOR_H
-#define _UI_INPUT_INPUTDISPATCHER_MONITOR_H
+#pragma once
#include <input/InputTransport.h>
@@ -30,5 +29,3 @@
};
} // namespace android::inputdispatcher
-
-#endif // _UI_INPUT_INPUTDISPATCHER_MONITOR_H
diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h
index 1fb51e1..cf5f1e5 100644
--- a/services/inputflinger/dispatcher/TouchState.h
+++ b/services/inputflinger/dispatcher/TouchState.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_INPUTDISPATCHER_TOUCHSTATE_H
-#define _UI_INPUT_INPUTDISPATCHER_TOUCHSTATE_H
+#pragma once
#include "Monitor.h"
#include "TouchedWindow.h"
@@ -67,5 +66,3 @@
} // namespace inputdispatcher
} // namespace android
-
-#endif // _UI_INPUT_INPUTDISPATCHER_TOUCHSTATE_H
diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h
index a7839db..a6c505b 100644
--- a/services/inputflinger/dispatcher/TouchedWindow.h
+++ b/services/inputflinger/dispatcher/TouchedWindow.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_INPUTDISPATCHER_TOUCHEDWINDOW_H
-#define _UI_INPUT_INPUTDISPATCHER_TOUCHEDWINDOW_H
+#pragma once
namespace android {
@@ -38,5 +37,3 @@
} // namespace inputdispatcher
} // namespace android
-
-#endif // _UI_INPUT_INPUTDISPATCHER_TOUCHEDWINDOW_H
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherConfiguration.h b/services/inputflinger/dispatcher/include/InputDispatcherConfiguration.h
index 00abf47..5eb3a32 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherConfiguration.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherConfiguration.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERCONFIGURATION_H
-#define _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERCONFIGURATION_H
+#pragma once
#include <utils/Timers.h>
@@ -40,5 +39,3 @@
};
} // namespace android
-
-#endif // _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERCONFIGURATION_H
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherFactory.h b/services/inputflinger/dispatcher/include/InputDispatcherFactory.h
index 38d0c32..5247d8e 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherFactory.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherFactory.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERFACTORY_H
-#define _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERFACTORY_H
+#pragma once
#include <utils/StrongPointer.h>
@@ -29,5 +28,3 @@
const sp<InputDispatcherPolicyInterface>& policy);
} // namespace android
-
-#endif // _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERFACTORY_H
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 32b3ddb..484b0d3 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERINTERFACE_H
-#define _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERINTERFACE_H
+#pragma once
#include <InputListener.h>
#include <android-base/result.h>
@@ -226,5 +225,3 @@
};
} // namespace android
-
-#endif // _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERINTERFACE_H
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index 7c299b2..44f3baf 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERPOLICYINTERFACE_H
-#define _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERPOLICYINTERFACE_H
+#pragma once
#include "InputDispatcherConfiguration.h"
@@ -143,5 +142,3 @@
};
} // namespace android
-
-#endif // _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERPOLICYINTERFACE_H
diff --git a/services/inputflinger/host/InputDriver.h b/services/inputflinger/host/InputDriver.h
index e56673b..b4c9094 100644
--- a/services/inputflinger/host/InputDriver.h
+++ b/services/inputflinger/host/InputDriver.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_INPUT_DRIVER_H
-#define ANDROID_INPUT_DRIVER_H
+#pragma once
#include <stdint.h>
#include <sys/types.h>
@@ -192,4 +191,3 @@
}
} // namespace android
-#endif // ANDROID_INPUT_DRIVER_H
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
index 3cf1b2b..388988b 100644
--- a/services/inputflinger/host/InputFlinger.h
+++ b/services/inputflinger/host/InputFlinger.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_INPUT_FLINGER_H
-#define ANDROID_INPUT_FLINGER_H
+#pragma once
#include <stdint.h>
#include <sys/types.h>
@@ -58,5 +57,3 @@
};
} // namespace android
-
-#endif // ANDROID_INPUT_FLINGER_H
diff --git a/services/inputflinger/host/InputHost.h b/services/inputflinger/host/InputHost.h
index eda4a89..bdc4225 100644
--- a/services/inputflinger/host/InputHost.h
+++ b/services/inputflinger/host/InputHost.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_INPUT_HOST_H
-#define ANDROID_INPUT_HOST_H
+#pragma once
#include <vector>
@@ -55,4 +54,3 @@
};
} // namespace android
-#endif // ANDRIOD_INPUT_HOST_H
diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h
index d9822ce..c8ab6c5 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_LISTENER_H
-#define _UI_INPUT_LISTENER_H
+#pragma once
#include <vector>
@@ -292,5 +291,3 @@
};
} // namespace android
-
-#endif // _UI_INPUT_LISTENER_H
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 77c9142..cacb63c 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_READER_BASE_H
-#define _UI_INPUT_READER_BASE_H
+#pragma once
#include <android/os/IInputConstants.h>
#include <input/DisplayViewport.h>
@@ -114,6 +113,8 @@
virtual std::optional<int32_t> getBatteryCapacity(int32_t deviceId) = 0;
/* Get battery status of a particular input device. */
virtual std::optional<int32_t> getBatteryStatus(int32_t deviceId) = 0;
+ /* Get the device path for the battery of an input device. */
+ virtual std::optional<std::string> getBatteryDevicePath(int32_t deviceId) = 0;
virtual std::vector<InputDeviceLightInfo> getLights(int32_t deviceId) = 0;
@@ -395,5 +396,3 @@
};
} // namespace android
-
-#endif // _UI_INPUT_READER_COMMON_H
diff --git a/services/inputflinger/include/InputThread.h b/services/inputflinger/include/InputThread.h
index 407365a..5e75027 100644
--- a/services/inputflinger/include/InputThread.h
+++ b/services/inputflinger/include/InputThread.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_THREAD_H
-#define _UI_INPUT_THREAD_H
+#pragma once
#include <utils/Thread.h>
@@ -42,5 +41,3 @@
};
} // namespace android
-
-#endif // _UI_INPUT_THREAD_H
\ No newline at end of file
diff --git a/services/inputflinger/include/PointerControllerInterface.h b/services/inputflinger/include/PointerControllerInterface.h
index db4228d..647e10c 100644
--- a/services/inputflinger/include/PointerControllerInterface.h
+++ b/services/inputflinger/include/PointerControllerInterface.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _INPUTFLINGER_POINTER_CONTROLLER_INTERFACE_H
-#define _INPUTFLINGER_POINTER_CONTROLLER_INTERFACE_H
+#pragma once
#include <input/DisplayViewport.h>
#include <input/Input.h>
@@ -108,5 +107,3 @@
};
} // namespace android
-
-#endif // _INPUTFLINGER_POINTER_CONTROLLER_INTERFACE_H
diff --git a/services/inputflinger/include/VibrationElement.h b/services/inputflinger/include/VibrationElement.h
index 736041e..04c2e39 100644
--- a/services/inputflinger/include/VibrationElement.h
+++ b/services/inputflinger/include/VibrationElement.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _VIBRATION_ELEMENT_H
-#define _VIBRATION_ELEMENT_H
+#pragma once
#include <array>
#include <chrono>
@@ -71,5 +70,3 @@
};
} // namespace android
-
-#endif // _VIBRATION_ELEMENT_H
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index ff0b9a5..c9d21dc 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -1555,7 +1555,7 @@
// the lock to prevent event processing from being blocked by this call.
std::scoped_lock _l(mLock);
- const auto infos = getBatteryInfoLocked(deviceId);
+ const auto& infos = getBatteryInfoLocked(deviceId);
auto it = infos.find(batteryId);
if (it == infos.end()) {
return std::nullopt;
@@ -1596,7 +1596,7 @@
// the lock to prevent event processing from being blocked by this call.
std::scoped_lock _l(mLock);
- const auto infos = getBatteryInfoLocked(deviceId);
+ const auto& infos = getBatteryInfoLocked(deviceId);
auto it = infos.find(batteryId);
if (it == infos.end()) {
return std::nullopt;
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 4750d90..4c38ce8 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -721,7 +721,10 @@
if (!eventHubId) return {};
const auto batteryIds = mEventHub->getRawBatteryIds(*eventHubId);
- if (batteryIds.empty()) return {};
+ if (batteryIds.empty()) {
+ ALOGW("%s: There are no battery ids for EventHub device %d", __func__, *eventHubId);
+ return {};
+ }
return mEventHub->getBatteryCapacity(*eventHubId, batteryIds.front());
}
@@ -741,10 +744,35 @@
if (!eventHubId) return {};
const auto batteryIds = mEventHub->getRawBatteryIds(*eventHubId);
- if (batteryIds.empty()) return {};
+ if (batteryIds.empty()) {
+ ALOGW("%s: There are no battery ids for EventHub device %d", __func__, *eventHubId);
+ return {};
+ }
return mEventHub->getBatteryStatus(*eventHubId, batteryIds.front());
}
+std::optional<std::string> InputReader::getBatteryDevicePath(int32_t deviceId) {
+ std::scoped_lock _l(mLock);
+
+ InputDevice* device = findInputDeviceLocked(deviceId);
+ if (!device) return {};
+
+ std::optional<int32_t> eventHubId = device->getBatteryEventHubId();
+ if (!eventHubId) return {};
+ const auto batteryIds = mEventHub->getRawBatteryIds(*eventHubId);
+ if (batteryIds.empty()) {
+ ALOGW("%s: There are no battery ids for EventHub device %d", __func__, *eventHubId);
+ return {};
+ }
+ const auto batteryInfo = mEventHub->getRawBatteryInfo(*eventHubId, batteryIds.front());
+ if (!batteryInfo) {
+ ALOGW("%s: Failed to get RawBatteryInfo for battery %d of EventHub device %d", __func__,
+ batteryIds.front(), *eventHubId);
+ return {};
+ }
+ return batteryInfo->path;
+}
+
std::vector<InputDeviceLightInfo> InputReader::getLights(int32_t deviceId) {
std::scoped_lock _l(mLock);
diff --git a/services/inputflinger/reader/Macros.h b/services/inputflinger/reader/Macros.h
index 1bbf386..e107d88 100644
--- a/services/inputflinger/reader/Macros.h
+++ b/services/inputflinger/reader/Macros.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_MACROS_H
-#define _UI_INPUTREADER_MACROS_H
+#pragma once
#define LOG_TAG "InputReader"
@@ -115,5 +114,3 @@
}
} // namespace android
-
-#endif // _UI_INPUTREADER_MACROS_H
\ No newline at end of file
diff --git a/services/inputflinger/reader/controller/PeripheralController.h b/services/inputflinger/reader/controller/PeripheralController.h
index ac951eb..25cf435 100644
--- a/services/inputflinger/reader/controller/PeripheralController.h
+++ b/services/inputflinger/reader/controller/PeripheralController.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_LIGHT_CONTROLLER_H
-#define _UI_INPUTREADER_LIGHT_CONTROLLER_H
+#pragma once
#include "PeripheralControllerInterface.h"
@@ -150,5 +149,3 @@
};
} // namespace android
-
-#endif // _UI_INPUTREADER_LIGHT_CONTROLLER_H
diff --git a/services/inputflinger/reader/controller/PeripheralControllerInterface.h b/services/inputflinger/reader/controller/PeripheralControllerInterface.h
index 306e361..76ed1ca 100644
--- a/services/inputflinger/reader/controller/PeripheralControllerInterface.h
+++ b/services/inputflinger/reader/controller/PeripheralControllerInterface.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_INPUT_CONTROLLER_H
-#define _UI_INPUTREADER_INPUT_CONTROLLER_H
+#pragma once
#include "EventHub.h"
#include "InputDevice.h"
@@ -50,5 +49,3 @@
};
} // namespace android
-
-#endif // _UI_INPUTREADER_INPUT_CONTROLLER_H
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index dfb98f1..5cf2214 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _RUNTIME_EVENT_HUB_H
-#define _RUNTIME_EVENT_HUB_H
+#pragma once
#include <bitset>
#include <climits>
@@ -732,5 +731,3 @@
};
} // namespace android
-
-#endif // _RUNTIME_EVENT_HUB_H
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 3ef1840..4ae9ae9 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_INPUT_DEVICE_H
-#define _UI_INPUTREADER_INPUT_DEVICE_H
+#pragma once
#include <ftl/flags.h>
#include <input/DisplayViewport.h>
@@ -409,5 +408,3 @@
};
} // namespace android
-
-#endif //_UI_INPUTREADER_INPUT_DEVICE_H
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index ae41e01..fbce87f 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_INPUT_READER_H
-#define _UI_INPUTREADER_INPUT_READER_H
+#pragma once
#include <PointerControllerInterface.h>
#include <android-base/thread_annotations.h>
@@ -100,6 +99,8 @@
std::optional<int32_t> getBatteryStatus(int32_t deviceId) override;
+ std::optional<std::string> getBatteryDevicePath(int32_t deviceId) override;
+
std::vector<InputDeviceLightInfo> getLights(int32_t deviceId) override;
std::vector<InputDeviceSensorInfo> getSensors(int32_t deviceId) override;
@@ -246,5 +247,3 @@
};
} // namespace android
-
-#endif // _UI_INPUTREADER_INPUT_READER_H
diff --git a/services/inputflinger/reader/include/InputReaderContext.h b/services/inputflinger/reader/include/InputReaderContext.h
index 823d160..f2f156c 100644
--- a/services/inputflinger/reader/include/InputReaderContext.h
+++ b/services/inputflinger/reader/include/InputReaderContext.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_INPUT_READER_CONTEXT_H
-#define _UI_INPUTREADER_INPUT_READER_CONTEXT_H
+#pragma once
#include <input/InputDevice.h>
@@ -65,5 +64,3 @@
};
} // namespace android
-
-#endif // _UI_INPUTREADER_INPUT_READER_CONTEXT_H
diff --git a/services/inputflinger/reader/include/StylusState.h b/services/inputflinger/reader/include/StylusState.h
index 17f158c..8d14d3c 100644
--- a/services/inputflinger/reader/include/StylusState.h
+++ b/services/inputflinger/reader/include/StylusState.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_STYLUS_STATE_H
-#define _UI_INPUTREADER_STYLUS_STATE_H
+#pragma once
#include <input/Input.h>
@@ -49,5 +48,3 @@
};
} // namespace android
-
-#endif // _UI_INPUTREADER_STYLUS_STATE_H
diff --git a/services/inputflinger/reader/include/TouchVideoDevice.h b/services/inputflinger/reader/include/TouchVideoDevice.h
index 7de9b830..08eba31 100644
--- a/services/inputflinger/reader/include/TouchVideoDevice.h
+++ b/services/inputflinger/reader/include/TouchVideoDevice.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTFLINGER_TOUCH_VIDEO_DEVICE_H
-#define _UI_INPUTFLINGER_TOUCH_VIDEO_DEVICE_H
+#pragma once
#include <android-base/unique_fd.h>
#include <input/TouchVideoFrame.h>
@@ -123,5 +122,3 @@
};
} // namespace android
-
-#endif // _UI_INPUTFLINGER_TOUCH_VIDEO_DEVICE_H
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index 6058a1e..d6d324b 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -25,6 +25,8 @@
#include "PointerControllerInterface.h"
#include "TouchCursorInputMapperCommon.h"
+#include "input/PrintTools.h"
+
namespace android {
// The default velocity control parameters that has no effect.
@@ -117,6 +119,7 @@
toString(mCursorScrollAccumulator.haveRelativeHWheel()));
dump += StringPrintf(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale);
dump += StringPrintf(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale);
+ dump += StringPrintf(INDENT3 "DisplayId: %s\n", toString(mDisplayId).c_str());
dump += StringPrintf(INDENT3 "Orientation: %d\n", mOrientation);
dump += StringPrintf(INDENT3 "ButtonState: 0x%08x\n", mButtonState);
dump += StringPrintf(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState)));
@@ -205,21 +208,34 @@
if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO) ||
configurePointerCapture) {
+ const bool isPointer = mParameters.mode == Parameters::Mode::POINTER;
+
+ mDisplayId = ADISPLAY_ID_NONE;
+ if (auto viewport = mDeviceContext.getAssociatedViewport(); viewport) {
+ // This InputDevice is associated with a viewport.
+ // Only generate events for the associated display.
+ const bool mismatchedPointerDisplay =
+ isPointer && (viewport->displayId != mPointerController->getDisplayId());
+ mDisplayId = mismatchedPointerDisplay ? std::nullopt
+ : std::make_optional(viewport->displayId);
+ } else if (isPointer) {
+ // The InputDevice is not associated with a viewport, but it controls the mouse pointer.
+ mDisplayId = mPointerController->getDisplayId();
+ }
+
mOrientation = DISPLAY_ORIENTATION_0;
const bool isOrientedDevice =
(mParameters.orientationAware && mParameters.hasAssociatedDisplay);
-
// InputReader works in the un-rotated display coordinate space, so we don't need to do
// anything if the device is already orientation-aware. If the device is not
// orientation-aware, then we need to apply the inverse rotation of the display so that
// when the display rotation is applied later as a part of the per-window transform, we
// get the expected screen coordinates. When pointer capture is enabled, we do not apply any
// rotations and report values directly from the input device.
- if (!isOrientedDevice && mParameters.mode != Parameters::Mode::POINTER_RELATIVE) {
- std::optional<DisplayViewport> internalViewport =
- config->getDisplayViewportByType(ViewportType::INTERNAL);
- if (internalViewport) {
- mOrientation = getInverseRotation(internalViewport->orientation);
+ if (!isOrientedDevice && mDisplayId &&
+ mParameters.mode != Parameters::Mode::POINTER_RELATIVE) {
+ if (auto viewport = config->getDisplayViewportById(*mDisplayId); viewport) {
+ mOrientation = getInverseRotation(viewport->orientation);
}
}
@@ -282,6 +298,11 @@
}
void CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) {
+ if (!mDisplayId) {
+ // Ignore events when there is no target display configured.
+ return;
+ }
+
int32_t lastButtonState = mButtonState;
int32_t currentButtonState = mCursorButtonAccumulator.getButtonState();
mButtonState = currentButtonState;
@@ -327,7 +348,6 @@
mPointerVelocityControl.move(when, &deltaX, &deltaY);
- int32_t displayId = ADISPLAY_ID_NONE;
float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
if (mSource == AINPUT_SOURCE_MOUSE) {
@@ -351,7 +371,6 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
- displayId = mPointerController->getDisplayId();
} else {
// Pointer capture and navigation modes
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX);
@@ -373,7 +392,7 @@
// Synthesize key down from buttons if needed.
synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, readTime, getDeviceId(),
- mSource, displayId, policyFlags, lastButtonState, currentButtonState);
+ mSource, *mDisplayId, policyFlags, lastButtonState, currentButtonState);
// Send motion event.
if (downChanged || moved || scrolled || buttonsChanged) {
@@ -394,7 +413,7 @@
int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit());
buttonState &= ~actionButton;
NotifyMotionArgs releaseArgs(getContext()->getNextId(), when, readTime,
- getDeviceId(), mSource, displayId, policyFlags,
+ getDeviceId(), mSource, *mDisplayId, policyFlags,
AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
metaState, buttonState, MotionClassification::NONE,
AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
@@ -406,7 +425,7 @@
}
NotifyMotionArgs args(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
- displayId, policyFlags, motionEventAction, 0, 0, metaState,
+ *mDisplayId, policyFlags, motionEventAction, 0, 0, metaState,
currentButtonState, MotionClassification::NONE,
AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords,
mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime,
@@ -419,7 +438,7 @@
int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit());
buttonState |= actionButton;
NotifyMotionArgs pressArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
- mSource, displayId, policyFlags,
+ mSource, *mDisplayId, policyFlags,
AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
metaState, buttonState, MotionClassification::NONE,
AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
@@ -435,7 +454,7 @@
// Send hover move after UP to tell the application that the mouse is hovering now.
if (motionEventAction == AMOTION_EVENT_ACTION_UP && (mSource == AINPUT_SOURCE_MOUSE)) {
NotifyMotionArgs hoverArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
- mSource, displayId, policyFlags,
+ mSource, *mDisplayId, policyFlags,
AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
currentButtonState, MotionClassification::NONE,
AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
@@ -450,7 +469,7 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
NotifyMotionArgs scrollArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
- mSource, displayId, policyFlags,
+ mSource, *mDisplayId, policyFlags,
AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
currentButtonState, MotionClassification::NONE,
AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
@@ -462,7 +481,7 @@
// Synthesize key up from buttons if needed.
synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, readTime, getDeviceId(), mSource,
- displayId, policyFlags, lastButtonState, currentButtonState);
+ *mDisplayId, policyFlags, lastButtonState, currentButtonState);
mCursorMotionAccumulator.finishSync();
mCursorScrollAccumulator.finishSync();
@@ -477,16 +496,7 @@
}
std::optional<int32_t> CursorInputMapper::getAssociatedDisplayId() {
- if (mParameters.hasAssociatedDisplay) {
- if (mParameters.mode == Parameters::Mode::POINTER) {
- return std::make_optional(mPointerController->getDisplayId());
- } else {
- // If the device is orientationAware and not a mouse,
- // it expects to dispatch events to any display
- return std::make_optional(ADISPLAY_ID_NONE);
- }
- }
- return std::nullopt;
+ return mDisplayId;
}
} // namespace android
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h
index 75aeffb..a0229a7 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.h
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_CURSOR_INPUT_MAPPER_H
-#define _UI_INPUTREADER_CURSOR_INPUT_MAPPER_H
+#pragma once
#include "CursorButtonAccumulator.h"
#include "CursorScrollAccumulator.h"
@@ -111,6 +110,10 @@
VelocityControl mWheelXVelocityControl;
VelocityControl mWheelYVelocityControl;
+ // The display that events generated by this mapper should target. This can be set to
+ // ADISPLAY_ID_NONE to target the focused display. If there is no display target (i.e.
+ // std::nullopt), all events will be ignored.
+ std::optional<int32_t> mDisplayId;
int32_t mOrientation;
std::shared_ptr<PointerControllerInterface> mPointerController;
@@ -125,5 +128,3 @@
};
} // namespace android
-
-#endif // _UI_INPUTREADER_CURSOR_INPUT_MAPPER_H
diff --git a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h
index 516aa51..03d9909 100644
--- a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h
+++ b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_EXTERNAL_STYLUS_INPUT_MAPPER_H
-#define _UI_INPUTREADER_EXTERNAL_STYLUS_INPUT_MAPPER_H
+#pragma once
#include "InputMapper.h"
@@ -49,5 +48,3 @@
};
} // namespace android
-
-#endif // _UI_INPUTREADER_EXTERNAL_STYLUS_INPUT_MAPPER_H
\ No newline at end of file
diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h
index 7858728..5567cac 100644
--- a/services/inputflinger/reader/mapper/InputMapper.h
+++ b/services/inputflinger/reader/mapper/InputMapper.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_INPUT_MAPPER_H
-#define _UI_INPUTREADER_INPUT_MAPPER_H
+#pragma once
#include "EventHub.h"
#include "InputDevice.h"
@@ -109,5 +108,3 @@
};
} // namespace android
-
-#endif // _UI_INPUTREADER_INPUT_MAPPER_H
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.h b/services/inputflinger/reader/mapper/JoystickInputMapper.h
index 307bf5b..e002397 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.h
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_JOYSTICK_INPUT_MAPPER_H
-#define _UI_INPUTREADER_JOYSTICK_INPUT_MAPPER_H
+#pragma once
#include "InputMapper.h"
@@ -111,5 +110,3 @@
};
} // namespace android
-
-#endif // _UI_INPUTREADER_JOYSTICK_INPUT_MAPPER_H
\ No newline at end of file
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
index 31251f4..2136d25 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.h
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_KEYBOARD_INPUT_MAPPER_H
-#define _UI_INPUTREADER_KEYBOARD_INPUT_MAPPER_H
+#pragma once
#include "InputMapper.h"
@@ -102,5 +101,3 @@
};
} // namespace android
-
-#endif // _UI_INPUTREADER_KEYBOARD_INPUT_MAPPER_H
\ No newline at end of file
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
index fe8af5d..212c9c9 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_MULTI_TOUCH_INPUT_MAPPER_H
-#define _UI_INPUTREADER_MULTI_TOUCH_INPUT_MAPPER_H
+#pragma once
#include "TouchInputMapper.h"
@@ -122,5 +121,3 @@
};
} // namespace android
-
-#endif // _UI_INPUTREADER_MULTI_TOUCH_INPUT_MAPPER_H
\ No newline at end of file
diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h
index 1859355..42e2421 100644
--- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h
+++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_ROTARY_ENCODER_INPUT_MAPPER_H
-#define _UI_INPUTREADER_ROTARY_ENCODER_INPUT_MAPPER_H
+#pragma once
#include "CursorScrollAccumulator.h"
#include "InputMapper.h"
@@ -46,5 +45,3 @@
};
} // namespace android
-
-#endif // _UI_INPUTREADER_ROTARY_ENCODER_INPUT_MAPPER_H
\ No newline at end of file
diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.h b/services/inputflinger/reader/mapper/SensorInputMapper.h
index 27a6177..38d4c3c 100644
--- a/services/inputflinger/reader/mapper/SensorInputMapper.h
+++ b/services/inputflinger/reader/mapper/SensorInputMapper.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_SENSOR_INPUT_MAPPER_H
-#define _UI_INPUTREADER_SENSOR_INPUT_MAPPER_H
+#pragma once
#include "InputMapper.h"
@@ -133,5 +132,3 @@
};
} // namespace android
-
-#endif // _UI_INPUTREADER_SENSOR_INPUT_MAPPER_H
\ No newline at end of file
diff --git a/services/inputflinger/reader/mapper/SingleTouchInputMapper.h b/services/inputflinger/reader/mapper/SingleTouchInputMapper.h
index 9cb3f67..f54c195 100644
--- a/services/inputflinger/reader/mapper/SingleTouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/SingleTouchInputMapper.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_SINGLE_TOUCH_INPUT_MAPPER_H
-#define _UI_INPUTREADER_SINGLE_TOUCH_INPUT_MAPPER_H
+#pragma once
#include "SingleTouchMotionAccumulator.h"
#include "TouchInputMapper.h"
@@ -40,5 +39,3 @@
};
} // namespace android
-
-#endif // _UI_INPUTREADER_SINGLE_TOUCH_INPUT_MAPPER_H
\ No newline at end of file
diff --git a/services/inputflinger/reader/mapper/SwitchInputMapper.h b/services/inputflinger/reader/mapper/SwitchInputMapper.h
index 64b9aa2..e0c949f 100644
--- a/services/inputflinger/reader/mapper/SwitchInputMapper.h
+++ b/services/inputflinger/reader/mapper/SwitchInputMapper.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_SWITCH_INPUT_MAPPER_H
-#define _UI_INPUTREADER_SWITCH_INPUT_MAPPER_H
+#pragma once
#include "InputMapper.h"
@@ -41,5 +40,3 @@
};
} // namespace android
-
-#endif // _UI_INPUTREADER_SWITCH_INPUT_MAPPER_H
\ No newline at end of file
diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
index 31a3d2e..42d819b 100644
--- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
+++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H
-#define _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H
+#pragma once
#include <input/DisplayViewport.h>
#include <stdint.h>
@@ -99,5 +98,3 @@
}
} // namespace android
-
-#endif // _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 539e24a..8c241f2 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -2712,17 +2712,18 @@
// Update the velocity tracker.
{
- std::vector<VelocityTracker::Position> positions;
+ std::vector<float> positionsX;
+ std::vector<float> positionsY;
for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty();) {
uint32_t id = idBits.clearFirstMarkedBit();
const RawPointerData::Pointer& pointer =
mCurrentRawState.rawPointerData.pointerForId(id);
- float x = pointer.x * mPointerXMovementScale;
- float y = pointer.y * mPointerYMovementScale;
- positions.push_back({x, y});
+ positionsX.push_back(pointer.x * mPointerXMovementScale);
+ positionsY.push_back(pointer.y * mPointerYMovementScale);
}
mPointerGesture.velocityTracker.addMovement(when, mCurrentCookedState.fingerIdBits,
- positions);
+ {{AMOTION_EVENT_AXIS_X, positionsX},
+ {AMOTION_EVENT_AXIS_Y, positionsY}});
}
// If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning
@@ -2829,9 +2830,12 @@
float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed;
for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty();) {
uint32_t id = idBits.clearFirstMarkedBit();
- float vx, vy;
- if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) {
- float speed = hypotf(vx, vy);
+ std::optional<float> vx =
+ mPointerGesture.velocityTracker.getVelocity(AMOTION_EVENT_AXIS_X, id);
+ std::optional<float> vy =
+ mPointerGesture.velocityTracker.getVelocity(AMOTION_EVENT_AXIS_Y, id);
+ if (vx && vy) {
+ float speed = hypotf(*vx, *vy);
if (speed > bestSpeed) {
bestId = id;
bestSpeed = speed;
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index fe17006..bd4cff6 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H
-#define _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H
+#pragma once
#include <stdint.h>
@@ -805,5 +804,3 @@
};
} // namespace android
-
-#endif // _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H
diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.h b/services/inputflinger/reader/mapper/VibratorInputMapper.h
index d3c22b6..894c573 100644
--- a/services/inputflinger/reader/mapper/VibratorInputMapper.h
+++ b/services/inputflinger/reader/mapper/VibratorInputMapper.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_VIBRATOR_INPUT_MAPPER_H
-#define _UI_INPUTREADER_VIBRATOR_INPUT_MAPPER_H
+#pragma once
#include "InputMapper.h"
@@ -50,5 +49,3 @@
};
} // namespace android
-
-#endif // _UI_INPUTREADER_VIBRATOR_INPUT_MAPPER_H
\ No newline at end of file
diff --git a/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h b/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h
index 9e15906..ed4c789 100644
--- a/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h
+++ b/services/inputflinger/reader/mapper/accumulator/CursorButtonAccumulator.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_CURSOR_BUTTON_ACCUMULATOR_H
-#define _UI_INPUTREADER_CURSOR_BUTTON_ACCUMULATOR_H
+#pragma once
#include <stdint.h>
@@ -48,5 +47,3 @@
};
} // namespace android
-
-#endif // _UI_INPUTREADER_CURSOR_BUTTON_ACCUMULATOR_H
\ No newline at end of file
diff --git a/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h b/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h
index 1649559..ae1b7a3 100644
--- a/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h
+++ b/services/inputflinger/reader/mapper/accumulator/CursorScrollAccumulator.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_CURSOR_SCROLL_ACCUMULATOR_H
-#define _UI_INPUTREADER_CURSOR_SCROLL_ACCUMULATOR_H
+#pragma once
#include <stdint.h>
@@ -56,5 +55,3 @@
};
} // namespace android
-
-#endif // _UI_INPUTREADER_CURSOR_SCROLL_ACCUMULATOR_H
\ No newline at end of file
diff --git a/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.h b/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.h
index 4c011f1..93056f0 100644
--- a/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.h
+++ b/services/inputflinger/reader/mapper/accumulator/SingleTouchMotionAccumulator.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_SINGLE_TOUCH_MOTION_ACCUMULATOR_H
-#define _UI_INPUTREADER_SINGLE_TOUCH_MOTION_ACCUMULATOR_H
+#pragma once
#include <stdint.h>
@@ -53,5 +52,3 @@
};
} // namespace android
-
-#endif // _UI_INPUTREADER_SINGLE_TOUCH_MOTION_ACCUMULATOR_H
\ No newline at end of file
diff --git a/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h b/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h
index 22ebb72..7b889be 100644
--- a/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h
+++ b/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUTREADER_TOUCH_BUTTON_ACCUMULATOR_H
-#define _UI_INPUTREADER_TOUCH_BUTTON_ACCUMULATOR_H
+#pragma once
#include <stdint.h>
@@ -62,5 +61,3 @@
};
} // namespace android
-
-#endif // _UI_INPUTREADER_TOUCH_BUTTON_ACCUMULATOR_H
\ No newline at end of file
diff --git a/services/inputflinger/reporter/InputReporterInterface.h b/services/inputflinger/reporter/InputReporterInterface.h
index e5d3606..72a4aeb 100644
--- a/services/inputflinger/reporter/InputReporterInterface.h
+++ b/services/inputflinger/reporter/InputReporterInterface.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_INPUT_REPORTER_INTERFACE_H
-#define _UI_INPUT_REPORTER_INTERFACE_H
+#pragma once
#include <utils/RefBase.h>
@@ -49,5 +48,3 @@
sp<InputReporterInterface> createInputReporter();
} // namespace android
-
-#endif // _UI_INPUT_REPORTER_INTERFACE_H
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 851043d..ee6993c 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -31,6 +31,7 @@
#include <SingleTouchInputMapper.h>
#include <SwitchInputMapper.h>
#include <TestInputListener.h>
+#include <TestInputListenerMatchers.h>
#include <TouchInputMapper.h>
#include <UinputDevice.h>
#include <VibratorInputMapper.h>
@@ -47,7 +48,7 @@
namespace android {
using namespace ftl::flag_operators;
-
+using testing::AllOf;
using std::chrono_literals::operator""ms;
// Timeout for waiting for an expected event
@@ -59,7 +60,9 @@
// Arbitrary display properties.
static constexpr int32_t DISPLAY_ID = 0;
+static const std::string DISPLAY_UNIQUE_ID = "local:1";
static constexpr int32_t SECONDARY_DISPLAY_ID = DISPLAY_ID + 1;
+static const std::string SECONDARY_DISPLAY_UNIQUE_ID = "local:2";
static constexpr int32_t DISPLAY_WIDTH = 480;
static constexpr int32_t DISPLAY_HEIGHT = 800;
static constexpr int32_t VIRTUAL_DISPLAY_ID = 1;
@@ -78,6 +81,7 @@
static constexpr int32_t DEFAULT_BATTERY = 1;
static constexpr int32_t BATTERY_STATUS = 4;
static constexpr int32_t BATTERY_CAPACITY = 66;
+static const std::string BATTERY_DEVPATH = "/sys/devices/mydevice/power_supply/mybattery";
static constexpr int32_t LIGHT_BRIGHTNESS = 0x55000000;
static constexpr int32_t LIGHT_COLOR = 0x7F448866;
static constexpr int32_t LIGHT_PLAYER_ID = 2;
@@ -1014,7 +1018,12 @@
std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t deviceId,
int32_t batteryId) const override {
- return std::nullopt;
+ if (batteryId != DEFAULT_BATTERY) return {};
+ static const auto BATTERY_INFO = RawBatteryInfo{.id = DEFAULT_BATTERY,
+ .name = "default battery",
+ .flags = InputBatteryClass::CAPACITY,
+ .path = BATTERY_DEVPATH};
+ return BATTERY_INFO;
}
std::vector<int32_t> getRawLightIds(int32_t deviceId) const override {
@@ -2232,6 +2241,21 @@
ASSERT_EQ(mReader->getBatteryStatus(deviceId), BATTERY_STATUS);
}
+TEST_F(InputReaderTest, BatteryGetDevicePath) {
+ constexpr int32_t deviceId = END_RESERVED_ID + 1000;
+ ftl::Flags<InputDeviceClass> deviceClass =
+ InputDeviceClass::KEYBOARD | InputDeviceClass::BATTERY;
+ constexpr int32_t eventHubId = 1;
+ const char* DEVICE_LOCATION = "BLUETOOTH";
+ std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION);
+ device->addController<FakePeripheralController>(eventHubId);
+ mReader->pushNextDevice(device);
+
+ ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr));
+
+ ASSERT_EQ(mReader->getBatteryDevicePath(deviceId), BATTERY_DEVPATH);
+}
+
TEST_F(InputReaderTest, LightGetColor) {
constexpr int32_t deviceId = END_RESERVED_ID + 1000;
ftl::Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::LIGHT;
@@ -2909,7 +2933,6 @@
// Device should be disabled because it is associated with a specific display, but the
// corresponding display is not found.
- const std::string DISPLAY_UNIQUE_ID = "displayUniqueId";
mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID);
mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
InputReaderConfiguration::CHANGE_DISPLAY_INFO);
@@ -2940,7 +2963,6 @@
mDevice->addMapper<FakeInputMapper>(EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD);
mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0);
- const std::string DISPLAY_UNIQUE_ID = "displayUniqueId";
mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID);
mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
DISPLAY_ORIENTATION_0, /* isActive= */ true, DISPLAY_UNIQUE_ID,
@@ -4255,10 +4277,14 @@
int32_t rotatedX, int32_t rotatedY);
void prepareDisplay(int32_t orientation) {
- const std::string uniqueId = "local:0";
- const ViewportType viewportType = ViewportType::INTERNAL;
- setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
- orientation, uniqueId, NO_PORT, viewportType);
+ setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation,
+ DISPLAY_UNIQUE_ID, NO_PORT, ViewportType::INTERNAL);
+ }
+
+ void prepareSecondaryDisplay() {
+ setDisplayInfoAndReconfigure(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ DISPLAY_ORIENTATION_0, SECONDARY_DISPLAY_UNIQUE_ID, NO_PORT,
+ ViewportType::EXTERNAL);
}
static void assertCursorPointerCoords(const PointerCoords& coords, float x, float y,
@@ -4535,6 +4561,7 @@
}
TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldNotRotateMotions) {
+ mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID);
addConfigurationProperty("cursor.mode", "navigation");
// InputReader works in the un-rotated coordinate space, so orientation-aware devices do not
// need to be rotated.
@@ -4553,11 +4580,13 @@
}
TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldRotateMotions) {
+ mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID);
addConfigurationProperty("cursor.mode", "navigation");
// Since InputReader works in the un-rotated coordinate space, only devices that are not
// orientation-aware are affected by display rotation.
CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
+ clearViewports();
prepareDisplay(DISPLAY_ORIENTATION_0);
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, 1));
@@ -4568,6 +4597,7 @@
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, -1, 0));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1));
+ clearViewports();
prepareDisplay(DISPLAY_ORIENTATION_90);
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, -1, 0));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, 1));
@@ -4578,6 +4608,7 @@
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, -1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, -1));
+ clearViewports();
prepareDisplay(DISPLAY_ORIENTATION_180);
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, -1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, -1));
@@ -4588,6 +4619,7 @@
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 1, 0));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, -1));
+ clearViewports();
prepareDisplay(DISPLAY_ORIENTATION_270);
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 1, 0));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, -1));
@@ -5084,33 +5116,78 @@
ASSERT_EQ(20, args.pointerCoords[0].getY());
}
-TEST_F(CursorInputMapperTest, Process_ShouldHandleDisplayId) {
+TEST_F(CursorInputMapperTest, ConfigureDisplayId_NoAssociatedViewport) {
CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
- // Setup for second display.
- constexpr int32_t SECOND_DISPLAY_ID = 1;
- const std::string SECOND_DISPLAY_UNIQUE_ID = "local:1";
- mFakePolicy->addDisplayViewport(SECOND_DISPLAY_ID, 800, 480, DISPLAY_ORIENTATION_0,
- true /*isActive*/, SECOND_DISPLAY_UNIQUE_ID, NO_PORT,
- ViewportType::EXTERNAL);
- mFakePolicy->setDefaultPointerDisplayId(SECOND_DISPLAY_ID);
+ // Set up the default display.
+ prepareDisplay(DISPLAY_ORIENTATION_90);
+
+ // Set up the secondary display as the display on which the pointer should be shown.
+ // The InputDevice is not associated with any display.
+ prepareSecondaryDisplay();
+ mFakePolicy->setDefaultPointerDisplayId(SECONDARY_DISPLAY_ID);
configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
- mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
+ mFakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
mFakePointerController->setPosition(100, 200);
mFakePointerController->setButtonState(0);
- NotifyMotionArgs args;
+ // Ensure input events are generated for the secondary display.
process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10);
process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20);
process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
- ASSERT_EQ(AINPUT_SOURCE_MOUSE, args.source);
- ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action);
- ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
- 110.0f, 220.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
+ WithSource(AINPUT_SOURCE_MOUSE), WithDisplayId(SECONDARY_DISPLAY_ID),
+ WithCoords(110.0f, 220.0f))));
ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 110.0f, 220.0f));
- ASSERT_EQ(SECOND_DISPLAY_ID, args.displayId);
+}
+
+TEST_F(CursorInputMapperTest, ConfigureDisplayId_WithAssociatedViewport) {
+ CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
+
+ // Set up the default display.
+ prepareDisplay(DISPLAY_ORIENTATION_90);
+
+ // Set up the secondary display as the display on which the pointer should be shown,
+ // and associate the InputDevice with the secondary display.
+ prepareSecondaryDisplay();
+ mFakePolicy->setDefaultPointerDisplayId(SECONDARY_DISPLAY_ID);
+ mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, SECONDARY_DISPLAY_UNIQUE_ID);
+ configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+
+ mFakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
+ mFakePointerController->setPosition(100, 200);
+ mFakePointerController->setButtonState(0);
+
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
+ WithSource(AINPUT_SOURCE_MOUSE), WithDisplayId(SECONDARY_DISPLAY_ID),
+ WithCoords(110.0f, 220.0f))));
+ ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 110.0f, 220.0f));
+}
+
+TEST_F(CursorInputMapperTest, ConfigureDisplayId_IgnoresEventsForMismatchedPointerDisplay) {
+ CursorInputMapper& mapper = addMapperAndConfigure<CursorInputMapper>();
+
+ // Set up the default display as the display on which the pointer should be shown.
+ prepareDisplay(DISPLAY_ORIENTATION_90);
+ mFakePolicy->setDefaultPointerDisplayId(DISPLAY_ID);
+
+ // Associate the InputDevice with the secondary display.
+ prepareSecondaryDisplay();
+ mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, SECONDARY_DISPLAY_UNIQUE_ID);
+ configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+
+ // The mapper should not generate any events because it is associated with a display that is
+ // different from the pointer display.
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20);
+ process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
}
// --- TouchInputMapperTest ---
diff --git a/services/inputflinger/tests/TestInputListener.h b/services/inputflinger/tests/TestInputListener.h
index 0bdfc6b..cad698f 100644
--- a/services/inputflinger/tests/TestInputListener.h
+++ b/services/inputflinger/tests/TestInputListener.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_TEST_INPUT_LISTENER_H
-#define _UI_TEST_INPUT_LISTENER_H
+#pragma once
#include <android-base/thread_annotations.h>
#include <gmock/gmock.h>
@@ -103,4 +102,3 @@
};
} // namespace android
-#endif
diff --git a/services/inputflinger/tests/TestInputListenerMatchers.h b/services/inputflinger/tests/TestInputListenerMatchers.h
new file mode 100644
index 0000000..03736a3
--- /dev/null
+++ b/services/inputflinger/tests/TestInputListenerMatchers.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/input.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+
+MATCHER_P(WithMotionAction, action, "InputEvent with specified action") {
+ if (action == AMOTION_EVENT_ACTION_CANCEL) {
+ *result_listener << "expected FLAG_CANCELED to be set with ACTION_CANCEL, but was not set";
+ return (arg.flags & AMOTION_EVENT_FLAG_CANCELED) != 0;
+ }
+ *result_listener << "expected action " << MotionEvent::actionToString(action) << ", but got "
+ << MotionEvent::actionToString(arg.action);
+ return action == arg.action;
+}
+
+MATCHER_P(WithSource, source, "InputEvent with specified source") {
+ *result_listener << "expected source " << source << ", but got " << arg.source;
+ return arg.source == source;
+}
+
+MATCHER_P(WithDisplayId, displayId, "InputEvent with specified displayId") {
+ *result_listener << "expected displayId " << displayId << ", but got " << arg.displayId;
+ return arg.displayId == displayId;
+}
+
+MATCHER_P2(WithCoords, x, y, "InputEvent with specified coords") {
+ const auto argX = arg.pointerCoords[0].getX();
+ const auto argY = arg.pointerCoords[0].getY();
+ *result_listener << "expected coords (" << x << ", " << y << "), but got (" << argX << ", "
+ << argY << ")";
+ return argX == x && argY == y;
+}
+
+MATCHER_P(WithFlags, flags, "InputEvent with specified flags") {
+ *result_listener << "expected flags " << flags << ", but got " << arg.flags;
+ return arg.flags == flags;
+}
+
+} // namespace android
diff --git a/services/inputflinger/tests/UinputDevice.h b/services/inputflinger/tests/UinputDevice.h
index a37fc2b..e0ff8c3 100644
--- a/services/inputflinger/tests/UinputDevice.h
+++ b/services/inputflinger/tests/UinputDevice.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _UI_TEST_INPUT_UINPUT_INJECTOR_H
-#define _UI_TEST_INPUT_UINPUT_INJECTOR_H
+#pragma once
#include <android-base/unique_fd.h>
#include <gtest/gtest.h>
@@ -155,5 +154,3 @@
};
} // namespace android
-
-#endif // _UI_TEST_INPUT_UINPUT_INJECTOR_H
diff --git a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
index 526e4eb..4c84160 100644
--- a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
+++ b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
@@ -24,6 +24,7 @@
#include "ui/events/ozone/evdev/touch_filter/neural_stylus_palm_detection_filter.h"
#include "TestInputListener.h"
+#include "TestInputListenerMatchers.h"
using ::testing::AllOf;
@@ -55,21 +56,6 @@
constexpr int32_t FLAG_CANCELED = AMOTION_EVENT_FLAG_CANCELED;
-MATCHER_P(WithAction, action, "MotionEvent with specified action") {
- bool result = true;
- if (action == CANCEL) {
- result &= (arg.flags & FLAG_CANCELED) != 0;
- }
- result &= arg.action == action;
- *result_listener << "expected to receive " << MotionEvent::actionToString(action)
- << " but received " << MotionEvent::actionToString(arg.action) << " instead.";
- return result;
-}
-
-MATCHER_P(WithFlags, flags, "MotionEvent with specified flags") {
- return arg.flags == flags;
-}
-
static nsecs_t toNs(std::chrono::nanoseconds duration) {
return duration.count();
}
@@ -605,19 +591,19 @@
// Small touch down
NotifyMotionArgs args1 = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2, 3}});
mBlocker->notifyMotion(&args1);
- mTestListener.assertNotifyMotionWasCalled(WithAction(DOWN));
+ mTestListener.assertNotifyMotionWasCalled(WithMotionAction(DOWN));
// Large touch oval on the next move
NotifyMotionArgs args2 =
generateMotionArgs(0 /*downTime*/, RESAMPLE_PERIOD, MOVE, {{4, 5, 200}});
mBlocker->notifyMotion(&args2);
- mTestListener.assertNotifyMotionWasCalled(WithAction(MOVE));
+ mTestListener.assertNotifyMotionWasCalled(WithMotionAction(MOVE));
// Lift up the touch to force the model to decide on whether it's a palm
NotifyMotionArgs args3 =
generateMotionArgs(0 /*downTime*/, 2 * RESAMPLE_PERIOD, UP, {{4, 5, 200}});
mBlocker->notifyMotion(&args3);
- mTestListener.assertNotifyMotionWasCalled(WithAction(CANCEL));
+ mTestListener.assertNotifyMotionWasCalled(WithMotionAction(CANCEL));
}
/**
@@ -633,14 +619,14 @@
NotifyMotionArgs args1 = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2, 3}});
args1.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
mBlocker->notifyMotion(&args1);
- mTestListener.assertNotifyMotionWasCalled(WithAction(DOWN));
+ mTestListener.assertNotifyMotionWasCalled(WithMotionAction(DOWN));
// Move the stylus, setting large TOUCH_MAJOR/TOUCH_MINOR dimensions
NotifyMotionArgs args2 =
generateMotionArgs(0 /*downTime*/, RESAMPLE_PERIOD, MOVE, {{4, 5, 200}});
args2.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
mBlocker->notifyMotion(&args2);
- mTestListener.assertNotifyMotionWasCalled(WithAction(MOVE));
+ mTestListener.assertNotifyMotionWasCalled(WithMotionAction(MOVE));
// Lift up the stylus. If it were a touch event, this would force the model to decide on whether
// it's a palm.
@@ -648,7 +634,7 @@
generateMotionArgs(0 /*downTime*/, 2 * RESAMPLE_PERIOD, UP, {{4, 5, 200}});
args3.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
mBlocker->notifyMotion(&args3);
- mTestListener.assertNotifyMotionWasCalled(WithAction(UP));
+ mTestListener.assertNotifyMotionWasCalled(WithMotionAction(UP));
}
/**
@@ -664,21 +650,21 @@
// Touch down
NotifyMotionArgs args1 = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2, 3}});
mBlocker->notifyMotion(&args1);
- mTestListener.assertNotifyMotionWasCalled(WithAction(DOWN));
+ mTestListener.assertNotifyMotionWasCalled(WithMotionAction(DOWN));
// Stylus pointer down
NotifyMotionArgs args2 = generateMotionArgs(0 /*downTime*/, RESAMPLE_PERIOD, POINTER_1_DOWN,
{{1, 2, 3}, {10, 20, 30}});
args2.pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
mBlocker->notifyMotion(&args2);
- mTestListener.assertNotifyMotionWasCalled(WithAction(POINTER_1_DOWN));
+ mTestListener.assertNotifyMotionWasCalled(WithMotionAction(POINTER_1_DOWN));
// Large touch oval on the next finger move
NotifyMotionArgs args3 = generateMotionArgs(0 /*downTime*/, 2 * RESAMPLE_PERIOD, MOVE,
{{1, 2, 300}, {11, 21, 30}});
args3.pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
mBlocker->notifyMotion(&args3);
- mTestListener.assertNotifyMotionWasCalled(WithAction(MOVE));
+ mTestListener.assertNotifyMotionWasCalled(WithMotionAction(MOVE));
// Lift up the finger pointer. It should be canceled due to the heuristic filter.
NotifyMotionArgs args4 = generateMotionArgs(0 /*downTime*/, 3 * RESAMPLE_PERIOD, POINTER_0_UP,
@@ -686,14 +672,14 @@
args4.pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
mBlocker->notifyMotion(&args4);
mTestListener.assertNotifyMotionWasCalled(
- AllOf(WithAction(POINTER_0_UP), WithFlags(FLAG_CANCELED)));
+ AllOf(WithMotionAction(POINTER_0_UP), WithFlags(FLAG_CANCELED)));
NotifyMotionArgs args5 =
generateMotionArgs(0 /*downTime*/, 4 * RESAMPLE_PERIOD, MOVE, {{12, 22, 30}});
args5.pointerProperties[0].id = args4.pointerProperties[1].id;
args5.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
mBlocker->notifyMotion(&args5);
- mTestListener.assertNotifyMotionWasCalled(WithAction(MOVE));
+ mTestListener.assertNotifyMotionWasCalled(WithMotionAction(MOVE));
// Lift up the stylus pointer
NotifyMotionArgs args6 =
@@ -701,7 +687,7 @@
args6.pointerProperties[0].id = args4.pointerProperties[1].id;
args6.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
mBlocker->notifyMotion(&args6);
- mTestListener.assertNotifyMotionWasCalled(WithAction(UP));
+ mTestListener.assertNotifyMotionWasCalled(WithMotionAction(UP));
}
using UnwantedInteractionBlockerTestDeathTest = UnwantedInteractionBlockerTest;
diff --git a/services/inputflinger/tests/fuzzers/Android.bp b/services/inputflinger/tests/fuzzers/Android.bp
index 455a1e2..f4ecba2 100644
--- a/services/inputflinger/tests/fuzzers/Android.bp
+++ b/services/inputflinger/tests/fuzzers/Android.bp
@@ -46,3 +46,105 @@
cc: ["android-framework-input@google.com"],
},
}
+
+cc_defaults {
+ name: "inputflinger_fuzz_defaults",
+ defaults: [
+ "inputflinger_defaults",
+ ],
+ include_dirs: [
+ "frameworks/native/services/inputflinger",
+ ],
+ shared_libs: [
+ "android.hardware.input.classifier@1.0",
+ "android.hardware.input.processor-V1-ndk",
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "liblog",
+ "libutils",
+ "libui",
+ "libinput",
+ "libinputflinger",
+ "libinputreader",
+ "libinputflinger_base",
+ "libstatslog",
+ ],
+ header_libs: [
+ "libbatteryservice_headers",
+ "libinputreader_headers",
+ ],
+ fuzz_config: {
+ cc: ["android-framework-input@google.com"],
+ },
+}
+
+cc_fuzz {
+ name: "inputflinger_cursor_input_fuzzer",
+ defaults: [
+ "inputflinger_fuzz_defaults",
+ ],
+ srcs: [
+ "CursorInputFuzzer.cpp",
+ ],
+}
+
+cc_fuzz {
+ name: "inputflinger_keyboard_input_fuzzer",
+ defaults: [
+ "inputflinger_fuzz_defaults",
+ ],
+ srcs: [
+ "KeyboardInputFuzzer.cpp",
+ ],
+}
+
+cc_fuzz {
+ name: "inputflinger_multitouch_input_fuzzer",
+ defaults: [
+ "inputflinger_fuzz_defaults",
+ ],
+ srcs: [
+ "MultiTouchInputFuzzer.cpp",
+ ],
+}
+
+cc_fuzz {
+ name: "inputflinger_switch_input_fuzzer",
+ defaults: [
+ "inputflinger_fuzz_defaults",
+ ],
+ srcs: [
+ "SwitchInputFuzzer.cpp",
+ ],
+}
+
+cc_fuzz {
+ name: "inputflinger_input_reader_fuzzer",
+ defaults: [
+ "inputflinger_fuzz_defaults",
+ ],
+ srcs: [
+ "InputReaderFuzzer.cpp",
+ ],
+}
+
+cc_fuzz {
+ name: "inputflinger_blocking_queue_fuzzer",
+ defaults: [
+ "inputflinger_fuzz_defaults",
+ ],
+ srcs: [
+ "BlockingQueueFuzzer.cpp",
+ ],
+}
+
+cc_fuzz {
+ name: "inputflinger_input_classifier_fuzzer",
+ defaults: [
+ "inputflinger_fuzz_defaults",
+ ],
+ srcs: [
+ "InputClassifierFuzzer.cpp",
+ ],
+}
diff --git a/services/inputflinger/tests/fuzzers/BlockingQueueFuzzer.cpp b/services/inputflinger/tests/fuzzers/BlockingQueueFuzzer.cpp
new file mode 100644
index 0000000..d2595bf
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/BlockingQueueFuzzer.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#include <fuzzer/FuzzedDataProvider.h>
+#include <thread>
+#include "BlockingQueue.h"
+
+// Chosen to be a number large enough for variation in fuzzer runs, but not consume too much memory.
+static constexpr size_t MAX_CAPACITY = 1024;
+
+namespace android {
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+ size_t capacity = fdp.ConsumeIntegralInRange<size_t>(1, MAX_CAPACITY);
+ size_t filled = 0;
+ BlockingQueue<int32_t> queue(capacity);
+
+ while (fdp.remaining_bytes() > 0) {
+ fdp.PickValueInArray<std::function<void()>>({
+ [&]() -> void {
+ size_t numPushes = fdp.ConsumeIntegralInRange<size_t>(0, capacity + 1);
+ for (size_t i = 0; i < numPushes; i++) {
+ queue.push(fdp.ConsumeIntegral<int32_t>());
+ }
+ filled = std::min(capacity, filled + numPushes);
+ },
+ [&]() -> void {
+ // Pops blocks if it is empty, so only pop up to num elements inserted.
+ size_t numPops = fdp.ConsumeIntegralInRange<size_t>(0, filled);
+ for (size_t i = 0; i < numPops; i++) {
+ queue.pop();
+ }
+ filled > numPops ? filled -= numPops : filled = 0;
+ },
+ [&]() -> void {
+ queue.clear();
+ filled = 0;
+ },
+ [&]() -> void {
+ int32_t eraseElement = fdp.ConsumeIntegral<int32_t>();
+ queue.erase([&](int32_t element) {
+ if (element == eraseElement) {
+ filled--;
+ return true;
+ }
+ return false;
+ });
+ },
+ })();
+ }
+
+ return 0;
+}
+
+} // namespace android
diff --git a/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp
new file mode 100644
index 0000000..4b542aa
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#include <CursorInputMapper.h>
+#include <FuzzContainer.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+namespace android {
+
+static void addProperty(FuzzContainer& fuzzer, std::shared_ptr<FuzzedDataProvider> fdp) {
+ // Pick a random property to set for the mapper to have set.
+ fdp->PickValueInArray<std::function<void()>>(
+ {[&]() -> void { fuzzer.addProperty("cursor.mode", "pointer"); },
+ [&]() -> void { fuzzer.addProperty("cursor.mode", "navigation"); },
+ [&]() -> void {
+ fuzzer.addProperty("cursor.mode", fdp->ConsumeRandomLengthString(100).data());
+ },
+ [&]() -> void {
+ fuzzer.addProperty("cursor.orientationAware",
+ fdp->ConsumeRandomLengthString(100).data());
+ }})();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
+ std::shared_ptr<FuzzedDataProvider> fdp = std::make_shared<FuzzedDataProvider>(data, size);
+ FuzzContainer fuzzer(fdp);
+
+ CursorInputMapper& mapper = fuzzer.getMapper<CursorInputMapper>();
+ auto policyConfig = fuzzer.getPolicyConfig();
+
+ // Loop through mapper operations until randomness is exhausted.
+ while (fdp->remaining_bytes() > 0) {
+ fdp->PickValueInArray<std::function<void()>>({
+ [&]() -> void { addProperty(fuzzer, fdp); },
+ [&]() -> void {
+ std::string dump;
+ mapper.dump(dump);
+ },
+ [&]() -> void { mapper.getSources(); },
+ [&]() -> void {
+ mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig,
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ [&]() -> void {
+ // Need to reconfigure with 0 or you risk a NPE.
+ mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig, 0);
+ InputDeviceInfo info;
+ mapper.populateDeviceInfo(&info);
+ },
+ [&]() -> void {
+ int32_t type, code;
+ type = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidTypes)
+ : fdp->ConsumeIntegral<int32_t>();
+ code = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidCodes)
+ : fdp->ConsumeIntegral<int32_t>();
+
+ // Need to reconfigure with 0 or you risk a NPE.
+ mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig, 0);
+ RawEvent rawEvent{fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeIntegral<int32_t>(),
+ type,
+ code,
+ fdp->ConsumeIntegral<int32_t>()};
+ mapper.process(&rawEvent);
+ },
+ [&]() -> void { mapper.reset(fdp->ConsumeIntegral<nsecs_t>()); },
+ [&]() -> void {
+ mapper.getScanCodeState(fdp->ConsumeIntegral<uint32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ [&]() -> void {
+ // Need to reconfigure with 0 or you risk a NPE.
+ mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig, 0);
+ mapper.getAssociatedDisplayId();
+ },
+ })();
+ }
+
+ return 0;
+}
+
+} // namespace android
diff --git a/services/inputflinger/tests/fuzzers/FuzzContainer.h b/services/inputflinger/tests/fuzzers/FuzzContainer.h
new file mode 100644
index 0000000..62615d0
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/FuzzContainer.h
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <InputDevice.h>
+#include <InputMapper.h>
+#include <InputReader.h>
+#include <MapperHelpers.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+namespace android {
+
+class FuzzContainer {
+ std::shared_ptr<FuzzEventHub> mFuzzEventHub;
+ sp<FuzzInputReaderPolicy> mFuzzPolicy;
+ std::unique_ptr<FuzzInputListener> mFuzzListener;
+ std::unique_ptr<FuzzInputReaderContext> mFuzzContext;
+ std::unique_ptr<InputDevice> mFuzzDevice;
+ InputReaderConfiguration mPolicyConfig;
+ std::shared_ptr<FuzzedDataProvider> mFdp;
+
+public:
+ FuzzContainer(std::shared_ptr<FuzzedDataProvider> fdp) : mFdp(fdp) {
+ // Setup parameters.
+ std::string deviceName = mFdp->ConsumeRandomLengthString(16);
+ std::string deviceLocation = mFdp->ConsumeRandomLengthString(12);
+ int32_t deviceID = mFdp->ConsumeIntegralInRange<int32_t>(0, 5);
+ int32_t deviceGeneration = mFdp->ConsumeIntegralInRange<int32_t>(/*from*/ 0, /*to*/ 5);
+
+ // Create mocked objects.
+ mFuzzEventHub = std::make_shared<FuzzEventHub>(mFdp);
+ mFuzzPolicy = sp<FuzzInputReaderPolicy>::make(mFdp);
+ mFuzzListener = std::make_unique<FuzzInputListener>();
+ mFuzzContext = std::make_unique<FuzzInputReaderContext>(mFuzzEventHub, mFuzzPolicy,
+ *mFuzzListener, mFdp);
+
+ InputDeviceIdentifier identifier;
+ identifier.name = deviceName;
+ identifier.location = deviceLocation;
+ mFuzzDevice = std::make_unique<InputDevice>(mFuzzContext.get(), deviceID, deviceGeneration,
+ identifier);
+ mFuzzPolicy->getReaderConfiguration(&mPolicyConfig);
+ }
+
+ ~FuzzContainer() {}
+
+ void configureDevice() {
+ nsecs_t arbitraryTime = mFdp->ConsumeIntegral<nsecs_t>();
+ mFuzzDevice->configure(arbitraryTime, &mPolicyConfig, 0);
+ mFuzzDevice->reset(arbitraryTime);
+ }
+
+ void addProperty(std::string key, std::string value) {
+ mFuzzEventHub->addProperty(key, value);
+ configureDevice();
+ }
+
+ InputReaderConfiguration& getPolicyConfig() { return mPolicyConfig; }
+
+ template <class T, typename... Args>
+ T& getMapper(Args... args) {
+ T& mapper = mFuzzDevice->addMapper<T>(mFdp->ConsumeIntegral<int32_t>(), args...);
+ configureDevice();
+ return mapper;
+ }
+};
+
+} // namespace android
diff --git a/services/inputflinger/tests/fuzzers/InputClassifierFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputClassifierFuzzer.cpp
new file mode 100644
index 0000000..c407cff
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/InputClassifierFuzzer.cpp
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+#include <MapperHelpers.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include "InputCommonConverter.h"
+#include "InputProcessor.h"
+
+namespace android {
+
+static constexpr int32_t MAX_AXES = 64;
+
+// Used by two fuzz operations and a bit lengthy, so pulled out into a function.
+NotifyMotionArgs generateFuzzedMotionArgs(FuzzedDataProvider &fdp) {
+ // Create a basic motion event for testing
+ PointerProperties properties;
+ properties.id = 0;
+ properties.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+ PointerCoords coords;
+ coords.clear();
+ for (int32_t i = 0; i < fdp.ConsumeIntegralInRange<int32_t>(0, MAX_AXES); i++) {
+ coords.setAxisValue(fdp.ConsumeIntegral<int32_t>(), fdp.ConsumeFloatingPoint<float>());
+ }
+
+ const nsecs_t downTime = 2;
+ const nsecs_t readTime = downTime + fdp.ConsumeIntegralInRange<nsecs_t>(0, 1E8);
+ NotifyMotionArgs motionArgs(fdp.ConsumeIntegral<uint32_t>() /*sequenceNum*/,
+ downTime /*eventTime*/, readTime,
+ fdp.ConsumeIntegral<int32_t>() /*deviceId*/, AINPUT_SOURCE_ANY,
+ ADISPLAY_ID_DEFAULT,
+ fdp.ConsumeIntegral<uint32_t>() /*policyFlags*/,
+ AMOTION_EVENT_ACTION_DOWN,
+ fdp.ConsumeIntegral<int32_t>() /*actionButton*/,
+ fdp.ConsumeIntegral<int32_t>() /*flags*/, AMETA_NONE,
+ fdp.ConsumeIntegral<int32_t>() /*buttonState*/,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
+ 1 /*pointerCount*/, &properties, &coords,
+ fdp.ConsumeFloatingPoint<float>() /*xPrecision*/,
+ fdp.ConsumeFloatingPoint<float>() /*yPrecision*/,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, downTime,
+ {} /*videoFrames*/);
+ return motionArgs;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+
+ std::unique_ptr<FuzzInputListener> mFuzzListener = std::make_unique<FuzzInputListener>();
+ std::unique_ptr<InputProcessorInterface> mClassifier =
+ std::make_unique<InputProcessor>(*mFuzzListener);
+
+ while (fdp.remaining_bytes() > 0) {
+ fdp.PickValueInArray<std::function<void()>>({
+ [&]() -> void {
+ // SendToNextStage_NotifyConfigurationChangedArgs
+ NotifyConfigurationChangedArgs
+ args(fdp.ConsumeIntegral<uint32_t>() /*sequenceNum*/,
+ fdp.ConsumeIntegral<nsecs_t>() /*eventTime*/);
+ mClassifier->notifyConfigurationChanged(&args);
+ },
+ [&]() -> void {
+ // SendToNextStage_NotifyKeyArgs
+ const nsecs_t eventTime = fdp.ConsumeIntegral<nsecs_t>();
+ const nsecs_t readTime =
+ eventTime + fdp.ConsumeIntegralInRange<nsecs_t>(0, 1E8);
+ NotifyKeyArgs keyArgs(fdp.ConsumeIntegral<uint32_t>() /*sequenceNum*/,
+ eventTime, readTime,
+ fdp.ConsumeIntegral<int32_t>() /*deviceId*/,
+ AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_DEFAULT,
+ fdp.ConsumeIntegral<uint32_t>() /*policyFlags*/,
+ AKEY_EVENT_ACTION_DOWN,
+ fdp.ConsumeIntegral<int32_t>() /*flags*/, AKEYCODE_HOME,
+ fdp.ConsumeIntegral<int32_t>() /*scanCode*/, AMETA_NONE,
+ fdp.ConsumeIntegral<nsecs_t>() /*downTime*/);
+
+ mClassifier->notifyKey(&keyArgs);
+ },
+ [&]() -> void {
+ // SendToNextStage_NotifyMotionArgs
+ NotifyMotionArgs motionArgs = generateFuzzedMotionArgs(fdp);
+ mClassifier->notifyMotion(&motionArgs);
+ },
+ [&]() -> void {
+ // SendToNextStage_NotifySwitchArgs
+ NotifySwitchArgs switchArgs(fdp.ConsumeIntegral<uint32_t>() /*sequenceNum*/,
+ fdp.ConsumeIntegral<nsecs_t>() /*eventTime*/,
+ fdp.ConsumeIntegral<uint32_t>() /*policyFlags*/,
+ fdp.ConsumeIntegral<uint32_t>() /*switchValues*/,
+ fdp.ConsumeIntegral<uint32_t>() /*switchMask*/);
+
+ mClassifier->notifySwitch(&switchArgs);
+ },
+ [&]() -> void {
+ // SendToNextStage_NotifyDeviceResetArgs
+ NotifyDeviceResetArgs resetArgs(fdp.ConsumeIntegral<uint32_t>() /*sequenceNum*/,
+ fdp.ConsumeIntegral<nsecs_t>() /*eventTime*/,
+ fdp.ConsumeIntegral<int32_t>() /*deviceId*/);
+
+ mClassifier->notifyDeviceReset(&resetArgs);
+ },
+ [&]() -> void {
+ // InputClassifierConverterTest
+ const NotifyMotionArgs motionArgs = generateFuzzedMotionArgs(fdp);
+ aidl::android::hardware::input::common::MotionEvent motionEvent =
+ notifyMotionArgsToHalMotionEvent(motionArgs);
+ },
+ })();
+ }
+ return 0;
+}
+
+} // namespace android
diff --git a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
new file mode 100644
index 0000000..f5bd297
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
@@ -0,0 +1,284 @@
+/*
+ * 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.
+ */
+
+#include <InputReader.h>
+#include <MapperHelpers.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <input/InputDevice.h>
+#include <chrono>
+#include <thread>
+
+namespace android {
+
+constexpr InputDeviceSensorType kInputDeviceSensorType[] = {
+ InputDeviceSensorType::ACCELEROMETER,
+ InputDeviceSensorType::MAGNETIC_FIELD,
+ InputDeviceSensorType::ORIENTATION,
+ InputDeviceSensorType::GYROSCOPE,
+ InputDeviceSensorType::LIGHT,
+ InputDeviceSensorType::PRESSURE,
+ InputDeviceSensorType::TEMPERATURE,
+ InputDeviceSensorType::PROXIMITY,
+ InputDeviceSensorType::GRAVITY,
+ InputDeviceSensorType::LINEAR_ACCELERATION,
+ InputDeviceSensorType::ROTATION_VECTOR,
+ InputDeviceSensorType::RELATIVE_HUMIDITY,
+ InputDeviceSensorType::AMBIENT_TEMPERATURE,
+ InputDeviceSensorType::MAGNETIC_FIELD_UNCALIBRATED,
+ InputDeviceSensorType::GAME_ROTATION_VECTOR,
+ InputDeviceSensorType::GYROSCOPE_UNCALIBRATED,
+ InputDeviceSensorType::SIGNIFICANT_MOTION,
+};
+
+class FuzzInputReader : public InputReaderInterface {
+public:
+ FuzzInputReader(std::shared_ptr<EventHubInterface> fuzzEventHub,
+ const sp<InputReaderPolicyInterface>& fuzzPolicy,
+ InputListenerInterface& fuzzListener) {
+ reader = std::make_unique<InputReader>(fuzzEventHub, fuzzPolicy, fuzzListener);
+ }
+
+ void dump(std::string& dump) { reader->dump(dump); }
+
+ void monitor() { reader->monitor(); }
+
+ bool isInputDeviceEnabled(int32_t deviceId) { return reader->isInputDeviceEnabled(deviceId); }
+
+ status_t start() { return reader->start(); }
+
+ status_t stop() { return reader->stop(); }
+
+ std::vector<InputDeviceInfo> getInputDevices() const { return reader->getInputDevices(); }
+
+ int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask, int32_t scanCode) {
+ return reader->getScanCodeState(deviceId, sourceMask, scanCode);
+ }
+
+ int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, int32_t keyCode) {
+ return reader->getKeyCodeState(deviceId, sourceMask, keyCode);
+ }
+
+ int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t sw) {
+ return reader->getSwitchState(deviceId, sourceMask, sw);
+ }
+
+ void toggleCapsLockState(int32_t deviceId) { reader->toggleCapsLockState(deviceId); }
+
+ bool hasKeys(int32_t deviceId, uint32_t sourceMask, const std::vector<int32_t>& keyCodes,
+ uint8_t* outFlags) {
+ return reader->hasKeys(deviceId, sourceMask, keyCodes, outFlags);
+ }
+
+ void requestRefreshConfiguration(uint32_t changes) {
+ reader->requestRefreshConfiguration(changes);
+ }
+
+ void vibrate(int32_t deviceId, const VibrationSequence& sequence, ssize_t repeat,
+ int32_t token) {
+ reader->vibrate(deviceId, sequence, repeat, token);
+ }
+
+ void cancelVibrate(int32_t deviceId, int32_t token) { reader->cancelVibrate(deviceId, token); }
+
+ bool isVibrating(int32_t deviceId) { return reader->isVibrating(deviceId); }
+
+ std::vector<int32_t> getVibratorIds(int32_t deviceId) {
+ return reader->getVibratorIds(deviceId);
+ }
+
+ std::optional<int32_t> getBatteryCapacity(int32_t deviceId) {
+ return reader->getBatteryCapacity(deviceId);
+ }
+
+ std::optional<int32_t> getBatteryStatus(int32_t deviceId) {
+ return reader->getBatteryStatus(deviceId);
+ }
+
+ std::optional<std::string> getBatteryDevicePath(int32_t deviceId) {
+ return reader->getBatteryDevicePath(deviceId);
+ }
+
+ std::vector<InputDeviceLightInfo> getLights(int32_t deviceId) {
+ return reader->getLights(deviceId);
+ }
+
+ std::vector<InputDeviceSensorInfo> getSensors(int32_t deviceId) {
+ return reader->getSensors(deviceId);
+ }
+
+ bool canDispatchToDisplay(int32_t deviceId, int32_t displayId) {
+ return reader->canDispatchToDisplay(deviceId, displayId);
+ }
+
+ bool enableSensor(int32_t deviceId, InputDeviceSensorType sensorType,
+ std::chrono::microseconds samplingPeriod,
+ std::chrono::microseconds maxBatchReportLatency) {
+ return reader->enableSensor(deviceId, sensorType, samplingPeriod, maxBatchReportLatency);
+ }
+
+ void disableSensor(int32_t deviceId, InputDeviceSensorType sensorType) {
+ return reader->disableSensor(deviceId, sensorType);
+ }
+
+ void flushSensor(int32_t deviceId, InputDeviceSensorType sensorType) {
+ return reader->flushSensor(deviceId, sensorType);
+ }
+
+ bool setLightColor(int32_t deviceId, int32_t lightId, int32_t color) {
+ return reader->setLightColor(deviceId, lightId, color);
+ }
+
+ bool setLightPlayerId(int32_t deviceId, int32_t lightId, int32_t playerId) {
+ return reader->setLightPlayerId(deviceId, lightId, playerId);
+ }
+
+ std::optional<int32_t> getLightColor(int32_t deviceId, int32_t lightId) {
+ return reader->getLightColor(deviceId, lightId);
+ }
+
+ std::optional<int32_t> getLightPlayerId(int32_t deviceId, int32_t lightId) {
+ return reader->getLightPlayerId(deviceId, lightId);
+ }
+
+ int32_t getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const {
+ return reader->getKeyCodeForKeyLocation(deviceId, locationKeyCode);
+ }
+
+private:
+ std::unique_ptr<InputReaderInterface> reader;
+};
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
+ std::shared_ptr<FuzzedDataProvider> fdp = std::make_shared<FuzzedDataProvider>(data, size);
+
+ FuzzInputListener fuzzListener;
+ sp<FuzzInputReaderPolicy> fuzzPolicy = sp<FuzzInputReaderPolicy>::make(fdp);
+ std::shared_ptr<FuzzEventHub> fuzzEventHub = std::make_shared<FuzzEventHub>(fdp);
+ std::unique_ptr<FuzzInputReader> reader =
+ std::make_unique<FuzzInputReader>(fuzzEventHub, fuzzPolicy, fuzzListener);
+ fuzzEventHub->addEvents(fdp);
+ size_t patternCount = fdp->ConsumeIntegralInRange<size_t>(1, 260);
+ VibrationSequence pattern(patternCount);
+ for (size_t i = 0; i < patternCount; ++i) {
+ VibrationElement element(i);
+ element.addChannel(fdp->ConsumeIntegral<int32_t>() /* vibratorId */,
+ fdp->ConsumeIntegral<uint8_t>() /* amplitude */);
+ pattern.addElement(element);
+ }
+ reader->vibrate(fdp->ConsumeIntegral<int32_t>(), pattern,
+ fdp->ConsumeIntegral<ssize_t>() /*repeat*/,
+ fdp->ConsumeIntegral<int32_t>() /*token*/);
+ reader->start();
+
+ // Loop through mapper operations until randomness is exhausted.
+ while (fdp->remaining_bytes() > 0) {
+ fdp->PickValueInArray<std::function<void()>>({
+ [&]() -> void {
+ std::string dump;
+ reader->dump(dump);
+ },
+ [&]() -> void { reader->monitor(); },
+ [&]() -> void { reader->getInputDevices(); },
+ [&]() -> void { reader->isInputDeviceEnabled(fdp->ConsumeIntegral<int32_t>()); },
+ [&]() -> void {
+ reader->getScanCodeState(fdp->ConsumeIntegral<int32_t>(),
+ fdp->ConsumeIntegral<uint32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ [&]() -> void {
+ reader->getKeyCodeState(fdp->ConsumeIntegral<int32_t>(),
+ fdp->ConsumeIntegral<uint32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ [&]() -> void {
+ reader->getSwitchState(fdp->ConsumeIntegral<int32_t>(),
+ fdp->ConsumeIntegral<uint32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ [&]() -> void { reader->toggleCapsLockState(fdp->ConsumeIntegral<int32_t>()); },
+ [&]() -> void {
+ size_t count = fdp->ConsumeIntegralInRange<size_t>(1, 1024);
+ std::vector<uint8_t> outFlags(count);
+ std::vector<int32_t> keyCodes;
+ for (size_t i = 0; i < count; ++i) {
+ keyCodes.push_back(fdp->ConsumeIntegral<int32_t>());
+ }
+ reader->hasKeys(fdp->ConsumeIntegral<int32_t>(),
+ fdp->ConsumeIntegral<uint32_t>(), keyCodes, outFlags.data());
+ },
+ [&]() -> void {
+ reader->requestRefreshConfiguration(fdp->ConsumeIntegral<uint32_t>());
+ },
+ [&]() -> void {
+ reader->cancelVibrate(fdp->ConsumeIntegral<int32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ [&]() -> void {
+ reader->canDispatchToDisplay(fdp->ConsumeIntegral<int32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ [&]() -> void {
+ reader->getKeyCodeForKeyLocation(fdp->ConsumeIntegral<int32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ [&]() -> void { reader->getBatteryCapacity(fdp->ConsumeIntegral<int32_t>()); },
+ [&]() -> void { reader->getBatteryStatus(fdp->ConsumeIntegral<int32_t>()); },
+ [&]() -> void { reader->getBatteryDevicePath(fdp->ConsumeIntegral<int32_t>()); },
+ [&]() -> void { reader->getLights(fdp->ConsumeIntegral<int32_t>()); },
+ [&]() -> void { reader->getSensors(fdp->ConsumeIntegral<int32_t>()); },
+ [&]() -> void {
+ reader->getLightPlayerId(fdp->ConsumeIntegral<int32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ [&]() -> void {
+ reader->getLightColor(fdp->ConsumeIntegral<int32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ [&]() -> void {
+ reader->setLightPlayerId(fdp->ConsumeIntegral<int32_t>(),
+ fdp->ConsumeIntegral<int32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ [&]() -> void {
+ reader->setLightColor(fdp->ConsumeIntegral<int32_t>(),
+ fdp->ConsumeIntegral<int32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ [&]() -> void {
+ reader->flushSensor(fdp->ConsumeIntegral<int32_t>(),
+ fdp->PickValueInArray<InputDeviceSensorType>(
+ kInputDeviceSensorType));
+ },
+ [&]() -> void {
+ reader->disableSensor(fdp->ConsumeIntegral<int32_t>(),
+ fdp->PickValueInArray<InputDeviceSensorType>(
+ kInputDeviceSensorType));
+ },
+ [&]() -> void {
+ reader->enableSensor(fdp->ConsumeIntegral<int32_t>(),
+ fdp->PickValueInArray<InputDeviceSensorType>(
+ kInputDeviceSensorType),
+ std::chrono::microseconds(fdp->ConsumeIntegral<size_t>()),
+ std::chrono::microseconds(fdp->ConsumeIntegral<size_t>()));
+ },
+ })();
+ }
+
+ reader->stop();
+ return 0;
+}
+
+} // namespace android
diff --git a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp
new file mode 100644
index 0000000..c48a099
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+#include <FuzzContainer.h>
+#include <KeyboardInputMapper.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+namespace android {
+
+const int32_t kMaxKeycodes = 100;
+
+static void addProperty(FuzzContainer& fuzzer, std::shared_ptr<FuzzedDataProvider> fdp) {
+ // Pick a random property to set for the mapper to have set.
+ fdp->PickValueInArray<std::function<void()>>(
+ {[&]() -> void { fuzzer.addProperty("keyboard.orientationAware", "1"); },
+ [&]() -> void {
+ fuzzer.addProperty("keyboard.orientationAware",
+ fdp->ConsumeRandomLengthString(100).data());
+ },
+ [&]() -> void {
+ fuzzer.addProperty("keyboard.doNotWakeByDefault",
+ fdp->ConsumeRandomLengthString(100).data());
+ },
+ [&]() -> void {
+ fuzzer.addProperty("keyboard.handlesKeyRepeat",
+ fdp->ConsumeRandomLengthString(100).data());
+ }})();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
+ std::shared_ptr<FuzzedDataProvider> fdp = std::make_shared<FuzzedDataProvider>(data, size);
+ FuzzContainer fuzzer(fdp);
+
+ KeyboardInputMapper& mapper =
+ fuzzer.getMapper<KeyboardInputMapper>(fdp->ConsumeIntegral<uint32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ auto policyConfig = fuzzer.getPolicyConfig();
+
+ // Loop through mapper operations until randomness is exhausted.
+ while (fdp->remaining_bytes() > 0) {
+ fdp->PickValueInArray<std::function<void()>>({
+ [&]() -> void { addProperty(fuzzer, fdp); },
+ [&]() -> void {
+ std::string dump;
+ mapper.dump(dump);
+ },
+ [&]() -> void {
+ InputDeviceInfo info;
+ mapper.populateDeviceInfo(&info);
+ },
+ [&]() -> void { mapper.getSources(); },
+ [&]() -> void {
+ mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig,
+ fdp->ConsumeIntegral<uint32_t>());
+ },
+ [&]() -> void { mapper.reset(fdp->ConsumeIntegral<nsecs_t>()); },
+ [&]() -> void {
+ int32_t type, code;
+ type = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidTypes)
+ : fdp->ConsumeIntegral<int32_t>();
+ code = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidCodes)
+ : fdp->ConsumeIntegral<int32_t>();
+ RawEvent rawEvent{fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeIntegral<int32_t>(),
+ type,
+ code,
+ fdp->ConsumeIntegral<int32_t>()};
+ mapper.process(&rawEvent);
+ },
+ [&]() -> void {
+ mapper.getKeyCodeState(fdp->ConsumeIntegral<uint32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ [&]() -> void {
+ mapper.getScanCodeState(fdp->ConsumeIntegral<uint32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ [&]() -> void {
+ std::vector<int32_t> keyCodes;
+ int32_t numBytes = fdp->ConsumeIntegralInRange<int32_t>(0, kMaxKeycodes);
+ for (int32_t i = 0; i < numBytes; ++i) {
+ keyCodes.push_back(fdp->ConsumeIntegral<int32_t>());
+ }
+ mapper.markSupportedKeyCodes(fdp->ConsumeIntegral<uint32_t>(), keyCodes,
+ nullptr);
+ },
+ [&]() -> void { mapper.getMetaState(); },
+ [&]() -> void { mapper.updateMetaState(fdp->ConsumeIntegral<int32_t>()); },
+ [&]() -> void { mapper.getAssociatedDisplayId(); },
+ })();
+ }
+
+ return 0;
+}
+
+} // namespace android
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
new file mode 100644
index 0000000..53a7b16
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -0,0 +1,372 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <InputDevice.h>
+#include <InputMapper.h>
+#include <InputReader.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include "android/hardware/input/InputDeviceCountryCode.h"
+
+using android::hardware::input::InputDeviceCountryCode;
+
+constexpr size_t kValidTypes[] = {EV_SW,
+ EV_SYN,
+ SYN_REPORT,
+ EV_ABS,
+ EV_KEY,
+ EV_MSC,
+ EV_REL,
+ android::EventHubInterface::DEVICE_ADDED,
+ android::EventHubInterface::DEVICE_REMOVED,
+ android::EventHubInterface::FINISHED_DEVICE_SCAN};
+
+constexpr size_t kValidCodes[] = {
+ SYN_REPORT,
+ ABS_MT_SLOT,
+ SYN_MT_REPORT,
+ ABS_MT_POSITION_X,
+ ABS_MT_POSITION_Y,
+ ABS_MT_TOUCH_MAJOR,
+ ABS_MT_TOUCH_MINOR,
+ ABS_MT_WIDTH_MAJOR,
+ ABS_MT_WIDTH_MINOR,
+ ABS_MT_ORIENTATION,
+ ABS_MT_TRACKING_ID,
+ ABS_MT_PRESSURE,
+ ABS_MT_DISTANCE,
+ ABS_MT_TOOL_TYPE,
+ SYN_MT_REPORT,
+ MSC_SCAN,
+ REL_X,
+ REL_Y,
+ REL_WHEEL,
+ REL_HWHEEL,
+ BTN_LEFT,
+ BTN_RIGHT,
+ BTN_MIDDLE,
+ BTN_BACK,
+ BTN_SIDE,
+ BTN_FORWARD,
+ BTN_EXTRA,
+ BTN_TASK,
+};
+
+constexpr InputDeviceCountryCode kCountryCodes[] = {
+ InputDeviceCountryCode::INVALID,
+ InputDeviceCountryCode::NOT_SUPPORTED,
+ InputDeviceCountryCode::ARABIC,
+ InputDeviceCountryCode::BELGIAN,
+ InputDeviceCountryCode::CANADIAN_BILINGUAL,
+ InputDeviceCountryCode::CANADIAN_FRENCH,
+ InputDeviceCountryCode::CZECH_REPUBLIC,
+ InputDeviceCountryCode::DANISH,
+ InputDeviceCountryCode::FINNISH,
+ InputDeviceCountryCode::FRENCH,
+ InputDeviceCountryCode::GERMAN,
+ InputDeviceCountryCode::GREEK,
+ InputDeviceCountryCode::HEBREW,
+ InputDeviceCountryCode::HUNGARY,
+ InputDeviceCountryCode::INTERNATIONAL,
+ InputDeviceCountryCode::ITALIAN,
+ InputDeviceCountryCode::JAPAN,
+ InputDeviceCountryCode::KOREAN,
+ InputDeviceCountryCode::LATIN_AMERICAN,
+ InputDeviceCountryCode::DUTCH,
+ InputDeviceCountryCode::NORWEGIAN,
+ InputDeviceCountryCode::PERSIAN,
+ InputDeviceCountryCode::POLAND,
+ InputDeviceCountryCode::PORTUGUESE,
+ InputDeviceCountryCode::RUSSIA,
+ InputDeviceCountryCode::SLOVAKIA,
+ InputDeviceCountryCode::SPANISH,
+ InputDeviceCountryCode::SWEDISH,
+ InputDeviceCountryCode::SWISS_FRENCH,
+ InputDeviceCountryCode::SWISS_GERMAN,
+ InputDeviceCountryCode::SWITZERLAND,
+ InputDeviceCountryCode::TAIWAN,
+ InputDeviceCountryCode::TURKISH_Q,
+ InputDeviceCountryCode::UK,
+ InputDeviceCountryCode::US,
+ InputDeviceCountryCode::YUGOSLAVIA,
+ InputDeviceCountryCode::TURKISH_F,
+};
+
+constexpr size_t kMaxSize = 256;
+
+namespace android {
+
+class FuzzEventHub : public EventHubInterface {
+ InputDeviceIdentifier mIdentifier;
+ std::vector<TouchVideoFrame> mVideoFrames;
+ PropertyMap mFuzzConfig;
+ size_t mCount = 0;
+ std::array<RawEvent, kMaxSize> mBuf;
+ std::shared_ptr<FuzzedDataProvider> mFdp;
+
+public:
+ FuzzEventHub(std::shared_ptr<FuzzedDataProvider> fdp) : mFdp(std::move(fdp)) {}
+ ~FuzzEventHub() {}
+ void addProperty(std::string key, std::string value) { mFuzzConfig.addProperty(key, value); }
+ void addEvents(std::shared_ptr<FuzzedDataProvider> fdp) {
+ mCount = fdp->ConsumeIntegralInRange<size_t>(0, kMaxSize);
+
+ for (size_t i = 0; i < mCount; ++i) {
+ int32_t type = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidTypes)
+ : fdp->ConsumeIntegral<int32_t>();
+ int32_t code = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidCodes)
+ : fdp->ConsumeIntegral<int32_t>();
+ mBuf[i] = {fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeIntegral<int32_t>(),
+ type,
+ code,
+ fdp->ConsumeIntegral<int32_t>()};
+ }
+ }
+
+ ftl::Flags<InputDeviceClass> getDeviceClasses(int32_t deviceId) const override {
+ return ftl::Flags<InputDeviceClass>(mFdp->ConsumeIntegral<uint32_t>());
+ }
+ InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const override {
+ return mIdentifier;
+ }
+ int32_t getDeviceControllerNumber(int32_t deviceId) const override {
+ return mFdp->ConsumeIntegral<int32_t>();
+ }
+ void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const override {
+ *outConfiguration = mFuzzConfig;
+ }
+ status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
+ RawAbsoluteAxisInfo* outAxisInfo) const override {
+ return mFdp->ConsumeIntegral<status_t>();
+ }
+ bool hasRelativeAxis(int32_t deviceId, int axis) const override { return mFdp->ConsumeBool(); }
+ bool hasInputProperty(int32_t deviceId, int property) const override {
+ return mFdp->ConsumeBool();
+ }
+ bool hasMscEvent(int32_t deviceId, int mscEvent) const override { return mFdp->ConsumeBool(); }
+ status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState,
+ int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const override {
+ return mFdp->ConsumeIntegral<status_t>();
+ }
+ status_t mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const override {
+ return mFdp->ConsumeIntegral<status_t>();
+ }
+ void setExcludedDevices(const std::vector<std::string>& devices) override {}
+ size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) override {
+ for (size_t i = 0; i < mCount; ++i) buffer[i] = mBuf[i];
+
+ return mCount;
+ }
+ std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) override { return mVideoFrames; }
+
+ base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(
+ int32_t deviceId, int32_t absCode) const override {
+ return base::ResultError("Fuzzer", UNKNOWN_ERROR);
+ };
+ // Raw batteries are sysfs power_supply nodes we found from the EventHub device sysfs node,
+ // containing the raw info of the sysfs node structure.
+ std::vector<int32_t> getRawBatteryIds(int32_t deviceId) const override { return {}; }
+ std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t deviceId,
+ int32_t BatteryId) const override {
+ return std::nullopt;
+ };
+
+ std::vector<int32_t> getRawLightIds(int32_t deviceId) const override { return {}; };
+ std::optional<RawLightInfo> getRawLightInfo(int32_t deviceId, int32_t lightId) const override {
+ return std::nullopt;
+ };
+ std::optional<int32_t> getLightBrightness(int32_t deviceId, int32_t lightId) const override {
+ return std::nullopt;
+ };
+ void setLightBrightness(int32_t deviceId, int32_t lightId, int32_t brightness) override{};
+ std::optional<std::unordered_map<LightColor, int32_t>> getLightIntensities(
+ int32_t deviceId, int32_t lightId) const override {
+ return std::nullopt;
+ };
+ void setLightIntensities(int32_t deviceId, int32_t lightId,
+ std::unordered_map<LightColor, int32_t> intensities) override{};
+
+ InputDeviceCountryCode getCountryCode(int32_t deviceId) const override {
+ return mFdp->PickValueInArray<InputDeviceCountryCode>(kCountryCodes);
+ };
+
+ int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const override {
+ return mFdp->ConsumeIntegral<int32_t>();
+ }
+ int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const override {
+ return mFdp->ConsumeIntegral<int32_t>();
+ }
+ int32_t getSwitchState(int32_t deviceId, int32_t sw) const override {
+ return mFdp->ConsumeIntegral<int32_t>();
+ }
+ int32_t getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const override {
+ return mFdp->ConsumeIntegral<int32_t>();
+ }
+ status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis,
+ int32_t* outValue) const override {
+ return mFdp->ConsumeIntegral<status_t>();
+ }
+ bool markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes,
+ uint8_t* outFlags) const override {
+ return mFdp->ConsumeBool();
+ }
+ bool hasScanCode(int32_t deviceId, int32_t scanCode) const override {
+ return mFdp->ConsumeBool();
+ }
+ bool hasKeyCode(int32_t deviceId, int32_t keyCode) const override {
+ return mFdp->ConsumeBool();
+ }
+ bool hasLed(int32_t deviceId, int32_t led) const override { return mFdp->ConsumeBool(); }
+ void setLedState(int32_t deviceId, int32_t led, bool on) override {}
+ void getVirtualKeyDefinitions(
+ int32_t deviceId, std::vector<VirtualKeyDefinition>& outVirtualKeys) const override {}
+ const std::shared_ptr<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const override {
+ return nullptr;
+ }
+ bool setKeyboardLayoutOverlay(int32_t deviceId, std::shared_ptr<KeyCharacterMap> map) override {
+ return mFdp->ConsumeBool();
+ }
+ void vibrate(int32_t deviceId, const VibrationElement& effect) override {}
+ void cancelVibrate(int32_t deviceId) override {}
+
+ std::vector<int32_t> getVibratorIds(int32_t deviceId) const override { return {}; };
+
+ /* Query battery level. */
+ std::optional<int32_t> getBatteryCapacity(int32_t deviceId, int32_t batteryId) const override {
+ return std::nullopt;
+ };
+
+ /* Query battery status. */
+ std::optional<int32_t> getBatteryStatus(int32_t deviceId, int32_t batteryId) const override {
+ return std::nullopt;
+ };
+
+ void requestReopenDevices() override {}
+ void wake() override {}
+ void dump(std::string& dump) const override {}
+ void monitor() const override {}
+ bool isDeviceEnabled(int32_t deviceId) const override { return mFdp->ConsumeBool(); }
+ status_t enableDevice(int32_t deviceId) override { return mFdp->ConsumeIntegral<status_t>(); }
+ status_t disableDevice(int32_t deviceId) override { return mFdp->ConsumeIntegral<status_t>(); }
+};
+
+class FuzzPointerController : public PointerControllerInterface {
+ std::shared_ptr<FuzzedDataProvider> mFdp;
+
+public:
+ FuzzPointerController(std::shared_ptr<FuzzedDataProvider> mFdp) : mFdp(mFdp) {}
+ ~FuzzPointerController() {}
+ bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const override {
+ return mFdp->ConsumeBool();
+ }
+ void move(float deltaX, float deltaY) override {}
+ void setButtonState(int32_t buttonState) override {}
+ int32_t getButtonState() const override { return mFdp->ConsumeIntegral<int32_t>(); }
+ void setPosition(float x, float y) override {}
+ void getPosition(float* outX, float* outY) const override {}
+ void fade(Transition transition) override {}
+ void unfade(Transition transition) override {}
+ void setPresentation(Presentation presentation) override {}
+ void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
+ BitSet32 spotIdBits, int32_t displayId) override {}
+ void clearSpots() override {}
+ int32_t getDisplayId() const override { return mFdp->ConsumeIntegral<int32_t>(); }
+ void setDisplayViewport(const DisplayViewport& displayViewport) override {}
+};
+
+class FuzzInputReaderPolicy : public InputReaderPolicyInterface {
+ TouchAffineTransformation mTransform;
+ std::shared_ptr<FuzzPointerController> mPointerController;
+ std::shared_ptr<FuzzedDataProvider> mFdp;
+
+protected:
+ ~FuzzInputReaderPolicy() {}
+
+public:
+ FuzzInputReaderPolicy(std::shared_ptr<FuzzedDataProvider> mFdp) : mFdp(mFdp) {
+ mPointerController = std::make_shared<FuzzPointerController>(mFdp);
+ }
+ void getReaderConfiguration(InputReaderConfiguration* outConfig) override {}
+ std::shared_ptr<PointerControllerInterface> obtainPointerController(int32_t deviceId) override {
+ return mPointerController;
+ }
+ void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override {}
+ std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay(
+ const InputDeviceIdentifier& identifier) override {
+ return nullptr;
+ }
+ std::string getDeviceAlias(const InputDeviceIdentifier& identifier) {
+ return mFdp->ConsumeRandomLengthString(32);
+ }
+ TouchAffineTransformation getTouchAffineTransformation(const std::string& inputDeviceDescriptor,
+ int32_t surfaceRotation) override {
+ return mTransform;
+ }
+ void setTouchAffineTransformation(const TouchAffineTransformation t) { mTransform = t; }
+};
+
+class FuzzInputListener : public virtual InputListenerInterface {
+public:
+ void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override {}
+ void notifyKey(const NotifyKeyArgs* args) override {}
+ void notifyMotion(const NotifyMotionArgs* args) override {}
+ void notifySwitch(const NotifySwitchArgs* args) override {}
+ void notifySensor(const NotifySensorArgs* args) override{};
+ void notifyVibratorState(const NotifyVibratorStateArgs* args) override{};
+ void notifyDeviceReset(const NotifyDeviceResetArgs* args) override {}
+ void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override{};
+};
+
+class FuzzInputReaderContext : public InputReaderContext {
+ std::shared_ptr<EventHubInterface> mEventHub;
+ sp<InputReaderPolicyInterface> mPolicy;
+ InputListenerInterface& mListener;
+ std::shared_ptr<FuzzedDataProvider> mFdp;
+
+public:
+ FuzzInputReaderContext(std::shared_ptr<EventHubInterface> eventHub,
+ const sp<InputReaderPolicyInterface>& policy,
+ InputListenerInterface& listener,
+ std::shared_ptr<FuzzedDataProvider> mFdp)
+ : mEventHub(eventHub), mPolicy(policy), mListener(listener), mFdp(mFdp) {}
+ ~FuzzInputReaderContext() {}
+ void updateGlobalMetaState() override {}
+ int32_t getGlobalMetaState() { return mFdp->ConsumeIntegral<int32_t>(); }
+ void disableVirtualKeysUntil(nsecs_t time) override {}
+ bool shouldDropVirtualKey(nsecs_t now, int32_t keyCode, int32_t scanCode) override {
+ return mFdp->ConsumeBool();
+ }
+ void fadePointer() override {}
+ std::shared_ptr<PointerControllerInterface> getPointerController(int32_t deviceId) override {
+ return mPolicy->obtainPointerController(0);
+ }
+ void requestTimeoutAtTime(nsecs_t when) override {}
+ int32_t bumpGeneration() override { return mFdp->ConsumeIntegral<int32_t>(); }
+ void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) override {}
+ void dispatchExternalStylusState(const StylusState& outState) override {}
+ InputReaderPolicyInterface* getPolicy() override { return mPolicy.get(); }
+ InputListenerInterface& getListener() override { return mListener; }
+ EventHubInterface* getEventHub() override { return mEventHub.get(); }
+ int32_t getNextId() override { return mFdp->ConsumeIntegral<int32_t>(); }
+
+ void updateLedMetaState(int32_t metaState) override{};
+ int32_t getLedMetaState() override { return mFdp->ConsumeIntegral<int32_t>(); };
+};
+
+} // namespace android
diff --git a/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp
new file mode 100644
index 0000000..59b0642
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+#include <FuzzContainer.h>
+#include <MultiTouchInputMapper.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+namespace android {
+
+const int32_t kMaxKeycodes = 100;
+
+static void addProperty(FuzzContainer& fuzzer, std::shared_ptr<FuzzedDataProvider> fdp) {
+ // Pick a random property to set for the mapper to have set.
+ fdp->PickValueInArray<std::function<void()>>(
+ {[&]() -> void { fuzzer.addProperty("touch.deviceType", "touchScreen"); },
+ [&]() -> void {
+ fuzzer.addProperty("touch.deviceType", fdp->ConsumeRandomLengthString(8).data());
+ },
+ [&]() -> void {
+ fuzzer.addProperty("touch.size.scale", fdp->ConsumeRandomLengthString(8).data());
+ },
+ [&]() -> void {
+ fuzzer.addProperty("touch.size.bias", fdp->ConsumeRandomLengthString(8).data());
+ },
+ [&]() -> void {
+ fuzzer.addProperty("touch.size.isSummed",
+ fdp->ConsumeRandomLengthString(8).data());
+ },
+ [&]() -> void {
+ fuzzer.addProperty("touch.size.calibration",
+ fdp->ConsumeRandomLengthString(8).data());
+ },
+ [&]() -> void {
+ fuzzer.addProperty("touch.pressure.scale",
+ fdp->ConsumeRandomLengthString(8).data());
+ },
+ [&]() -> void {
+ fuzzer.addProperty("touch.size.calibration",
+ fdp->ConsumeBool() ? "diameter" : "area");
+ },
+ [&]() -> void {
+ fuzzer.addProperty("touch.pressure.calibration",
+ fdp->ConsumeRandomLengthString(8).data());
+ }})();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
+ std::shared_ptr<FuzzedDataProvider> fdp = std::make_shared<FuzzedDataProvider>(data, size);
+ FuzzContainer fuzzer(fdp);
+
+ MultiTouchInputMapper& mapper = fuzzer.getMapper<MultiTouchInputMapper>();
+ auto policyConfig = fuzzer.getPolicyConfig();
+
+ // Loop through mapper operations until randomness is exhausted.
+ while (fdp->remaining_bytes() > 0) {
+ fdp->PickValueInArray<std::function<void()>>({
+ [&]() -> void { addProperty(fuzzer, fdp); },
+ [&]() -> void {
+ std::string dump;
+ mapper.dump(dump);
+ },
+ [&]() -> void {
+ InputDeviceInfo info;
+ mapper.populateDeviceInfo(&info);
+ },
+ [&]() -> void { mapper.getSources(); },
+ [&]() -> void {
+ mapper.configure(fdp->ConsumeIntegral<nsecs_t>(), &policyConfig,
+ fdp->ConsumeIntegral<uint32_t>());
+ },
+ [&]() -> void { mapper.reset(fdp->ConsumeIntegral<nsecs_t>()); },
+ [&]() -> void {
+ int32_t type = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidTypes)
+ : fdp->ConsumeIntegral<int32_t>();
+ int32_t code = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidCodes)
+ : fdp->ConsumeIntegral<int32_t>();
+ RawEvent rawEvent{fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeIntegral<int32_t>(),
+ type,
+ code,
+ fdp->ConsumeIntegral<int32_t>()};
+ mapper.process(&rawEvent);
+ },
+ [&]() -> void {
+ mapper.getKeyCodeState(fdp->ConsumeIntegral<uint32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ [&]() -> void {
+ mapper.getScanCodeState(fdp->ConsumeIntegral<uint32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ [&]() -> void {
+ std::vector<int32_t> keyCodes;
+ int32_t numBytes = fdp->ConsumeIntegralInRange<int32_t>(0, kMaxKeycodes);
+ for (int32_t i = 0; i < numBytes; ++i) {
+ keyCodes.push_back(fdp->ConsumeIntegral<int32_t>());
+ }
+ mapper.markSupportedKeyCodes(fdp->ConsumeIntegral<uint32_t>(), keyCodes,
+ nullptr);
+ },
+ [&]() -> void {
+ mapper.cancelTouch(fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeIntegral<nsecs_t>());
+ },
+ [&]() -> void { mapper.timeoutExpired(fdp->ConsumeIntegral<nsecs_t>()); },
+ [&]() -> void {
+ StylusState state{fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeFloatingPoint<float>(),
+ fdp->ConsumeIntegral<uint32_t>(),
+ fdp->ConsumeIntegral<int32_t>()};
+ mapper.updateExternalStylusState(state);
+ },
+ [&]() -> void { mapper.getAssociatedDisplayId(); },
+ })();
+ }
+
+ return 0;
+}
+
+} // namespace android
diff --git a/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp
new file mode 100644
index 0000000..e76bd72
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#include <FuzzContainer.h>
+#include <SwitchInputMapper.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+namespace android {
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
+ std::shared_ptr<FuzzedDataProvider> fdp = std::make_shared<FuzzedDataProvider>(data, size);
+ FuzzContainer fuzzer(fdp);
+
+ SwitchInputMapper& mapper = fuzzer.getMapper<SwitchInputMapper>();
+ auto policyConfig = fuzzer.getPolicyConfig();
+
+ // Loop through mapper operations until randomness is exhausted.
+ while (fdp->remaining_bytes() > 0) {
+ fdp->PickValueInArray<std::function<void()>>({
+ [&]() -> void {
+ std::string dump;
+ mapper.dump(dump);
+ },
+ [&]() -> void { mapper.getSources(); },
+ [&]() -> void {
+ int32_t type = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidTypes)
+ : fdp->ConsumeIntegral<int32_t>();
+ int32_t code = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidCodes)
+ : fdp->ConsumeIntegral<int32_t>();
+ RawEvent rawEvent{fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeIntegral<nsecs_t>(),
+ fdp->ConsumeIntegral<int32_t>(),
+ type,
+ code,
+ fdp->ConsumeIntegral<int32_t>()};
+ mapper.process(&rawEvent);
+ },
+ [&]() -> void {
+ mapper.getSwitchState(fdp->ConsumeIntegral<uint32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ })();
+ }
+
+ return 0;
+}
+
+} // namespace android
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index de050e0..10ca990 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -39,7 +39,6 @@
#include <thread>
using namespace android::hardware::sensors;
-using android::hardware::Return;
using android::util::ProtoOutputStream;
namespace android {
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp
index 2dd12e9..291c770 100644
--- a/services/sensorservice/SensorDirectConnection.cpp
+++ b/services/sensorservice/SensorDirectConnection.cpp
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-#include "SensorDevice.h"
#include "SensorDirectConnection.h"
#include <android/util/ProtoOutputStream.h>
#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
#include <hardware/sensors.h>
+#include "SensorDevice.h"
#define UNUSED(x) (void)(x)
@@ -51,7 +51,7 @@
stopAll();
mService->cleanupConnection(this);
if (mMem.handle != nullptr) {
- native_handle_close(mMem.handle);
+ native_handle_close_with_tag(mMem.handle);
native_handle_delete(const_cast<struct native_handle*>(mMem.handle));
}
mDestroyed = true;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index e0a4f03..21d6b6b 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -16,7 +16,6 @@
#include <android-base/strings.h>
#include <android/content/pm/IPackageManagerNative.h>
#include <android/util/ProtoOutputStream.h>
-#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
#include <binder/ActivityManager.h>
#include <binder/BinderService.h>
#include <binder/IServiceManager.h>
@@ -25,6 +24,7 @@
#include <cutils/ashmem.h>
#include <cutils/misc.h>
#include <cutils/properties.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
#include <hardware/sensors.h>
#include <hardware_legacy/power.h>
#include <log/log.h>
@@ -1475,6 +1475,7 @@
if (!clone) {
return nullptr;
}
+ native_handle_set_fdsan_tag(clone);
sp<SensorDirectConnection> conn;
SensorDevice& dev(SensorDevice::getInstance());
@@ -1488,7 +1489,7 @@
}
if (conn == nullptr) {
- native_handle_close(clone);
+ native_handle_close_with_tag(clone);
native_handle_delete(clone);
} else {
// add to list of direct connections
diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp
index caf7f03..b00d1a7 100644
--- a/services/sensorservice/tests/sensorservicetest.cpp
+++ b/services/sensorservice/tests/sensorservicetest.cpp
@@ -89,6 +89,17 @@
// Should print -22 (BAD_VALUE) and the device runtime shouldn't restart
printf("createInvalidDirectChannel=%d\n", ret);
+
+ // Secondary test: correct channel creation & destruction (should print 0)
+ ret = mgr.createDirectChannel(kMemSize, ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER,
+ resourceHandle);
+ printf("createValidDirectChannel=%d\n", ret);
+
+ // Third test: double-destroy (should not crash)
+ mgr.destroyDirectChannel(ret);
+ AHardwareBuffer_release(hardwareBuffer);
+ printf("duplicate destroyDirectChannel...\n");
+ mgr.destroyDirectChannel(ret);
}
int main() {
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 5e9fe65..b911ae7 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -141,16 +141,16 @@
name: "libsurfaceflinger_sources",
srcs: [
"BackgroundExecutor.cpp",
- "ClientCache.cpp",
"Client.cpp",
- "EffectLayer.cpp",
+ "ClientCache.cpp",
+ "Display/DisplaySnapshot.cpp",
"DisplayDevice.cpp",
"DisplayHardware/AidlComposerHal.cpp",
- "DisplayHardware/HidlComposerHal.cpp",
"DisplayHardware/ComposerHal.cpp",
"DisplayHardware/FramebufferSurface.cpp",
"DisplayHardware/HWC2.cpp",
"DisplayHardware/HWComposer.cpp",
+ "DisplayHardware/HidlComposerHal.cpp",
"DisplayHardware/PowerAdvisor.cpp",
"DisplayHardware/VirtualDisplaySurface.cpp",
"DisplayRenderArea.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
index 16cb41b..5e84be1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
@@ -56,6 +56,9 @@
// similar requests if needed.
virtual void createClientCompositionCache(uint32_t cacheSize) = 0;
+ // Sends the brightness setting to HWC
+ virtual void applyDisplayBrightness(const bool applyImmediately) = 0;
+
protected:
~Display() = default;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index 9753a6c..a738da0 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -53,31 +53,8 @@
// Called before composition starts. Should return true if this layer has
// pending updates which would require an extra display refresh cycle to
// process.
- virtual bool onPreComposition(nsecs_t refreshStartTime) = 0;
-
- // Used with latchCompositionState()
- enum class StateSubset {
- // Gets the basic geometry (bounds, transparent region, visibility,
- // transforms, alpha) for the layer, for computing visibility and
- // coverage.
- BasicGeometry,
-
- // Gets the full geometry (crops, buffer transforms, metadata) and
- // content (buffer or color) state for the layer.
- GeometryAndContent,
-
- // Gets the per frame content (buffer or color) state for the layer.
- Content,
-
- // Gets the cursor state for the layer.
- Cursor,
- };
-
- // Prepares the output-independent composition state for the layer. The
- // StateSubset argument selects what portion of the state is actually needed
- // by the CompositionEngine code, since computing everything may be
- // expensive.
- virtual void prepareCompositionState(StateSubset) = 0;
+ virtual bool onPreComposition(nsecs_t refreshStartTime,
+ bool updatingOutputGeometryThisFrame) = 0;
struct ClientCompositionTargetSettings {
enum class BlurSetting {
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 2203639..874b330 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -262,9 +262,6 @@
// Presents the output, finalizing all composition details
virtual void present(const CompositionRefreshArgs&) = 0;
- // Latches the front-end layer state for each output layer
- virtual void updateLayerStateFromFE(const CompositionRefreshArgs&) const = 0;
-
// Enables predicting composition strategy to run client composition earlier
virtual void setPredictCompositionStrategy(bool) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
index 386808d..0907926 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
@@ -51,8 +51,6 @@
// Debugging
void dump(std::string&) const override;
- void updateLayerStateFromFE(CompositionRefreshArgs& args);
-
// Testing
void setNeedsAnotherUpdateForTest(bool);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index fa7bc5d..33a10a3 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -72,6 +72,7 @@
const compositionengine::DisplayColorProfileCreationArgs&) override;
void createRenderSurface(const compositionengine::RenderSurfaceCreationArgs&) override;
void createClientCompositionCache(uint32_t cacheSize) override;
+ void applyDisplayBrightness(const bool applyImmediately) override;
// Internal helpers used by chooseCompositionStrategy()
using ChangedTypes = android::HWComposer::DeviceRequestedChanges::ChangedTypes;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 38a391b..23d5570 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -89,7 +89,6 @@
compositionengine::Output::CoverageState&) override;
void setReleasedLayers(const compositionengine::CompositionRefreshArgs&) override;
- void updateLayerStateFromFE(const CompositionRefreshArgs&) const override;
void updateCompositionState(const compositionengine::CompositionRefreshArgs&) override;
void planComposition() override;
void writeCompositionState(const compositionengine::CompositionRefreshArgs&) override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
index 72e6f3b..7e99ec2 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
@@ -41,6 +41,7 @@
MOCK_METHOD1(createDisplayColorProfile, void(const DisplayColorProfileCreationArgs&));
MOCK_METHOD1(createRenderSurface, void(const RenderSurfaceCreationArgs&));
MOCK_METHOD1(createClientCompositionCache, void(uint32_t));
+ MOCK_METHOD1(applyDisplayBrightness, void(const bool));
MOCK_METHOD1(setPredictCompositionStrategy, void(bool));
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index 2b704e6..be0dbce 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -42,9 +42,8 @@
MOCK_CONST_METHOD0(getCompositionState, const LayerFECompositionState*());
- MOCK_METHOD1(onPreComposition, bool(nsecs_t));
+ MOCK_METHOD2(onPreComposition, bool(nsecs_t, bool));
- MOCK_METHOD1(prepareCompositionState, void(compositionengine::LayerFE::StateSubset));
MOCK_CONST_METHOD1(prepareClientComposition,
std::optional<compositionengine::LayerFE::LayerSettings>(
compositionengine::LayerFE::ClientCompositionTargetSettings&));
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 2a04949..7592cac 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -91,7 +91,6 @@
void(sp<compositionengine::LayerFE>&, compositionengine::Output::CoverageState&));
MOCK_METHOD1(setReleasedLayers, void(const compositionengine::CompositionRefreshArgs&));
- MOCK_CONST_METHOD1(updateLayerStateFromFE, void(const CompositionRefreshArgs&));
MOCK_METHOD1(updateCompositionState, void(const CompositionRefreshArgs&));
MOCK_METHOD0(planComposition, void());
MOCK_METHOD1(writeCompositionState, void(const CompositionRefreshArgs&));
diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
index 6203dc6..855507e 100644
--- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
@@ -105,8 +105,6 @@
}
}
- updateLayerStateFromFE(args);
-
for (const auto& output : args.outputs) {
output->present(args);
}
@@ -119,8 +117,6 @@
for (const auto& output : args.outputs) {
for (auto* layer : output->getOutputLayersOrderedByZ()) {
if (layer->isHardwareCursor()) {
- // Latch the cursor composition state from each front-end layer.
- layer->getLayerFE().prepareCompositionState(LayerFE::StateSubset::Cursor);
layer->writeCursorPositionToHWC();
}
}
@@ -136,7 +132,7 @@
mRefreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
for (auto& layer : args.layers) {
- if (layer->onPreComposition(mRefreshStartTime)) {
+ if (layer->onPreComposition(mRefreshStartTime, args.updatingOutputGeometryThisFrame)) {
needsAnotherUpdate = true;
}
}
@@ -152,12 +148,5 @@
mNeedsAnotherUpdate = value;
}
-void CompositionEngine::updateLayerStateFromFE(CompositionRefreshArgs& args) {
- // Update the composition state from each front-end layer
- for (const auto& output : args.outputs) {
- output->updateLayerStateFromFE(args);
- }
-}
-
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 0ebbcd0..0b69d44 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -203,6 +203,24 @@
setReleasedLayers(std::move(releasedLayers));
}
+void Display::applyDisplayBrightness(const bool applyImmediately) {
+ auto& hwc = getCompositionEngine().getHwComposer();
+ const auto halDisplayId = HalDisplayId::tryCast(*getDisplayId());
+ if (const auto physicalDisplayId = PhysicalDisplayId::tryCast(*halDisplayId);
+ physicalDisplayId && getState().displayBrightness) {
+ const status_t result =
+ hwc.setDisplayBrightness(*physicalDisplayId, *getState().displayBrightness,
+ getState().displayBrightnessNits,
+ Hwc2::Composer::DisplayBrightnessOptions{
+ .applyImmediately = applyImmediately})
+ .get();
+ ALOGE_IF(result != NO_ERROR, "setDisplayBrightness failed for %s: %d, (%s)",
+ getName().c_str(), result, strerror(-result));
+ }
+ // Clear out the display brightness now that it's been communicated to composer.
+ editState().displayBrightness.reset();
+}
+
void Display::beginFrame() {
Output::beginFrame();
@@ -212,20 +230,7 @@
return;
}
- auto& hwc = getCompositionEngine().getHwComposer();
- if (const auto physicalDisplayId = PhysicalDisplayId::tryCast(*halDisplayId);
- physicalDisplayId && getState().displayBrightness) {
- const status_t result =
- hwc.setDisplayBrightness(*physicalDisplayId, *getState().displayBrightness,
- getState().displayBrightnessNits,
- Hwc2::Composer::DisplayBrightnessOptions{
- .applyImmediately = false})
- .get();
- ALOGE_IF(result != NO_ERROR, "setDisplayBrightness failed for %s: %d, (%s)",
- getName().c_str(), result, strerror(-result));
- }
- // Clear out the display brightness now that it's been communicated to composer.
- editState().displayBrightness.reset();
+ applyDisplayBrightness(false);
}
bool Display::chooseCompositionStrategy(
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index b5894cf..e3f3680 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -501,7 +501,6 @@
// appear on multiple outputs.
if (!coverage.latchedLayers.count(layerFE)) {
coverage.latchedLayers.insert(layerFE);
- layerFE->prepareCompositionState(compositionengine::LayerFE::StateSubset::BasicGeometry);
}
// Only consider the layers on this output
@@ -725,14 +724,6 @@
// The base class does nothing with this call.
}
-void Output::updateLayerStateFromFE(const CompositionRefreshArgs& args) const {
- for (auto* layer : getOutputLayersOrderedByZ()) {
- layer->getLayerFE().prepareCompositionState(
- args.updatingGeometryThisFrame ? LayerFE::StateSubset::GeometryAndContent
- : LayerFE::StateSubset::Content);
- }
-}
-
void Output::updateCompositionState(const compositionengine::CompositionRefreshArgs& refreshArgs) {
ATRACE_CALL();
ALOGV(__FUNCTION__);
diff --git a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
index de9de01..b570979 100644
--- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
@@ -108,12 +108,6 @@
EXPECT_CALL(*mOutput2, prepare(Ref(mRefreshArgs), _));
EXPECT_CALL(*mOutput3, prepare(Ref(mRefreshArgs), _));
- // The next step in presenting is to make sure all outputs have the latest
- // state from the front-end (SurfaceFlinger).
- EXPECT_CALL(*mOutput1, updateLayerStateFromFE(Ref(mRefreshArgs)));
- EXPECT_CALL(*mOutput2, updateLayerStateFromFE(Ref(mRefreshArgs)));
- EXPECT_CALL(*mOutput3, updateLayerStateFromFE(Ref(mRefreshArgs)));
-
// The last step is to actually present each output.
EXPECT_CALL(*mOutput1, present(Ref(mRefreshArgs)));
EXPECT_CALL(*mOutput2, present(Ref(mRefreshArgs)));
@@ -175,21 +169,18 @@
{
InSequence seq;
EXPECT_CALL(mOutput2Layer1.outputLayer, isHardwareCursor()).WillRepeatedly(Return(true));
- EXPECT_CALL(*mOutput2Layer1.layerFE, prepareCompositionState(LayerFE::StateSubset::Cursor));
EXPECT_CALL(mOutput2Layer1.outputLayer, writeCursorPositionToHWC());
}
{
InSequence seq;
EXPECT_CALL(mOutput3Layer1.outputLayer, isHardwareCursor()).WillRepeatedly(Return(true));
- EXPECT_CALL(*mOutput3Layer1.layerFE, prepareCompositionState(LayerFE::StateSubset::Cursor));
EXPECT_CALL(mOutput3Layer1.outputLayer, writeCursorPositionToHWC());
}
{
InSequence seq;
EXPECT_CALL(mOutput3Layer2.outputLayer, isHardwareCursor()).WillRepeatedly(Return(true));
- EXPECT_CALL(*mOutput3Layer2.layerFE, prepareCompositionState(LayerFE::StateSubset::Cursor));
EXPECT_CALL(mOutput3Layer2.outputLayer, writeCursorPositionToHWC());
}
@@ -222,9 +213,12 @@
nsecs_t ts1 = 0;
nsecs_t ts2 = 0;
nsecs_t ts3 = 0;
- EXPECT_CALL(*mLayer1FE, onPreComposition(_)).WillOnce(DoAll(SaveArg<0>(&ts1), Return(false)));
- EXPECT_CALL(*mLayer2FE, onPreComposition(_)).WillOnce(DoAll(SaveArg<0>(&ts2), Return(false)));
- EXPECT_CALL(*mLayer3FE, onPreComposition(_)).WillOnce(DoAll(SaveArg<0>(&ts3), Return(false)));
+ EXPECT_CALL(*mLayer1FE, onPreComposition(_, _))
+ .WillOnce(DoAll(SaveArg<0>(&ts1), Return(false)));
+ EXPECT_CALL(*mLayer2FE, onPreComposition(_, _))
+ .WillOnce(DoAll(SaveArg<0>(&ts2), Return(false)));
+ EXPECT_CALL(*mLayer3FE, onPreComposition(_, _))
+ .WillOnce(DoAll(SaveArg<0>(&ts3), Return(false)));
mRefreshArgs.outputs = {mOutput1};
mRefreshArgs.layers = {mLayer1FE, mLayer2FE, mLayer3FE};
@@ -238,9 +232,9 @@
}
TEST_F(CompositionTestPreComposition, preCompositionDefaultsToNoUpdateNeeded) {
- EXPECT_CALL(*mLayer1FE, onPreComposition(_)).WillOnce(Return(false));
- EXPECT_CALL(*mLayer2FE, onPreComposition(_)).WillOnce(Return(false));
- EXPECT_CALL(*mLayer3FE, onPreComposition(_)).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer1FE, onPreComposition(_, _)).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer2FE, onPreComposition(_, _)).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer3FE, onPreComposition(_, _)).WillOnce(Return(false));
mEngine.setNeedsAnotherUpdateForTest(true);
@@ -255,9 +249,9 @@
TEST_F(CompositionTestPreComposition,
preCompositionSetsNeedsAnotherUpdateIfAtLeastOneLayerRequestsIt) {
- EXPECT_CALL(*mLayer1FE, onPreComposition(_)).WillOnce(Return(true));
- EXPECT_CALL(*mLayer2FE, onPreComposition(_)).WillOnce(Return(false));
- EXPECT_CALL(*mLayer3FE, onPreComposition(_)).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer1FE, onPreComposition(_, _)).WillOnce(Return(true));
+ EXPECT_CALL(*mLayer2FE, onPreComposition(_, _)).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer3FE, onPreComposition(_, _)).WillOnce(Return(false));
mRefreshArgs.outputs = {mOutput1};
mRefreshArgs.layers = {mLayer1FE, mLayer2FE, mLayer3FE};
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index ace2864..eb209e9 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -758,56 +758,6 @@
}
/*
- * Output::updateLayerStateFromFE()
- */
-
-using OutputUpdateLayerStateFromFETest = OutputTest;
-
-TEST_F(OutputUpdateLayerStateFromFETest, handlesNoOutputLayerCase) {
- CompositionRefreshArgs refreshArgs;
-
- mOutput->updateLayerStateFromFE(refreshArgs);
-}
-
-TEST_F(OutputUpdateLayerStateFromFETest, preparesContentStateForAllContainedLayers) {
- InjectedLayer layer1;
- InjectedLayer layer2;
- InjectedLayer layer3;
-
- EXPECT_CALL(*layer1.layerFE.get(), prepareCompositionState(LayerFE::StateSubset::Content));
- EXPECT_CALL(*layer2.layerFE.get(), prepareCompositionState(LayerFE::StateSubset::Content));
- EXPECT_CALL(*layer3.layerFE.get(), prepareCompositionState(LayerFE::StateSubset::Content));
-
- injectOutputLayer(layer1);
- injectOutputLayer(layer2);
- injectOutputLayer(layer3);
-
- CompositionRefreshArgs refreshArgs;
- refreshArgs.updatingGeometryThisFrame = false;
-
- mOutput->updateLayerStateFromFE(refreshArgs);
-}
-
-TEST_F(OutputUpdateLayerStateFromFETest, preparesGeometryAndContentStateForAllContainedLayers) {
- InjectedLayer layer1;
- InjectedLayer layer2;
- InjectedLayer layer3;
-
- EXPECT_CALL(*layer1.layerFE, prepareCompositionState(LayerFE::StateSubset::GeometryAndContent));
- EXPECT_CALL(*layer2.layerFE, prepareCompositionState(LayerFE::StateSubset::GeometryAndContent));
- EXPECT_CALL(*layer3.layerFE, prepareCompositionState(LayerFE::StateSubset::GeometryAndContent));
-
- injectOutputLayer(layer1);
- injectOutputLayer(layer2);
- injectOutputLayer(layer3);
-
- CompositionRefreshArgs refreshArgs;
- refreshArgs.updatingGeometryThisFrame = true;
-
- mOutput->updateLayerStateFromFE(refreshArgs);
-}
-
-/*
* Output::updateAndWriteCompositionState()
*/
@@ -1536,9 +1486,6 @@
TEST_F(OutputEnsureOutputLayerIfVisibleTest, performsGeomLatchBeforeCheckingIfLayerIncluded) {
EXPECT_CALL(mOutput, includesLayer(sp<LayerFE>(mLayer.layerFE))).WillOnce(Return(false));
- EXPECT_CALL(*mLayer.layerFE,
- prepareCompositionState(compositionengine::LayerFE::StateSubset::BasicGeometry));
-
mGeomSnapshots.clear();
ensureOutputLayerIfVisible();
diff --git a/services/surfaceflinger/Display/DisplayMap.h b/services/surfaceflinger/Display/DisplayMap.h
new file mode 100644
index 0000000..baf0da9
--- /dev/null
+++ b/services/surfaceflinger/Display/DisplayMap.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <ftl/small_map.h>
+
+namespace android::display {
+
+// The static capacities were chosen to exceed a typical number of physical and/or virtual displays.
+
+template <typename Key, typename Value>
+using DisplayMap = ftl::SmallMap<Key, Value, 5>;
+
+template <typename Key, typename Value>
+using PhysicalDisplayMap = ftl::SmallMap<Key, Value, 3>;
+
+} // namespace android::display
diff --git a/services/surfaceflinger/Display/DisplaySnapshot.cpp b/services/surfaceflinger/Display/DisplaySnapshot.cpp
new file mode 100644
index 0000000..b4f104a
--- /dev/null
+++ b/services/surfaceflinger/Display/DisplaySnapshot.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#include <functional>
+#include <utility>
+
+#include <ftl/algorithm.h>
+#include <ftl/enum.h>
+
+#include "DisplaySnapshot.h"
+
+namespace android::display {
+
+DisplaySnapshot::DisplaySnapshot(PhysicalDisplayId displayId,
+ ui::DisplayConnectionType connectionType,
+ DisplayModes&& displayModes,
+ std::optional<DeviceProductInfo>&& deviceProductInfo)
+ : mDisplayId(displayId),
+ mConnectionType(connectionType),
+ mDisplayModes(std::move(displayModes)),
+ mDeviceProductInfo(std::move(deviceProductInfo)) {}
+
+std::optional<DisplayModeId> DisplaySnapshot::translateModeId(hal::HWConfigId hwcId) const {
+ return ftl::find_if(mDisplayModes,
+ [hwcId](const DisplayModes::value_type& pair) {
+ return pair.second->getHwcId() == hwcId;
+ })
+ .transform(&ftl::to_key<DisplayModes>);
+}
+
+void DisplaySnapshot::dump(std::string& out) const {
+ using namespace std::string_literals;
+
+ out += " connectionType="s;
+ out += ftl::enum_string(mConnectionType);
+
+ out += "\n deviceProductInfo="s;
+ if (mDeviceProductInfo) {
+ mDeviceProductInfo->dump(out);
+ } else {
+ out += "{}"s;
+ }
+}
+
+} // namespace android::display
diff --git a/services/surfaceflinger/Display/DisplaySnapshot.h b/services/surfaceflinger/Display/DisplaySnapshot.h
new file mode 100644
index 0000000..0279220
--- /dev/null
+++ b/services/surfaceflinger/Display/DisplaySnapshot.h
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <optional>
+#include <string>
+
+#include <ui/DisplayId.h>
+#include <ui/StaticDisplayInfo.h>
+
+#include "../DisplayHardware/DisplayMode.h"
+
+namespace android::display {
+
+// Immutable state of a physical display, captured on hotplug.
+class DisplaySnapshot {
+public:
+ DisplaySnapshot(PhysicalDisplayId, ui::DisplayConnectionType, DisplayModes&&,
+ std::optional<DeviceProductInfo>&&);
+
+ DisplaySnapshot(const DisplaySnapshot&) = delete;
+ DisplaySnapshot(DisplaySnapshot&&) = default;
+
+ PhysicalDisplayId displayId() const { return mDisplayId; }
+ ui::DisplayConnectionType connectionType() const { return mConnectionType; }
+
+ std::optional<DisplayModeId> translateModeId(hal::HWConfigId) const;
+
+ const auto& displayModes() const { return mDisplayModes; }
+ const auto& deviceProductInfo() const { return mDeviceProductInfo; }
+
+ void dump(std::string&) const;
+
+private:
+ const PhysicalDisplayId mDisplayId;
+ const ui::DisplayConnectionType mConnectionType;
+
+ // Effectively const except in move constructor.
+ DisplayModes mDisplayModes;
+ std::optional<DeviceProductInfo> mDeviceProductInfo;
+};
+
+} // namespace android::display
diff --git a/services/surfaceflinger/Display/PhysicalDisplay.h b/services/surfaceflinger/Display/PhysicalDisplay.h
new file mode 100644
index 0000000..cba1014
--- /dev/null
+++ b/services/surfaceflinger/Display/PhysicalDisplay.h
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <functional>
+#include <utility>
+
+#include <binder/IBinder.h>
+#include <ui/DisplayId.h>
+#include <utils/StrongPointer.h>
+
+#include "DisplayMap.h"
+#include "DisplaySnapshot.h"
+
+namespace android::display {
+
+// TODO(b/229877597): Replace with AIDL type.
+using DisplayToken = IBinder;
+
+class PhysicalDisplay {
+public:
+ template <typename... Args>
+ PhysicalDisplay(sp<DisplayToken> token, Args&&... args)
+ : mToken(std::move(token)), mSnapshot(std::forward<Args>(args)...) {}
+
+ PhysicalDisplay(const PhysicalDisplay&) = delete;
+ PhysicalDisplay(PhysicalDisplay&&) = default;
+
+ const sp<DisplayToken>& token() const { return mToken; }
+ const DisplaySnapshot& snapshot() const { return mSnapshot; }
+
+ // Transformers for PhysicalDisplays::get.
+
+ using SnapshotRef = std::reference_wrapper<const DisplaySnapshot>;
+ SnapshotRef snapshotRef() const { return std::cref(mSnapshot); }
+
+ bool isInternal() const {
+ return mSnapshot.connectionType() == ui::DisplayConnectionType::Internal;
+ }
+
+ // Predicate for ftl::find_if on PhysicalDisplays.
+ static constexpr auto hasToken(const sp<DisplayToken>& token) {
+ return [&token](const std::pair<const PhysicalDisplayId, PhysicalDisplay>& pair) {
+ return pair.second.token() == token;
+ };
+ }
+
+private:
+ const sp<DisplayToken> mToken;
+
+ // Effectively const except in move constructor.
+ DisplaySnapshot mSnapshot;
+};
+
+using PhysicalDisplays = PhysicalDisplayMap<PhysicalDisplayId, PhysicalDisplay>;
+
+// Combinator for ftl::Optional<PhysicalDisplayId>::and_then.
+constexpr auto getPhysicalDisplay(const PhysicalDisplays& displays) {
+ return [&](PhysicalDisplayId id) { return displays.get(id); };
+}
+
+} // namespace android::display
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 2866a34..029e449 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -39,6 +39,7 @@
#include <system/window.h>
#include <ui/GraphicTypes.h>
+#include "Display/DisplaySnapshot.h"
#include "DisplayDevice.h"
#include "Layer.h"
#include "RefreshRateOverlay.h"
@@ -63,12 +64,10 @@
mHwComposer(args.hwComposer),
mDisplayToken(args.displayToken),
mSequenceId(args.sequenceId),
- mConnectionType(args.connectionType),
mCompositionDisplay{args.compositionDisplay},
mActiveModeFPSTrace("ActiveModeFPS -" + to_string(getId())),
mActiveModeFPSHwcTrace("ActiveModeFPS_HWC -" + to_string(getId())),
mPhysicalOrientation(args.physicalOrientation),
- mSupportedModes(std::move(args.supportedModes)),
mIsPrimary(args.isPrimary),
mRefreshRateConfigs(std::move(args.refreshRateConfigs)) {
mCompositionDisplay->editState().isSecure = args.isSecure;
@@ -132,10 +131,6 @@
}
}
-void DisplayDevice::setDeviceProductInfo(std::optional<DeviceProductInfo> info) {
- mDeviceProductInfo = std::move(info);
-}
-
auto DisplayDevice::getInputInfo() const -> InputInfo {
gui::DisplayInfo info;
info.displayId = getLayerStack().id;
@@ -169,6 +164,15 @@
}
void DisplayDevice::setPowerMode(hal::PowerMode mode) {
+ if (mode == hal::PowerMode::OFF || mode == hal::PowerMode::ON) {
+ if (mStagedBrightness && mBrightness != *mStagedBrightness) {
+ getCompositionDisplay()->setNextBrightness(*mStagedBrightness);
+ mBrightness = *mStagedBrightness;
+ }
+ mStagedBrightness = std::nullopt;
+ getCompositionDisplay()->applyDisplayBrightness(true);
+ }
+
mPowerMode = mode;
getCompositionDisplay()->setCompositionEnabled(mPowerMode.has_value() &&
@@ -187,16 +191,20 @@
return mPowerMode && *mPowerMode != hal::PowerMode::OFF;
}
-void DisplayDevice::setActiveMode(DisplayModeId id) {
- const auto mode = getMode(id);
- LOG_FATAL_IF(!mode, "Cannot set active mode which is not supported.");
- ATRACE_INT(mActiveModeFPSTrace.c_str(), mode->getFps().getIntValue());
- mActiveMode = mode;
+void DisplayDevice::setActiveMode(DisplayModeId modeId, const display::DisplaySnapshot& snapshot) {
+ const auto modeOpt = snapshot.displayModes().get(modeId);
+ LOG_ALWAYS_FATAL_IF(!modeOpt, "Unknown mode");
+
+ mActiveMode = modeOpt->get();
+ const Fps fps = mActiveMode->getFps();
+
+ ATRACE_INT(mActiveModeFPSTrace.c_str(), fps.getIntValue());
+
if (mRefreshRateConfigs) {
- mRefreshRateConfigs->setActiveModeId(mActiveMode->getId());
+ mRefreshRateConfigs->setActiveModeId(modeId);
}
if (mRefreshRateOverlay) {
- mRefreshRateOverlay->changeRefreshRate(mActiveMode->getFps());
+ mRefreshRateOverlay->changeRefreshRate(fps);
}
}
@@ -220,25 +228,6 @@
return mActiveMode;
}
-const DisplayModes& DisplayDevice::getSupportedModes() const {
- return mSupportedModes;
-}
-
-DisplayModePtr DisplayDevice::getMode(DisplayModeId modeId) const {
- const DisplayModePtr nullMode;
- return mSupportedModes.get(modeId).value_or(std::cref(nullMode));
-}
-
-std::optional<DisplayModeId> DisplayDevice::translateModeId(hal::HWConfigId hwcId) const {
- const auto it =
- std::find_if(mSupportedModes.begin(), mSupportedModes.end(),
- [hwcId](const auto& pair) { return pair.second->getHwcId() == hwcId; });
- if (it != mSupportedModes.end()) {
- return it->second->getId();
- }
- return {};
-}
-
nsecs_t DisplayDevice::getVsyncPeriodFromHWC() const {
const auto physicalId = getPhysicalId();
if (!mHwComposer.isConnected(physicalId)) {
@@ -268,10 +257,10 @@
return mCompositionDisplay->getState().dataspace;
}
-void DisplayDevice::setLayerStack(ui::LayerStack stack) {
- mCompositionDisplay->setLayerFilter({stack, isInternal()});
+void DisplayDevice::setLayerFilter(ui::LayerFilter filter) {
+ mCompositionDisplay->setLayerFilter(filter);
if (mRefreshRateOverlay) {
- mRefreshRateOverlay->setLayerStack(stack);
+ mRefreshRateOverlay->setLayerStack(filter.layerStack);
}
}
@@ -343,11 +332,7 @@
std::string name = "Display "s + to_string(getId()) + " ("s;
- if (mConnectionType) {
- name += isInternal() ? "internal"s : "external"s;
- } else {
- name += "virtual"s;
- }
+ name += isVirtual() ? "virtual"s : "physical"s;
if (isPrimary()) {
name += ", primary"s;
@@ -361,15 +346,6 @@
result += getDebugName();
- if (!isVirtual()) {
- result += "\n deviceProductInfo="s;
- if (mDeviceProductInfo) {
- mDeviceProductInfo->dump(result);
- } else {
- result += "{}"s;
- }
- }
-
result += "\n powerMode="s;
result += mPowerMode.has_value() ? to_string(mPowerMode.value()) : "OFF(reset)";
result += '\n';
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 3eead17..d79a6b5 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -65,6 +65,10 @@
class DisplaySurface;
} // namespace compositionengine
+namespace display {
+class DisplaySnapshot;
+} // namespace display
+
class DisplayDevice : public RefBase {
public:
constexpr static float sDefaultMinLumiance = 0.0;
@@ -80,11 +84,8 @@
return mCompositionDisplay;
}
- std::optional<ui::DisplayConnectionType> getConnectionType() const { return mConnectionType; }
-
- bool isVirtual() const { return !mConnectionType; }
+ bool isVirtual() const { return VirtualDisplayId::tryCast(getId()).has_value(); }
bool isPrimary() const { return mIsPrimary; }
- bool isInternal() const { return mConnectionType == ui::DisplayConnectionType::Internal; }
// isSecure indicates whether this display can be trusted to display
// secure surfaces.
@@ -94,7 +95,7 @@
int getHeight() const;
ui::Size getSize() const { return {getWidth(), getHeight()}; }
- void setLayerStack(ui::LayerStack);
+ void setLayerFilter(ui::LayerFilter);
void setDisplaySize(int width, int height);
void setProjection(ui::Rotation orientation, Rect viewport, Rect frame);
void stageBrightness(float brightness) REQUIRES(kMainThreadContext);
@@ -164,11 +165,6 @@
void setDisplayName(const std::string& displayName);
const std::string& getDisplayName() const { return mDisplayName; }
- void setDeviceProductInfo(std::optional<DeviceProductInfo> info);
- const std::optional<DeviceProductInfo>& getDeviceProductInfo() const {
- return mDeviceProductInfo;
- }
-
struct InputInfo {
gui::DisplayInfo info;
ui::Transform transform;
@@ -211,24 +207,14 @@
return mUpcomingActiveMode;
}
- void setActiveMode(DisplayModeId) REQUIRES(kMainThreadContext);
+ // Precondition: DisplaySnapshot must contain a mode with DisplayModeId.
+ void setActiveMode(DisplayModeId, const display::DisplaySnapshot&) REQUIRES(kMainThreadContext);
+
status_t initiateModeChange(const ActiveModeInfo&,
const hal::VsyncPeriodChangeConstraints& constraints,
hal::VsyncPeriodChangeTimeline* outTimeline)
REQUIRES(kMainThreadContext);
- // Return the immutable list of supported display modes. The HWC may report different modes
- // after a hotplug reconnect event, in which case the DisplayDevice object will be recreated.
- // Hotplug reconnects are common for external displays.
- const DisplayModes& getSupportedModes() const;
-
- // Returns nullptr if the given mode ID is not supported. A previously
- // supported mode may be no longer supported for some devices like TVs and
- // set-top boxes after a hotplug reconnect.
- DisplayModePtr getMode(DisplayModeId) const;
-
- std::optional<DisplayModeId> translateModeId(hal::HWConfigId) const;
-
// Returns the refresh rate configs for this display.
scheduler::RefreshRateConfigs& refreshRateConfigs() const { return *mRefreshRateConfigs; }
@@ -267,7 +253,6 @@
HWComposer& mHwComposer;
const wp<IBinder> mDisplayToken;
const int32_t mSequenceId;
- const std::optional<ui::DisplayConnectionType> mConnectionType;
const std::shared_ptr<compositionengine::Display> mCompositionDisplay;
@@ -285,7 +270,6 @@
DisplayModePtr mActiveMode;
std::optional<float> mStagedBrightness = std::nullopt;
float mBrightness = -1.f;
- const DisplayModes mSupportedModes;
std::atomic<nsecs_t> mLastHwVsync = 0;
@@ -294,8 +278,6 @@
uint32_t mFlags = 0;
- std::optional<DeviceProductInfo> mDeviceProductInfo;
-
std::vector<ui::Hdr> mOverrideHdrTypes;
std::shared_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs;
@@ -313,14 +295,11 @@
struct DisplayDeviceState {
struct Physical {
PhysicalDisplayId id;
- ui::DisplayConnectionType type;
hardware::graphics::composer::hal::HWDisplayId hwcDisplayId;
- std::optional<DeviceProductInfo> deviceProductInfo;
- DisplayModes supportedModes;
DisplayModePtr activeMode;
bool operator==(const Physical& other) const {
- return id == other.id && type == other.type && hwcDisplayId == other.hwcDisplayId;
+ return id == other.id && hwcDisplayId == other.hwcDisplayId;
}
};
@@ -356,7 +335,6 @@
std::shared_ptr<scheduler::RefreshRateConfigs> refreshRateConfigs;
int32_t sequenceId{0};
- std::optional<ui::DisplayConnectionType> connectionType;
bool isSecure{false};
sp<ANativeWindow> nativeWindow;
sp<compositionengine::DisplaySurface> displaySurface;
@@ -367,7 +345,6 @@
std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> hwcColorModes;
std::optional<hardware::graphics::composer::hal::PowerMode> initialPowerMode;
bool isPrimary{false};
- DisplayModes supportedModes;
DisplayModeId activeModeId;
};
diff --git a/services/surfaceflinger/EffectLayer.cpp b/services/surfaceflinger/EffectLayer.cpp
deleted file mode 100644
index 7180fa6..0000000
--- a/services/surfaceflinger/EffectLayer.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
-// #define LOG_NDEBUG 0
-#undef LOG_TAG
-#define LOG_TAG "EffectLayer"
-
-#include "EffectLayer.h"
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/types.h>
-
-#include <compositionengine/CompositionEngine.h>
-#include <compositionengine/LayerFECompositionState.h>
-#include <renderengine/RenderEngine.h>
-#include <ui/GraphicBuffer.h>
-#include <utils/Errors.h>
-#include <utils/Log.h>
-
-#include "DisplayDevice.h"
-#include "SurfaceFlinger.h"
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-EffectLayer::EffectLayer(const LayerCreationArgs& args) : BufferStateLayer(args) {}
-EffectLayer::~EffectLayer() = default;
-
-} // namespace android
diff --git a/services/surfaceflinger/EffectLayer.h b/services/surfaceflinger/EffectLayer.h
deleted file mode 100644
index 311d493..0000000
--- a/services/surfaceflinger/EffectLayer.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2007 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 <sys/types.h>
-
-#include <cstdint>
-
-#include "BufferStateLayer.h"
-
-namespace android {
-
-// A layer that can render a combination of the following effects.
-// * fill the bounds of the layer with a color
-// * render a shadow cast by the bounds of the layer
-// If no effects are enabled, the layer is considered to be invisible.
-class EffectLayer : public BufferStateLayer {
-public:
- explicit EffectLayer(const LayerCreationArgs&);
- ~EffectLayer() override;
-};
-
-} // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 47bd91e..08b71c2 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -65,9 +65,9 @@
#include <mutex>
#include <sstream>
+#include "BufferStateLayer.h"
#include "DisplayDevice.h"
#include "DisplayHardware/HWComposer.h"
-#include "EffectLayer.h"
#include "FrameTimeline.h"
#include "FrameTracer/FrameTracer.h"
#include "LayerProtoHelper.h"
@@ -465,6 +465,10 @@
for (const sp<Layer>& child : mDrawingChildren) {
child->computeBounds(mBounds, mEffectiveTransform, childShadowRadius);
}
+
+ if (mPotentialCursor) {
+ prepareCursorCompositionState();
+ }
}
Rect Layer::getCroppedBufferSize(const State& s) const {
@@ -650,30 +654,6 @@
return sp<compositionengine::LayerFE>::fromExisting(layerFE);
}
-void Layer::prepareCompositionState(compositionengine::LayerFE::StateSubset subset) {
- using StateSubset = compositionengine::LayerFE::StateSubset;
-
- switch (subset) {
- case StateSubset::BasicGeometry:
- prepareBasicGeometryCompositionState();
- break;
-
- case StateSubset::GeometryAndContent:
- prepareBasicGeometryCompositionState();
- prepareGeometryCompositionState();
- preparePerFrameCompositionState();
- break;
-
- case StateSubset::Content:
- preparePerFrameCompositionState();
- break;
-
- case StateSubset::Cursor:
- prepareCursorCompositionState();
- break;
- }
-}
-
const char* Layer::getDebugName() const {
return mName.c_str();
}
@@ -2205,8 +2185,8 @@
renderengine::ShadowSettings state = mFlinger->mDrawingState.globalShadowSettings;
// Note: this preserves existing behavior of shadowing the entire layer and not cropping it if
- // transparent regions are present. This may not be necessary since shadows are only cast by
- // SurfaceFlinger's EffectLayers, which do not typically use transparent regions.
+ // transparent regions are present. This may not be necessary since shadows are typically cast
+ // by layers without transparent regions.
state.boundaries = mBounds;
// Shift the spot light x-position to the middle of the display and then
@@ -3426,7 +3406,7 @@
return fenceSignaled;
}
-bool Layer::onPreComposition(nsecs_t refreshStartTime) {
+bool Layer::onPreComposition(nsecs_t refreshStartTime, bool /* updatingOutputGeometryThisFrame */) {
for (const auto& handle : mDrawingState.callbackHandles) {
handle->refreshStartTime = refreshStartTime;
}
@@ -3947,7 +3927,7 @@
}
if (display) {
- const Fps refreshRate = display->refreshRateConfigs().getActiveMode()->getFps();
+ const Fps refreshRate = display->refreshRateConfigs().getActiveModePtr()->getFps();
const std::optional<Fps> renderRate =
mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
@@ -4240,6 +4220,18 @@
return getBackgroundBlurRadius() > 0 || getDrawingState().blurRegions.size() > 0;
}
+void Layer::updateSnapshot(bool updateGeometry) {
+ if (!getCompositionEngineLayerFE()) {
+ return;
+ }
+
+ if (updateGeometry) {
+ prepareBasicGeometryCompositionState();
+ prepareGeometryCompositionState();
+ }
+ preparePerFrameCompositionState();
+}
+
// ---------------------------------------------------------------------------
std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index f6b9b0f..5030fd8 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -574,9 +574,8 @@
// implements compositionengine::LayerFE
const compositionengine::LayerFECompositionState* getCompositionState() const;
bool fenceHasSignaled() const;
- bool onPreComposition(nsecs_t);
- void prepareCompositionState(compositionengine::LayerFE::StateSubset subset) override;
-
+ // Called before composition. updatingOutputGeometryThisFrame is used by ARC++'s Layer subclass.
+ bool onPreComposition(nsecs_t refreshStartTime, bool updatingOutputGeometryThisFrame);
std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings&) const override;
void onLayerDisplayed(ftl::SharedFuture<FenceResult>);
@@ -868,6 +867,7 @@
bool simpleBufferUpdate(const layer_state_t&) const;
static bool isOpaqueFormat(PixelFormat format);
+ void updateSnapshot(bool updateGeometry);
protected:
friend class impl::SurfaceInterceptor;
diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp
index e17b01f..6bc7dc1 100644
--- a/services/surfaceflinger/LayerRenderArea.cpp
+++ b/services/surfaceflinger/LayerRenderArea.cpp
@@ -18,7 +18,6 @@
#include <ui/Transform.h>
#include "DisplayDevice.h"
-#include "EffectLayer.h"
#include "Layer.h"
#include "LayerRenderArea.h"
#include "SurfaceFlinger.h"
@@ -110,7 +109,7 @@
// layer which has no properties set and which does not draw.
// We hold the statelock as the reparent-for-drawing operation modifies the
// hierarchy and there could be readers on Binder threads, like dump.
- sp<EffectLayer> screenshotParentLayer = mFlinger.getFactory().createEffectLayer(
+ auto screenshotParentLayer = mFlinger.getFactory().createEffectLayer(
{&mFlinger, nullptr, "Screenshot Parent"s, ISurfaceComposerClient::eNoColorFill,
LayerMetadata()});
{
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index 747032b..4af1f5c 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -188,10 +188,10 @@
VSyncSource::VSyncData DispSyncSource::getLatestVSyncData() const {
std::lock_guard lock(mVsyncMutex);
- nsecs_t expectedPresentTime = mVSyncTracker.nextAnticipatedVSyncTimeFrom(
+ nsecs_t expectedPresentationTime = mVSyncTracker.nextAnticipatedVSyncTimeFrom(
systemTime() + mWorkDuration.get().count() + mReadyDuration.count());
- nsecs_t deadline = expectedPresentTime - mWorkDuration.get().count() - mReadyDuration.count();
- return {expectedPresentTime, deadline};
+ nsecs_t deadline = expectedPresentationTime - mReadyDuration.count();
+ return {expectedPresentationTime, deadline};
}
void DispSyncSource::dump(std::string& result) const {
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index a48c921..00886f0 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -27,6 +27,7 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <ftl/enum.h>
+#include <ftl/fake_guard.h>
#include <utils/Trace.h>
#include "../SurfaceFlingerProperties.h"
@@ -279,6 +280,15 @@
ATRACE_CALL();
ALOGV("%s: %zu layers", __func__, layers.size());
+ const auto& activeMode = *getActiveModeItLocked()->second;
+
+ // Keep the display at max refresh rate for the duration of powering on the display.
+ if (signals.powerOnImminent) {
+ ALOGV("Power On Imminent");
+ const auto& max = getMaxRefreshRateByPolicyLocked(activeMode.getGroup());
+ return {max, GlobalSignals{.powerOnImminent = true}};
+ }
+
int noVoteLayers = 0;
int minVoteLayers = 0;
int maxVoteLayers = 0;
@@ -325,6 +335,7 @@
const Policy* policy = getCurrentPolicyLocked();
const auto& defaultMode = mDisplayModes.get(policy->defaultMode)->get();
+
// If the default mode group is different from the group of current mode,
// this means a layer requesting a seamed mode switch just disappeared and
// we should switch back to the default group.
@@ -332,7 +343,7 @@
// of the current mode, in order to prevent unnecessary seamed mode switches
// (e.g. when pausing a video playback).
const auto anchorGroup =
- seamedFocusedLayers > 0 ? mActiveModeIt->second->getGroup() : defaultMode->getGroup();
+ seamedFocusedLayers > 0 ? activeMode.getGroup() : defaultMode->getGroup();
// Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've
// selected a refresh rate to see if we should apply touch boost.
@@ -387,12 +398,12 @@
for (auto& [modeIt, overallScore, fixedRateBelowThresholdLayersScore] : scores) {
const auto& [id, mode] = *modeIt;
- const bool isSeamlessSwitch = mode->getGroup() == mActiveModeIt->second->getGroup();
+ const bool isSeamlessSwitch = mode->getGroup() == activeMode.getGroup();
if (layer.seamlessness == Seamlessness::OnlySeamless && !isSeamlessSwitch) {
ALOGV("%s ignores %s to avoid non-seamless switch. Current mode = %s",
formatLayerInfo(layer, weight).c_str(), to_string(*mode).c_str(),
- to_string(*mActiveModeIt->second).c_str());
+ to_string(activeMode).c_str());
continue;
}
@@ -401,7 +412,7 @@
ALOGV("%s ignores %s because it's not focused and the switch is going to be seamed."
" Current mode = %s",
formatLayerInfo(layer, weight).c_str(), to_string(*mode).c_str(),
- to_string(*mActiveModeIt->second).c_str());
+ to_string(activeMode).c_str());
continue;
}
@@ -413,7 +424,7 @@
const bool isInPolicyForDefault = mode->getGroup() == anchorGroup;
if (layer.seamlessness == Seamlessness::Default && !isInPolicyForDefault) {
ALOGV("%s ignores %s. Current mode = %s", formatLayerInfo(layer, weight).c_str(),
- to_string(*mode).c_str(), to_string(*mActiveModeIt->second).c_str());
+ to_string(*mode).c_str(), to_string(activeMode).c_str());
continue;
}
@@ -676,7 +687,7 @@
const DisplayModePtr& current = desiredActiveModeId
? mDisplayModes.get(*desiredActiveModeId)->get()
- : mActiveModeIt->second;
+ : getActiveModeItLocked()->second;
const DisplayModePtr& min = mMinRefreshRateModeIt->second;
if (current == min) {
@@ -688,16 +699,17 @@
}
const DisplayModePtr& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() const {
+ const auto& activeMode = *getActiveModeItLocked()->second;
+
for (const DisplayModeIterator modeIt : mPrimaryRefreshRates) {
const auto& mode = modeIt->second;
- if (mActiveModeIt->second->getGroup() == mode->getGroup()) {
+ if (activeMode.getGroup() == mode->getGroup()) {
return mode;
}
}
- ALOGE("Can't find min refresh rate by policy with the same mode group"
- " as the current mode %s",
- to_string(*mActiveModeIt->second).c_str());
+ ALOGE("Can't find min refresh rate by policy with the same mode group as the current mode %s",
+ to_string(activeMode).c_str());
// Default to the lowest refresh rate.
return mPrimaryRefreshRates.front()->second;
@@ -708,6 +720,11 @@
return getMaxRefreshRateByPolicyLocked();
}
+const DisplayModePtr& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked() const {
+ const int anchorGroup = getActiveModeItLocked()->second->getGroup();
+ return getMaxRefreshRateByPolicyLocked(anchorGroup);
+}
+
const DisplayModePtr& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked(int anchorGroup) const {
for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); ++it) {
const auto& mode = (*it)->second;
@@ -716,17 +733,28 @@
}
}
- ALOGE("Can't find max refresh rate by policy with the same mode group"
- " as the current mode %s",
- to_string(*mActiveModeIt->second).c_str());
+ const auto& activeMode = *getActiveModeItLocked()->second;
+ ALOGE("Can't find max refresh rate by policy with the same mode group as the current mode %s",
+ to_string(activeMode).c_str());
// Default to the highest refresh rate.
return mPrimaryRefreshRates.back()->second;
}
-DisplayModePtr RefreshRateConfigs::getActiveMode() const {
+DisplayModePtr RefreshRateConfigs::getActiveModePtr() const {
std::lock_guard lock(mLock);
- return mActiveModeIt->second;
+ return getActiveModeItLocked()->second;
+}
+
+const DisplayMode& RefreshRateConfigs::getActiveMode() const {
+ // Reads from kMainThreadContext do not require mLock.
+ ftl::FakeGuard guard(mLock);
+ return *mActiveModeIt->second;
+}
+
+DisplayModeIterator RefreshRateConfigs::getActiveModeItLocked() const {
+ // Reads under mLock do not require kMainThreadContext.
+ return FTL_FAKE_GUARD(kMainThreadContext, mActiveModeIt);
}
void RefreshRateConfigs::setActiveModeId(DisplayModeId modeId) {
@@ -744,7 +772,7 @@
Config config)
: mKnownFrameRates(constructKnownFrameRates(modes)), mConfig(config) {
initializeIdleTimer();
- updateDisplayModes(std::move(modes), activeModeId);
+ FTL_FAKE_GUARD(kMainThreadContext, updateDisplayModes(std::move(modes), activeModeId));
}
void RefreshRateConfigs::initializeIdleTimer() {
@@ -976,7 +1004,7 @@
std::lock_guard lock(mLock);
- const auto activeModeId = mActiveModeIt->first;
+ const auto activeModeId = getActiveModeItLocked()->first;
result += " activeModeId="s;
result += std::to_string(activeModeId.value());
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index a79002e..19bcb94 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -31,6 +31,7 @@
#include "DisplayHardware/HWComposer.h"
#include "Scheduler/OneShotTimer.h"
#include "Scheduler/StrongTyping.h"
+#include "ThreadContext.h"
namespace android::scheduler {
@@ -184,9 +185,13 @@
bool touch = false;
// True if the system hasn't seen any buffers posted to layers recently.
bool idle = false;
+ // Whether the display is about to be powered on, or has been in PowerMode::ON
+ // within the timeout of DisplayPowerTimer.
+ bool powerOnImminent = false;
bool operator==(GlobalSignals other) const {
- return touch == other.touch && idle == other.idle;
+ return touch == other.touch && idle == other.idle &&
+ powerOnImminent == other.powerOnImminent;
}
};
@@ -207,8 +212,11 @@
// uses the primary range, not the app request range.
DisplayModePtr getMaxRefreshRateByPolicy() const EXCLUDES(mLock);
- void setActiveModeId(DisplayModeId) EXCLUDES(mLock);
- DisplayModePtr getActiveMode() const EXCLUDES(mLock);
+ void setActiveModeId(DisplayModeId) EXCLUDES(mLock) REQUIRES(kMainThreadContext);
+
+ // See mActiveModeIt for thread safety.
+ DisplayModePtr getActiveModePtr() const EXCLUDES(mLock);
+ const DisplayMode& getActiveMode() const REQUIRES(kMainThreadContext);
// Returns a known frame rate that is the closest to frameRate
Fps findClosestKnownFrameRate(Fps frameRate) const;
@@ -332,6 +340,9 @@
void constructAvailableRefreshRates() REQUIRES(mLock);
+ // See mActiveModeIt for thread safety.
+ DisplayModeIterator getActiveModeItLocked() const REQUIRES(mLock);
+
std::pair<DisplayModePtr, GlobalSignals> getBestRefreshRateLocked(
const std::vector<LayerRequirement>&, GlobalSignals) const REQUIRES(mLock);
@@ -345,10 +356,8 @@
// Returns the highest refresh rate according to the current policy. May change at runtime. Only
// uses the primary range, not the app request range.
+ const DisplayModePtr& getMaxRefreshRateByPolicyLocked() const REQUIRES(mLock);
const DisplayModePtr& getMaxRefreshRateByPolicyLocked(int anchorGroup) const REQUIRES(mLock);
- const DisplayModePtr& getMaxRefreshRateByPolicyLocked() const REQUIRES(mLock) {
- return getMaxRefreshRateByPolicyLocked(mActiveModeIt->second->getGroup());
- }
const Policy* getCurrentPolicyLocked() const REQUIRES(mLock);
bool isPolicyValidLocked(const Policy& policy) const REQUIRES(mLock);
@@ -361,7 +370,8 @@
float calculateNonExactMatchingLayerScoreLocked(const LayerRequirement&, Fps refreshRate) const
REQUIRES(mLock);
- void updateDisplayModes(DisplayModes, DisplayModeId activeModeId) EXCLUDES(mLock);
+ void updateDisplayModes(DisplayModes, DisplayModeId activeModeId) EXCLUDES(mLock)
+ REQUIRES(kMainThreadContext);
void initializeIdleTimer();
@@ -377,7 +387,10 @@
// is also dependent, so must be reset as well.
DisplayModes mDisplayModes GUARDED_BY(mLock);
- DisplayModeIterator mActiveModeIt GUARDED_BY(mLock);
+ // Written under mLock exclusively from kMainThreadContext, so reads from kMainThreadContext
+ // need not be under mLock.
+ DisplayModeIterator mActiveModeIt GUARDED_BY(mLock) GUARDED_BY(kMainThreadContext);
+
DisplayModeIterator mMinRefreshRateModeIt GUARDED_BY(mLock);
DisplayModeIterator mMaxRefreshRateModeIt GUARDED_BY(mLock);
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 55ae013..ff6b461 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -182,7 +182,7 @@
impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction() const {
return [this](uid_t uid) {
- const Fps refreshRate = holdRefreshRateConfigs()->getActiveMode()->getFps();
+ const Fps refreshRate = holdRefreshRateConfigs()->getActiveModePtr()->getFps();
const nsecs_t currentPeriod = mVsyncSchedule->period().ns() ?: refreshRate.getPeriodNsecs();
const auto frameRate = getFrameRateOverride(uid);
@@ -320,7 +320,7 @@
// mode change is in progress. In that case we shouldn't dispatch an event
// as it will be dispatched when the current mode changes.
if (std::scoped_lock lock(mRefreshRateConfigsLock);
- mRefreshRateConfigs->getActiveMode() != mPolicy.mode) {
+ mRefreshRateConfigs->getActiveModePtr() != mPolicy.mode) {
return;
}
@@ -453,7 +453,7 @@
if (now - last > kIgnoreDelay) {
const auto refreshRate = [&] {
std::scoped_lock lock(mRefreshRateConfigsLock);
- return mRefreshRateConfigs->getActiveMode()->getFps();
+ return mRefreshRateConfigs->getActiveModePtr()->getFps();
}();
resyncToHardwareVsync(false, refreshRate);
}
@@ -577,7 +577,7 @@
// magic number
const Fps refreshRate = [&] {
std::scoped_lock lock(mRefreshRateConfigsLock);
- return mRefreshRateConfigs->getActiveMode()->getFps();
+ return mRefreshRateConfigs->getActiveModePtr()->getFps();
}();
constexpr Fps FPS_THRESHOLD_FOR_KERNEL_TIMER = 65_Hz;
@@ -704,17 +704,13 @@
const auto configs = holdRefreshRateConfigs();
- // If Display Power is not in normal operation we want to be in performance mode. When coming
- // back to normal mode, a grace period is given with DisplayPowerTimer.
- if (mDisplayPowerTimer &&
- (mPolicy.displayPowerMode != hal::PowerMode::ON ||
- mPolicy.displayPowerTimer == TimerState::Reset)) {
- constexpr GlobalSignals kNoSignals;
- return {configs->getMaxRefreshRateByPolicy(), kNoSignals};
- }
+ const bool powerOnImminent = mDisplayPowerTimer &&
+ (mPolicy.displayPowerMode != hal::PowerMode::ON ||
+ mPolicy.displayPowerTimer == TimerState::Reset);
const GlobalSignals signals{.touch = mTouchTimer && mPolicy.touch == TouchState::Active,
- .idle = mPolicy.idleTimer == TimerState::Expired};
+ .idle = mPolicy.idleTimer == TimerState::Expired,
+ .powerOnImminent = powerOnImminent};
return configs->getBestRefreshRate(mPolicy.contentRequirements, signals);
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index eb3856d..afb3459 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -229,7 +229,7 @@
nsecs_t getVsyncPeriodFromRefreshRateConfigs() const EXCLUDES(mRefreshRateConfigsLock) {
std::scoped_lock lock(mRefreshRateConfigsLock);
- return mRefreshRateConfigs->getActiveMode()->getFps().getPeriodNsecs();
+ return mRefreshRateConfigs->getActiveModePtr()->getFps().getPeriodNsecs();
}
// Returns the framerate of the layer with the given sequence ID
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cc93db3..e31490c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -53,9 +53,10 @@
#include <configstore/Utils.h>
#include <cutils/compiler.h>
#include <cutils/properties.h>
+#include <ftl/algorithm.h>
#include <ftl/fake_guard.h>
#include <ftl/future.h>
-#include <ftl/small_map.h>
+#include <ftl/unit.h>
#include <gui/AidlStatusUtil.h>
#include <gui/BufferQueue.h>
#include <gui/DebugEGLImageTracker.h>
@@ -108,6 +109,7 @@
#include "BufferStateLayer.h"
#include "Client.h"
#include "Colorizer.h"
+#include "Display/DisplayMap.h"
#include "DisplayDevice.h"
#include "DisplayHardware/ComposerHal.h"
#include "DisplayHardware/FramebufferSurface.h"
@@ -116,7 +118,6 @@
#include "DisplayHardware/PowerAdvisor.h"
#include "DisplayHardware/VirtualDisplaySurface.h"
#include "DisplayRenderArea.h"
-#include "EffectLayer.h"
#include "Effects/Daltonizer.h"
#include "FlagManager.h"
#include "FpsReporter.h"
@@ -172,6 +173,8 @@
OutputCompositionState::CompositionStrategyPredictionState;
using base::StringAppendF;
+using display::PhysicalDisplay;
+using display::PhysicalDisplays;
using gui::DisplayInfo;
using gui::GameMode;
using gui::IDisplayEventConnection;
@@ -594,12 +597,12 @@
std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIdsLocked() const {
std::vector<PhysicalDisplayId> displayIds;
- displayIds.reserve(mPhysicalDisplayTokens.size());
+ displayIds.reserve(mPhysicalDisplays.size());
const auto defaultDisplayId = getDefaultDisplayDeviceLocked()->getPhysicalId();
displayIds.push_back(defaultDisplayId);
- for (const auto& [id, token] : mPhysicalDisplayTokens) {
+ for (const auto& [id, display] : mPhysicalDisplays) {
if (id != defaultDisplayId) {
displayIds.push_back(id);
}
@@ -608,6 +611,12 @@
return displayIds;
}
+std::optional<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIdLocked(
+ const sp<display::DisplayToken>& displayToken) const {
+ return ftl::find_if(mPhysicalDisplays, PhysicalDisplay::hasToken(displayToken))
+ .transform(&ftl::to_key<PhysicalDisplays>);
+}
+
sp<IBinder> SurfaceFlinger::getPhysicalDisplayToken(PhysicalDisplayId displayId) const {
Mutex::Autolock lock(mStateLock);
return getPhysicalDisplayTokenLocked(displayId);
@@ -932,16 +941,19 @@
Mutex::Autolock lock(mStateLock);
- const auto display = getDisplayDeviceLocked(displayToken);
- if (!display) {
+ const auto displayOpt = ftl::find_if(mPhysicalDisplays, PhysicalDisplay::hasToken(displayToken))
+ .transform(&ftl::to_mapped_ref<PhysicalDisplays>)
+ .and_then(getDisplayDeviceAndSnapshot());
+
+ if (!displayOpt) {
return NAME_NOT_FOUND;
}
- if (const auto connectionType = display->getConnectionType())
- info->connectionType = *connectionType;
- else {
- return INVALID_OPERATION;
- }
+ const auto& [display, snapshotRef] = *displayOpt;
+ const auto& snapshot = snapshotRef.get();
+
+ info->connectionType = snapshot.connectionType();
+ info->deviceProductInfo = snapshot.deviceProductInfo();
if (mEmulatedDisplayDensity) {
info->density = mEmulatedDisplayDensity;
@@ -953,7 +965,6 @@
info->density /= ACONFIGURATION_DENSITY_MEDIUM;
info->secure = display->isSecure();
- info->deviceProductInfo = display->getDeviceProductInfo();
info->installOrientation = display->getPhysicalOrientation();
return NO_ERROR;
@@ -967,23 +978,22 @@
Mutex::Autolock lock(mStateLock);
- const auto display = getDisplayDeviceLocked(displayToken);
- if (!display) {
+ const auto displayOpt = ftl::find_if(mPhysicalDisplays, PhysicalDisplay::hasToken(displayToken))
+ .transform(&ftl::to_mapped_ref<PhysicalDisplays>)
+ .and_then(getDisplayDeviceAndSnapshot());
+ if (!displayOpt) {
return NAME_NOT_FOUND;
}
- const auto displayId = PhysicalDisplayId::tryCast(display->getId());
- if (!displayId) {
- return INVALID_OPERATION;
- }
+ const auto& [display, snapshotRef] = *displayOpt;
+ const auto& snapshot = snapshotRef.get();
- info->activeDisplayModeId = display->getActiveMode()->getId().value();
+ const auto& displayModes = snapshot.displayModes();
- const auto& supportedModes = display->getSupportedModes();
info->supportedDisplayModes.clear();
- info->supportedDisplayModes.reserve(supportedModes.size());
+ info->supportedDisplayModes.reserve(displayModes.size());
- for (const auto& [id, mode] : supportedModes) {
+ for (const auto& [id, mode] : displayModes) {
ui::DisplayMode outMode;
outMode.id = static_cast<int32_t>(id.value());
@@ -1027,21 +1037,24 @@
info->supportedDisplayModes.push_back(outMode);
}
+ const PhysicalDisplayId displayId = snapshot.displayId();
+
+ info->activeDisplayModeId = display->getActiveMode()->getId().value();
info->activeColorMode = display->getCompositionDisplay()->getState().colorMode;
- info->supportedColorModes = getDisplayColorModes(*display);
+ info->supportedColorModes = getDisplayColorModes(displayId);
info->hdrCapabilities = display->getHdrCapabilities();
info->autoLowLatencyModeSupported =
- getHwComposer().hasDisplayCapability(*displayId,
+ getHwComposer().hasDisplayCapability(displayId,
DisplayCapability::AUTO_LOW_LATENCY_MODE);
info->gameContentTypeSupported =
- getHwComposer().supportsContentType(*displayId, hal::ContentType::GAME);
+ getHwComposer().supportsContentType(displayId, hal::ContentType::GAME);
info->preferredBootDisplayMode = static_cast<ui::DisplayModeId>(-1);
if (getHwComposer().hasCapability(Capability::BOOT_DISPLAY_CONFIG)) {
- if (const auto hwcId = getHwComposer().getPreferredBootDisplayMode(*displayId)) {
- if (const auto modeId = display->translateModeId(*hwcId)) {
+ if (const auto hwcId = getHwComposer().getPreferredBootDisplayMode(displayId)) {
+ if (const auto modeId = snapshot.translateModeId(*hwcId)) {
info->preferredBootDisplayMode = modeId->value();
}
}
@@ -1089,39 +1102,44 @@
}
}
-status_t SurfaceFlinger::setActiveModeFromBackdoor(const sp<IBinder>& displayToken, int modeId) {
+status_t SurfaceFlinger::setActiveModeFromBackdoor(const sp<display::DisplayToken>& displayToken,
+ DisplayModeId modeId) {
ATRACE_CALL();
if (!displayToken) {
return BAD_VALUE;
}
+ const char* const whence = __func__;
auto future = mScheduler->schedule([=]() -> status_t {
- const auto display = FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(displayToken));
- if (!display) {
- ALOGE("Attempt to set allowed display modes for invalid display token %p",
- displayToken.get());
+ const auto displayOpt =
+ FTL_FAKE_GUARD(mStateLock,
+ ftl::find_if(mPhysicalDisplays,
+ PhysicalDisplay::hasToken(displayToken))
+ .transform(&ftl::to_mapped_ref<PhysicalDisplays>)
+ .and_then(getDisplayDeviceAndSnapshot()));
+ if (!displayOpt) {
+ ALOGE("%s: Invalid physical display token %p", whence, displayToken.get());
return NAME_NOT_FOUND;
}
- if (display->isVirtual()) {
- ALOGW("Attempt to set allowed display modes for virtual display");
- return INVALID_OPERATION;
- }
+ const auto& [display, snapshotRef] = *displayOpt;
+ const auto& snapshot = snapshotRef.get();
- const auto mode = display->getMode(DisplayModeId{modeId});
- if (!mode) {
- ALOGW("Attempt to switch to an unsupported mode %d.", modeId);
+ const auto fpsOpt = snapshot.displayModes().get(modeId).transform(
+ [](const DisplayModePtr& mode) { return mode->getFps(); });
+
+ if (!fpsOpt) {
+ ALOGE("%s: Invalid mode %d for display %s", whence, modeId.value(),
+ to_string(snapshot.displayId()).c_str());
return BAD_VALUE;
}
- const auto fps = mode->getFps();
+ const Fps fps = *fpsOpt;
// Keep the old switching type.
- const auto allowGroupSwitching =
+ const bool allowGroupSwitching =
display->refreshRateConfigs().getCurrentPolicy().allowGroupSwitching;
- const scheduler::RefreshRateConfigs::Policy policy{mode->getId(),
- allowGroupSwitching,
- {fps, fps}};
+ const scheduler::RefreshRateConfigs::Policy policy{modeId, allowGroupSwitching, {fps, fps}};
constexpr bool kOverridePolicy = false;
return setDesiredDisplayModeSpecsInternal(display, policy, kOverridePolicy);
@@ -1138,9 +1156,7 @@
return;
}
- const auto upcomingModeInfo =
- FTL_FAKE_GUARD(kMainThreadContext, display->getUpcomingActiveMode());
-
+ const auto upcomingModeInfo = display->getUpcomingActiveMode();
if (!upcomingModeInfo.mode) {
// There is no pending mode change. This can happen if the active
// display changed and the mode change happened on a different display.
@@ -1159,9 +1175,12 @@
return;
}
- // We just created this display so we can call even if we are not on the main thread.
- ftl::FakeGuard guard(kMainThreadContext);
- display->setActiveMode(upcomingModeInfo.mode->getId());
+ mPhysicalDisplays.get(display->getPhysicalId())
+ .transform(&PhysicalDisplay::snapshotRef)
+ .transform(ftl::unit_fn([&](const display::DisplaySnapshot& snapshot) {
+ FTL_FAKE_GUARD(kMainThreadContext,
+ display->setActiveMode(upcomingModeInfo.mode->getId(), snapshot));
+ }));
const Fps refreshRate = upcomingModeInfo.mode->getFps();
mRefreshRateStats->setRefreshRate(refreshRate);
@@ -1191,12 +1210,16 @@
std::optional<PhysicalDisplayId> displayToUpdateImmediately;
- for (const auto& iter : mDisplays) {
- const auto& display = iter.second;
- if (!display || !display->isInternal()) {
+ for (const auto& [id, physical] : mPhysicalDisplays) {
+ const auto& snapshot = physical.snapshot();
+
+ if (snapshot.connectionType() != ui::DisplayConnectionType::Internal) {
continue;
}
+ const auto display = getDisplayDeviceLocked(id);
+ if (!display) continue;
+
// Store the local variable to release the lock.
const auto desiredActiveMode = display->getDesiredActiveMode();
if (!desiredActiveMode) {
@@ -1210,20 +1233,23 @@
continue;
}
- const auto desiredMode = display->getMode(desiredActiveMode->mode->getId());
- if (!desiredMode) {
+ const auto desiredModeId = desiredActiveMode->mode->getId();
+ const auto refreshRateOpt =
+ snapshot.displayModes()
+ .get(desiredModeId)
+ .transform([](const DisplayModePtr& mode) { return mode->getFps(); });
+
+ if (!refreshRateOpt) {
ALOGW("Desired display mode is no longer supported. Mode ID = %d",
- desiredActiveMode->mode->getId().value());
+ desiredModeId.value());
clearDesiredActiveModeState(display);
continue;
}
- const auto refreshRate = desiredMode->getFps();
- ALOGV("%s changing active mode to %d(%s) for display %s", __func__,
- desiredMode->getId().value(), to_string(refreshRate).c_str(),
- to_string(display->getId()).c_str());
+ ALOGV("%s changing active mode to %d(%s) for display %s", __func__, desiredModeId.value(),
+ to_string(*refreshRateOpt).c_str(), to_string(display->getId()).c_str());
- if (display->getActiveMode()->getId() == desiredActiveMode->mode->getId()) {
+ if (display->getActiveMode()->getId() == desiredModeId) {
// we are already in the requested mode, there is nothing left to do
desiredActiveModeChangeDone(display);
continue;
@@ -1232,8 +1258,7 @@
// Desired active mode was set, it is different than the mode currently in use, however
// allowed modes might have changed by the time we process the refresh.
// Make sure the desired mode is still allowed
- const auto displayModeAllowed =
- display->refreshRateConfigs().isModeAllowed(desiredActiveMode->mode->getId());
+ const auto displayModeAllowed = display->refreshRateConfigs().isModeAllowed(desiredModeId);
if (!displayModeAllowed) {
clearDesiredActiveModeState(display);
continue;
@@ -1245,9 +1270,8 @@
constraints.seamlessRequired = false;
hal::VsyncPeriodChangeTimeline outTimeline;
- const auto status = FTL_FAKE_GUARD(kMainThreadContext,
- display->initiateModeChange(*desiredActiveMode,
- constraints, &outTimeline));
+ const auto status =
+ display->initiateModeChange(*desiredActiveMode, constraints, &outTimeline);
if (status != NO_ERROR) {
// initiateModeChange may fail if a hotplug event is just about
@@ -1295,15 +1319,18 @@
future.wait();
}
-std::vector<ColorMode> SurfaceFlinger::getDisplayColorModes(const DisplayDevice& display) {
- auto modes = getHwComposer().getColorModes(display.getPhysicalId());
+std::vector<ColorMode> SurfaceFlinger::getDisplayColorModes(PhysicalDisplayId displayId) {
+ auto modes = getHwComposer().getColorModes(displayId);
+
+ const bool isInternalDisplay = mPhysicalDisplays.get(displayId)
+ .transform(&PhysicalDisplay::isInternal)
+ .value_or(false);
// If the display is internal and the configuration claims it's not wide color capable,
// filter out all wide color modes. The typical reason why this happens is that the
// hardware is not good enough to support GPU composition of wide color, and thus the
// OEMs choose to disable this capability.
- if (display.getConnectionType() == ui::DisplayConnectionType::Internal &&
- !hasWideColorDisplay) {
+ if (isInternalDisplay && !hasWideColorDisplay) {
const auto newEnd = std::remove_if(modes.begin(), modes.end(), isWideColorMode);
modes.erase(newEnd, modes.end());
}
@@ -1319,13 +1346,13 @@
Mutex::Autolock lock(mStateLock);
- const auto display = getDisplayDeviceLocked(displayToken);
+ const auto display = ftl::find_if(mPhysicalDisplays, PhysicalDisplay::hasToken(displayToken))
+ .transform(&ftl::to_mapped_ref<PhysicalDisplays>);
if (!display) {
return NAME_NOT_FOUND;
}
- const auto connectionType = display->getConnectionType();
- if (connectionType != ui::DisplayConnectionType::Internal) {
+ if (!display.transform(&PhysicalDisplay::isInternal).value()) {
return INVALID_OPERATION;
}
@@ -1353,7 +1380,7 @@
return INVALID_OPERATION;
}
- const auto modes = getDisplayColorModes(*display);
+ const auto modes = getDisplayColorModes(display->getPhysicalId());
const bool exists = std::find(modes.begin(), modes.end(), mode) != modes.end();
if (mode < ColorMode::NATIVE || !exists) {
@@ -1381,30 +1408,31 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::setBootDisplayMode(const sp<IBinder>& displayToken,
- ui::DisplayModeId modeId) {
+status_t SurfaceFlinger::setBootDisplayMode(const sp<display::DisplayToken>& displayToken,
+ DisplayModeId modeId) {
const char* const whence = __func__;
auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) -> status_t {
- const auto display = getDisplayDeviceLocked(displayToken);
- if (!display) {
- ALOGE("%s: Invalid display token %p", whence, displayToken.get());
+ const auto snapshotOpt =
+ ftl::find_if(mPhysicalDisplays, PhysicalDisplay::hasToken(displayToken))
+ .transform(&ftl::to_mapped_ref<PhysicalDisplays>)
+ .transform(&PhysicalDisplay::snapshotRef);
+
+ if (!snapshotOpt) {
+ ALOGE("%s: Invalid physical display token %p", whence, displayToken.get());
return NAME_NOT_FOUND;
}
- if (display->isVirtual()) {
- ALOGE("%s: Invalid operation on virtual display", whence);
- return INVALID_OPERATION;
- }
+ const auto& snapshot = snapshotOpt->get();
+ const auto hwcIdOpt = snapshot.displayModes().get(modeId).transform(
+ [](const DisplayModePtr& mode) { return mode->getHwcId(); });
- const auto displayId = display->getPhysicalId();
- const auto mode = display->getMode(DisplayModeId{modeId});
- if (!mode) {
- ALOGE("%s: Invalid mode %d for display %s", whence, modeId,
- to_string(displayId).c_str());
+ if (!hwcIdOpt) {
+ ALOGE("%s: Invalid mode %d for display %s", whence, modeId.value(),
+ to_string(snapshot.displayId()).c_str());
return BAD_VALUE;
}
- return getHwComposer().setBootDisplayMode(displayId, mode->getHwcId());
+ return getHwComposer().setBootDisplayMode(snapshot.displayId(), *hwcIdOpt);
});
return future.get();
}
@@ -2129,7 +2157,7 @@
// Hold mStateLock as chooseRefreshRateForContent promotes wp<Layer> to sp<Layer>
// and may eventually call to ~Layer() if it holds the last reference
{
- Mutex::Autolock _l(mStateLock);
+ Mutex::Autolock lock(mStateLock);
mScheduler->chooseRefreshRateForContent();
setActiveModeInHwcIfNeeded();
}
@@ -2161,10 +2189,6 @@
displayIds.push_back(display->getId());
}
mPowerAdvisor->setDisplays(displayIds);
- mDrawingState.traverseInZOrder([&refreshArgs](Layer* layer) {
- if (auto layerFE = layer->getCompositionEngineLayerFE())
- refreshArgs.layers.push_back(layerFE);
- });
if (DOES_CONTAIN_BORDER) {
refreshArgs.borderInfoList.clear();
@@ -2195,6 +2219,12 @@
refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty;
refreshArgs.updatingGeometryThisFrame = mGeometryDirty.exchange(false) || mVisibleRegionsDirty;
+ mDrawingState.traverseInZOrder([&refreshArgs](Layer* layer) {
+ layer->updateSnapshot(refreshArgs.updatingGeometryThisFrame);
+ if (auto layerFE = layer->getCompositionEngineLayerFE()) {
+ refreshArgs.layers.push_back(layerFE);
+ }
+ });
refreshArgs.blursAreExpensive = mBlursAreExpensive;
refreshArgs.internalDisplayRotationFlags = DisplayDevice::getPrimaryDisplayRotationFlags();
@@ -2467,7 +2497,13 @@
mTimeStats->incrementTotalFrames();
mTimeStats->setPresentFenceGlobal(presentFenceTime);
- if (display && display->isInternal() && display->getPowerMode() == hal::PowerMode::ON &&
+ const bool isInternalDisplay = display &&
+ FTL_FAKE_GUARD(mStateLock, mPhysicalDisplays)
+ .get(display->getPhysicalId())
+ .transform(&PhysicalDisplay::isInternal)
+ .value_or(false);
+
+ if (isInternalDisplay && display && display->getPowerMode() == hal::PowerMode::ON &&
presentFenceTime->isValid()) {
mScheduler->addPresentFence(std::move(presentFenceTime));
}
@@ -2601,10 +2637,11 @@
return {};
}
- DisplayModes oldModes;
- if (const auto token = getPhysicalDisplayTokenLocked(displayId)) {
- oldModes = getDisplayDeviceLocked(token)->getSupportedModes();
- }
+ const DisplayModes oldModes = mPhysicalDisplays.get(displayId)
+ .transform([](const PhysicalDisplay& display) {
+ return display.snapshot().displayModes();
+ })
+ .value_or(DisplayModes{});
ui::DisplayModeId nextModeId = 1 +
std::accumulate(oldModes.begin(), oldModes.end(), static_cast<ui::DisplayModeId>(-1),
@@ -2669,21 +2706,22 @@
const char* SurfaceFlinger::processHotplug(PhysicalDisplayId displayId,
hal::HWDisplayId hwcDisplayId, bool connected,
DisplayIdentificationInfo&& info) {
- const auto tokenOpt = mPhysicalDisplayTokens.get(displayId);
+ const auto displayOpt = mPhysicalDisplays.get(displayId);
if (!connected) {
- LOG_ALWAYS_FATAL_IF(!tokenOpt);
+ LOG_ALWAYS_FATAL_IF(!displayOpt);
+ const auto& display = displayOpt->get();
- if (const ssize_t index = mCurrentState.displays.indexOfKey(tokenOpt->get()); index >= 0) {
+ if (const ssize_t index = mCurrentState.displays.indexOfKey(display.token()); index >= 0) {
const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
mInterceptor->saveDisplayDeletion(state.sequenceId);
mCurrentState.displays.removeItemsAt(index);
}
- mPhysicalDisplayTokens.erase(displayId);
+ mPhysicalDisplays.erase(displayId);
return "Disconnecting";
}
- auto [supportedModes, activeMode] = loadDisplayModes(displayId);
+ auto [displayModes, activeMode] = loadDisplayModes(displayId);
if (!activeMode) {
// TODO(b/241286153): Report hotplug failure to the framework.
ALOGE("Failed to hotplug display %s", to_string(displayId).c_str());
@@ -2691,30 +2729,42 @@
return nullptr;
}
- if (tokenOpt) {
- auto& state = mCurrentState.displays.editValueFor(tokenOpt->get());
- state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId.
- state.physical->supportedModes = std::move(supportedModes);
- state.physical->activeMode = std::move(activeMode);
+ if (displayOpt) {
+ const auto& display = displayOpt->get();
+ const auto& snapshot = display.snapshot();
+
+ std::optional<DeviceProductInfo> deviceProductInfo;
if (getHwComposer().updatesDeviceProductInfoOnHotplugReconnect()) {
- state.physical->deviceProductInfo = std::move(info.deviceProductInfo);
+ deviceProductInfo = std::move(info.deviceProductInfo);
+ } else {
+ deviceProductInfo = snapshot.deviceProductInfo();
}
+
+ const auto it =
+ mPhysicalDisplays.try_replace(displayId, display.token(), displayId,
+ snapshot.connectionType(), std::move(displayModes),
+ std::move(deviceProductInfo));
+
+ auto& state = mCurrentState.displays.editValueFor(it->second.token());
+ state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId.
+ state.physical->activeMode = std::move(activeMode);
return "Reconnecting";
}
+ const sp<IBinder> token = sp<BBinder>::make();
+
+ mPhysicalDisplays.try_emplace(displayId, token, displayId,
+ getHwComposer().getDisplayConnectionType(displayId),
+ std::move(displayModes), std::move(info.deviceProductInfo));
+
DisplayDeviceState state;
state.physical = {.id = displayId,
- .type = getHwComposer().getDisplayConnectionType(displayId),
.hwcDisplayId = hwcDisplayId,
- .deviceProductInfo = std::move(info.deviceProductInfo),
- .supportedModes = std::move(supportedModes),
.activeMode = std::move(activeMode)};
state.isSecure = true; // All physical displays are currently considered secure.
state.displayName = std::move(info.name);
- sp<IBinder> token = sp<BBinder>::make();
mCurrentState.displays.add(token, state);
- mPhysicalDisplayTokens.try_emplace(displayId, std::move(token));
mInterceptor->saveDisplayCreation(state);
return "Connecting";
}
@@ -2739,8 +2789,6 @@
creationArgs.supportedPerFrameMetadata = 0;
if (const auto& physical = state.physical) {
- creationArgs.connectionType = physical->type;
- creationArgs.supportedModes = physical->supportedModes;
creationArgs.activeModeId = physical->activeMode->getId();
const auto [kernelIdleTimerController, idleTimerTimeoutMs] =
getKernelIdleTimerProperties(compositionDisplay->getId());
@@ -2751,9 +2799,17 @@
base::GetIntProperty("debug.sf.frame_rate_multiple_threshold", 0),
.idleTimerTimeout = idleTimerTimeoutMs,
.kernelIdleTimerController = kernelIdleTimerController};
+
creationArgs.refreshRateConfigs =
- std::make_shared<scheduler::RefreshRateConfigs>(creationArgs.supportedModes,
- creationArgs.activeModeId, config);
+ mPhysicalDisplays.get(physical->id)
+ .transform(&PhysicalDisplay::snapshotRef)
+ .transform([&](const display::DisplaySnapshot& snapshot) {
+ return std::make_shared<
+ scheduler::RefreshRateConfigs>(snapshot.displayModes(),
+ creationArgs.activeModeId,
+ config);
+ })
+ .value_or(nullptr);
}
if (const auto id = PhysicalDisplayId::tryCast(compositionDisplay->getId())) {
@@ -2811,13 +2867,17 @@
compositionengine::Output::ColorProfile{defaultColorMode, defaultDataSpace,
RenderIntent::COLORIMETRIC,
Dataspace::UNKNOWN});
- if (!state.isVirtual()) {
- FTL_FAKE_GUARD(kMainThreadContext,
- display->setActiveMode(state.physical->activeMode->getId()));
- display->setDeviceProductInfo(state.physical->deviceProductInfo);
+
+ if (const auto& physical = state.physical) {
+ mPhysicalDisplays.get(physical->id)
+ .transform(&PhysicalDisplay::snapshotRef)
+ .transform(ftl::unit_fn([&](const display::DisplaySnapshot& snapshot) {
+ FTL_FAKE_GUARD(kMainThreadContext,
+ display->setActiveMode(physical->activeMode->getId(), snapshot));
+ }));
}
- display->setLayerStack(state.layerStack);
+ display->setLayerFilter(makeLayerFilterForDisplay(display->getId(), state.layerStack));
display->setProjection(state.orientation, state.layerStackSpaceRect,
state.orientedDisplaySpaceRect);
display->setDisplayName(state.displayName);
@@ -2973,7 +3033,8 @@
if (const auto display = getDisplayDeviceLocked(displayToken)) {
if (currentState.layerStack != drawingState.layerStack) {
- display->setLayerStack(currentState.layerStack);
+ display->setLayerFilter(
+ makeLayerFilterForDisplay(display->getId(), currentState.layerStack));
}
if (currentState.flags != drawingState.flags) {
display->setFlags(currentState.flags);
@@ -2997,9 +3058,10 @@
}
}
}
+
void SurfaceFlinger::updateInternalDisplayVsyncLocked(const sp<DisplayDevice>& activeDisplay) {
mVsyncConfiguration->reset();
- const Fps refreshRate = activeDisplay->refreshRateConfigs().getActiveMode()->getFps();
+ const Fps refreshRate = activeDisplay->refreshRateConfigs().getActiveMode().getFps();
updatePhaseConfiguration(refreshRate);
mRefreshRateStats->setRefreshRate(refreshRate);
}
@@ -3219,7 +3281,7 @@
void SurfaceFlinger::buildWindowInfos(std::vector<WindowInfo>& outWindowInfos,
std::vector<DisplayInfo>& outDisplayInfos) {
- ftl::SmallMap<ui::LayerStack, DisplayDevice::InputInfo, 4> displayInputInfos;
+ display::DisplayMap<ui::LayerStack, DisplayDevice::InputInfo> displayInputInfos;
for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
const auto layerStack = display->getLayerStack();
@@ -4661,8 +4723,6 @@
}
}
-// ---------------------------------------------------------------------------
-
void SurfaceFlinger::onInitializeDisplays() {
const auto display = getDefaultDisplayDeviceLocked();
if (!display) return;
@@ -4700,8 +4760,9 @@
void SurfaceFlinger::initializeDisplays() {
// Async since we may be called from the main thread.
- static_cast<void>(
- mScheduler->schedule([this]() FTL_FAKE_GUARD(mStateLock) { onInitializeDisplays(); }));
+ static_cast<void>(mScheduler->schedule(
+ [this]() FTL_FAKE_GUARD(mStateLock)
+ FTL_FAKE_GUARD(kMainThreadContext) { onInitializeDisplays(); }));
}
void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) {
@@ -4718,8 +4779,12 @@
return;
}
+ const bool isInternalDisplay = mPhysicalDisplays.get(displayId)
+ .transform(&PhysicalDisplay::isInternal)
+ .value_or(false);
+
const auto activeDisplay = getDisplayDeviceLocked(mActiveDisplayToken);
- if (activeDisplay != display && display->isInternal() && activeDisplay &&
+ if (isInternalDisplay && activeDisplay != display && activeDisplay &&
activeDisplay->isPoweredOn()) {
ALOGW("Trying to change power mode on non active display while the active display is ON");
}
@@ -4729,10 +4794,10 @@
if (mInterceptor->isEnabled()) {
mInterceptor->savePowerModeUpdate(display->getSequenceId(), static_cast<int32_t>(mode));
}
- const auto refreshRate = display->refreshRateConfigs().getActiveMode()->getFps();
+ const auto refreshRate = display->refreshRateConfigs().getActiveMode().getFps();
if (*currentMode == hal::PowerMode::OFF) {
// Turn on the display
- if (display->isInternal() && (!activeDisplay || !activeDisplay->isPoweredOn())) {
+ if (isInternalDisplay && (!activeDisplay || !activeDisplay->isPoweredOn())) {
onActiveDisplayChangedLocked(display);
}
// Keep uclamp in a separate syscall and set it before changing to RT due to b/190237315.
@@ -4803,7 +4868,8 @@
}
void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
- auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
+ auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) FTL_FAKE_GUARD(
+ kMainThreadContext) {
const auto display = getDisplayDeviceLocked(displayToken);
if (!display) {
ALOGE("Attempt to set power mode %d for invalid display token %p", mode,
@@ -4991,10 +5057,20 @@
}
void SurfaceFlinger::dumpDisplays(std::string& result) const {
- for (const auto& [token, display] : mDisplays) {
- display->dump(result);
+ for (const auto& [id, display] : mPhysicalDisplays) {
+ if (const auto device = getDisplayDeviceLocked(id)) {
+ device->dump(result);
+ }
+ display.snapshot().dump(result);
result += '\n';
}
+
+ for (const auto& [token, display] : mDisplays) {
+ if (display->isVirtual()) {
+ display->dump(result);
+ result += '\n';
+ }
+ }
}
void SurfaceFlinger::dumpDisplayIdentificationData(std::string& result) const {
@@ -5793,7 +5869,7 @@
}();
mDebugDisplayModeSetByBackdoor = false;
- const status_t result = setActiveModeFromBackdoor(display, modeId);
+ const status_t result = setActiveModeFromBackdoor(display, DisplayModeId{modeId});
mDebugDisplayModeSetByBackdoor = result == NO_ERROR;
return result;
}
@@ -6667,6 +6743,20 @@
}
}
+std::optional<DisplayModePtr> SurfaceFlinger::getPreferredDisplayMode(
+ PhysicalDisplayId displayId, DisplayModeId defaultModeId) const {
+ if (const auto schedulerMode = mScheduler->getPreferredDisplayMode();
+ schedulerMode && schedulerMode->getPhysicalDisplayId() == displayId) {
+ return schedulerMode;
+ }
+
+ return mPhysicalDisplays.get(displayId)
+ .transform(&PhysicalDisplay::snapshotRef)
+ .and_then([&](const display::DisplaySnapshot& snapshot) {
+ return snapshot.displayModes().get(defaultModeId);
+ });
+}
+
status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal(
const sp<DisplayDevice>& display,
const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy) {
@@ -6685,7 +6775,7 @@
return NO_ERROR;
}
- scheduler::RefreshRateConfigs::Policy currentPolicy =
+ const scheduler::RefreshRateConfigs::Policy currentPolicy =
display->refreshRateConfigs().getCurrentPolicy();
ALOGV("Setting desired display mode specs: %s", currentPolicy.toString().c_str());
@@ -6700,27 +6790,25 @@
mScheduler->onNonPrimaryDisplayModeChanged(mAppConnectionHandle, activeMode);
}
- const DisplayModePtr preferredDisplayMode = [&] {
- const auto schedulerMode = mScheduler->getPreferredDisplayMode();
- if (schedulerMode && schedulerMode->getPhysicalDisplayId() == display->getPhysicalId()) {
- return schedulerMode;
- }
-
- return display->getMode(currentPolicy.defaultMode);
- }();
-
- ALOGV("trying to switch to Scheduler preferred mode %d (%s)",
- preferredDisplayMode->getId().value(), to_string(preferredDisplayMode->getFps()).c_str());
-
- if (display->refreshRateConfigs().isModeAllowed(preferredDisplayMode->getId())) {
- ALOGV("switching to Scheduler preferred display mode %d",
- preferredDisplayMode->getId().value());
- setDesiredActiveMode({preferredDisplayMode, DisplayModeEvent::Changed});
- } else {
- LOG_ALWAYS_FATAL("Desired display mode not allowed: %d",
- preferredDisplayMode->getId().value());
+ auto preferredModeOpt =
+ getPreferredDisplayMode(display->getPhysicalId(), currentPolicy.defaultMode);
+ if (!preferredModeOpt) {
+ ALOGE("%s: Preferred mode is unknown", __func__);
+ return NAME_NOT_FOUND;
}
+ auto preferredMode = std::move(*preferredModeOpt);
+ const auto preferredModeId = preferredMode->getId();
+
+ ALOGV("Switching to Scheduler preferred mode %d (%s)", preferredModeId.value(),
+ to_string(preferredMode->getFps()).c_str());
+
+ if (!display->refreshRateConfigs().isModeAllowed(preferredModeId)) {
+ ALOGE("%s: Preferred mode %d is disallowed", __func__, preferredModeId.value());
+ return INVALID_OPERATION;
+ }
+
+ setDesiredActiveMode({std::move(preferredMode), DisplayModeEvent::Changed});
return NO_ERROR;
}
@@ -6879,9 +6967,11 @@
}
void SurfaceFlinger::enableRefreshRateOverlay(bool enable) {
- for (const auto& [ignored, display] : mDisplays) {
- if (display->isInternal()) {
- display->enableRefreshRateOverlay(enable, mRefreshRateOverlaySpinner);
+ for (const auto& [id, display] : mPhysicalDisplays) {
+ if (display.snapshot().connectionType() == ui::DisplayConnectionType::Internal) {
+ if (const auto device = getDisplayDeviceLocked(id)) {
+ device->enableRefreshRateOverlay(enable, mRefreshRateOverlaySpinner);
+ }
}
}
}
@@ -6930,7 +7020,7 @@
refreshRate = *frameRateOverride;
} else if (!getHwComposer().isHeadless()) {
if (const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked())) {
- refreshRate = display->refreshRateConfigs().getActiveMode()->getFps();
+ refreshRate = display->refreshRateConfigs().getActiveModePtr()->getFps();
}
}
@@ -7367,8 +7457,7 @@
int displayModeId) {
status_t status = checkAccessPermission();
if (status == OK) {
- status = mFlinger->setBootDisplayMode(display,
- static_cast<ui::DisplayModeId>(displayModeId));
+ status = mFlinger->setBootDisplayMode(display, DisplayModeId{displayModeId});
}
return binderStatusFromStatusT(status);
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 3101885..f7684a0 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -29,7 +29,6 @@
#include <cutils/atomic.h>
#include <cutils/compiler.h>
#include <ftl/future.h>
-#include <ftl/small_map.h>
#include <gui/BufferQueue.h>
#include <gui/CompositorTiming.h>
#include <gui/FrameTimestamps.h>
@@ -59,6 +58,8 @@
#include <ui/FenceResult.h>
#include "ClientCache.h"
+#include "Display/DisplayMap.h"
+#include "Display/PhysicalDisplay.h"
#include "DisplayDevice.h"
#include "DisplayHardware/HWC2.h"
#include "DisplayHardware/PowerAdvisor.h"
@@ -515,7 +516,7 @@
status_t getDisplayNativePrimaries(const sp<IBinder>& displayToken, ui::DisplayPrimaries&);
status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode);
status_t getBootDisplayModeSupport(bool* outSupport) const;
- status_t setBootDisplayMode(const sp<IBinder>& displayToken, ui::DisplayModeId id);
+ status_t setBootDisplayMode(const sp<display::DisplayToken>&, DisplayModeId);
status_t clearBootDisplayMode(const sp<IBinder>& displayToken);
void setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on);
void setGameContentType(const sp<IBinder>& displayToken, bool on);
@@ -647,34 +648,39 @@
// Show spinner with refresh rate overlay
bool mRefreshRateOverlaySpinner = false;
- // Called on the main thread in response to initializeDisplays()
- void onInitializeDisplays() REQUIRES(mStateLock);
// Sets the desired active mode bit. It obtains the lock, and sets mDesiredActiveMode.
void setDesiredActiveMode(const ActiveModeInfo& info) REQUIRES(mStateLock);
- status_t setActiveModeFromBackdoor(const sp<IBinder>& displayToken, int id);
+ status_t setActiveModeFromBackdoor(const sp<display::DisplayToken>&, DisplayModeId);
// Sets the active mode and a new refresh rate in SF.
- void updateInternalStateWithChangedMode() REQUIRES(mStateLock);
+ void updateInternalStateWithChangedMode() REQUIRES(mStateLock, kMainThreadContext);
// Calls to setActiveMode on the main thread if there is a pending mode change
// that needs to be applied.
- void setActiveModeInHwcIfNeeded() REQUIRES(mStateLock);
+ void setActiveModeInHwcIfNeeded() REQUIRES(mStateLock, kMainThreadContext);
void clearDesiredActiveModeState(const sp<DisplayDevice>&) REQUIRES(mStateLock);
// Called when active mode is no longer is progress
void desiredActiveModeChangeDone(const sp<DisplayDevice>&) REQUIRES(mStateLock);
// Called on the main thread in response to setPowerMode()
void setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode)
- REQUIRES(mStateLock);
+ REQUIRES(mStateLock, kMainThreadContext);
// Returns true if the display has a visible HDR layer in its layer stack.
bool hasVisibleHdrLayer(const sp<DisplayDevice>& display) REQUIRES(mStateLock);
+ // Returns the preferred mode for PhysicalDisplayId if the Scheduler has selected one for that
+ // display. Falls back to the display's defaultModeId otherwise.
+ std::optional<DisplayModePtr> getPreferredDisplayMode(PhysicalDisplayId,
+ DisplayModeId defaultModeId) const
+ REQUIRES(mStateLock);
+
// Sets the desired display mode specs.
status_t setDesiredDisplayModeSpecsInternal(
const sp<DisplayDevice>& display,
const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy)
EXCLUDES(mStateLock);
- void commitTransactions() EXCLUDES(mStateLock);
- void commitTransactionsLocked(uint32_t transactionFlags) REQUIRES(mStateLock);
+ void commitTransactions() EXCLUDES(mStateLock) REQUIRES(kMainThreadContext);
+ void commitTransactionsLocked(uint32_t transactionFlags)
+ REQUIRES(mStateLock, kMainThreadContext);
void doCommitTransactions() REQUIRES(mStateLock);
// Returns whether a new buffer has been latched.
@@ -817,8 +823,14 @@
/*
* Display and layer stack management
*/
- // called when starting, or restarting after system_server death
+
+ // Called during boot, and restart after system_server death.
void initializeDisplays();
+ void onInitializeDisplays() REQUIRES(mStateLock, kMainThreadContext);
+
+ bool isDisplayActiveLocked(const sp<const DisplayDevice>& display) const REQUIRES(mStateLock) {
+ return display->getDisplayToken() == mActiveDisplayToken;
+ }
sp<const DisplayDevice> getDisplayDeviceLocked(const wp<IBinder>& displayToken) const
REQUIRES(mStateLock) {
@@ -867,6 +879,21 @@
return getDefaultDisplayDeviceLocked();
}
+ using DisplayDeviceAndSnapshot =
+ std::pair<sp<DisplayDevice>, display::PhysicalDisplay::SnapshotRef>;
+
+ // Combinator for ftl::Optional<PhysicalDisplay>::and_then.
+ auto getDisplayDeviceAndSnapshot() REQUIRES(mStateLock) {
+ return [this](const display::PhysicalDisplay& display) REQUIRES(
+ mStateLock) -> ftl::Optional<DisplayDeviceAndSnapshot> {
+ if (auto device = getDisplayDeviceLocked(display.snapshot().displayId())) {
+ return std::make_pair(std::move(device), display.snapshotRef());
+ }
+
+ return {};
+ };
+ }
+
// Returns the first display that matches a `bool(const DisplayDevice&)` predicate.
template <typename Predicate>
sp<DisplayDevice> findDisplay(Predicate p) const REQUIRES(mStateLock) {
@@ -882,8 +909,13 @@
// region of all screens presenting this layer stack.
void invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty);
- bool isDisplayActiveLocked(const sp<const DisplayDevice>& display) const REQUIRES(mStateLock) {
- return display->getDisplayToken() == mActiveDisplayToken;
+ ui::LayerFilter makeLayerFilterForDisplay(DisplayId displayId, ui::LayerStack layerStack)
+ REQUIRES(mStateLock) {
+ return {layerStack,
+ PhysicalDisplayId::tryCast(displayId)
+ .and_then(display::getPhysicalDisplay(mPhysicalDisplays))
+ .transform(&display::PhysicalDisplay::isInternal)
+ .value_or(false)};
}
/*
@@ -926,11 +958,12 @@
const DisplayDeviceState& state,
const sp<compositionengine::DisplaySurface>& displaySurface,
const sp<IGraphicBufferProducer>& producer) REQUIRES(mStateLock);
- void processDisplayChangesLocked() REQUIRES(mStateLock);
+ void processDisplayChangesLocked() REQUIRES(mStateLock, kMainThreadContext);
void processDisplayRemoved(const wp<IBinder>& displayToken) REQUIRES(mStateLock);
void processDisplayChanged(const wp<IBinder>& displayToken,
const DisplayDeviceState& currentState,
- const DisplayDeviceState& drawingState) REQUIRES(mStateLock);
+ const DisplayDeviceState& drawingState)
+ REQUIRES(mStateLock, kMainThreadContext);
void dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected);
@@ -959,21 +992,16 @@
/*
* Display identification
*/
- sp<IBinder> getPhysicalDisplayTokenLocked(PhysicalDisplayId displayId) const
+ sp<display::DisplayToken> getPhysicalDisplayTokenLocked(PhysicalDisplayId displayId) const
REQUIRES(mStateLock) {
- const sp<IBinder> nullToken;
- return mPhysicalDisplayTokens.get(displayId).value_or(std::cref(nullToken));
+ const sp<display::DisplayToken> nullToken;
+ return mPhysicalDisplays.get(displayId)
+ .transform([](const display::PhysicalDisplay& display) { return display.token(); })
+ .value_or(std::cref(nullToken));
}
std::optional<PhysicalDisplayId> getPhysicalDisplayIdLocked(
- const sp<IBinder>& displayToken) const REQUIRES(mStateLock) {
- for (const auto& [id, token] : mPhysicalDisplayTokens) {
- if (token == displayToken) {
- return id;
- }
- }
- return {};
- }
+ const sp<display::DisplayToken>&) const REQUIRES(mStateLock);
// Returns the first display connected at boot.
//
@@ -996,7 +1024,8 @@
VirtualDisplayId acquireVirtualDisplay(ui::Size, ui::PixelFormat) REQUIRES(mStateLock);
void releaseVirtualDisplay(VirtualDisplayId);
- void onActiveDisplayChangedLocked(const sp<DisplayDevice>& activeDisplay) REQUIRES(mStateLock);
+ void onActiveDisplayChangedLocked(const sp<DisplayDevice>& activeDisplay)
+ REQUIRES(mStateLock, kMainThreadContext);
void onActiveDisplaySizeChanged(const sp<DisplayDevice>& activeDisplay);
@@ -1063,14 +1092,14 @@
/*
* Misc
*/
- std::vector<ui::ColorMode> getDisplayColorModes(const DisplayDevice&) REQUIRES(mStateLock);
+ std::vector<ui::ColorMode> getDisplayColorModes(PhysicalDisplayId) REQUIRES(mStateLock);
static int calculateMaxAcquiredBufferCount(Fps refreshRate,
std::chrono::nanoseconds presentLatency);
int getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) const;
void updateInternalDisplayVsyncLocked(const sp<DisplayDevice>& activeDisplay)
- REQUIRES(mStateLock);
+ REQUIRES(mStateLock, kMainThreadContext);
bool isHdrLayer(Layer* layer) const;
@@ -1164,12 +1193,10 @@
// Displays are composited in `mDisplays` order. Internal displays are inserted at boot and
// never removed, so take precedence over external and virtual displays.
//
- // The static capacities were chosen to exceed a typical number of physical/virtual displays.
- //
// May be read from any thread, but must only be written from the main thread.
- ftl::SmallMap<wp<IBinder>, const sp<DisplayDevice>, 5> mDisplays GUARDED_BY(mStateLock);
- ftl::SmallMap<PhysicalDisplayId, const sp<IBinder>, 3> mPhysicalDisplayTokens
- GUARDED_BY(mStateLock);
+ display::DisplayMap<wp<IBinder>, const sp<DisplayDevice>> mDisplays GUARDED_BY(mStateLock);
+
+ display::PhysicalDisplays mPhysicalDisplays GUARDED_BY(mStateLock);
struct {
DisplayIdGenerator<GpuVirtualDisplayId> gpu;
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index 15a791e..319d014 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -24,7 +24,6 @@
#include "BufferStateLayer.h"
#include "DisplayDevice.h"
-#include "EffectLayer.h"
#include "FrameTracer/FrameTracer.h"
#include "Layer.h"
#include "NativeWindowSurface.h"
@@ -94,8 +93,8 @@
return sp<BufferStateLayer>::make(args);
}
-sp<EffectLayer> DefaultFactory::createEffectLayer(const LayerCreationArgs& args) {
- return sp<EffectLayer>::make(args);
+sp<Layer> DefaultFactory::createEffectLayer(const LayerCreationArgs& args) {
+ return sp<Layer>::make(args);
}
std::unique_ptr<FrameTracer> DefaultFactory::createFrameTracer() {
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 8d00379..6602240 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -42,7 +42,7 @@
const sp<IGraphicBufferProducer>&) override;
std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() override;
sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) override;
- sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) override;
+ sp<Layer> createEffectLayer(const LayerCreationArgs& args) override;
std::unique_ptr<FrameTracer> createFrameTracer() override;
std::unique_ptr<frametimeline::FrameTimeline> createFrameTimeline(
std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid) override;
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 291838f..dc2afd3 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -33,7 +33,6 @@
class BufferLayerConsumer;
class BufferStateLayer;
class DisplayDevice;
-class EffectLayer;
class FrameTracer;
class GraphicBuffer;
class HWComposer;
@@ -91,7 +90,7 @@
virtual std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() = 0;
virtual sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) = 0;
- virtual sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) = 0;
+ virtual sp<Layer> createEffectLayer(const LayerCreationArgs& args) = 0;
virtual std::unique_ptr<FrameTracer> createFrameTracer() = 0;
virtual std::unique_ptr<frametimeline::FrameTimeline> createFrameTimeline(
std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid) = 0;
diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
index 312d4ab..6501e20 100644
--- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
@@ -84,9 +84,7 @@
return sp<BufferStateLayer>::make(args);
}
- sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) {
- return sp<EffectLayer>::make(args);
- }
+ sp<Layer> createEffectLayer(const LayerCreationArgs& args) { return sp<Layer>::make(args); }
std::unique_ptr<FrameTracer> createFrameTracer() override {
return std::make_unique<testing::NiceMock<mock::FrameTracer>>();
diff --git a/services/surfaceflinger/fuzzer/README.md b/services/surfaceflinger/fuzzer/README.md
index 7a5f229..a06c41b 100644
--- a/services/surfaceflinger/fuzzer/README.md
+++ b/services/surfaceflinger/fuzzer/README.md
@@ -78,9 +78,8 @@
Layer supports the following parameters:
1. Display Connection Types (parameter name: `fakeDisplay`)
2. State Sets (parameter name: `traverseInZOrder`)
-3. State Subsets (parameter name: `prepareCompositionState`)
-4. Disconnect modes (parameter name: `disconnect`)
-5. Data Spaces (parameter name: `setDataspace`)
+3. Disconnect modes (parameter name: `disconnect`)
+4. Data Spaces (parameter name: `setDataspace`)
You can find the possible values in the fuzzer's source code.
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
index 28b875a..79112bd 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
@@ -237,7 +237,8 @@
mTestableFlinger.enableHalVirtualDisplays(mFdp.ConsumeBool());
- mTestableFlinger.commitTransactionsLocked(mFdp.ConsumeIntegral<uint32_t>());
+ FTL_FAKE_GUARD(kMainThreadContext,
+ mTestableFlinger.commitTransactionsLocked(mFdp.ConsumeIntegral<uint32_t>()));
mTestableFlinger.notifyPowerBoost(mFdp.ConsumeIntegral<int32_t>());
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 3aa3633..2297618 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -33,7 +33,6 @@
#include "BufferStateLayer.h"
#include "DisplayDevice.h"
#include "DisplayHardware/ComposerHal.h"
-#include "EffectLayer.h"
#include "FrameTimeline/FrameTimeline.h"
#include "FrameTracer/FrameTracer.h"
#include "Layer.h"
@@ -360,8 +359,8 @@
return nullptr;
}
- sp<EffectLayer> createEffectLayer(const LayerCreationArgs &args) override {
- return sp<EffectLayer>::make(args);
+ sp<Layer> createEffectLayer(const LayerCreationArgs &args) override {
+ return sp<Layer>::make(args);
}
std::unique_ptr<FrameTracer> createFrameTracer() override {
@@ -600,14 +599,18 @@
mFlinger->binderDied(display);
mFlinger->onFirstRef();
- mFlinger->commitTransactions();
mFlinger->updateInputFlinger();
mFlinger->updateCursorAsync();
setVsyncConfig(&mFdp);
- FTL_FAKE_GUARD(kMainThreadContext,
- mFlinger->flushTransactionQueues(getFuzzedVsyncId(mFdp)));
+ {
+ ftl::FakeGuard guard(kMainThreadContext);
+
+ mFlinger->commitTransactions();
+ mFlinger->flushTransactionQueues(getFuzzedVsyncId(mFdp));
+ mFlinger->postComposition();
+ }
mFlinger->setTransactionFlags(mFdp.ConsumeIntegral<uint32_t>());
mFlinger->clearTransactionFlags(mFdp.ConsumeIntegral<uint32_t>());
@@ -624,8 +627,6 @@
mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mFdp.ConsumeIntegral<uid_t>());
- FTL_FAKE_GUARD(kMainThreadContext, mFlinger->postComposition());
-
mFlinger->calculateExpectedPresentTime({});
mFlinger->enableHalVirtualDisplays(mFdp.ConsumeBool());
@@ -664,7 +665,8 @@
}
mRefreshRateConfigs = std::make_shared<scheduler::RefreshRateConfigs>(modes, kModeId60);
- const auto fps = mRefreshRateConfigs->getActiveMode()->getFps();
+ const auto fps =
+ FTL_FAKE_GUARD(kMainThreadContext, mRefreshRateConfigs->getActiveMode().getFps());
mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(fps);
mFlinger->mVsyncModulator = sp<scheduler::VsyncModulator>::make(
mFlinger->mVsyncConfiguration->getCurrentConfigs());
@@ -715,9 +717,9 @@
void enableHalVirtualDisplays(bool enable) { mFlinger->enableHalVirtualDisplays(enable); }
- auto commitTransactionsLocked(uint32_t transactionFlags) {
+ void commitTransactionsLocked(uint32_t transactionFlags) FTL_FAKE_GUARD(kMainThreadContext) {
Mutex::Autolock lock(mFlinger->mStateLock);
- return mFlinger->commitTransactionsLocked(transactionFlags);
+ mFlinger->commitTransactionsLocked(transactionFlags);
}
auto setDisplayStateLocked(const DisplayState &s) {
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
index aeccc52..9ece260 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
@@ -17,7 +17,6 @@
#include <BufferStateLayer.h>
#include <Client.h>
#include <DisplayDevice.h>
-#include <EffectLayer.h>
#include <LayerRenderArea.h>
#include <ftl/future.h>
#include <fuzzer/FuzzedDataProvider.h>
@@ -79,13 +78,13 @@
TestableSurfaceFlinger flinger;
sp<Client> client = sp<Client>::make(sp<SurfaceFlinger>::fromExisting(flinger.flinger()));
const LayerCreationArgs layerCreationArgs = createLayerCreationArgs(&flinger, client);
- sp<EffectLayer> effectLayer = sp<EffectLayer>::make(layerCreationArgs);
+ sp<Layer> effectLayer = sp<Layer>::make(layerCreationArgs);
effectLayer->setColor({(mFdp.ConsumeFloatingPointInRange<float>(0, 255) /*x*/,
mFdp.ConsumeFloatingPointInRange<float>(0, 255) /*y*/,
mFdp.ConsumeFloatingPointInRange<float>(0, 255) /*z*/)});
effectLayer->setDataspace(mFdp.PickValueInArray(kDataspaces));
- sp<EffectLayer> parent = sp<EffectLayer>::make(layerCreationArgs);
+ sp<Layer> parent = sp<Layer>::make(layerCreationArgs);
effectLayer->setChildrenDrawingParent(parent);
const FrameTimelineInfo frameInfo = getFuzzedFrameTimelineInfo();
@@ -149,7 +148,8 @@
layer->computeSourceBounds(getFuzzedFloatRect(&mFdp));
layer->fenceHasSignaled();
- layer->onPreComposition(mFdp.ConsumeIntegral<int64_t>());
+ layer->onPreComposition(mFdp.ConsumeIntegral<int64_t>(),
+ false /*updatingOutputGeometryThisFrame*/);
const std::vector<sp<CallbackHandle>> callbacks;
layer->setTransactionCompletedListeners(callbacks);
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index 9584492..3fc2b7e 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -366,7 +366,7 @@
{modeId,
{Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()),
Fps::fromValue(mFdp.ConsumeFloatingPoint<float>())}});
- refreshRateConfigs.setActiveModeId(modeId);
+ FTL_FAKE_GUARD(kMainThreadContext, refreshRateConfigs.setActiveModeId(modeId));
RefreshRateConfigs::isFractionalPairOrMultiple(Fps::fromValue(
mFdp.ConsumeFloatingPoint<float>()),
diff --git a/services/surfaceflinger/tests/LayerTransaction_test.cpp b/services/surfaceflinger/tests/LayerTransaction_test.cpp
index 513fdc3..c206e1f 100644
--- a/services/surfaceflinger/tests/LayerTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTransaction_test.cpp
@@ -154,6 +154,36 @@
ASSERT_EQ(OK, producer->disconnect(NATIVE_WINDOW_API_CPU));
}
+
+// b/245052266 - we possible could support blur and a buffer at the same layer but
+// might break existing assumptions at higher level. This test captures the current
+// expectations. A layer drawing a buffer will not support blur.
+TEST_F(LayerTransactionTest, BufferTakesPriorityOverBlur) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+ Transaction().setBackgroundBlurRadius(layer, 5).apply();
+ {
+ SCOPED_TRACE("BufferTakesPriorityOverBlur");
+ const Rect rect(0, 0, 32, 32);
+ auto shot = screenshot();
+ shot->expectColor(rect, Color::RED);
+ }
+}
+
+TEST_F(LayerTransactionTest, BufferTakesPriorityOverColor) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+ Transaction().setColor(layer, {Color::GREEN.r, Color::GREEN.g, Color::GREEN.b}).apply();
+ {
+ SCOPED_TRACE("BufferTakesPriorityOverColor");
+ const Rect rect(0, 0, 32, 32);
+ auto shot = screenshot();
+ shot->expectColor(rect, Color::RED);
+ }
+}
+
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 77625b3..9485f48 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -38,7 +38,6 @@
#include <utils/String8.h>
#include "DisplayRenderArea.h"
-#include "EffectLayer.h"
#include "Layer.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
@@ -309,16 +308,20 @@
compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
ceDisplayArgs);
+ constexpr auto kDisplayConnectionType = ui::DisplayConnectionType::Internal;
+ constexpr bool kIsPrimary = true;
+
test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay,
- ui::DisplayConnectionType::Internal, HWC_DISPLAY,
- true /* isPrimary */)
+ kDisplayConnectionType, HWC_DISPLAY, kIsPrimary)
.setDisplaySurface(test->mDisplaySurface)
.setNativeWindow(test->mNativeWindow)
.setSecure(Derived::IS_SECURE)
.setPowerMode(Derived::INIT_POWER_MODE)
.inject();
Mock::VerifyAndClear(test->mNativeWindow.get());
- test->mDisplay->setLayerStack(LAYER_STACK);
+
+ constexpr bool kIsInternal = kDisplayConnectionType == ui::DisplayConnectionType::Internal;
+ test->mDisplay->setLayerFilter({LAYER_STACK, kIsInternal});
}
template <typename Case>
@@ -853,13 +856,13 @@
template <typename LayerProperties>
struct EffectLayerVariant : public BaseLayerVariant<LayerProperties> {
using Base = BaseLayerVariant<LayerProperties>;
- using FlingerLayerType = sp<EffectLayer>;
+ using FlingerLayerType = sp<Layer>;
static FlingerLayerType createLayer(CompositionTest* test) {
- FlingerLayerType layer = Base::template createLayerWithFactory<EffectLayer>(test, [test]() {
- return sp<EffectLayer>::make(
- LayerCreationArgs(test->mFlinger.flinger(), sp<Client>(), "test-layer",
- LayerProperties::LAYER_FLAGS, LayerMetadata()));
+ FlingerLayerType layer = Base::template createLayerWithFactory<Layer>(test, [test]() {
+ return sp<Layer>::make(LayerCreationArgs(test->mFlinger.flinger(), sp<Client>(),
+ "test-layer", LayerProperties::LAYER_FLAGS,
+ LayerMetadata()));
});
auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer);
@@ -941,12 +944,12 @@
template <typename LayerProperties>
struct ContainerLayerVariant : public BaseLayerVariant<LayerProperties> {
using Base = BaseLayerVariant<LayerProperties>;
- using FlingerLayerType = sp<EffectLayer>;
+ using FlingerLayerType = sp<Layer>;
static FlingerLayerType createLayer(CompositionTest* test) {
LayerCreationArgs args(test->mFlinger.flinger(), sp<Client>(), "test-container-layer",
LayerProperties::LAYER_FLAGS, LayerMetadata());
- FlingerLayerType layer = sp<EffectLayer>::make(args);
+ FlingerLayerType layer = sp<Layer>::make(args);
Base::template initLayerDrawingStateAndComputeBounds(test, layer);
return layer;
}
diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
index ec27eda..67ace1a 100644
--- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
@@ -292,9 +292,10 @@
TEST_F(DispSyncSourceTest, getLatestVsyncData) {
const nsecs_t now = systemTime();
- const nsecs_t vsyncInternalDuration = mWorkDuration.count() + mReadyDuration.count();
+ const nsecs_t expectedPresentationTime =
+ now + mWorkDuration.count() + mReadyDuration.count() + 1;
EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_))
- .WillOnce(Return(now + vsyncInternalDuration + 1));
+ .WillOnce(Return(expectedPresentationTime));
{
InSequence seq;
EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
@@ -306,10 +307,8 @@
EXPECT_TRUE(mDispSyncSource);
const auto vsyncData = mDispSyncSource->getLatestVSyncData();
- ASSERT_GT(vsyncData.deadlineTimestamp, now);
- ASSERT_GT(vsyncData.expectedPresentationTime, vsyncData.deadlineTimestamp);
- EXPECT_EQ(vsyncData.deadlineTimestamp,
- vsyncData.expectedPresentationTime - vsyncInternalDuration);
+ ASSERT_EQ(vsyncData.expectedPresentationTime, expectedPresentationTime);
+ EXPECT_EQ(vsyncData.deadlineTimestamp, expectedPresentationTime - mReadyDuration.count());
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp
index 0b4e196..9789df5 100644
--- a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp
@@ -25,7 +25,6 @@
#include <gui/LayerMetadata.h>
#include "BufferStateLayer.h"
-#include "EffectLayer.h"
#include "FpsReporter.h"
#include "Layer.h"
#include "TestableSurfaceFlinger.h"
diff --git a/services/surfaceflinger/tests/unittests/LayerTest.cpp b/services/surfaceflinger/tests/unittests/LayerTest.cpp
index 4974f90..95e54f6 100644
--- a/services/surfaceflinger/tests/unittests/LayerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerTest.cpp
@@ -17,7 +17,6 @@
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
-#include <EffectLayer.h>
#include <gtest/gtest.h>
#include <ui/FloatRect.h>
#include <ui/Transform.h>
diff --git a/services/surfaceflinger/tests/unittests/LayerTestUtils.cpp b/services/surfaceflinger/tests/unittests/LayerTestUtils.cpp
index b7a8a93..14304d1 100644
--- a/services/surfaceflinger/tests/unittests/LayerTestUtils.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerTestUtils.cpp
@@ -35,7 +35,7 @@
sp<Layer> EffectLayerFactory::createLayer(TestableSurfaceFlinger& flinger) {
sp<Client> client;
LayerCreationArgs args(flinger.flinger(), client, "color-layer", LAYER_FLAGS, LayerMetadata());
- return sp<EffectLayer>::make(args);
+ return sp<Layer>::make(args);
}
std::string PrintToStringParamName(
diff --git a/services/surfaceflinger/tests/unittests/LayerTestUtils.h b/services/surfaceflinger/tests/unittests/LayerTestUtils.h
index fc9b6a2..ab446fa 100644
--- a/services/surfaceflinger/tests/unittests/LayerTestUtils.h
+++ b/services/surfaceflinger/tests/unittests/LayerTestUtils.h
@@ -23,8 +23,6 @@
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
-#include "BufferStateLayer.h"
-#include "EffectLayer.h"
#include "Layer.h"
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 188fd58..5d9b2a8 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "SchedulerUnittests"
#include <ftl/enum.h>
+#include <ftl/fake_guard.h>
#include <gmock/gmock.h>
#include <log/log.h>
#include <ui/Size.h>
@@ -41,6 +42,16 @@
struct TestableRefreshRateConfigs : RefreshRateConfigs {
using RefreshRateConfigs::RefreshRateConfigs;
+ void setActiveModeId(DisplayModeId modeId) {
+ ftl::FakeGuard guard(kMainThreadContext);
+ return RefreshRateConfigs::setActiveModeId(modeId);
+ }
+
+ const DisplayMode& getActiveMode() const {
+ ftl::FakeGuard guard(kMainThreadContext);
+ return RefreshRateConfigs::getActiveMode();
+ }
+
DisplayModePtr getMinSupportedRefreshRate() const {
std::lock_guard lock(mLock);
return mMinRefreshRateModeIt->second;
@@ -243,20 +254,20 @@
TEST_F(RefreshRateConfigsTest, twoModes_getActiveMode) {
TestableRefreshRateConfigs configs(kModes_60_90, kModeId60);
{
- const auto mode = configs.getActiveMode();
- EXPECT_EQ(mode->getId(), kModeId60);
+ const auto& mode = configs.getActiveMode();
+ EXPECT_EQ(mode.getId(), kModeId60);
}
configs.setActiveModeId(kModeId90);
{
- const auto mode = configs.getActiveMode();
- EXPECT_EQ(mode->getId(), kModeId90);
+ const auto& mode = configs.getActiveMode();
+ EXPECT_EQ(mode.getId(), kModeId90);
}
EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}}), 0);
{
- const auto mode = configs.getActiveMode();
- EXPECT_EQ(mode->getId(), kModeId90);
+ const auto& mode = configs.getActiveMode();
+ EXPECT_EQ(mode.getId(), kModeId90);
}
}
@@ -966,6 +977,32 @@
EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers));
}
+TEST_F(RefreshRateConfigsTest, powerOnImminentConsidered) {
+ RefreshRateConfigs configs(kModes_60_90, kModeId60);
+
+ auto [refreshRate, signals] = configs.getBestRefreshRate({}, {});
+ EXPECT_FALSE(signals.powerOnImminent);
+ EXPECT_EQ(kMode90, refreshRate);
+
+ std::tie(refreshRate, signals) = configs.getBestRefreshRate({}, {.powerOnImminent = true});
+ EXPECT_TRUE(signals.powerOnImminent);
+ EXPECT_EQ(kMode90, refreshRate);
+
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}};
+ auto& lr1 = layers[0];
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 60_Hz;
+ lr1.name = "60Hz ExplicitExactOrMultiple";
+
+ std::tie(refreshRate, signals) = configs.getBestRefreshRate(layers, {.powerOnImminent = false});
+ EXPECT_FALSE(signals.powerOnImminent);
+ EXPECT_EQ(kMode60, refreshRate);
+
+ std::tie(refreshRate, signals) = configs.getBestRefreshRate(layers, {.powerOnImminent = true});
+ EXPECT_TRUE(signals.powerOnImminent);
+ EXPECT_EQ(kMode90, refreshRate);
+}
+
TEST_F(RefreshRateConfigsTest, touchConsidered) {
RefreshRateConfigs configs(kModes_60_90, kModeId60);
@@ -1898,30 +1935,30 @@
}
TEST_F(RefreshRateConfigsTest, getFrameRateDivisor) {
- RefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId30);
+ TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId30);
const auto frameRate = 30_Hz;
- Fps displayRefreshRate = configs.getActiveMode()->getFps();
+ Fps displayRefreshRate = configs.getActiveMode().getFps();
EXPECT_EQ(1, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
configs.setActiveModeId(kModeId60);
- displayRefreshRate = configs.getActiveMode()->getFps();
+ displayRefreshRate = configs.getActiveMode().getFps();
EXPECT_EQ(2, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
configs.setActiveModeId(kModeId72);
- displayRefreshRate = configs.getActiveMode()->getFps();
+ displayRefreshRate = configs.getActiveMode().getFps();
EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
configs.setActiveModeId(kModeId90);
- displayRefreshRate = configs.getActiveMode()->getFps();
+ displayRefreshRate = configs.getActiveMode().getFps();
EXPECT_EQ(3, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
configs.setActiveModeId(kModeId120);
- displayRefreshRate = configs.getActiveMode()->getFps();
+ displayRefreshRate = configs.getActiveMode().getFps();
EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
configs.setActiveModeId(kModeId90);
- displayRefreshRate = configs.getActiveMode()->getFps();
+ displayRefreshRate = configs.getActiveMode().getFps();
EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, 22.5_Hz));
EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(24_Hz, 25_Hz));
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
index 6752a39..abf1786 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
@@ -22,7 +22,6 @@
#include <gui/LayerMetadata.h>
#include "BufferStateLayer.h"
-#include "EffectLayer.h"
#include "Layer.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
@@ -60,7 +59,7 @@
void setupScheduler();
sp<BufferStateLayer> createBufferStateLayer();
- sp<EffectLayer> createEffectLayer();
+ sp<Layer> createEffectLayer();
void setParent(Layer* child, Layer* parent);
void commitTransaction(Layer* layer);
@@ -96,10 +95,10 @@
return sp<BufferStateLayer>::make(args);
}
-sp<EffectLayer> RefreshRateSelectionTest::createEffectLayer() {
+sp<Layer> RefreshRateSelectionTest::createEffectLayer() {
sp<Client> client;
LayerCreationArgs args(mFlinger.flinger(), client, "color-layer", LAYER_FLAGS, LayerMetadata());
- return sp<EffectLayer>::make(args);
+ return sp<Layer>::make(args);
}
void RefreshRateSelectionTest::setParent(Layer* child, Layer* parent) {
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index 6ee8174..51c6bea 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -25,7 +25,6 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#include "BufferStateLayer.h"
-#include "EffectLayer.h"
#include "Layer.h"
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion"
@@ -374,11 +373,6 @@
const auto& layerFactory = GetParam();
auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
- if (!parent->isVisible()) {
- // This is a hack as all the test layers except EffectLayer are not visible,
- // but since the logic is unified in Layer, it should be fine.
- return;
- }
auto child = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
addChild(parent, child);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
index 71f1a2b..73f654b 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
@@ -118,9 +118,7 @@
ASSERT_TRUE(displayId);
const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value;
ASSERT_TRUE(hwcDisplayId);
- expectedPhysical = {.id = *displayId,
- .type = *connectionType,
- .hwcDisplayId = *hwcDisplayId};
+ expectedPhysical = {.id = *displayId, .hwcDisplayId = *hwcDisplayId};
}
// The display should have been set up in the current display state
@@ -145,10 +143,13 @@
const auto displayId = Case::Display::DISPLAY_ID::get();
ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
- const auto displayTokenOpt = mFlinger.mutablePhysicalDisplayTokens().get(displayId);
- ASSERT_TRUE(displayTokenOpt);
+ const auto displayOpt = mFlinger.mutablePhysicalDisplays().get(displayId);
+ ASSERT_TRUE(displayOpt);
- verifyDisplayIsConnected<Case>(displayTokenOpt->get());
+ const auto& display = displayOpt->get();
+ EXPECT_EQ(Case::Display::CONNECTION_TYPE::value, display.snapshot().connectionType());
+
+ verifyDisplayIsConnected<Case>(display.token());
}
void DisplayTransactionCommitTest::verifyDisplayIsNotConnected(const sp<IBinder>& displayToken) {
@@ -247,10 +248,10 @@
// HWComposer should not have an entry for the display
EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
- // SF should not have a display token.
+ // SF should not have a PhysicalDisplay.
const auto displayId = Case::Display::DISPLAY_ID::get();
ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
- ASSERT_FALSE(mFlinger.mutablePhysicalDisplayTokens().contains(displayId));
+ ASSERT_FALSE(mFlinger.mutablePhysicalDisplays().contains(displayId));
// The existing token should have been removed.
verifyDisplayIsNotConnected(existing.token());
@@ -329,10 +330,10 @@
// HWComposer should not have an entry for the display
EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
- // SF should not have a display token.
+ // SF should not have a PhysicalDisplay.
const auto displayId = Case::Display::DISPLAY_ID::get();
ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
- ASSERT_FALSE(mFlinger.mutablePhysicalDisplayTokens().contains(displayId));
+ ASSERT_FALSE(mFlinger.mutablePhysicalDisplays().contains(displayId));
}(),
testing::KilledBySignal(SIGABRT), "Primary display cannot be disconnected.");
}
@@ -376,9 +377,9 @@
const auto displayId = Case::Display::DISPLAY_ID::get();
ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
- const auto displayTokenOpt = mFlinger.mutablePhysicalDisplayTokens().get(displayId);
- ASSERT_TRUE(displayTokenOpt);
- EXPECT_NE(existing.token(), displayTokenOpt->get());
+ const auto displayOpt = mFlinger.mutablePhysicalDisplays().get(displayId);
+ ASSERT_TRUE(displayOpt);
+ EXPECT_NE(existing.token(), displayOpt->get().token());
// A new display should be connected in its place.
verifyPhysicalDisplayIsConnected<Case>();
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
index 1756368..9e54083 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
@@ -253,14 +253,16 @@
using DispSync = DispSyncVariant;
using Transition = TransitionVariant;
- static auto injectDisplayWithInitialPowerMode(DisplayTransactionTest* test, PowerMode mode) {
+ static sp<DisplayDevice> injectDisplayWithInitialPowerMode(DisplayTransactionTest* test,
+ PowerMode mode) {
Display::injectHwcDisplayWithNoDefaultCapabilities(test);
- auto display = Display::makeFakeExistingDisplayInjector(test);
- display.inject();
- display.mutableDisplayDevice()->setPowerMode(mode);
- if (display.mutableDisplayDevice()->isInternal()) {
- test->mFlinger.mutableActiveDisplayToken() =
- display.mutableDisplayDevice()->getDisplayToken();
+ auto injector = Display::makeFakeExistingDisplayInjector(test);
+ const auto display = injector.inject();
+ display->setPowerMode(mode);
+ if (injector.physicalDisplay()
+ .transform(&display::PhysicalDisplay::isInternal)
+ .value_or(false)) {
+ test->mFlinger.mutableActiveDisplayToken() = display->getDisplayToken();
}
return display;
@@ -353,8 +355,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.setPowerModeInternal(display.mutableDisplayDevice(),
- Case::Transition::TARGET_POWER_MODE);
+ mFlinger.setPowerModeInternal(display, Case::Transition::TARGET_POWER_MODE);
// --------------------------------------------------------------------
// Postconditions
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
index 6aeb3fe..ec2c2b4 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
@@ -246,11 +246,14 @@
.setDpiY(DEFAULT_DPI)
.setGroup(0)
.build();
+
state.physical = {.id = *displayId,
- .type = *connectionType,
.hwcDisplayId = *hwcDisplayId,
- .supportedModes = makeModes(activeMode),
- .activeMode = std::move(activeMode)};
+ .activeMode = activeMode};
+
+ mFlinger.mutablePhysicalDisplays().emplace_or_replace(*displayId, displayToken, *displayId,
+ *connectionType,
+ makeModes(activeMode), std::nullopt);
}
state.isSecure = static_cast<bool>(Case::Display::SECURE);
@@ -264,7 +267,6 @@
ASSERT_TRUE(device != nullptr);
EXPECT_EQ(Case::Display::DISPLAY_ID::get(), device->getId());
- EXPECT_EQ(Case::Display::CONNECTION_TYPE::value, device->getConnectionType());
EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), device->isVirtual());
EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
@@ -280,7 +282,6 @@
device->receivesInput());
if constexpr (Case::Display::CONNECTION_TYPE::value) {
- EXPECT_EQ(1, device->getSupportedModes().size());
EXPECT_NE(nullptr, device->getActiveMode());
EXPECT_EQ(Case::Display::HWC_ACTIVE_CONFIG_ID, device->getActiveMode()->getHwcId());
}
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 6c6c9aa..1ce6e18 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -32,7 +32,6 @@
#include "BufferStateLayer.h"
#include "DisplayDevice.h"
-#include "EffectLayer.h"
#include "FakeVsyncConfiguration.h"
#include "FrameTracer/FrameTracer.h"
#include "Layer.h"
@@ -125,7 +124,7 @@
return nullptr;
}
- sp<EffectLayer> createEffectLayer(const LayerCreationArgs&) override { return nullptr; }
+ sp<Layer> createEffectLayer(const LayerCreationArgs&) override { return nullptr; }
std::unique_ptr<FrameTracer> createFrameTracer() override {
return std::make_unique<mock::FrameTracer>();
@@ -223,7 +222,7 @@
configs = std::make_shared<scheduler::RefreshRateConfigs>(modes, kModeId60);
}
- const auto fps = configs->getActiveMode()->getFps();
+ const auto fps = FTL_FAKE_GUARD(kMainThreadContext, configs->getActiveMode().getFps());
mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(fps);
mFlinger->mVsyncModulator = sp<scheduler::VsyncModulator>::make(
mFlinger->mVsyncConfiguration->getCurrentConfigs());
@@ -371,6 +370,7 @@
void commitTransactionsLocked(uint32_t transactionFlags) {
Mutex::Autolock lock(mFlinger->mStateLock);
+ ftl::FakeGuard guard(kMainThreadContext);
mFlinger->commitTransactionsLocked(transactionFlags);
}
@@ -464,6 +464,7 @@
void onActiveDisplayChanged(const sp<DisplayDevice>& activeDisplay) {
Mutex::Autolock lock(mFlinger->mStateLock);
+ ftl::FakeGuard guard(kMainThreadContext);
mFlinger->onActiveDisplayChangedLocked(activeDisplay);
}
@@ -503,6 +504,7 @@
*/
const auto& displays() const { return mFlinger->mDisplays; }
+ const auto& physicalDisplays() const { return mFlinger->mPhysicalDisplays; }
const auto& currentState() const { return mFlinger->mCurrentState; }
const auto& drawingState() const { return mFlinger->mDrawingState; }
const auto& transactionFlags() const { return mFlinger->mTransactionFlags; }
@@ -515,12 +517,12 @@
auto& mutableCurrentState() { return mFlinger->mCurrentState; }
auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; }
auto& mutableDisplays() { return mFlinger->mDisplays; }
+ auto& mutablePhysicalDisplays() { return mFlinger->mPhysicalDisplays; }
auto& mutableDrawingState() { return mFlinger->mDrawingState; }
auto& mutableGeometryDirty() { return mFlinger->mGeometryDirty; }
auto& mutableInterceptor() { return mFlinger->mInterceptor; }
auto& mutableMainThreadId() { return mFlinger->mMainThreadId; }
auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; }
- auto& mutablePhysicalDisplayTokens() { return mFlinger->mPhysicalDisplayTokens; }
auto& mutableTexturePool() { return mFlinger->mTexturePool; }
auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
auto& mutableDebugDisableHWC() { return mFlinger->mDebugDisableHWC; }
@@ -725,14 +727,20 @@
: mFlinger(flinger),
mCreationArgs(flinger.mFlinger, flinger.mFlinger->getHwComposer(), mDisplayToken,
display),
+ mConnectionType(connectionType),
mHwcDisplayId(hwcDisplayId) {
- mCreationArgs.connectionType = connectionType;
mCreationArgs.isPrimary = isPrimary;
mCreationArgs.initialPowerMode = hal::PowerMode::ON;
}
sp<IBinder> token() const { return mDisplayToken; }
+ auto physicalDisplay() const {
+ return ftl::Optional(mCreationArgs.compositionDisplay->getDisplayId())
+ .and_then(&PhysicalDisplayId::tryCast)
+ .and_then(display::getPhysicalDisplay(mFlinger.physicalDisplays()));
+ }
+
DisplayDeviceState& mutableDrawingDisplayState() {
return mFlinger.mutableDrawingState().displays.editValueFor(mDisplayToken);
}
@@ -760,7 +768,7 @@
// the `configs` parameter in favor of an alternative setRefreshRateConfigs API.
auto& setDisplayModes(DisplayModes modes, DisplayModeId activeModeId,
std::shared_ptr<scheduler::RefreshRateConfigs> configs = nullptr) {
- mCreationArgs.supportedModes = std::move(modes);
+ mDisplayModes = std::move(modes);
mCreationArgs.activeModeId = activeModeId;
mCreationArgs.refreshRateConfigs = std::move(configs);
return *this;
@@ -806,7 +814,7 @@
sp<DisplayDevice> inject() NO_THREAD_SAFETY_ANALYSIS {
const auto displayId = mCreationArgs.compositionDisplay->getDisplayId();
- auto& modes = mCreationArgs.supportedModes;
+ auto& modes = mDisplayModes;
auto& activeModeId = mCreationArgs.activeModeId;
if (displayId && !mCreationArgs.refreshRateConfigs) {
@@ -834,8 +842,13 @@
}
}
+ sp<DisplayDevice> display = sp<DisplayDevice>::make(mCreationArgs);
+ mFlinger.mutableDisplays().emplace_or_replace(mDisplayToken, display);
+
DisplayDeviceState state;
- if (const auto type = mCreationArgs.connectionType) {
+ state.isSecure = mCreationArgs.isSecure;
+
+ if (mConnectionType) {
LOG_ALWAYS_FATAL_IF(!displayId);
const auto physicalId = PhysicalDisplayId::tryCast(*displayId);
LOG_ALWAYS_FATAL_IF(!physicalId);
@@ -845,29 +858,21 @@
LOG_ALWAYS_FATAL_IF(!activeMode);
state.physical = {.id = *physicalId,
- .type = *type,
.hwcDisplayId = *mHwcDisplayId,
- .deviceProductInfo = {},
- .supportedModes = modes,
.activeMode = activeMode->get()};
- }
- state.isSecure = mCreationArgs.isSecure;
+ const auto it = mFlinger.mutablePhysicalDisplays()
+ .emplace_or_replace(*physicalId, mDisplayToken, *physicalId,
+ *mConnectionType, std::move(modes),
+ std::nullopt)
+ .first;
- sp<DisplayDevice> display = sp<DisplayDevice>::make(mCreationArgs);
- if (!display->isVirtual()) {
- display->setActiveMode(activeModeId);
+ display->setActiveMode(activeModeId, it->second.snapshot());
}
- mFlinger.mutableDisplays().emplace_or_replace(mDisplayToken, display);
mFlinger.mutableCurrentState().displays.add(mDisplayToken, state);
mFlinger.mutableDrawingState().displays.add(mDisplayToken, state);
- if (const auto& physical = state.physical) {
- mFlinger.mutablePhysicalDisplayTokens().emplace_or_replace(physical->id,
- mDisplayToken);
- }
-
return display;
}
@@ -875,6 +880,8 @@
TestableSurfaceFlinger& mFlinger;
sp<BBinder> mDisplayToken = sp<BBinder>::make();
DisplayDeviceCreationArgs mCreationArgs;
+ DisplayModes mDisplayModes;
+ const std::optional<ui::DisplayConnectionType> mConnectionType;
const std::optional<hal::HWDisplayId> mHwcDisplayId;
};