Merge "Make VelocityTracker 1D"
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/libs/binder/Android.bp b/libs/binder/Android.bp
index 246963a..2b88852 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -480,6 +480,9 @@
java: {
enabled: false,
},
+ cpp: {
+ gen_trace: false,
+ },
},
}
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/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/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..f15d871
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
@@ -0,0 +1,279 @@
+/*
+ * 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::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->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/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 5e9fe65..3348cec 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -141,19 +141,20 @@
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",
+ "EffectLayer.cpp",
"Effects/Daltonizer.cpp",
"EventLog/EventLog.cpp",
"FlagManager.cpp",
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..ebaf35a 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;
@@ -187,16 +182,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 +219,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 +248,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 +323,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 +337,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/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cc93db3..ca578e1 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"
@@ -172,6 +174,8 @@
OutputCompositionState::CompositionStrategyPredictionState;
using base::StringAppendF;
+using display::PhysicalDisplay;
+using display::PhysicalDisplays;
using gui::DisplayInfo;
using gui::GameMode;
using gui::IDisplayEventConnection;
@@ -594,12 +598,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 +612,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 +942,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 +966,6 @@
info->density /= ACONFIGURATION_DENSITY_MEDIUM;
info->secure = display->isSecure();
- info->deviceProductInfo = display->getDeviceProductInfo();
info->installOrientation = display->getPhysicalOrientation();
return NO_ERROR;
@@ -967,23 +979,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 +1038,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 +1103,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);
@@ -1159,9 +1178,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 +1213,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 +1236,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 +1261,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;
@@ -1295,15 +1323,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 +1350,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 +1384,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 +1412,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();
}
@@ -2467,7 +2499,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 +2639,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 +2708,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 +2731,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 +2791,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 +2801,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 +2869,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 +3035,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);
@@ -3219,7 +3282,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();
@@ -4718,8 +4781,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");
}
@@ -4732,7 +4799,7 @@
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.
@@ -4991,10 +5058,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 +5870,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 +6744,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 +6776,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 +6791,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 +6968,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);
+ }
}
}
}
@@ -7367,8 +7458,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..2af17e7 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);
@@ -651,7 +652,7 @@
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);
// Calls to setActiveMode on the main thread if there is a pending mode change
@@ -667,6 +668,12 @@
// 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,
@@ -820,6 +827,10 @@
// called when starting, or restarting after system_server death
void initializeDisplays();
+ 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) {
return const_cast<SurfaceFlinger*>(this)->getDisplayDeviceLocked(displayToken);
@@ -867,6 +878,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 +908,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)};
}
/*
@@ -959,21 +990,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.
//
@@ -1063,7 +1089,7 @@
/*
* 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);
@@ -1164,12 +1190,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/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..e546c2f 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -309,16 +309,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>
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..a6b3f7c 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -503,6 +503,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 +516,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 +726,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 +767,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 +813,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 +841,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 +857,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 +879,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;
};